在android usb挂载分析----vold启动,我们的vold模块已经启动了,通信的机制也已经建立起来了,接下来我们分析一下MountService的启动,也就是我们FrameWork层的启动,首先看下其大概流程:
MountService的启动在SystemServer.java中,有如下代码:
- try {
- /*
- * NotificationManagerService is dependant on MountService,
- * (for media / usb notifications) so we must start MountService first.
- */
- Slog.i(TAG, "Mount Service");
- ServiceManager.addService("mount", new MountService(context));
- } catch (Throwable e) {
- Slog.e(TAG, "Failure starting Mount Service", e);
- }
这里new 了一个MountService,并把service添加到了ServiceManager,我们看下MountService的构造函数:
- /**
- * Constructs a new MountService instance
- *
- * @param context Binder context for this service
- */
- public MountService(Context context) {
- mContext = context;
- // XXX: This will go away soon in favor of IMountServiceObserver
- mPms = (PackageManagerService) ServiceManager.getService("package");//获取包管理服务
- mContext.registerReceiver(mBroadcastReceiver,
- new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);//注册广播接收器
- mHandlerThread = new HandlerThread("MountService");//处理消息
- mHandlerThread.start();
- mHandler = new MountServiceHandler(mHandlerThread.getLooper());
- // Add OBB Action Handler to MountService thread.
- mObbActionHandler = new ObbActionHandler(mHandlerThread.getLooper());
- /*
- * Vold does not run in the simulator, so pretend the connector thread
- * ran and did its thing.
- */
- if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
- mReady = true;
- mUmsEnabling = true;
- return;
- }
- /*
- * Create the connection to vold with a maximum queue of twice the
- * amount of containers we'd ever expect to have. This keeps an
- * "asec list" from blocking a thread repeatedly.
- */
- mConnector = new NativeDaemonConnector(this, "vold",
- PackageManagerService.MAX_CONTAINERS * 2, VOLD_TAG);
- mReady = false;
- Thread thread = new Thread(mConnector, VOLD_TAG);
- thread.start();
- }
后面new 了一个NativeDaemonConnector,注意这里传递了一个"vold"字符串,跟我们在vold启动的时候传给CommandListener是一样的。NativeDaemonConnector实现了Runnable接口
接下来调用 thread.start()启动线程,我们看下它的run函数
- public void run() {
- while (true) {
- try {
- listenToSocket();
- } catch (Exception e) {
- Slog.e(TAG, "Error in NativeDaemonConnector", e);
- SystemClock.sleep(5000);
- }
- }
- }
在循环中调用listenToSocket函数,看下这个函数
- private void listenToSocket() throws IOException {
- LocalSocket socket = null;
- try {
- socket = new LocalSocket();
- LocalSocketAddress address = new LocalSocketAddress(mSocket, //这里mSocket=“vold"
- LocalSocketAddress.Namespace.RESERVED); //注意这里的RESERVED
- socket.connect(address); //连接到vold模块监听的套接字处
- mCallbacks.onDaemonConnected(); //实现在MountService中
- InputStream inputStream = socket.getInputStream();
- mOutputStream = socket.getOutputStream();
- 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);
- if (LOCAL_LOGD) Slog.d(TAG, String.format("RCV <- {%s}", event));
- String[] tokens = event.split(" ");
- try {
- int code = Integer.parseInt(tokens[0]);
- if (code >= ResponseCode.UnsolicitedInformational) {
- try {
- if (!mCallbacks.onEvent(code, event, tokens)) {//实现在MountService中
- Slog.w(TAG, String.format(
- "Unhandled event (%s)", event));
- }
- } catch (Exception ex) {
- Slog.e(TAG, String.format(
- "Error handling '%s'", event), ex);
- }
- }
- 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 (this) {
- 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);
- }
- }
- }
onDaemonConnected的实现在MountServices中,将向下下发volume list消息 获取到了磁盘的标签,挂载点与状态,调用connect函数连接到vold模块,connetc最终调用native函数connectLocal(
system/core/libcutils/socket_local_client.c)进行连接工作,我们看下他的jni层代码,最后调用的:
- int socket_local_client_connect(int fd, const char *name, int namespaceId,
- int type)
- {
- struct sockaddr_un addr;
- socklen_t alen;
- size_t namelen;
- int err;
- err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen);
- if (err < 0) {
- goto error;
- }
- if(connect(fd, (struct sockaddr *) &addr, alen) < 0) {
- goto error;
- }
- return fd;
- error:
- return -1;
- }
- /**
- * connect to peer named "name"
- * returns fd or -1 on error
- */
我们再跟进socket_make_sockaddr_un函数,这时namespaceId传的ANDROID_SOCKET_NAMESPACE_RESERVED,所以会执行下面几句:
- case ANDROID_SOCKET_NAMESPACE_RESERVED:
- namelen = strlen(name) + strlen(ANDROID_RESERVED_SOCKET_PREFIX);
- /* unix_path_max appears to be missing on linux */
- if (namelen > sizeof(*p_addr)
- - offsetof(struct sockaddr_un, sun_path) - 1) {
- goto error;
- }
- strcpy(p_addr->sun_path, ANDROID_RESERVED_SOCKET_PREFIX); // ANDROID_RESERVED_SOCKET_PREFIX="/dev/socket/"
- strcat(p_addr->sun_path, name);
- break;
注意在前面 connect 函数中的套接字的构造,使用了AF_LOCAL:
- int socket_local_client(const char *name, int namespaceId, int type)
- {
- int s;
- s = socket(<span style="color:#ff0000;">AF_LOCAL</span>, type, 0);
- if(s < 0) return -1;
- if ( 0 > socket_local_client_connect(s, name, namespaceId, type)) {
- close(s);
- return -1;
- }
- return s;
- }
这样,就建立了一条从FrameWork层到vold层的通信链路,后面FrameWork层就等待Vold发送消息过来了。。。
FrameWork层的通信也ok了,就可以等待U盘挂载了。。