Android 存储系统之架构篇

澳门新葡亰3522平台游戏 7

基于Android 6.0的源码,剖析存储架构的设计

基于Android 6.0源码, 来分析存储相关架构,涉及源码:

Android
存储系统之源码篇

Android
存储系统之源码篇

Android
存储系统之架构篇

Android
存储系统之架构篇

一、概述

本文讲述Android存储系统的架构与设计,涉及到最为核心的便是MountService和Vold这两个模块以及之间的交互。上一篇文章Android存储系统之源码篇从源码角度介绍相关模块的创建与启动过程,那么本文主要从全局角度把握和剖析Android的存储系统。

MountService:Android
Binder服务端,运行在system_server进程,用于跟Vold进行消息通信,比如MountServiceVold发送挂载SD卡的命令,或者接收到来自Vold的外设热插拔事件。MountService作为Binder服务端,那么相应的Binder客户端便是StorageManager,通过binder
IPC与MountService交互。

Vold:全称为Volume Daemon,用于管理外部存储设备的Native
daemon进程,这是一个非常重要的守护进程,主要由NetlinkManager,VolumeManager,CommandListener这3部分组成。

/framework/base/services/java/com/android/server/SystemServer.java
/framework/base/services/core/java/com/android/server/MountService.java
/framework/base/services/core/java/com/android/server/NativeDaemonConnector.java
/framework/base/services/core/java/com/android/server/NativeDaemonEvent.java
/framework/base/core/java/android/os/storage/IMountService.java
/framework/base/core/java/android/os/storage/IMountServiceListener.java
/framework/base/core/java/android/os/storage/StorageManager.java

/system/vold/Main.cpp
/system/vold/VolumeManager.cpp
/system/vold/NetlinkManager.cpp
/system/vold/NetlinkHandler.cpp
/system/vold/CommandListener.cpp
/system/vold/VoldCommand.cpp
/system/vold/VolumeBase.cpp
/system/vold/PublicVolume.cpp
/system/vold/EmulatedVolume.cpp
/system/vold/PublicVolume.cpp
/system/vold/Disk.cpp

/system/core/libsysutils/src/NetlinkListener.cpp
/system/core/libsysutils/src/SocketListener.cpp
/system/core/libsysutils/src/FrameworkListener.cpp
/system/core/libsysutils/src/FrameworkCommand.cpp
/system/core/include/sysutils/NetlinkListener.h
/system/core/include/sysutils/SocketListener.h
/system/core/include/sysutils/FrameworkListener.h
/system/core/include/sysutils/FrameworkCommand.h

1.1 模块架构

从模块地角度划分Android整个存储架构:

澳门新葡亰3522平台游戏 1

图解:

  • Linux Kernel:通过uevent向Vold的NetlinkManager发送Uevent事件;
  • NetlinkManager:接收来自Kernel的Uevent事件,再转发给VolumeManager;
  • VolumeManager:接收来自NetlinkManager的事件,再转发给CommandListener进行处理;
  • CommandListener:接收来自VolumeManager的事件,通过socket通信方式发送给MountService;
  • MountService:接收来自CommandListener的事件。

一、概述

本文主要介绍跟存储相关的模块MountService和Vold的整体流程与架构设计.

  • MountService:Android
    Binder服务,运行在system_server进程,用于跟Vold进行消息通信,比如MountServiceVold发送挂载SD卡的命令,或者接收到来自Vold的外设热插拔事件。
  • Vold:全称为Volume
    Daemon,用于管理外部存储设备的Native守护进程,这是一个非常重要的守护进程,由NetlinkManager,VolumeManager,CommandListener这3部分组成。

1.2 进程架构

(1)先看看Java framework层的线程:

root@gityuan:/ # ps -t | grep 1212
system    1212  557   2334024 160340 SyS_epoll_ 7faedddbe4 S system_server
system    2662  1212  2334024 160340 SyS_epoll_ 7faedddbe4 S MountService
system    2663  1212  2334024 160340 unix_strea 7faedde73c S VoldConnector
system    2664  1212  2334024 160340 unix_strea 7faedde73c S CryptdConnector
...

MountService运行在system_server进程,这里查询的便是system_server进程的所有子线程,system_server进程承载整个framework所有核心服务,子线程数有很多,这里只列举与MountService模块相关的子线程。

(2)再看看Native层的线程:

root@gityuan:/ # ps -t | grep " 387 "
USER      PID   PPID  VSIZE  RSS   WCHAN              PC  NAME
root      387   1     13572  2912  hrtimer_na 7fa34755d4 S /system/bin/vold
root      397   387   13572  2912  poll_sched 7fa3474d1c S vold
root      399   387   13572  2912  poll_sched 7fa3474d1c S vold
root      400   387   13572  2912  poll_sched 7fa3474d1c S vold
media_rw  2702  387   7140   2036  inotify_re 7f84b1d6ac S /system/bin/sdcard

Vold作为native守护进程,进程名为”/system/bin/vold”,pid=387,通过ps -t可查询到该进程下所有的子进程/线程。

小技巧:有读者可能会好奇,为什么/system/bin/sdcard是子进程,而非子线程呢?要回答这个问题,有两个方法,其一就是直接看撸源码,会发现这是通过fork方式创建的,而其他子线程都是通过pthread_create方式创建的。当然其实还有个更快捷的小技巧,就是直接看上图中的第4列,这一列的含义是VSIZE,代表的是进程虚拟地址空间大小,是否共享地址空间,这是进程与线程最大的区别,再来看看/sdcard的VSIZE大小跟父进程不一样,基本可以确实/sdcard是子进程。

(3) 从进程/线程视角来看Android存储架构:

澳门新葡亰3522平台游戏 2

  • Java层:采用 1个主线程(system_server)
    3个子线程(VoldConnector, MountService, CryptdConnector);
  • Native层:采用 1个主线程(/system/bin/vold) + 3个子线程(vold)
    1子进程(/system/bin/sdcard);

注:图中红色字代表的进程/线程名,vold进程通过pthread_create的方式创建的3个子线程名都为vold,图中只是为了便于区别才标注为vold1,
vold2, volD3,其实名称都为vold。

Android还可划分为内核空间(Kernel Space)和用户空间(User
space),从上图可看出,Android存储系统在User
space总共采用9个进程/线程的架构模型。当然,除了这9个进/线程,另外还会在handler消息处理过程中使用到system_server的两个子线程:android.fgandroid.io

Tips: 同一个模块可以运行在各个不同的进程/线程,
同一个进程可以运行不同模块的代码,所以从进程角度和模块角度划分看到的有所不同的.

二、MountService

MountService运行在system_server进程,在系统启动到阶段PHASE_WAIT_FOR_DEFAULT_DISPLAY后,进入startOtherServices会启动MountService.

1.3 类关系图

澳门新葡亰3522平台游戏 3

澳门新葡亰3522平台游戏 4

上图中4个蓝色块便是前面谈到的核心模块。

2.1 启动

[-> SystemServer.java]

private void startOtherServices() {
    ...
    IMountService mountService = null;
    //启动MountService服务,【见小节2.2】
    mSystemServiceManager.startService(MOUNT_SERVICE_CLASS);
    //等价new IMountService.Stub.Proxy(),即获取MountService的proxy对象
    mountService = IMountService.Stub.asInterface(
            ServiceManager.getService("mount"));
    ...

    mActivityManagerService.systemReady(new Runnable() {
        public void run() {
            //启动到阶段550【见小节2.7】
            mSystemServiceManager.startBootPhase(
                        SystemService.PHASE_ACTIVITY_MANAGER_READY);
        ...
    });
}

NotificationManagerService依赖于MountService,比如media/usb通知事件,所以需要先启动MountService。此处MOUNT_SERVICE_CLASS=com.android.server.MountService$Lifecycle.

二、 通信架构

Android存储系统中涉及各个进程间通信,这个架构采用的socket,并没有采用Android
binder
IPC机制。这样的架构代码大量更少,整体架构逻辑也相对简单,在介绍通信过程前,先来看看MountService对象的实例化过程,那么也就基本明白进程架构中system_sever进程为了MountService服务而单独创建与共享使用到线程情况。

public MountService(Context context) {
    sSelf = this;

    mContext = context;
    //FgThread线程名为“"android.fg",创建IMountServiceListener回调方法
    mCallbacks = new Callbacks(FgThread.get().getLooper());
    //获取PKMS的Client端对象
    mPms = (PackageManagerService) ServiceManager.getService("package");
    //创建“MountService”线程
    HandlerThread hthread = new HandlerThread(TAG);
    hthread.start();

    mHandler = new MountServiceHandler(hthread.getLooper());
    //IoThread线程名为"android.io",创建OBB操作的handler
    mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper());

    File dataDir = Environment.getDataDirectory();
    File systemDir = new File(dataDir, "system");
    mLastMaintenanceFile = new File(systemDir, LAST_FSTRIM_FILE);
    //判断/data/system/last-fstrim文件,不存在则创建,存在则更新最后修改时间
    if (!mLastMaintenanceFile.exists()) {
        (new FileOutputStream(mLastMaintenanceFile)).close();
        ...
    } else {
        mLastMaintenance = mLastMaintenanceFile.lastModified();
    }
    ...
    //将MountServiceInternalImpl登记到sLocalServiceObjects
    LocalServices.addService(MountServiceInternal.class, mMountServiceInternal);
    //创建用于VoldConnector的NDC对象
    mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25,
            null);
    mConnector.setDebug(true);
    //创建线程名为"VoldConnector"的线程,用于跟vold通信
    Thread thread = new Thread(mConnector, VOLD_TAG);
    thread.start();

    //创建用于CryptdConnector工作的NDC对象
    mCryptConnector = new NativeDaemonConnector(this, "cryptd",
            MAX_CONTAINERS * 2, CRYPTD_TAG, 25, null);
    mCryptConnector.setDebug(true);
    //创建线程名为"CryptdConnector"的线程,用于加密
    Thread crypt_thread = new Thread(mCryptConnector, CRYPTD_TAG);
    crypt_thread.start();

    //注册监听用户添加、删除的广播
    final IntentFilter userFilter = new IntentFilter();
    userFilter.addAction(Intent.ACTION_USER_ADDED);
    userFilter.addAction(Intent.ACTION_USER_REMOVED);
    mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);

    //内部私有volume的路径为/data,该volume通过dumpsys mount是不会显示的
    addInternalVolume();

    //默认为false
    if (WATCHDOG_ENABLE) {
        Watchdog.getInstance().addMonitor(this);
    }
}

其主要功能依次是:

  1. 创建ICallbacks回调方法,FgThread线程名为”android.fg”,此处用到的Looper便是线程”android.fg”中的Looper;
  2. 创建并启动线程名为”MountService”的handlerThread;
  3. 创建OBB操作的handler,IoThread线程名为”android.io”,此处用到的的Looper便是线程”android.io”中的Looper;
  4. 创建NativeDaemonConnector对象
  5. 创建并启动线程名为”VoldConnector”的线程;
  6. 创建并启动线程名为”CryptdConnector”的线程;
  7. 注册监听用户添加、删除的广播;

从这里便可知道共创建了3个线程:MountService,VoldConnector,CryptdConnector,另外还会使用到系统进程中的两个线程android.fgandroid.io.
这便是在文章开头进程架构图中Java framework层进程的创建情况.

接下来,我们分别从MountService向vold发送消息和接收消息两个方面,以及Kernel向vold上报事件3个方面展开。

2.2 startService

mSystemServiceManager.startService(MOUNT_SERVICE_CLASS)主要完成3件事:

  • 创建MOUNT_SERVICE_CLASS所指类的Lifecycle对象;
  • 将该对象添加SystemServiceManager的mServices服务列表;
  • 最后调用Lifecycle的onStart()方法,主要工作量这个过程,如下:

[-> MountService.java]

class MountService extends IMountService.Stub
        implements INativeDaemonConnectorCallbacks, Watchdog.Monitor {
    public static class Lifecycle extends SystemService {
        public void onStart() {
            //创建MountService对象【见小节2.3】
            mMountService = new MountService(getContext());
            //登记Binder服务
            publishBinderService("mount", mMountService);
        }
        ...
    }
    ...
}

创建MountService对象,并向Binder服务的大管家ServiceManager登记,该服务名为“mount”,对应服务对象为mMountService。登记之后,其他地方当需要MountService的服务时便可以通过服务名来向ServiceManager来查询具体的MountService服务。

2.1 MountService发送消息

system_server进程与vold守护进程间采用socket进行通信,这个通信过程是由MountService线程向vold线程发送消息。这里以执行mount调用为例:

2.3 MountService

[-> MountService.java]

public MountService(Context context) {
    sSelf = this;

    mContext = context;
    //FgThread线程名为“"android.fg",创建IMountServiceListener回调方法【见小节2.4】
    mCallbacks = new Callbacks(FgThread.get().getLooper());
    //获取PKMS的Client端对象
    mPms = (PackageManagerService) ServiceManager.getService("package");
    //创建“MountService”线程
    HandlerThread hthread = new HandlerThread(TAG);
    hthread.start();

    mHandler = new MountServiceHandler(hthread.getLooper());
    //IoThread线程名为"android.io",创建OBB操作的handler
    mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper());

    File dataDir = Environment.getDataDirectory();
    File systemDir = new File(dataDir, "system");
    mLastMaintenanceFile = new File(systemDir, LAST_FSTRIM_FILE);
    //判断/data/system/last-fstrim文件,不存在则创建,存在则更新最后修改时间
    if (!mLastMaintenanceFile.exists()) {
        (new FileOutputStream(mLastMaintenanceFile)).close();
        ...
    } else {
        mLastMaintenance = mLastMaintenanceFile.lastModified();
    }
    ...
    //将MountServiceInternalImpl登记到sLocalServiceObjects
    LocalServices.addService(MountServiceInternal.class, mMountServiceInternal);
    //创建用于VoldConnector的NDC对象【见小节2.5】
    mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25,
            null);
    mConnector.setDebug(true);
    //创建线程名为"VoldConnector"的线程,用于跟vold通信【见小节2.6】
    Thread thread = new Thread(mConnector, VOLD_TAG);
    thread.start();

    //创建用于CryptdConnector工作的NDC对象
    mCryptConnector = new NativeDaemonConnector(this, "cryptd",
            MAX_CONTAINERS * 2, CRYPTD_TAG, 25, null);
    mCryptConnector.setDebug(true);
    //创建线程名为"CryptdConnector"的线程,用于加密
    Thread crypt_thread = new Thread(mCryptConnector, CRYPTD_TAG);
    crypt_thread.start();

    //注册监听用户添加、删除的广播
    final IntentFilter userFilter = new IntentFilter();
    userFilter.addAction(Intent.ACTION_USER_ADDED);
    userFilter.addAction(Intent.ACTION_USER_REMOVED);
    mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);

    //内部私有volume的路径为/data,该volume通过dumpsys mount是不会显示的
    addInternalVolume();

    //默认为false
    if (WATCHDOG_ENABLE) {
        Watchdog.getInstance().addMonitor(this);
    }
}

其主要功能依次是:

  1. 创建ICallbacks回调方法,FgThread线程名为”android.fg”,此处用到的Looper便是线程”android.fg”中的Looper;
  2. 创建并启动线程名为”MountService”的handlerThread;
  3. 创建OBB操作的handler,IoThread线程名为”android.io”,此处用到的的Looper便是线程”android.io”中的Looper;
  4. 创建NativeDaemonConnector对象
  5. 创建并启动线程名为”VoldConnector”的线程;
  6. 创建并启动线程名为”CryptdConnector”的线程;
  7. 注册监听用户添加、删除的广播;

从这里便可知道共创建了3个线程:”MountService”,”VoldConnector”,”CryptdConnector”,另外还会使用到系统进程中的两个线程”android.fg”和”android.io”.
这便是在文章开头进程架构图中Java framework层进程的创建情况.

接下来再分别看看MountService创建过程中的Callbacks实例化,
NativeDaemonConnector实例化,以及”vold”线程的运行.

2.1.1 MS.mount

class MountService extends IMountService.Stub
        implements INativeDaemonConnectorCallbacks, Watchdog.Monitor {

    public void mount(String volId) {
        ...
        try {
            //【见小节2.1.2】
            mConnector.execute("volume", "mount", vol.id, vol.mountFlags, vol.mountUserId);
        } catch (NativeDaemonConnectorException e) {
            throw e.rethrowAsParcelableException();
        }
    }
}

2.4 Callbacks

class MountService {
    ...
    private static class Callbacks extends Handler {
        private final RemoteCallbackList<IMountServiceListener>
                        mCallbacks = new RemoteCallbackList<>();
        public Callbacks(Looper looper) {
            super(looper);
        }
        ...
    }
}

创建Callbacks时的Looper为FgThread.get().getLooper(),其中FgThread采用单例模式,是一个线程名为”android.fg”的HandlerThread。另外,Callbacks对象有一个成员变量mCallbacks,如下:

[-> RemoteCallbackList.java]

public class RemoteCallbackList<E extends IInterface> {
    ArrayMap<IBinder, Callback> mCallbacks
            = new ArrayMap<IBinder, Callback>();

    //Binder死亡通知
    private final class Callback implements IBinder.DeathRecipient {
        public void binderDied() {
            ...
        }
    }

    //注册死亡回调
    public boolean register(E callback, Object cookie) {
        synchronized (mCallbacks) {
            ...
            IBinder binder = callback.asBinder();
            Callback cb = new Callback(callback, cookie);
            binder.linkToDeath(cb, 0);
            mCallbacks.put(binder, cb);
            ...
        }
    }
    ...
}

通过register()方法添加IMountServiceListener对象信息到mCallbacks澳门新葡亰3522平台游戏,成员变量。RemoteCallbackList的内部类Callback继承于IBinder.DeathRecipient,很显然这是死亡通知,当binder服务端进程死亡后,回调binderDied方法通知binder客户端进行相应地处理。

2.1.2 NDC.execute

[-> NativeDaemonConnector.java]

public NativeDaemonEvent execute(String cmd, Object... args)
    throws NativeDaemonConnectorException {
    return execute(DEFAULT_TIMEOUT, cmd, args);
}

其中DEFAULT_TIMEOUT=1min,即命令执行超时时长为1分钟。经过层层调用到executeForList()

public NativeDaemonEvent[] executeForList(long timeoutMs, String cmd, Object... args)
        throws NativeDaemonConnectorException {
    final long startTime = SystemClock.elapsedRealtime();

    final ArrayList<NativeDaemonEvent> events = Lists.newArrayList();

    final StringBuilder rawBuilder = new StringBuilder();
    final StringBuilder logBuilder = new StringBuilder();

    //mSequenceNumber初始化值为0,每执行一次该方法则进行加1操作
    final int sequenceNumber = mSequenceNumber.incrementAndGet();

    makeCommand(rawBuilder, logBuilder, sequenceNumber, cmd, args);

    //例如:“3 volume reset”
    final String rawCmd = rawBuilder.toString();
    final String logCmd = logBuilder.toString();

    log("SND -> {" + logCmd + "}");

    synchronized (mDaemonLock) {
        //将cmd写入到socket的输出流
        mOutputStream.write(rawCmd.getBytes(StandardCharsets.UTF_8));
        ...
    }

    NativeDaemonEvent event = null;
    do {
        //阻塞等待,直到收到相应指令的响应码
        event = mResponseQueue.remove(sequenceNumber, timeoutMs, logCmd);
        events.add(event);
    //当收到的事件响应码属于[100,200)区间,则继续等待后续事件上报
    } while (event.isClassContinue());

    final long endTime = SystemClock.elapsedRealtime();
    //对于执行时间超过500ms则会记录到log
    if (endTime - startTime > WARN_EXECUTE_DELAY_MS) {
        loge("NDC Command {" + logCmd + "} took too long (" + (endTime - startTime) + "ms)");
    }
    ...
    return events.toArray(new NativeDaemonEvent[events.size()]);
}
  • 首先,将带执行的命令mSequenceNumber执行加1操作;
  • 再将cmd(例如3 volume reset)写入到socket的输出流;
  • 通过循环与poll机制阻塞等待底层响应该操作完成的结果;
  • 有两个情况会跳出循环:
    • 当超过1分钟未收到vold相应事件的响应码,则跳出阻塞等待;
    • 当收到底层的响应码,且响应码不属于[100,200)区间,则跳出循环。
  • 对于执行时间超过500ms的时间,则额外输出以NDC Command开头的log信息,提示可能存在优化之处。

2.5 NativeDaemonConnector

[-> NativeDaemonConnector.java]

NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket,
        int responseQueueSize, String logTag, int maxLogSize, PowerManager.WakeLock wl) {
    this(callbacks, socket, responseQueueSize, logTag, maxLogSize, wl,
            FgThread.get().getLooper());
}

NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket,
        int responseQueueSize, String logTag, int maxLogSize, PowerManager.WakeLock wl,
        Looper looper) {
    mCallbacks = callbacks;
    //socket名为"vold"
    mSocket = socket;
    //对象响应个数为500
    mResponseQueue = new ResponseQueue(responseQueueSize);
    mWakeLock = wl;
    if (mWakeLock != null) {
        mWakeLock.setReferenceCounted(true);
    }
    mLooper = looper;
    mSequenceNumber = new AtomicInteger(0);
    //TAG为"VoldConnector"
    TAG = logTag != null ? logTag : "NativeDaemonConnector";
    mLocalLog = new LocalLog(maxLogSize);
}
  • mLooper为FgThread.get().getLooper(),即运行在”android.fg”线程;
  • mResponseQueue对象中成员变量mPendingCmds数据类型为LinkedList,记录着vold进程上报的响应事件,事件个数上限为500。

2.1.3 FL.onDataAvailable

MountService线程通过socket发送cmd事件给vold,对于vold守护进程在启动的过程,初始化CommandListener时通过pthread_create创建子线程vold来专门监听MountService发送过来的消息,当该线程接收到socket消息时,便会调用onDataAvailable()方法

[-> FrameworkListener.cpp]

bool FrameworkListener::onDataAvailable(SocketClient *c) {
    char buffer[CMD_BUF_SIZE];
    int len;
    // 多次尝试从socket管道读取数据
    len = TEMP_FAILURE_RETRY(read(c->getSocket(), buffer, sizeof(buffer)));
    ...

    for (i = 0; i < len; i++) {
        if (buffer[i] == '') {
            //分发该命令【见小节2.1.4】
            dispatchCommand(c, buffer + offset);
            ...
        }
    }
    return true;
}

2.6 NDC.run

[-> NativeDaemonConnector.java]

final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdog.Monitor {
    public void run() {
        mCallbackHandler = new Handler(mLooper, this);

        while (true) {
            try {
                //监听vold的socket【见小节2.13】
                listenToSocket();
            } catch (Exception e) {
                loge("Error in NativeDaemonConnector: " + e);
                SystemClock.sleep(5000);
            }
        }
    }
}

在线程VoldConnector中建立了名为vold的socket的客户端,通过循环方式不断监听Vold服务端发送过来的消息。
另外,同理还有一个线程CryptdConnector也采用类似的方式,建立了cryptd`的socket客户端,监听Vold中另个线程发送过来的消息。到此,MountService与NativeDaemonConnector都已经启动,那么接下来到系统启动到达阶段PHASE_ACTIVITY_MANAGER_READY,则调用到onBootPhase方法。

2.1.4 FL.dispatchCommand

[-> FrameworkListener.cpp]

void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) {
    ...
    for (i = mCommands->begin(); i != mCommands->end(); ++i) {
        FrameworkCommand *c = *i;

        if (!strcmp(argv[0], c->getCommand())) {
            //找到相应的类处理该命令
            if (c->runCommand(cli, argc, argv)) {
                SLOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno));
            }
            goto out;
        }
    }
    ...
}

这是用于分发从MountService发送过来的命令,针对不同的命令调用不同的类,总共有以下6类:

  • DumpCmd
  • VolumeCmd
  • AsecCmd
  • ObbCmd
  • StorageCmd
  • FstrimCmd

另外,在处理过程中遇到下面情况,则会直接发送响应吗500的应答消息给MountService

  • 当无法找到匹配的类,则会直接向MountService返回响应码500,内容”Command
    not recognized”的应答消息;
  • 命令参数过长导致socket管道溢出,则会发送响应码500,内容”Command too
    long”的应答消息。

2.7 onBootPhase

[-> MountService.java ::Lifecycle]

由于MountService的内部Lifecycle已添加SystemServiceManager的mServices服务列表;系统启动到PHASE_ACTIVITY_MANAGER_READY时会回调mServices中的onBootPhase方法

public static class Lifecycle extends SystemService {
    public void onBootPhase(int phase) {
        if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
            mMountService.systemReady();
        }
    }
}

再调用MountService.systemReady方法,该方法主要是通过mHandler发送消息。

private void systemReady() {
    mSystemReady = true;
    mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget();
}

此处mHandler = new MountServiceHandler(hthread.getLooper()),采用的是线程”MountService”中的Looper。到此system_server主线程通过handler向线程”MountService”发送H_SYSTEM_READY消息,接下来进入线程”MountService”的MountServiceHandler对象(简称MSH)的handleMessage()来处理相关的消息。

2.1.5 CL.runCommand

例如前面发送过来的是volume mount,则会调用到CommandListener的内部类VolumeCmd的runCommand来处理该消息,并进入mount分支。

int CommandListener::VolumeCmd::runCommand(SocketClient *cli,
                                           int argc, char **argv) {
    VolumeManager *vm = VolumeManager::Instance();
    std::lock_guard<std::mutex> lock(vm->getLock());
    ...
    std::string cmd(argv[1]);
    if (cmd == "reset") {
           return sendGenericOkFail(cli, vm->reset());
    }else if (cmd == "mount" && argc > 2) {
        // mount [volId] [flags] [user]
        std::string id(argv[2]);
        auto vol = vm->findVolume(id);
        if (vol == nullptr) {
            return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume", false);
        }

        int mountFlags = (argc > 3) ? atoi(argv[3]) : 0;
        userid_t mountUserId = (argc > 4) ? atoi(argv[4]) : -1;

        vol->setMountFlags(mountFlags);
        vol->setMountUserId(mountUserId);
        //真正的挂载操作【见2.1.6】
        int res = vol->mount();
        if (mountFlags & android::vold::VolumeBase::MountFlags::kPrimary) {
            vm->setPrimary(vol);
        }
        //发送应答消息给MountService【见2.2.1】
        return sendGenericOkFail(cli, res);
    }
    // 省略其他的else if
    ...
}

2.8 MSH.handleMessage

[-> MountService.java ::MountServiceHandler]

class MountServiceHandler extends Handler {
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case H_SYSTEM_READY: {
                handleSystemReady(); //【见小节2.9】
                break;
            }
            ...
        }
    }
}

2.1.6 mount

这里便进入了VolumeManager模块,执行volume设备真正的挂载操作。对于挂载内置存储和外置存储流程是有所不同的,这里就不再细说,简单的调用流程:

VolumeCmd.runCommand
    VolumeBase.mount
        EmulatedVolume.doMount(内置)
        PublicVolume.doMount(外置)
            vfat::Check
            vfat::Mount
            fork (/sdcard)

2.9 handleSystemReady

[-> MountService.java]

private void handleSystemReady() {
    synchronized (mLock) {
        //【见小节2.10】
        resetIfReadyAndConnectedLocked();
    }

    //计划执行日常的fstrim操作【】
    MountServiceIdler.scheduleIdlePass(mContext);
}

2.1.7 小节

澳门新葡亰3522平台游戏 5

MountService向vold发送消息后,便阻塞在图中的MountService线程的NDC.execute()方法,那么何时才会退出呢?图的后半段MonutService接收消息的过程会有答案,那便是在收到消息,并且消息的响应吗不属于区间[600,700)则添加事件到ResponseQueue,从而唤醒阻塞的MountService继续执行。关于上图的后半段介绍的便是MountService接收消息的流程。

2.10 resetIfReadyAndConnectedLocked

[-> MountService.java]

private void resetIfReadyAndConnectedLocked() {
    Slog.d(TAG, "Thinking about reset, mSystemReady=" + mSystemReady
            + ", mDaemonConnected=" + mDaemonConnected);
    //当系统启动到阶段550,并且已经与vold守护进程建立连接,则执行reset
    if (mSystemReady && mDaemonConnected) {
        killMediaProvider();
        mDisks.clear();
        mVolumes.clear();

        //将/data为路径的private volume添加到mVolumes
        addInternalVolume();

        try {
            //【见小节2.11】
            mConnector.execute("volume", "reset");

            //告知所有已经存在和启动的users
            final UserManager um = mContext.getSystemService(UserManager.class);
            final List<UserInfo> users = um.getUsers();
            for (UserInfo user : users) {
                mConnector.execute("volume", "user_added", user.id, user.serialNumber);
            }
            for (int userId : mStartedUsers) {
                mConnector.execute("volume", "user_started", userId);
            }
        } catch (NativeDaemonConnectorException e) {
            Slog.w(TAG, "Failed to reset vold", e);
        }
    }
}

2.2 MountService接收消息

当Vold在处理完完MountService发送过来的消息后,会通过sendGenericOkFail发送应答消息给上层的MountService。

2.11 NDC.execute

[-> NativeDaemonConnector.java]

public NativeDaemonEvent execute(String cmd, Object... args)
        throws NativeDaemonConnectorException {
    return execute(DEFAULT_TIMEOUT, cmd, args);
}

其中DEFAULT_TIMEOUT=1min,即命令执行超时时长为1分钟。经过层层调用,executeForList()

public NativeDaemonEvent[] executeForList(long timeoutMs, String cmd, Object... args)
        throws NativeDaemonConnectorException {
    final long startTime = SystemClock.elapsedRealtime();

    final ArrayList<NativeDaemonEvent> events = Lists.newArrayList();

    final StringBuilder rawBuilder = new StringBuilder();
    final StringBuilder logBuilder = new StringBuilder();

    //mSequenceNumber初始化值为0,每执行一次该方法则进行加1操作
    final int sequenceNumber = mSequenceNumber.incrementAndGet();

    makeCommand(rawBuilder, logBuilder, sequenceNumber, cmd, args);

    //例如:“3 volume reset”
    final String rawCmd = rawBuilder.toString();
    final String logCmd = logBuilder.toString();

    log("SND -> {" + logCmd + "}");

    synchronized (mDaemonLock) {
        //将cmd写入到socket的输出流
        mOutputStream.write(rawCmd.getBytes(StandardCharsets.UTF_8));
        ...
    }

    NativeDaemonEvent event = null;
    do {
        //【见小节2.12】
        event = mResponseQueue.remove(sequenceNumber, timeoutMs, logCmd);
        events.add(event);
    //当收到的事件响应码属于[100,200)区间,则继续等待后续事件上报
    } while (event.isClassContinue());

    final long endTime = SystemClock.elapsedRealtime();
    //对于执行时间超过500ms则会记录到log
    if (endTime - startTime > WARN_EXECUTE_DELAY_MS) {
        loge("NDC Command {" + logCmd + "} took too long (" + (endTime - startTime) + "ms)");
    }
    ...
    return events.toArray(new NativeDaemonEvent[events.size()]);
}

首先,将带执行的命令mSequenceNumber执行加1操作,再将cmd(例如3 volume reset)写入到socket的输出流,通过循环与poll机制等待执行底层响应该操作结果,否则直到1分钟超时才结束该方法。即便收到底层的响应码,如果响应码属于[100,200)区间,则继续阻塞等待后续事件上报。

2.2.1 响应码

[-> CommandListener.cpp]

int CommandListener::sendGenericOkFail(SocketClient *cli, int cond) {
    if (!cond) {
        //【见小节2.2.2】
        return cli->sendMsg(ResponseCode::CommandOkay, "Command succeeded", false);
    } else {
        return cli->sendMsg(ResponseCode::OperationFailed, "Command failed", false);
    }
}
  • 当执行成功,则发送响应码为500的成功应答消息;
  • 当执行失败,则发送响应码为400的失败应答消息。

不同的响应码(VoldResponseCode),代表着系统不同的处理结果,主要分为下面几大类:

响应码 事件类别 对应方法
[100, 200) 部分响应,随后继续产生事件 isClassContinue
[200, 300) 成功响应 isClassOk
[400, 500) 远程服务端错误 isClassServerError
[500, 600) 本地客户端错误 isClassClientError
[600, 700) 远程Vold进程自触发的事件 isClassUnsolicited

例如当操作执行成功,VoldConnector线程能收到类似`RCV <- {200 3
Command succeeded}的响应事件。

其中对于[600,700)响应码是由Vold进程”不请自来”的事件,主要是针对disk,volume的一系列操作,比如设备创建,状态、路径改变,以及文件类型、uid、标签改变等事件都是底层直接触发。

命令 响应吗
DISK_CREATED 640
DISK_SIZE_CHANGED 641
DISK_LABEL_CHANGED 642
DISK_SCANNED 643
DISK_SYS_PATH_CHANGED 644
DISK_DESTROYED 649
VOLUME_CREATED 650
VOLUME_STATE_CHANGED 651
VOLUME_FS_TYPE_CHANGED 652
VOLUME_FS_UUID_CHANGED 653
VOLUME_FS_LABEL_CHANGED 654
VOLUME_PATH_CHANGED 655
VOLUME_INTERNAL_PATH_CHANGED 656
VOLUME_DESTROYED 659
MOVE_STATUS 660
BENCHMARK_RESULT 661
TRIM_RESULT 662

介绍完响应码,接着继续来说说发送应答消息的过程:

2.12 ResponseQueue.remove

[-> MountService.java ::ResponseQueue]

private static class ResponseQueue {
    public NativeDaemonEvent remove(int cmdNum, long timeoutMs, String logCmd) {
        PendingCmd found = null;
        synchronized (mPendingCmds) {
            //从mPendingCmds查询cmdNum
            for (PendingCmd pendingCmd : mPendingCmds) {
                if (pendingCmd.cmdNum == cmdNum) {
                    found = pendingCmd;
                    break;
                }
            }
            //如果已有的mPendingCmds中查询不到,则创建一个新的PendingCmd
            if (found == null) {
                found = new PendingCmd(cmdNum, logCmd);
                mPendingCmds.add(found);
            }
            found.availableResponseCount--;
            if (found.availableResponseCount == 0) mPendingCmds.remove(found);
        }
        NativeDaemonEvent result = null;
        try {
            //采用poll轮询方式等待底层上报该事件,直到1分钟超时
            result = found.responses.poll(timeoutMs, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {}
        return result;
    }
}

这里用到poll,先来看看responses = new ArrayBlockingQueue<NativeDaemonEvent>(10),这是一个长度为10的可阻塞队列。
这里的poll也是阻塞的方式来轮询事件。

2.2.2 SC.sendMsg

[-> SocketClient.cpp]

int SocketClient::sendMsg(int code, const char *msg, bool addErrno) {
    return sendMsg(code, msg, addErrno, mUseCmdNum);
}

sendMsg经过层层调用,进入sendDataLockedv方法

int SocketClient::sendDataLockedv(struct iovec *iov, int iovcnt) {
    ...
    struct sigaction new_action, old_action;
    memset(&new_action, 0, sizeof(new_action));
    new_action.sa_handler = SIG_IGN;
    sigaction(SIGPIPE, &new_action, &old_action);

    //将应答消息写入socket管道
    for (;;) {
        ssize_t rc = TEMP_FAILURE_RETRY(
            writev(mSocket, iov + current, iovcnt - current));

        if (rc > 0) {
            size_t written = rc;
            while ((current < iovcnt) && (written >= iov[current].iov_len)) {
                written -= iov[current].iov_len;
                current++;
            }
            if (current == iovcnt) {
                break;
            }
            iov[current].iov_base = (char *)iov[current].iov_base + written;
            iov[current].iov_len -= written;
            continue;
        }
        ...
        break;
    }

    sigaction(SIGPIPE, &old_action, &new_action);
    ...
    return ret;
}

responses.poll

[-> ArrayBlockingQueue.java]

public E poll(long timeout, TimeUnit unit) throws InterruptedException {
    long nanos = unit.toNanos(timeout);
    final ReentrantLock lock = this.lock;
    //可中断的锁等待
    lock.lockInterruptibly();
    try {
        //当队列长度为空,循环等待
        while (count == 0) {
            if (nanos <= 0)
                return null;
            nanos = notEmpty.awaitNanos(nanos);
        }
        return extract();
    } finally {
        lock.unlock();
    }
}

小知识:这里用到了ReentrantLock同步锁,该锁跟synchronized有功能有很相似,用于多线程并发访问。那么ReentrantLock与synchronized相比,

ReentrantLock优势:

  • ReentrantLock功能更为强大,比如有时间锁等候,可中断锁等候(lockInterruptibly),锁投票等功能;
  • ReentrantLock性能更好些;
  • ReentrantLock提供可轮询的锁请求(tryLock),相对不容易产生死锁;而synchronized只要进入,要么成功获取,要么一直阻塞等待。

ReentrantLock的劣势:

  • lock必须在finally块显式地释放,否则如果代码抛出Exception,锁将一直得不到释放;对于synchronized而言,JVM或者ART虚拟机都会确保该锁能自动释放。
  • synchronized锁,在dump线程转储时会记录锁信息,对于分析调试大有裨益;对于Lock来说,只是普通类,虚拟机无法识别。

再回到ResponseQueue.remove(),该方法中mPendingCmds中的内容是哪里添加的呢?其实是在NDC.listenToSocket循环监听到消息时添加的,则接下来看看监听过程。

2.2.3 NDC.listenToSocket

应答消息写入socket管道后,在MountService的另个线程”VoldConnector”中建立了名为vold的socket的客户端,通过循环方式不断监听Vold服务端发送过来的消息。

[-> NativeDaemonConnector.java]

private void listenToSocket() throws IOException {
    LocalSocket socket = null;
    try {
        socket = new LocalSocket();
        LocalSocketAddress address = determineSocketAddress();
        //建立与"/dev/socket/vold"的socket连接
        socket.connect(address);
        InputStream inputStream = socket.getInputStream();
        synchronized (mDaemonLock) {
            mOutputStream = socket.getOutputStream();
        }
        ...
        while (true) {
            int count = inputStream.read(buffer, start, BUFFER_SIZE - start);
            ...
            for (int i = 0; i < count; i++) {
                if (buffer[i] == 0) {
                    final String rawEvent = new String(
                            buffer, start, i - start, StandardCharsets.UTF_8);
                    //解析socket服务端发送的event
                    final NativeDaemonEvent event = NativeDaemonEvent.parseRawEvent(
                            rawEvent);
                    log("RCV <- {" + event + "}");

                    if (event.isClassUnsolicited()) {
                        ...
                        //当响应码区间为[600,700),则发送消息交由mCallbackHandler处理
                        if (mCallbackHandler.sendMessage(mCallbackHandler.obtainMessage(
                                event.getCode(), event.getRawEvent()))) {
                            releaseWl = false;
                        }
                    } else {
                        //对于其他响应码则添加到mResponseQueue队列
                        mResponseQueue.add(event.getCmdNumber(), event);
                    }
                }
            }
        }
    } finally {
        //收尾清理类工作
        ...
    }
}

监听也是阻塞的过程,当收到不同的消息相应码,采用不同的行为:

  • 当响应吗不属于区间[600,700):则将该事件添加到mResponseQueue,并且触发响应事件所对应的请求事件不再阻塞到ResponseQueue.poll,那么线程继续往下执行,即前面小节[2.1.2]
    NDC.execute的过程。
  • 当响应码区间为[600,700):则发送消息交由mCallbackHandler处理,向线程android.fg发送Handler消息,该线程收到后回调NativeDaemonConnector的handleMessage来处理。

2.13 listenToSocket

[-> NativeDaemonConnector.java]

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

    try {
        socket = new LocalSocket();
        LocalSocketAddress address = determineSocketAddress();
        //建立与"/dev/socket/vold"的socket连接
        socket.connect(address);

        InputStream inputStream = socket.getInputStream();
        synchronized (mDaemonLock) {
            mOutputStream = socket.getOutputStream();
        }
        //建立连接后,回调MS.onDaemonConnected【见小节2.15】
        mCallbacks.onDaemonConnected();

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

        while (true) {
            int count = inputStream.read(buffer, start, BUFFER_SIZE - start);
            ...

            for (int i = 0; i < count; i++) {
                if (buffer[i] == 0) {
                    final String rawEvent = new String(
                            buffer, start, i - start, StandardCharsets.UTF_8);

                    boolean releaseWl = false;
                    try {
                        //解析socket服务端发送的event
                        final NativeDaemonEvent event = NativeDaemonEvent.parseRawEvent(
                                rawEvent);

                        log("RCV <- {" + event + "}");
                        //当事件的响应码区间为[600,700),则发送消息交由mCallbackHandler处理
                        if (event.isClassUnsolicited()) {
                            if (mCallbacks.onCheckHoldWakeLock(event.getCode())
                                    && mWakeLock != null) {
                                mWakeLock.acquire();
                                releaseWl = true;
                            }
                            if (mCallbackHandler.sendMessage(mCallbackHandler.obtainMessage(
                                    event.getCode(), event.getRawEvent()))) {
                                releaseWl = false;
                            }
                        } else {
                            //对于其他的响应码则添加到mResponseQueue队列【见小节2.14】
                            mResponseQueue.add(event.getCmdNumber(), event);
                        }
                    } catch (IllegalArgumentException e) {
                        log("Problem parsing message " + e);
                    } finally {
                        if (releaseWl) {
                            mWakeLock.acquire();
                        }
                    }
                    start = i + 1;
                }
            }
            ...
        }
    } catch (IOException ex) {
        throw ex;
    } finally {
        //收尾清理类工作,关闭mOutputStream, socket
        ...
    }
}

这里有一个动作是mResponseQueue.add(),通过该方法便能触发ResponseQueue.poll阻塞操作继续往下执行。

2.2.4 小节

澳门新葡亰3522平台游戏 6

2.14 ResponseQueue.add

[-> NativeDaemonConnector.java]

private static class ResponseQueue {
    public void add(int cmdNum, NativeDaemonEvent response) {
       PendingCmd found = null;
       synchronized (mPendingCmds) {
           for (PendingCmd pendingCmd : mPendingCmds) {
               if (pendingCmd.cmdNum == cmdNum) {
                   found = pendingCmd;
                   break;
               }
           }
            //没有找到则创建相应的PendingCmd
           if (found == null) {
               while (mPendingCmds.size() >= mMaxCount) {
                   PendingCmd pendingCmd = mPendingCmds.remove();
               }
               found = new PendingCmd(cmdNum, null);
               mPendingCmds.add(found);
           }
           found.availableResponseCount++;
           if (found.availableResponseCount == 0) mPendingCmds.remove(found);
       }
       try {
           found.responses.put(response);
       } catch (InterruptedException e) { }
   }
}

2.3 Kernel上报事件

介绍完MonutService与vold之间的交互通信,那么再来看看Kernel是如何上报事件到vold的流程。再介绍这个之前,先简单看看vold启动时都创建了哪些对象。

[-> system/vold/Main.cpp]

int main(int argc, char** argv) {
    setenv("ANDROID_LOG_TAGS", "*:v", 1);
    android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));

    VolumeManager *vm;
    CommandListener *cl;
    CryptCommandListener *ccl;
    NetlinkManager *nm;

    mkdir("/dev/block/vold", 0755);

    //用于cryptfs检查,并mount加密的文件系统
    klog_set_level(6);

    //创建单例对象VolumeManager
    if (!(vm = VolumeManager::Instance())) {
        exit(1);
    }

    //创建单例对象NetlinkManager
    if (!(nm = NetlinkManager::Instance())) {
        exit(1);
    }

    if (property_get_bool("vold.debug", false)) {
        vm->setDebug(true);
    }

    // 创建CommandListener对象
    cl = new CommandListener();
    // 创建CryptCommandListener对象
    ccl = new CryptCommandListener();

    //给vm设置socket监听对象
    vm->setBroadcaster((SocketListener *) cl);
    //给nm设置socket监听对象
    nm->setBroadcaster((SocketListener *) cl);

    if (vm->start()) { //启动vm
        exit(1);
    }

    process_config(vm); //解析config参数

    if (nm->start()) {  //启动nm
        exit(1);
    }

    coldboot("/sys/block");

    //启动响应命令的监听器
    if (cl->startListener()) {
        exit(1);
    }

    if (ccl->startListener()) {
        exit(1);
    }

    //Vold成为监听线程
    while(1) {
        sleep(1000);
    }

    exit(0);
}

该方法的主要功能是创建并启动:VolumeManager,NetlinkManager
,NetlinkHandler,CommandListener,CryptCommandListener。

responses.put

[-> ArrayBlockingQueue.java]

public void put(E e) throws InterruptedException {
    checkNotNull(e);
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
        //当队列满了则等待
        while (count == items.length)
            notFull.await();
        insert(e);
    } finally {
        lock.unlock();
    }
}

看完了如何向mPendingCmds中增加待处理的命令,再来回过来看看,当当listenToSocket刚开始监听前,收到Native的Daemon连接后的执行操作.

2.3.1 Uevent && Netlink

Kernel上报事件给用户空间采用了Netlink方式,Netlink是一种特殊的socket,它是Linux所特有的。传送的消息是暂存在socket接收缓存中,并不被接收者立即处理,所以netlink是一种异步通信机制。而对于syscall和ioctl则都是同步通信机制。

Linux系统中大量采用Netlink机制来进行用户空间程序与kernel的通信。例如设备热插件,这会产生Uevent(User
Space
event,用户空间事件)是Linux系统中用户空间与内核空间之间通信的消息内容,主要用于设备驱动的事件通知。Uevent是Kobject的一部分,当Kobject状态改变时通知用户空间程序。对于kobject_action包括KOBJ_ADD,KOBJ_REMOVE,KOBJ_CHANGE,KOBJ_MOVE,KOBJ_ONLINE,KOBJ_OFFLINE,当发送任何一种action都会引发Kernel发送Uevent消息。

vold早已准备就绪等待着Kernel上报Uevent事件,接下来看看vold是如何接收Uevent事件,这就从NetlinkManager启动开始说起。

2.15 MS.onDaemonConnected

[-> MountService.java]

public void onDaemonConnected() {
    mDaemonConnected = true;
    mHandler.obtainMessage(H_DAEMON_CONNECTED).sendToTarget();
}

当前主线程发送消息H_DAEMON_CONNECTED给线程MountService`,该线程收到消息后调用MountServiceHandler的handleMessage()相应分支后,进而调用handleDaemonConnected()方法。

private void handleDaemonConnected() {
    synchronized (mLock) {
        resetIfReadyAndConnectedLocked();
    }

    //类型为CountDownLatch,用于多线程同步,阻塞await()直到计数器为零
    mConnectedSignal.countDown();
    if (mConnectedSignal.getCount() != 0) {
        return;
    }

    //调用PMS来加载ASECs
    mPms.scanAvailableAsecs();

    //用于通知ASEC扫描已完成
    mAsecsScanned.countDown();
}

这里的PMS.scanAvailableAsecs()经过层层调用,最终核心工作还是通过MountService.getSecureContainerList。

[-> MountService.java]

public String[] getSecureContainerList() {
    enforcePermission(android.Manifest.permission.ASEC_ACCESS);
    //等待mConnectedSignal计数锁达到零
    waitForReady();
    //当没有挂载Primary卷设备,则弹出警告
    warnOnNotMounted();

    try {
        //向vold进程发送asec list命令
        return NativeDaemonEvent.filterMessageList(
                mConnector.executeForList("asec", "list"), VoldResponseCode.AsecListResult);
    } catch (NativeDaemonConnectorException e) {
        return new String[0];
    }
}

2.3.2 NM.start

[-> NetlinkManager.java]

int NetlinkManager::start() {
    struct sockaddr_nl nladdr;
    int sz = 64 * 1024;
    int on = 1;

    memset(&nladdr, 0, sizeof(nladdr));
    nladdr.nl_family = AF_NETLINK;
    nladdr.nl_pid = getpid(); //记录当前进程的pid
    nladdr.nl_groups = 0xffffffff;

    //PF_NETLINK代表创建的是Netlink通信的socket
    if ((mSock = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC,
            NETLINK_KOBJECT_UEVENT)) < 0) {
        return -1;
    }

    //设置uevent的SO_RCVBUFFORCE选项
    if (setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) {
        goto out;
    }

    //设置uevent的SO_PASSCRED选项
    if (setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
        goto out;
    }
    //绑定uevent socket
    if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {
        goto out;
    }

    //创建NetlinkHandler
    mHandler = new NetlinkHandler(mSock);
    //启动NetlinkHandler
    if (mHandler->start()) {
        goto out;
    }
    return 0;

out:
    close(mSock);
    return -1;
}

NetlinkManager启动的过程中,会创建并启动NetlinkHandler,在该过程会通过pthrea_create创建子线程专门用于接收Kernel发送过程的Uevent事件,当收到数据时会调用NetlinkListener的onDataAvailable方法。

2.16 小节

这里以一张简单的流程图来说明上述过程:

澳门新葡亰3522平台游戏 7