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盘挂载了。。












更多相关文章

  1. 关于java、Android中Math的一些用法
  2. Android学习笔记十五.使用ContentProvider实现数据共享(一)
  3. Android(安卓)Retrofit源码解析
  4. android常用的方法
  5. android looper和handler
  6. ddroid 6.0权限管理开发
  7. Android(安卓)四大核心组件
  8. Android(安卓)引入第三方so后启动报错 /lib/arm64-v8a, /vendor/
  9. Android(安卓)7.0 AES加密报错:NoSuchProviderException: no such

随机推荐

  1. Android 拖动换图特效
  2. Android(安卓)JNI和NDK有什么区别
  3. 如何查看Android设备的CPU架构信息
  4. 圆形button
  5. Android NDK打印log到logcat的方法
  6. Android――ImageButton按下效果设计
  7. Android uri转Bitmap
  8. 使用Leancloud实现React Native App的消
  9. [android] 获取网页中的HTML数据
  10. 使用Android(安卓)Studio进行JNI开发 - Ma