Android熱插拔事件處理詳解
阿新 • • 發佈:2019-01-28
整個過程從Kernel檢測到SD卡插入事件開始,之前的一些硬體中斷的觸發以及driver的載入這裡並不敘述,一直到SD卡掛載訊息更新到“Android——系統設定——儲存”一項中。
1. Kernel發出SD卡插入uevent。
2. NetlinkHandler::onEvent()接收核心發出的uevent並進行解析。
3. VolumeManager::handlBlockEvent()處理經過第二步處理後的事件。
4. 接下來呼叫DirectVolume:: handleBlockEvent()。
在該方法中主要有兩點需要注意:
第一,程式首先會遍歷mPath容器,尋找與event對應的sysfs_path是否存在與mPath容器中。
第二,針對event中的action有4種處理方式:Add,Removed,Change,Noaction 。
例如:在Add action中會有如下操作(因為我們這裡所講的是SD卡的掛載流程,因此以Add來說明),首先建立裝置節點,其次對disk和partition兩種格式的裝置分別進行處理。SD卡屬於disk型別。
5. 經過上一步之後會呼叫DirectVolume::handleDiskAdded()方法,在該方法中會廣播disk insert訊息。
6. SocketListener::runListener會接收DirectVolume::handleDiskAdded()廣播的訊息。該方法主要完成對event中資料的獲取,通過Socket。(PS:這裡的SocketListener.cpp位於Android原始碼/system/core/libsysutils/src/中,後文的FramworkListener.cpp也是,之前自己找了很久 T_T)
7. 呼叫FrameworkListener::onDataAvailable()方法處理接收到的訊息內容。
8. FrameworkListener::dispatchCommand()該方法用於分發指令。
9. 在FrameworkListener::dispatchCommand()方法中,通過runCommand()方法去呼叫相應的指令。
10. 在/system/vold/CommandListener.cpp中有runCommand()的具體實現。在該類中可以找到這個方法:CommandListener::VolumeCmd::runCommand(),從字面意思上來看這個方法就是對Volume分發指令的解析。該方法中會執行“mount”函式:vm->mountVolume(arg[2])。
11. mountVolume(arg[2])在VolumeManager::mountVolume()中實現,在該方法中呼叫v->mountVol()。
12. mountVol()方法在Volume::mountVol()中實現,該函式是真正的掛載函式。(在該方法中,後續的處理都在該方法中,在Mount過程中會廣播相應的訊息給上層,通過setState()函式。)
13. setState(Volume::Checking);廣播給上層,正在檢查SD卡,為掛載做準備。
14. Fat::check();SD卡檢查方法,檢查SD卡是否是FAT格式。
15. Fat::doMount()掛載SD卡。
至此,SD的掛載已算初步完成,接下來應該將SD卡掛載後的訊息傳送給上層,在13中也提到過,在掛載以及檢查的過程中其實也有傳送訊息給上層的。
16. MountService的建構函式中會開啟監聽執行緒,用於監聽來自vold的socket資訊。
Thread thread = new Thread(mConnector,VOLD_TAG); thread.start();
17. mConnector是NativeDaemonConnector的物件,NativeDaemonConnector繼承了Runnable並Override了run方法。在run方法中通過一個while(true)呼叫ListenToSocket()方法來實現實時監聽。
18. 在ListenToSocket()中,首先建立與Vold通訊的Socket Server端,然後呼叫MountService中的onDaemonConnected()方法。(PS:Java與Native通訊可以通過JNI,那麼Native與Java通訊就需要通過Socket來實現了。Android中Native與Frameworks通訊 這篇文章中有簡介,感興趣的朋友可以參考一下)
19. onDaemonConnected()方法是在介面INativeDaemonConnectorCallbacks中定義的,MountService實現了該介面並Override了onDaemonConnected()方法。該方法開啟一個執行緒用於更新外接儲存裝置的狀態,主要更新狀態的方法也在其中實現。
20. 然後回到ListenToSocket中,通過inputStream來獲取Vold傳遞來的event,並存放在佇列中。
21. 然後這些event會在onDaemonConnected()通過佇列的”佇列.take()”方法取出。並根據不同的event呼叫updatePublicVolumeState()方法,在該方法中呼叫packageManagerService中的updateExteralState()方法來更新儲存裝置的狀態。(注:這裡不太理解packageManagerService中的unloadAllContainers(args)方法)
22. 更新是通過packageHelper.getMountService().finishMediaUpdate()方法來實現的。
23. 在updatePublicVolumeState()方法中,更新後會執行如下程式碼:
bl.mListener.onStorageStateChanged();
在Android原始碼/packages/apps/Settings/src/com.android.settings.deviceinfo/Memory.java程式碼中,實現了StorageEventListener 的匿名內部類,並Override了onStorageStateChanged();方法。因此在updatePublicVolumeState()中呼叫onStorageStateChanged();方法後,Memory.java中也會收到。在Memory.java中收到以後會在Setting介面進行更新,系統設定——儲存中會更新SD卡的狀態。從而SD卡的掛載從底層到達了上層。
1. Kernel發出SD卡插入uevent。
2. NetlinkHandler::onEvent()接收核心發出的uevent並進行解析。
3. VolumeManager::handlBlockEvent()處理經過第二步處理後的事件。
4. 接下來呼叫DirectVolume:: handleBlockEvent()。
在該方法中主要有兩點需要注意:
第一,程式首先會遍歷mPath容器,尋找與event對應的sysfs_path是否存在與mPath容器中。
第二,針對event中的action有4種處理方式:Add,Removed,Change,Noaction 。
例如:在Add action中會有如下操作(因為我們這裡所講的是SD卡的掛載流程,因此以Add來說明),首先建立裝置節點,其次對disk和partition兩種格式的裝置分別進行處理。SD卡屬於disk型別。
5. 經過上一步之後會呼叫DirectVolume::handleDiskAdded()方法,在該方法中會廣播disk insert訊息。
6. SocketListener::runListener會接收DirectVolume::handleDiskAdded()廣播的訊息。該方法主要完成對event中資料的獲取,通過Socket。(PS:這裡的SocketListener.cpp位於Android原始碼/system/core/libsysutils/src/中,後文的FramworkListener.cpp也是,之前自己找了很久 T_T)
7. 呼叫FrameworkListener::onDataAvailable()方法處理接收到的訊息內容。
8. FrameworkListener::dispatchCommand()該方法用於分發指令。
9. 在FrameworkListener::dispatchCommand()方法中,通過runCommand()方法去呼叫相應的指令。
10. 在/system/vold/CommandListener.cpp中有runCommand()的具體實現。在該類中可以找到這個方法:CommandListener::VolumeCmd::runCommand(),從字面意思上來看這個方法就是對Volume分發指令的解析。該方法中會執行“mount”函式:vm->mountVolume(arg[2])。
11. mountVolume(arg[2])在VolumeManager::mountVolume()中實現,在該方法中呼叫v->mountVol()。
12. mountVol()方法在Volume::mountVol()中實現,該函式是真正的掛載函式。(在該方法中,後續的處理都在該方法中,在Mount過程中會廣播相應的訊息給上層,通過setState()函式。)
13. setState(Volume::Checking);廣播給上層,正在檢查SD卡,為掛載做準備。
14. Fat::check();SD卡檢查方法,檢查SD卡是否是FAT格式。
15. Fat::doMount()掛載SD卡。
至此,SD的掛載已算初步完成,接下來應該將SD卡掛載後的訊息傳送給上層,在13中也提到過,在掛載以及檢查的過程中其實也有傳送訊息給上層的。
16. MountService的建構函式中會開啟監聽執行緒,用於監聽來自vold的socket資訊。
Thread thread = new Thread(mConnector,VOLD_TAG); thread.start();
17. mConnector是NativeDaemonConnector的物件,NativeDaemonConnector繼承了Runnable並Override了run方法。在run方法中通過一個while(true)呼叫ListenToSocket()方法來實現實時監聽。
18. 在ListenToSocket()中,首先建立與Vold通訊的Socket Server端,然後呼叫MountService中的onDaemonConnected()方法。(PS:Java與Native通訊可以通過JNI,那麼Native與Java通訊就需要通過Socket來實現了。Android中Native與Frameworks通訊 這篇文章中有簡介,感興趣的朋友可以參考一下)
19. onDaemonConnected()方法是在介面INativeDaemonConnectorCallbacks中定義的,MountService實現了該介面並Override了onDaemonConnected()方法。該方法開啟一個執行緒用於更新外接儲存裝置的狀態,主要更新狀態的方法也在其中實現。
20. 然後回到ListenToSocket中,通過inputStream來獲取Vold傳遞來的event,並存放在佇列中。
21. 然後這些event會在onDaemonConnected()通過佇列的”佇列.take()”方法取出。並根據不同的event呼叫updatePublicVolumeState()方法,在該方法中呼叫packageManagerService中的updateExteralState()方法來更新儲存裝置的狀態。(注:這裡不太理解packageManagerService中的unloadAllContainers(args)方法)
22. 更新是通過packageHelper.getMountService().finishMediaUpdate()方法來實現的。
23. 在updatePublicVolumeState()方法中,更新後會執行如下程式碼:
bl.mListener.onStorageStateChanged();
在Android原始碼/packages/apps/Settings/src/com.android.settings.deviceinfo/Memory.java程式碼中,實現了StorageEventListener 的匿名內部類,並Override了onStorageStateChanged();方法。因此在updatePublicVolumeState()中呼叫onStorageStateChanged();方法後,Memory.java中也會收到。在Memory.java中收到以後會在Setting介面進行更新,系統設定——儲存中會更新SD卡的狀態。從而SD卡的掛載從底層到達了上層。