前篇地址
Android SDCard UnMounted 流程分析(一)
Android SDCard UnMounted 流程分析(二)
前一篇講到SDCard unmout onEvent 發送socket 到框架層,接下來分析框架層得到數據后的流程。
MoutService
當android 系統啟動時,system將MountService 添加到啟動服務里面,而MountService 會開啟一個線程來運行NativeDaemonConnector,由它來監聽vold的消息,代碼:
mReady = false;
Thread thread = new Thread(mConnector, VOLD_TAG);
thread.start();
該函數運行在MountService的構造函數里面,而NativeDaemonConnector 本身就是繼承自Runnable。
NativeDaemonConnectorFramework與vold 的通信是通過socket來實現的,不過該socket 由 android做了一個封裝,LocalSocket 實現的socket功能。
NativeDaecomConnector 位於framework/base/service/java/com/android/server目錄下, 監聽vold 的消息代碼在繼承自Runnable對象的run方法里面 :
public void run() {
HandlerThread thread = new HandlerThread(TAG + " .CallbackHandler ");
thread.start();
mCallbackHandler = new Handler(thread.getLooper(), this);
while ( true) {
try {
listenToSocket();
} catch (Exception e) {
Slog.e(TAG, " Error in NativeDaemonConnector ", e);
SystemClock.sleep( 5000);
}
}
}
NativeDaemonConnector 類實例化了一個LocalSocket來與vold 通信。LocalSocket 里面有一個類LocalSocketImpl,該類部分是通過JNI實現的。
關於socket 內部如何通信,這個不是我們所關心的內容,因為如果要深入進去估計沒完沒了,有興趣的朋友可以參考源碼進入SocketListener查看:
建立連接
SocketListener::SocketListener
當main初始化CommandListener 后,會為socketName 傳入一個叫vold 的字符串
SocketListener::startListener
再回過頭看NativeDaemonConnector 的listenToSocket,代碼中實例化了一個LocalSocketAddress的實例,並傳入一個叫"vold"字符串的socket 名稱,這與CommandListener中繼承了FrameworkListener時給的"vold"名稱是一致的,兩個socket名稱一致則可以互相進行通訊了,代碼如下:
LocalSocket socket = null;
Slog.w(TAG,String.format( " NativeDaemonConnector--->listenToSocket:start "));
try {
socket = new LocalSocket();
LocalSocketAddress address = new LocalSocketAddress(mSocket,
LocalSocketAddress.Namespace.RESERVED);
socket.connect(address);
InputStream inputStream = socket.getInputStream();
mOutputStream = socket.getOutputStream();
mCallbacks.onDaemonConnected();
byte[] buffer = new byte[BUFFER_SIZE];
int start = 0;
while ( true) {
int count = inputStream.read(buffer, start, BUFFER_SIZE - start);
if (count < 0) break;
// Add our starting point to the count and reset the start.
count += start;
start = 0;
for ( int i = 0; i < count; i++) {
if (buffer[i] == 0) {
String event = new String(buffer, start, i - start);//解析socket 的數據並獲取event
if (LOCAL_LOGD) Slog.d(TAG, String.format( " RCV <- {%s} ", event));
String[] tokens = event.split( " ", 2);
try {
int code = Integer.parseInt(tokens[ 0]);
if (code >= ResponseCode.UnsolicitedInformational) {
mCallbackHandler.sendMessage(
mCallbackHandler.obtainMessage(code, event));//發送消息給handler
} else {
try {
mResponseQueue.put( event);
} catch (InterruptedException ex) {
Slog.e(TAG, " Failed to put response onto queue ", ex);
}
}
} catch (NumberFormatException nfe) {
Slog.w(TAG, String.format( " Bad msg (%s) ", event));
}
start = i + 1;
}
}
// We should end at the amount we read. If not, compact then
// buffer and read again.
if (start != count) {
final int remaining = BUFFER_SIZE - start;
System.arraycopy(buffer, start, buffer, 0, remaining);
start = remaining;
} else {
start = 0;
}
}
} catch (IOException ex) {
Slog.e(TAG, " Communications error ", ex);
throw ex;
} finally {
synchronized (mDaemonLock) {
if (mOutputStream != null) {
try {
mOutputStream.close();
} catch (IOException e) {
Slog.w(TAG, " Failed closing output stream ", e);
}
mOutputStream = null;
}
}
try {
if (socket != null) {
socket.close();
}
} catch (IOException ex) {
Slog.w(TAG, " Failed closing socket ", ex);
}
}
}
上面代碼,通過socket 並event 解析出來,並通handler 發送到handleMessage 中,當handleMessage接收到傳過來的消息時,會調用MountService 的onEvent 方法將code和event和sdcard 的狀態傳遞進去。代碼如下:
String event = (String) msg.obj;
Slog.w(TAG,String.format( " NativeDaemonConnector--->handleMessage the event value is "+ event));
try {
if (! mCallbacks.onEvent(msg.what, event, event.split(" "))) {
Slog.w(TAG, String.format(
" Unhandled event '%s' ", event));
}
} catch (Exception e) {
Slog.e(TAG, String.format(
" Error handling '%s' ", event), e);
}
return true;
}
又回到MountService ,在onEvent里面當接收到的code ==VoldResponseCode.VolumeBadRemoval時會調用updatePublicVolumeState,發送unmount改變的廣播,代碼如下:
if (DEBUG_EVENTS) Slog.i(TAG, " Sending unmounted event first ");
/* Send the media unmounted event first */
updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
action = Intent.ACTION_MEDIA_UNMOUNTED;
if (DEBUG_EVENTS) Slog.i(TAG, " Sending media bad removal ");
updatePublicVolumeState(path, Environment.MEDIA_BAD_REMOVAL);
action = Intent.ACTION_MEDIA_BAD_REMOVAL;}
到這里,進入updatePublicVolumeState看該函數里的主要代碼:
for ( int i = mListeners.size() - 1; i >= 0; i--) {
MountServiceBinderListener bl = mListeners. get(i);
try {
Slog.w(TAG, " MountService--->updatePublicVolumeState-->bl.mListener.onStorageStateChanged ");
bl.mListener.onStorageStateChanged(path, oldState, state);
} catch (RemoteException rex) {
Slog.e(TAG, " Listener dead ");
mListeners.remove(i);
} catch (Exception ex) {
Slog.e(TAG, " Listener failed ", ex);
}
}
}
}
並且調用sendStorageIntent 方法將SDCard的Action:android.intent.action.MEDIA_BAD_REMOVAL 和dat:file:///mnt/sdcard 通過這個廣播發送出去,代碼如下:
Intent intent = new Intent(action, Uri.parse( " file:// " + path));
// add StorageVolume extra
intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, mVolumeMap. get(path));
Slog.d(TAG, " sendStorageIntent " + intent);
mContext.sendBroadcast(intent);
}
再回到 updatePublicVolumeState ,調用了stateChange 后,將狀態為632的標識發送到NativeDaemonConnector 的handlemessage,當NativeDaemonConnector 發現SDCard的狀態發送改變時,比如unmount 的時候,從632(VolumeBadRemoval)變到605(VolumeStateChange)到onEvent,當onEvent再次得到請求時,進入判斷會直接執行notifyVolumeStateChange 函數,代碼如下:
/*
* One of the volumes we're managing has changed state.
* Format: "NNN Volume <label> <path> state changed
* from <old_#> (<old_str>) to <new_#> (<new_str>)"
*/
notifyVolumeStateChange(
cooked[ 2], cooked[ 3], Integer.parseInt(cooked[ 7]),
Integer.parseInt(cooked[ 10]));
}
notifyStateChange 會調用updatePublicVolumeState通知packageManger SDCard己經unmount.
再回到Vold
由於vold 啟動文件一開始就啟動了CommandListener的runcommand由於socket 一直在通訊,當發現值改變后,進入以下代碼runCommand 方法里面:
if (argc < 3 || argc > 4 ||
((argc == 4 && strcmp(argv[ 3], " force ")) &&
(argc == 4 && strcmp(argv[ 3], " force_and_revert ")))) {
cli->sendMsg(ResponseCode::CommandSyntaxError, " Usage: volume unmount <path> [force|force_and_revert] ", false);
return 0;
}
bool force = false;
bool revert = false;
if (argc >= 4 && !strcmp(argv[ 3], " force ")) {
force = true;
} else if (argc >= 4 && !strcmp(argv[ 3], " force_and_revert ")) {
force = true;
revert = true;
}
rc = vm->unmountVolume(argv[ 2], force, revert);
}
這時調用VolumeManage的unmoutVolume。該方法來源於Volume 的unmountVol,調用這個函數會unmount 三個掛載點,並同時調用setState通知框架unmount 成功,可以改變UI等一系列動作。
最后總結
MountService: 實現用於管理存儲設備的后台服務
StorageManage:訪問MountService 接口,並向應用層提供接口
PackageMangeService:是用於管理系統中所有apk,當SDCard發生變化時,向應用層發送消息
NativeDaemonConnector:創建socket實現mountservice 和vold 的通信
可以這么說:當vold 捕獲到uevent 事件,會將事件消息通知framework,framework 進行判斷,然后再下發執行命令。
粗糙圖
最后附一張比較粗糙的結構圖,時間較急,沒仔細畫好