Android SDCard UnMounted 流程分析(三)
6043 点击·0 回帖
![]() | ![]() | |
![]() | 讲到SDCard unmout onEvent 发送socket 到框架层,接下来分析框架层得到数据后的流程。 MoutService 当Android 系统启动时,system将MountService 添加到启动服务里面,而MountService 会开启一个线程来运行NativeDaemonConnector,由它来监听vold的消息,代码: mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG); mReady = false; Thread thread = new Thread(mConnector, VOLD_TAG); thread.start(); 该函数运行在MountService的构造函数里面,而NativeDaemonConnector 本身就是继承自Runnable。 NativeDaemonConnector Framework与vold 的通信是通过socket来实现的,不过该socket 由 Android做了一个封装,LocalSocket 实现的socket功能。 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实现的。 关于socket 内部如何通信,这个不是我们所关心的内容,因为如果要深入进去估计没完没了,有兴趣的朋友可以参考源码进入SocketListener查看: 建立连接 SocketListener::SocketListener 当main初始化CommandListener 后,会为socketName 传入一个叫vold 的字符串 SocketListener:tartListener 等待并接收连接请求 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--->listenToSockettart")); 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 == 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 进行判断,然后再下发执行命令。 粗糙图 最后附一张比较粗糙的结构图,时间较急,没仔细画好 ![]() | |
![]() | ![]() |