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

原创 2012年03月27日 23:00:12

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












Android Service之MountService源码分析

Android 存储设备管理框架 在android之VOLD进程启动源码分析一文中介绍了存储设备的管控中心Vold进程,Vold属于native后台进程,通过netlink方式接收kernel的ue...
  • yangwen123
  • yangwen123
  • 2013年05月16日 10:47
  • 20154

Android6.0 MountService和vold详解(一)Mountservice的初始化

Android6.0对存储这块的改动还是比较大的,前面我们讲过了Android5.1上相关的代码,这里我们主要讲下区别,至于相同的部分,比如通信部分就不讲了,大家感兴趣可以看我之前5.1MountSe...
  • kc58236582
  • kc58236582
  • 2015年12月29日 19:54
  • 6616

MountService初探

MountService作为Vold的客户端,会接收来自vold的消息,并且内部定义保存了各种Volume相关的状态定义: 1、VolumeStateclass VolumeState { ...
  • hailushijie
  • hailushijie
  • 2015年04月21日 22:16
  • 1559

MountService整理

刚毕业时第一个接触的模块就是Vold,这个模块虽然小,但深入下去是有一定难度的。花了点时间重新整理了下这一块的逻辑,也当温习下这个模块。 挂载核心在Vold,MountService相当于对外提...
  • guoqifa29
  • guoqifa29
  • 2015年07月23日 10:06
  • 752

Android实现识别/挂载U盘

关于U盘的挂载可以先看一下这篇文章http://blog.csdn.net/yimiyangguang1314/article/details/6298276,作者是将U盘直接挂载在SD卡下。我的机器...
  • goleftgoright
  • goleftgoright
  • 2012年09月24日 11:41
  • 24167

Android4.4----Vold挂载管理分析USB挂载(四)

在上一篇Android4.4----Vold挂载管理分析USB挂载(三)中,介绍了VolumeManager接收到kernel发出的add事件后,向上层发送了VolumeStateChange和Vol...
  • hedaogelaoshu
  • hedaogelaoshu
  • 2015年06月05日 14:55
  • 1111

android6.0 sm进程(获取MountService信息)

一、编译 我们先来看看sm的Android.mk # Copyright 2015 The Android Open Source Project # LOCAL_PATH:= $(call my...
  • kc58236582
  • kc58236582
  • 2016年05月18日 20:09
  • 2187

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

from :  http://blog.csdn.net/column/details/android-usb.html 在android usb挂载分析----vold启动,我们的...
  • Fybon
  • Fybon
  • 2015年03月26日 10:07
  • 722

安卓USB挂载设备监听

安卓USB接口挂载监听
  • aiyh0202
  • aiyh0202
  • 2016年10月10日 16:00
  • 1133

Android 存储设备管理 -- IMountService (二)

这里我们主要是梳理下图中的架构,以IMountService为例。 在StorageManager的构造函数中,用到了IMountService /** * Cons...
  • muojie
  • muojie
  • 2012年12月25日 15:34
  • 2386
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:android usb挂载分析---MountService启动
举报原因:
原因补充:

(最多只允许输入30个字)