Android—— 4.2 Vold挂载管理_MountService (六)

整个Vold机制应该算system层,与framwork层的交互在Android—— 4.2 Vold挂载管理_CommandListener (二)中有提到过,是通过一个"vold"的socket进行通信的,这里分析一下framework中负责与Vold通信的:MountService

撰写不易,转载请注明出处:http://blog.csdn.net/jscese/article/details/38978387

一.MountService启动:

在/frameworks/base/services/java/com/android/server/SystemServer.java中有:

            if (!"0".equals(SystemProperties.get("system_init.startmountservice"))) {
                try {
                    /*
                     * NotificationManagerService is dependant on MountService,
                     * (for media / usb notifications) so we must start MountService first.
                     */
                    Slog.i(TAG, "Mount Service");
                    mountService = new MountService(context);
                    ServiceManager.addService("mount", mountService);
                } catch (Throwable e) {
                    reportWtf("starting Mount Service", e);
                }
            }

开机启动的系统服务之一,关于系统初始启动详情可参考:Android——启动过程详析

public MountService(Context context) {
        mContext = context;

        synchronized (mVolumesLock) {
            readStorageListLocked(); // 解析/frameworks/base/core/res/res/xml/storage_list.xml保存volume到 MountService的list :mVolumes中
        }

        // XXX: This will go away soon in favor of IMountServiceObserver
        mPms = (PackageManagerService) ServiceManager.getService("package");

        mHandlerThread = new HandlerThread("MountService");
        mHandlerThread.start();
        mHandler = new MountServiceHandler(mHandlerThread.getLooper());//新建消息处理handler

        // Watch for user changes
        final IntentFilter userFilter = new IntentFilter();
        userFilter.addAction(Intent.ACTION_USER_ADDED);
        userFilter.addAction(Intent.ACTION_USER_REMOVED);
        mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);//注册广播接收

        // Watch for USB changes on primary volume
        final StorageVolume primary = getPrimaryPhysicalVolume();
        if (primary != null && primary.allowMassStorage()) {
            mContext.registerReceiver(
                    mUsbReceiver, new IntentFilter(UsbManager.ACTION_USB_STATE), null, mHandler);
        }

        // Add OBB Action Handler to MountService thread.
        mObbActionHandler = new ObbActionHandler(mHandlerThread.getLooper());

        /*
         * 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", MAX_CONTAINERS * 2, VOLD_TAG, 25);//创建 vold 的监听接收,用于接收system中Vold的socket消息

        Thread thread = new Thread(mConnector, VOLD_TAG);
        thread.start();//启动线程,NativeDaemonConnector实现了Runnable接口,实现在 run中

        // Add ourself to the Watchdog monitors if enabled.
        if (WATCHDOG_ENABLE) {
            Watchdog.getInstance().addMonitor(this);
        }
    }

二.MountService接收Socket:

上面有看到构造了NativeDaemonConnector用来接收来自下层的socket消息,先看构造:

    NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket,
            int responseQueueSize, String logTag, int maxLogSize) {
        mCallbacks = callbacks; //回调
        mSocket = socket; // socket名称
        mResponseQueue = new ResponseQueue(responseQueueSize);//构建一个响应队列
        mSequenceNumber = new AtomicInteger(0);
        TAG = logTag != null ? logTag : "NativeDaemonConnector";
        mLocalLog = new LocalLog(maxLogSize);
    }

在上面开启监测线程的run方法:

    public void run() {
        HandlerThread thread = new HandlerThread(TAG + ".CallbackHandler"); //TAG 为 VoldConnector,这里新建一个名为VoldConnector.CallbackHandler的消息处理线程,用于下面接收到vold 的socket之后的处理
        thread.start();
        mCallbackHandler = new Handler(thread.getLooper(), this); //创建handler 用于分发消息

        while (true) {
            try {
                listenToSocket();// while 循环 监听socket
            } catch (Exception e) {
                loge("Error in NativeDaemonConnector: " + e);
                SystemClock.sleep(5000);
            }
        }
    }

往里看listenToSocket

    private void listenToSocket() throws IOException {
        LocalSocket socket = null;

        try {
            socket = new LocalSocket();  //创建本地socket
            LocalSocketAddress address = new LocalSocketAddress(mSocket,
                    LocalSocketAddress.Namespace.RESERVED);//获得服务端vold socket的地址

            socket.connect(address);//连接

            InputStream inputStream = socket.getInputStream();
            synchronized (mDaemonLock) {
                mOutputStream = socket.getOutputStream();
            }//获取输入输出流

            mCallbacks.onDaemonConnected();//回调,在MountService中执行,初始化一些Volume状态信息

            byte[] buffer = new byte[BUFFER_SIZE];
            int start = 0;

            while (true) {
                int count = inputStream.read(buffer, start, BUFFER_SIZE - start);//读取数据到buffer
                if (count < 0) {//连接断开,跳出当前while ,外部while循环 重新调用该函数连接
                    loge("got " + count + " reading with start = " + start);
                    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) {
                        final String rawEvent = new String(
                                buffer, start, i - start, Charsets.UTF_8);
                        log("RCV <- {" + rawEvent + "}");

                        try {
                            final NativeDaemonEvent event = NativeDaemonEvent.parseRawEvent(
                                    rawEvent);   //解析成event 保存
                            if (event.isClassUnsolicited()) {    //判断event的code范围 code >= 600 && code < 700
                                // TODO: migrate to sending NativeDaemonEvent instances
                                mCallbackHandler.sendMessage(mCallbackHandler.obtainMessage( //发送消息,把event交给handle来分发处理
                                        event.getCode(), event.getRawEvent()));
                            } else {
                                mResponseQueue.add(event.getCmdNumber(), event);//加入到响应队列
                            }
                        } catch (IllegalArgumentException e) {
                            log("Problem parsing message: " + rawEvent + " - " + e);
                        }

                        start = i + 1;
                    }
                }

        ...

           }

     }

}

在NativeDaemonConnector中的handle处理为:

    @Override
    public boolean handleMessage(Message msg) {
        String event = (String) msg.obj;
        try {
            if (!mCallbacks.onEvent(msg.what, event, NativeDaemonEvent.unescapeArgs(event))) { //回调到MountService 的onEent函数
                log(String.format("Unhandled event '%s'", event));
            }
        } catch (Exception e) {
            loge("Error handling '" + event + "': " + e);
        }
        return true;
    }

到MountService中onEvent

    public boolean onEvent(int code, String raw, String[] cooked) {
        if (DEBUG_EVENTS) {
            StringBuilder builder = new StringBuilder();
            builder.append("onEvent::");
            builder.append(" raw= " + raw);
            if (cooked != null) {
                builder.append(" cooked = " );
                for (String str : cooked) {
                    builder.append(" " + str);
                }
            }
            Slog.i(TAG, builder.toString());
        }
        if (code == VoldResponseCode.VolumeStateChange) { //根据 Vold的Code 执行
            /*
             * One of the volumes we're managing has changed state.
             * Format: "NNN Volume <label> <path> state changed
             * from <old_#> (<old_str>) to <new_#> (<new_str>)"
             */
            notifyVolumeStateChange(
                    cooked[2], cooked[3], Integer.parseInt(cooked[7]),
                            Integer.parseInt(cooked[10])); //更新状态
        } else if ((code == VoldResponseCode.VolumeDiskInserted) ||
                   (code == VoldResponseCode.VolumeDiskRemoved) ||
                   (code == VoldResponseCode.VolumeBadRemoval))
    ...

                  if (code == VoldResponseCode.VolumeDiskInserted) { //如果接收到的是插入disk的消息,则执行挂载操作
                new Thread() {
                    @Override
                    public void run() {
                        try {
                            int rc;
                            if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) {
                                Slog.w(TAG, String.format("Insertion mount failed (%d)", rc));
                            }
                        } catch (Exception ex) {
                            Slog.w(TAG, "Failed to mount media on insertion", ex);
                        }
                    }
                }.start();
            }

    ...

}

可以看到根据code值执行相对应的操作,在Android—— 4.2 Vold挂载管理_DirectVolume/Volume (五)中的DirectVolume中
DirectVolume::handleBlockEvent中就发送了ResponseCode::VolumeDiskInserted

MountService中对Vold的socket接收大体就是这样!

三.MountService下发Command:

就从上面doMountVolume来解析,MountService中对Volume的各种操作都是需要转换成符合Vold中socket command,这样Vold中才能正确的解析识别调用!

    private int doMountVolume(String path) {
        int rc = StorageResultCode.OperationSucceeded;

        final StorageVolume volume;
        synchronized (mVolumesLock) {
            volume = mVolumesByPath.get(path);
        }

        if (DEBUG_EVENTS) Slog.i(TAG, "doMountVolume: Mouting " + path);
        try {
            mConnector.execute("volume", "mount", path);// 调用到NativeDaemonConnector中的execute
        }

     ...

}

NativeDaemonConnector中:

    public NativeDaemonEvent execute(String cmd, Object... args)
            throws NativeDaemonConnectorException {
        final NativeDaemonEvent[] events = executeForList(cmd, args);//由executeForList发送,返回NativeDaemonEent事件

        if (events.length != 1) {
            throw new NativeDaemonConnectorException(
                    "Expected exactly one response, but received " + events.length);
        }
        return events[0];
    }

最终调用到:

    public NativeDaemonEvent[] execute(int timeout, String cmd, Object... args)
            throws NativeDaemonConnectorException {
        final ArrayList<NativeDaemonEvent> events = Lists.newArrayList();

        final int sequenceNumber = mSequenceNumber.incrementAndGet();
        final StringBuilder cmdBuilder =
                new StringBuilder(Integer.toString(sequenceNumber)).append(' ');
        final long startTime = SystemClock.elapsedRealtime();

        makeCommand(cmdBuilder, cmd, args); //转换制作成标准的Command

        final String logCmd = cmdBuilder.toString(); /* includes cmdNum, cmd, args */
        log("SND -> {" + logCmd + "}");

        cmdBuilder.append('\0');
        final String sentCmd = cmdBuilder.toString(); /* logCmd + \0 */

        synchronized (mDaemonLock) {
            if (mOutputStream == null) {
                throw new NativeDaemonConnectorException("missing output stream");
            } else {
                try {
                    mOutputStream.write(sentCmd.getBytes(Charsets.UTF_8)); //通过在listenToSocket中获取的输出流,写入转换好的sentCmd
                } catch (IOException e) {
                    throw new NativeDaemonConnectorException("problem sending command", e);
                }
            }
        }

     ...

}

MountService 中往下发command的流程大体就是这样!

简单流程图:

至此,framework与Vold的分析就到这里!

时间: 08-31

Android—— 4.2 Vold挂载管理_MountService (六)的相关文章

Android—— 4.2 Vold挂载管理_Kernel_USB_Uevent (七)

在前文Android-- 4.2 Vold挂载管理_NetlinkManager (四)中有解析到Vold 是从kernel中获取uevent事件,来获取device信息,其中是通过一个Netlink的套接字,目前整个Vold机制也分析完了, 上篇 Android-- 4.2 Vold挂载管理_MountService (六) 分析了机制中最上层的,这里分析一下最下层的kernel uevent事件的发送,以USB设备为例! 撰写不易,转载请注明出处:http://blog.csdn.net/j

Android—— 4.2 Vold挂载管理_mmcblk内置-双sdcard (八)

Vold的学习过了一段时间了,才想着把mmcblock内置成sdcard的方法记录一下. 当初就是因为要做这个功能才去学习Vold机制,贴出之前的博客: Android-- 4.2 Vold挂载管理_主体构建main (一) Android-- 4.2 Vold挂载管理_CommandListener (二) Android-- 4.2 Vold挂载管理_VolumeManager (三) Android-- 4.2 Vold挂载管理_NetlinkManager (四) Android-- 4

Android—— 4.2 Vold挂载管理_NetlinkManager (四)

在前文Android-- 4.2 Vold挂载管理_主体构建main (一)中有结构图表示,Vold是kernel与用户层的一个交互管理模块, Android-- 4.2 Vold挂载管理_VolumeManager (三)简单介绍了核心VolumeManager的构建,这篇分析从kernel进程沟通到VolumeManager进程的关键:NetlinkManager 撰写不易,转载请注明出处:http://blog.csdn.net/jscese/article/details/3858602

Android—— 4.2 Vold挂载管理_CommandListener (二)

在前一篇博客中介绍了个大体结构 Android-- 4.2 Vold挂载管理_主体构建 (一),按照代码的顺序结构来依次分析,这里来看看CommandListener这个类做了什么. 撰写不易,转载请注明出处:http://blog.csdn.net/jscese/article/details/38434263 一:CommandListener构造 在/system/vold/main.cpp的main函数中构建实例: cl = new CommandListener(); vm->setB

Android—— 4.2 Vold挂载管理_VolumeManager (三)

在Android-- 4.2 Vold挂载管理_主体构建main (一)中分析了大体的框架,这里分析一下核心VolumeManager,再次补上结构框架图如下: 可以看到VolumeManager就是整个Android 磁盘挂载Vold机制的核心调度,上下连接的中转站! 我从Vold main代码的顺序结构来一次分析,上一篇Android-- 4.2 Vold挂载管理_CommandListener (二)  中分析了与framework层交互的CommandListener的功能作用. 这里分

Android—— 4.2 Vold挂载管理_DirectVolume/Volume (五)

在前文Android-- 4.2 Vold挂载管理_VolumeManager (三) 中解析了VolumeManager是怎么样抽取Volume实例以及DirectVolume与Volume之间的关系,在上篇Android-- 4.2 Vold挂载管理_NetlinkManager (四)中从kernel开始调用到handleBlockEvent,这里解析一下Vold挂载的真正操作,也就是Volume的操作! 撰写不易,转载请注明出处:http://blog.csdn.net/jscese/a

linux软件管理(六)

[教程主题]:linux软件管理 [1]软件包管理 在系统管理中,软件包的管理是最重要的,是系统管理的基础的基础, 只有我们学会软件包的管理才能谈得上其它的应用. RPM RPM是软件管理程序,提供软件的安装.升级.查询.反安装的功能.优点:a.安装方便,软件中所有数据都经过编译和打包b.查询.升级.反安装方便缺点:a.缺乏灵活性b.存在相依属性 用法: rpm  参数   软件包 指令选项-i:安装.-U:升级安装,如果不存在也安装.-F:更新安装,如果不存在不安装.-v:查看信息.-h:有进

Android 4.4(KitKat)窗口管理子系统 - 体系框架

窗口管理系统是Android中的主要子系统之一,它涉及到App中组件的管理,系统和应用窗口的管理和绘制等工作.由于其涉及模块众多,且与用户体验密切相关,所以它也是Android当中最为复杂的子系统之一.一个App从启动到主窗口显示出来,需要App,ActivityManagerService(AMS),WindowManagerService(WMS),SurfaceFlinger(SF)等几个模块相互合作.App负责业务逻辑,绘制自己的视图:AMS管理组件.进程信息和Activity的堆栈及状

Android 6.0 - 动态权限管理的解决方案(转)

转自:http://www.cnblogs.com/dubo-/p/6018262.html Android 6.0 - 动态权限管理的解决方案 转载请标注 Android 6.0版本(Api 23)推出了很多新的特性, 大幅提升了用户体验, 同时也为程序员带来新的负担. 动态权限管理就是这样, 一方面让用户更加容易的控制自己的隐私, 一方面需要重新适配应用权限. 时代总是不断发展, 程序总是以人为本, 让我们为应用添加动态权限管理吧! 这里提供了一个非常不错的解决方案, 提供源码, 项目可以直