Android5.0 vold-注册过程(上)

转载请标明出处:http://www.jianshu.com/users/183339cdc7ae/latest_articles

概述

前面几篇介绍了vold的框架和内部结构以及启动顺序,可以知道的是vold接受到消息后是如果工作的。这一片文章主要讲的是,vold中的接受上层消息的socket是如何注册的。

相关文章

Android5.0 vold-整体架构
Android5.0 vold-启动过程
Android5.0 vold-注册过程(下)

MountService

创建

由vold整体框架可以知道,vold能接受上层(MountService)发过来的信息,我们就从mountservice看起走,是在哪里注册的,先来看看构造方法.
这个NativeDaemonConnector类可以看出是继承自Runnable接口应用层(如:Setting)发送的命令会传给MountService,MountService中有一个线程来接受这个命令需要注意的是NativeDaemonConnector的第二个参数"vold",这里先记住这个参数的名字

 public MountService(Context context) {
     ...
     mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25,
                null);
     Thread thread = new Thread(mConnector, VOLD_TAG);
     thread.start();
     ...
 }

可以看出的是这个socket的名字就为vold.

NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket,
            int responseQueueSize, String logTag, int maxLogSize, PowerManager.WakeLock wl,
            Looper looper) {
        ...
        mSocket = socket;
        ...
}

因为之前执行了thread.start();所以我们再来看看NativeDaemonConnector的run方法
可以看到实例化了一个LocalSocket,这个LocalSocket是对unix socket操作的一个封装,可以理解为一个工具类,这里仅仅只是做了一个实例化的动作,还并没有创建socket
LocalSocketAddress对象也只是一个地址封装类,里面会封装socket的一个地址,查看代码可以知道的是这个地址名字就叫做“vold”,为前面mSocket的值,并且这个socket文件路径为: /dev/socket/vold
接下来是connect动作,这里面就会创建正真的socket并且指定地址为/dev/socket/vold在这个线程里面会监听由vold发过来的消息,然后再做后续的一些处理 [注:这里是vold发上来的信息]

 public void run() {
        ...
        while (true) {
           ...
           listenToSocket();
           ...      
        }
 }

 private void listenToSocket() throws IOException {
       LocalSocket socket = null;
       ...
       socket = new LocalSocket();
       LocalSocketAddress address = determineSocketAddress();
       socket.connect(address);
       ...
       int count = inputStream.read(buffer, start, BUFFER_SIZE - start);
       ...
       if (mCallbackHandler.sendMessage(mCallbackHandler.obtainMessage(
              event.getCode(), event.getRawEvent()))) {
       ...
       }     
 }

写入

上面说了socket的创建和读取信息,接下来看是如何往socket里面写的
mountService中会有一些方法供app层调用,这里以加密手机文件为例(命令:cryptfs),最终会封装一些参数到NativeDaemonConnector的execute方法
这个mOutputStream对象也就是之前创建的socket中获取的OutputStream
execute方法最终会往socket中写入数据

 public int encryptStorage(int type, String password) {
        ...
        mConnector.execute("cryptfs", "enablecrypto", "inplace", CRYPTO_TYPES[type],
                           new SensitiveArg(toHex(password)));
        ...
    }

    public NativeDaemonEvent[] execute(int timeout, String cmd, Object... args)
            throws NativeDaemonConnectorException {
        ...
        mOutputStream.write(rawCmd.getBytes(StandardCharsets.UTF_8));
        ...
    }

Vold

创建

我们回顾一下init.rc里面启动vold的代码重点是socket这一行.
根据init的语法可以知道的是,这一行会生产一个名叫vold的socket文件在/dev/socket/目录下

service vold /system/bin/vold
    class core
    socket vold stream 0660 root mount
    ioprio be 2

寻找

再回顾一下CommandListener的构造方法,这里传入的是vold一个字符串
这个vold会传入到SocketListener中,并赋值给mSocketName变量

CommandListener::CommandListener() :FrameworkListener("vold", true) 
FrameworkListener::FrameworkListener(const char *socketName, bool withSeq) :SocketListener(socketName, true, withSeq) {

根据前文我们可以知道,启动监听的时候会调用到startListener方法然后android_get_control_socket方法会根据mSocketName返回一个fd文件

int SocketListener::startListener(int backlog) {
    ...
        if ((mSock = android_get_control_socket(mSocketName)) < 0) {
            SLOGE("Obtaining file descriptor socket '%s' failed: %s",
                 mSocketName, strerror(errno));
            return -1;
        }
        SLOGV("got mSock = %d for %s", mSock, mSocketName);
   ...
}

android_get_control_socket的定义是在system/core/include/cutils/sockets.h中具体的实现就不仔细看了,看注释可以知道的是,这里返回的fd文件会是init.rc里面创建的文件也就是/dev/socket/vold文件

/*
 * android_get_control_socket - simple helper function to get the file
 * descriptor of our init-managed Unix domain socket. `name' is the name of the
 * socket, as given in init.rc. Returns -1 on error.
 *
 * This is inline and not in libcutils proper because we want to use this in
 * third-party daemons with minimal modification.
 */
static inline int android_get_control_socket(const char *name)
{..}

总结

根据上文可以知道是

  1. init.rc在启动vold的时候,会先创建一个/dev/socket/vold的socket文件
  2. 然后native vold启动完成时,会监听这个/dev/socket/vold socket
  3. 再然后是我们的MountService的启动,启动的时候会先得到/dev/socket/vold的地址,然后connect这个地址

这样可以往这个socket里面写入值了
如果对socket不是很熟悉的童鞋可以看看 关于socket的基本操作

你可能感兴趣的:(Android5.0 vold-注册过程(上))