長按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)。

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