zoukankan      html  css  js  c++  java
  • 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盘挂载了。。

  • 相关阅读:
    转:POI操作Excel:cell的背景颜色类型
    在table中tr的display:block在firefox下显示布局错乱问题
    [转]:颜色 16进制对照表
    js时间操作
    SQL 复制数据库里面的表到另一个表
    js 去除空格
    判断一个表单是否被修改过
    判断数据库,函数名,表名,存储过程名称等是否存在
    JS 获取radiobuttonlist checkboxlist的值
    Asp 结合JQuery EasyUI 框架完成的一个增删改查
  • 原文地址:https://www.cnblogs.com/senior-engineer/p/4849806.html
Copyright © 2011-2022 走看看