android usb挂载分析---MountService启动

 

android usb挂载分析---MountService启动

分类: android框架 u盘挂载

android usb挂载分析----vold启动,我们的vold模块已经启动了,通信的机制也已经建立起来了,接下来我们分析一下MountService的启动,也就是我们FrameWork层的启动,首先看下其大概流程:

 

MountService的启动在SystemServer.java中,有如下代码:

 

  1. try {  
  2.                /* 
  3.                 * NotificationManagerService is dependant on MountService, 
  4.                 * (for media / usb notifications) so we must start MountService first. 
  5.                 */  
  6.                Slog.i(TAG, "Mount Service");  
  7.                ServiceManager.addService("mount", new MountService(context));  
  8.            } catch (Throwable e) {  
  9.                Slog.e(TAG, "Failure starting Mount Service", e);  
  10.            }  
这里new 了一个MountService,并把service添加到了ServiceManager,我们看下MountService的构造函数:

 

  1. /** 
  2.  * Constructs a new MountService instance 
  3.  * 
  4.  * @param context  Binder context for this service 
  5.  */  
  6. public MountService(Context context) {  
  7.     mContext = context;  
  8.   
  9.     // XXX: This will go away soon in favor of IMountServiceObserver  
  10.     mPms = (PackageManagerService) ServiceManager.getService("package");//获取包管理服务  
  11.   
  12.     mContext.registerReceiver(mBroadcastReceiver,  
  13.             new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);//注册广播接收器  
  14.   
  15.     mHandlerThread = new HandlerThread("MountService");//处理消息  
  16.     mHandlerThread.start();  
  17.     mHandler = new MountServiceHandler(mHandlerThread.getLooper());  
  18.   
  19.     // Add OBB Action Handler to MountService thread.  
  20.     mObbActionHandler = new ObbActionHandler(mHandlerThread.getLooper());  
  21.   
  22.     /* 
  23.      * Vold does not run in the simulator, so pretend the connector thread 
  24.      * ran and did its thing. 
  25.      */  
  26.     if ("simulator".equals(SystemProperties.get("ro.product.device"))) {  
  27.         mReady = true;  
  28.         mUmsEnabling = true;  
  29.         return;  
  30.     }  
  31.   
  32.     /* 
  33.      * Create the connection to vold with a maximum queue of twice the 
  34.      * amount of containers we'd ever expect to have. This keeps an 
  35.      * "asec list" from blocking a thread repeatedly. 
  36.      */  
  37.     mConnector = new NativeDaemonConnector(this, "vold",  
  38.             PackageManagerService.MAX_CONTAINERS * 2, VOLD_TAG);  
  39.     mReady = false;  
  40.     Thread thread = new Thread(mConnector, VOLD_TAG);  
  41.     thread.start();  
  42. }  
后面new 了一个NativeDaemonConnector,注意这里传递了一个"vold"字符串,跟我们在vold启动的时候传给CommandListener是一样的。NativeDaemonConnector实现了Runnable接口

 

接下来调用 thread.start()启动线程,我们看下它的run函数

 

  1. public void run() {  
  2.   
  3.         while (true) {  
  4.             try {  
  5.                 listenToSocket();  
  6.             } catch (Exception e) {  
  7.                 Slog.e(TAG, "Error in NativeDaemonConnector", e);  
  8.                 SystemClock.sleep(5000);  
  9.             }  
  10.         }  
  11.     }  
在循环中调用listenToSocket函数,看下这个函数

 

 

  1. private void listenToSocket() throws IOException {  
  2.     LocalSocket socket = null;  
  3.   
  4.     try {  
  5.         socket = new LocalSocket();  
  6.         LocalSocketAddress address = new LocalSocketAddress(mSocket,   //这里mSocket=“vold"  
  7.                 LocalSocketAddress.Namespace.RESERVED);              //注意这里的RESERVED  
  8.   
  9.         socket.connect(address);              //连接到vold模块监听的套接字处  
  10.         mCallbacks.onDaemonConnected();       //实现在MountService中  
  11.   
  12.         InputStream inputStream = socket.getInputStream();  
  13.         mOutputStream = socket.getOutputStream();  
  14.   
  15.         byte[] buffer = new byte[BUFFER_SIZE];  
  16.         int start = 0;  
  17.   
  18.         while (true) {  
  19.             int count = inputStream.read(buffer, start, BUFFER_SIZE - start); //读取消息  
  20.             if (count < 0) break;  
  21.   
  22.             // Add our starting point to the count and reset the start.  
  23.             count += start;  
  24.             start = 0;  
  25.   
  26.             for (int i = 0; i < count; i++) {  
  27.                 if (buffer[i] == 0) {  
  28.                     String event = new String(buffer, start, i - start);  
  29.                     if (LOCAL_LOGD) Slog.d(TAG, String.format("RCV <- {%s}", event));  
  30.   
  31.                     String[] tokens = event.split(" ");  
  32.                     try {  
  33.                         int code = Integer.parseInt(tokens[0]);  
  34.   
  35.                         if (code >= ResponseCode.UnsolicitedInformational) {  
  36.                             try {  
  37.                                 if (!mCallbacks.onEvent(code, event, tokens)) {//实现在MountService中  
  38.                                     Slog.w(TAG, String.format(  
  39.                                             "Unhandled event (%s)", event));  
  40.                                 }  
  41.                             } catch (Exception ex) {  
  42.                                 Slog.e(TAG, String.format(  
  43.                                         "Error handling '%s'", event), ex);  
  44.                             }  
  45.                         }  
  46.                         try {  
  47.                             mResponseQueue.put(event);  
  48.                         } catch (InterruptedException ex) {  
  49.                             Slog.e(TAG, "Failed to put response onto queue", ex);  
  50.                         }  
  51.                     } catch (NumberFormatException nfe) {  
  52.                         Slog.w(TAG, String.format("Bad msg (%s)", event));  
  53.                     }  
  54.                     start = i + 1;  
  55.                 }  
  56.             }  
  57.   
  58.             // We should end at the amount we read. If not, compact then  
  59.             // buffer and read again.  
  60.             if (start != count) {  
  61.                 final int remaining = BUFFER_SIZE - start;  
  62.                 System.arraycopy(buffer, start, buffer, 0, remaining);  
  63.                 start = remaining;  
  64.             } else {  
  65.                 start = 0;  
  66.             }  
  67.         }  
  68.     } catch (IOException ex) {  
  69.         Slog.e(TAG, "Communications error", ex);  
  70.         throw ex;  
  71.     } finally {  
  72.         synchronized (this) {  
  73.             if (mOutputStream != null) {  
  74.                 try {  
  75.                     mOutputStream.close();  
  76.                 } catch (IOException e) {  
  77.                     Slog.w(TAG, "Failed closing output stream", e);  
  78.                 }  
  79.                 mOutputStream = null;  
  80.             }  
  81.         }  
  82.   
  83.         try {  
  84.             if (socket != null) {  
  85.                 socket.close();  
  86.             }  
  87.         } catch (IOException ex) {  
  88.             Slog.w(TAG, "Failed closing socket", ex);  
  89.         }  
  90.     }  
  91. }  

onDaemonConnected的实现在MountServices中,将向下下发volume list消息 获取到了磁盘的标签,挂载点与状态,调用connect函数连接到vold模块,connetc最终调用native函数connectLocal(

system/core/libcutils/socket_local_client.c)进行连接工作,我们看下他的jni层代码,最后调用的:

 

  1. int socket_local_client_connect(int fd, const char *name, int namespaceId,   
  2.         int type)  
  3. {  
  4.     struct sockaddr_un addr;  
  5.     socklen_t alen;  
  6.     size_t namelen;  
  7.     int err;  
  8.   
  9.     err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen);  
  10.   
  11.     if (err < 0) {  
  12.         goto error;  
  13.     }  
  14.   
  15.     if(connect(fd, (struct sockaddr *) &addr, alen) < 0) {  
  16.         goto error;  
  17.     }  
  18.   
  19.     return fd;  
  20.   
  21. error:  
  22.     return -1;  
  23. }  
  24.   
  25. /**  
  26.  * connect to peer named "name" 
  27.  * returns fd or -1 on error 
  28.  */  

我们再跟进socket_make_sockaddr_un函数,这时namespaceId传的ANDROID_SOCKET_NAMESPACE_RESERVED,所以会执行下面几句:

 

  1. case ANDROID_SOCKET_NAMESPACE_RESERVED:  
  2.            namelen = strlen(name) + strlen(ANDROID_RESERVED_SOCKET_PREFIX);  
  3.            /* unix_path_max appears to be missing on linux */  
  4.            if (namelen > sizeof(*p_addr)   
  5.                    - offsetof(struct sockaddr_un, sun_path) - 1) {  
  6.                goto error;  
  7.            }  
  8.   
  9.            strcpy(p_addr->sun_path, ANDROID_RESERVED_SOCKET_PREFIX);  //  ANDROID_RESERVED_SOCKET_PREFIX="/dev/socket/"  
  10.            strcat(p_addr->sun_path, name);  
  11.        break;  

注意在前面 connect  函数中的套接字的构造,使用了AF_LOCAL:

 

  1. int socket_local_client(const char *name, int namespaceId, int type)  
  2. {  
  3.     int s;  
  4.   
  5.     s = socket(<span style="color:#ff0000;">AF_LOCAL</span>, type, 0);  
  6.     if(s < 0) return -1;  
  7.   
  8.     if ( 0 > socket_local_client_connect(s, name, namespaceId, type)) {  
  9.         close(s);  
  10.         return -1;  
  11.     }  
  12.   
  13.     return s;  
  14. }  
这样,就建立了一条从FrameWork层到vold层的通信链路,后面FrameWork层就等待Vold发送消息过来了。。。

 

FrameWork层的通信也ok了,就可以等待U盘挂载了。。

posted @ 2015-09-30 17:40  maxiongying  阅读(1589)  评论(0编辑  收藏  举报