前篇地址
前一篇講到SDCard unmout onEvent 發送socket 到框架層,接下來分析框架層獲得數據後的流程。html
MoutServicejava
當android 系統啓動時,system將MountService 添加到啓動服務裏面,而MountService 會開啓一個線程來運行NativeDaemonConnector,由它來監聽vold的消息,代碼:android
mConnector =
new NativeDaemonConnector(
this,
"
vold
", MAX_CONTAINERS *
2, VOLD_TAG);
mReady =
false;
Thread thread =
new Thread(mConnector, VOLD_TAG);
thread.start();
該函數運行在MountService的構造函數裏面,而NativeDaemonConnector 自己就是繼承自Runnable。框架
NativeDaemonConnectorsocket
Framework與vold 的通訊是經過socket來實現的,不過該socket 由 android作了一個封裝,LocalSocket 實現的socket功能。ide
NativeDaecomConnector 位於framework/base/service/java/com/android/server目錄下, 監聽vold 的消息代碼在繼承自Runnable對象的run方法裏面 :函數
@Override
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實現的。oop
關於socket 內部如何通訊,這個不是咱們所關心的內容,由於若是要深刻進去估計沒完沒了,有興趣的朋友能夠參考源碼進入SocketListener查看:this
創建鏈接 spa
SocketListener::SocketListener
當main初始化CommandListener 後,會爲socketName 傳入一個叫vold 的字符串
SocketListener::startListener
等待並接收鏈接請求
SocketListener::runListener
得到命令參數
bool FrameworkListener::onDataAvailable
dispatchCommand 到相應的命令類,並返回一部分消息給上層
FrameworkListener::dispatchCommand
再回過頭看NativeDaemonConnector 的listenToSocket,代碼中實例化了一個LocalSocketAddress的實例,並傳入一個叫"vold"字符串的socket 名稱,這與CommandListener中繼承了FrameworkListener時給的"vold"名稱是一致的,兩個socket名稱一致則能夠互相進行通信了,代碼以下:
private
void listenToSocket() throws IOException {
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 的狀態傳遞進去。代碼以下:
public boolean handleMessage(Message msg) {
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改變的廣播,代碼以下:
else
if (code == VoldResponseCode.VolumeBadRemoval) {
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看該函數裏的主要代碼:
synchronized (mListeners) {
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 經過這個廣播發送出去,代碼以下:
private
void sendStorageIntent(String action, String path) {
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 函數,代碼以下:
if (code == VoldResponseCode.VolumeStateChange) {
/*
* 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 方法裏面:
else
if (!strcmp(argv[
1],
"
unmount
")) {
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 進行判斷,而後再下發執行命令。
粗糙圖
最後附一張比較粗糙的結構圖,時間較急,沒仔細畫好