在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进行连接工作,我们看下他的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(AF_LOCAL, 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盘挂载了。。