长按Power键关机从Framework到Kernel

InputEvent那部分就先不说了,因为是个很复杂的系统,估计三天三夜也说不清楚,会有相关文档说明的,这里就从中间层接收Key消息开始…

Framework层:

PhoneWindowManager.java

在interceptKeyBeforeQueueing函数有这样代码片段:
这里写图片描述

其中调用了interceptPowerKeyDown()函数:
这里写图片描述

第一个参数是一个线程,而第二个参数是时间,目前是0.5秒;下面看一个参数的定义:
这里写图片描述

获取长按power键的行为,我们这里是LONG_PRESS_POWER_SHUT_OFF,具体定义参考如下:
这里写图片描述

真正配置如下:
这里写图片描述

再回到mPowerLongPress定义,调用了函数:
mWindowManagerFuncs.shutdown()函数,下面就分析mWindowManagerFuncs的来龙去脉,要不然就找不到调用了谁的shutdown,解牛开始……

SystemServer.java
启动服务:WindowManagerService
这里写图片描述

WindowManagerService.java
进入main函数:
这里写图片描述

在WindowManagerService构造函数里面调用了initPolicy函数:
这里写图片描述

initPolicy函数原型如下:
这里写图片描述

分析到最后,你会发现调用的init函数其实是调用了PhoneWindowManager的init函数;

看00827行,那mPolicy又在哪里初始化的呢?
这里写图片描述

继续跟踪makeNewWindowManager函数:
这里写图片描述

请看0066行,再回到行0040,再看0032行,逻辑很清楚,最终调用到Policy类的函数:makeNewWindowManager();
Policy.java
这里写图片描述

可以看到Policy类继承了一个接口类IPolicy,直接new 了一个PhoneWindowManager();到这里很清楚的知道一件事情,上面第四页的mPolicy.init()其实等价于PhoneWindowManager.init()函数;

再回到PhoneWindowManager.java
这里写图片描述

终于看到行00868mWindowManagerFuncs的初始化了,而这个变量初始化是init函数的一个参数传递进来的,回头看看就不难发现,传递进来的参数原来是:WindowManagerService.this;所以最初的语句:
mWindowManagerFuncs.shutdown()->
WindowManagerService.this.shutdown()->

WindowManagerService.java
进入shutdown()函数:
这里写图片描述

ShutdownThread.java
这里写图片描述

在函数shutdownInner()函数里调用了这个函数:
这里写图片描述

函数beginShutDownSequence()有这样一行代码片段:
这里写图片描述

在线程run函数里面有这样一行代码:
这里写图片描述

原函数如下:
这里写图片描述

PowerManagerService.java
这里写图片描述

com_android_server_power_PowerManagerService.cpp
进入JNI
这里写图片描述

Android_reboot.c
这里写图片描述

Reboot.c
这里写图片描述

__reboot.s
这里写图片描述
这里写图片描述

从.java->.cpp->.c->.s是不是越来越底层啊,既然谈到底层,那就进入Kernel世界吧……

Kernel层:

__reboot通过syscall来到内核
这里写图片描述

先看看sys_reboot函数的定义:
这里写图片描述
与__reboot的调用参数一致。

而通过仔细查找,发现一个很有趣的函数,其定义为SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, void __user *, arg),对比__reboot的参数,能够符合。究竟是不是这个函数?
同样在include/linux/ 文件中,能够找到这样几个定义:
这里写图片描述

这样就不难看出,SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, void __user *, arg)就是sys_reboot,也就是上层调用的__reboot的最终实现。函数实现如下:
这里写图片描述
这里写图片描述

行00423会检测权限问题,只有超级用户才可以执行重启系统的操作;否则将返回权限错误。对应的权限列表在include/linux/capability.h中,重启操作为22。
这里写图片描述

行00427随后对magic number进行了校验;如果数据传输过程中没有发生错误的话,这里也当然不会有问题,所以只是一个安全性校验,基本不会发生错误。
之后有一个很有趣的检查,如果用户要求关机,而pm_power_off为空的话,就把用户的关机命令转换为挂起(00437),他的定义如下:
这里写图片描述

好的,只是一个函数指针,而且做了全局操作,整个kernel都可以调用它。以RK3188为例,在arch/arm/mach-rk3188/board-rk3188-h9.c中对这个函数指针进行了赋值:
这里写图片描述

msm_pm_power_off的具体实现就不再跟踪了,各家的都不一样,跟下去没有太大意义。现在只要知道,我分析的这个kernel是给了这个函数指针赋值的,所以不为空,关机命令将正常执行。
接下来就是这个函数的正题了,对用户命令进行解析操作,同时这个过程是用reboot_mutex互斥锁来进行保护的,以保证同一时间只可能有一个解析过程,避免冲突。

下边贴出所有关机重启相关的命令定义:
这里写图片描述

注释中的说明很详细了,比较陌生的就是关于CAD,其实就是用来想用Ctrl+Alt+Del操作的;然后SW_SYSPEND是软件休眠;KEXEC就太高端了,属于内核的一个补丁,用来利用老内核重启,详细资料:http://www.ibm.com/developerworks/cn/linux/l-kexec/?ca=dwcn-newsletter-linux
以上这些只有前六个命令被Android系统所使用,为什么这么说,可以去看bionic/libc/include/sys/reboot.h,上边已经贴出了。最终的最终,能够用到的就只有三个:
POWER_OFF
RESTART
RESTART2
重启调用的是kernel_restart,区别是参数是不是空,关机则调用kernel_power_off(),这里只分析关机,重启就自己分析,这里不做讲解了;

sys.c
这里写图片描述
这里写图片描述

这里调用了pm_power_off,在前面就已经初始化好了,回头看看就知道了。重启就自己分析:
void kernel_restart(char *cmd)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章