Android存储系统之源码篇

GZBCoy 8年前
   <pre>  <code class="language-java">/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    /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</code></pre>    <h2>一、概述</h2>    <p>本文主要介绍跟存储相关的模块MountService和Vold,并不涉及底层文件系统。</p>    <ul>     <li>MountService:Android Binder服务,运行在system_server进程,用于跟Vold进行消息通信,比如 MountService 向 Vold 发送挂载SD卡的命令,或者接收到来自 Vold 的外设热插拔事件。</li>     <li>Vold(全称为Volume Daemon),用于管理外部存储设备的Native守护进程,这是一个非常重要的守护进程,由NetlinkManager,VolumeManager,CommandListener这3部分组成。</li>    </ul>    <p>MountService的NativeDaemonConnector(Client端)和 Vold的CL模块(Server端)建立socket通信。</p>    <ol>     <li>Linux Kernel:通过uevent向Vold的NetlinkManager发送Uevent事件;</li>     <li>NetlinkManager:接收来自Kernel的 Uevent 事件,再转发给VolumeManager;</li>     <li>VolumeManager: 接收来自NetlinkManager的事件,再转发给CommandListener进行处理;</li>     <li>CommandListener: 接收来自VolumeManager的事件,通过 socket 通信方式发送给MountService;</li>     <li>MountService: 接收来自CommandListener的事件。</li>    </ol>    <h3>1.1 存储架构设计</h3>    <p>存储架构从进程/线程视角:</p>    <ul>     <li>Java层采用1个system_server主线程+3个子线程; 另外还会使用到系统进程中的两个线程”android.fg”和”android.io”。</li>     <li>Native采用1个vold主线程+3个子线程+1子进程的架构;</li>    </ul>    <p>先看看Java层的线程:</p>    <pre>  <code class="language-java">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  ...</code></pre>    <p>再看看Native层的线程:</p>    <pre>  <code class="language-java">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</code></pre>    <p>小技巧:有读者可能会好奇,为什么/system/bin/sdcard是子进程,而非子线程呢?要回答这个问题,有两个方法,其一就是直接看撸源码,会发现这是通过 fork 方式创建的,而其他子线程都是通过 pthread_create 方式创建的。当然其实还有个更快捷的小技巧,就是直接看上图中的第4列,这一列的含义是 VSIZE ,代表的是进程虚拟地址空间大小,是否共享地址空间,这是进程与线程最大的区别,再来看看/sdcard的VSIZE大小跟父进程不一样,基本可以确实/sdcard是子进程。</p>    <p>Tips: 同一个模块可以运行在各个不同的进程/线程, 同一个进程可以运行不同模块的代码。</p>    <h3>1.2 NativeDaemonEvent</h3>    <table>     <thead>      <tr>       <th>响应码</th>       <th>事件类别</th>       <th>对应方法</th>      </tr>     </thead>     <tbody>      <tr>       <td>[100, 200)</td>       <td>部分响应,随后继续产生事件</td>       <td>isClassContinue</td>      </tr>      <tr>       <td>[200, 300)</td>       <td>成功响应</td>       <td>isClassOk</td>      </tr>      <tr>       <td>[400, 500)</td>       <td>远程服务端错误</td>       <td>isClassServerError</td>      </tr>      <tr>       <td>[500, 600)</td>       <td>本地客户端错误</td>       <td>isClassClientError</td>      </tr>      <tr>       <td>[600, 700)</td>       <td>远程Vold进程自触发的事件</td>       <td>isClassUnsolicited</td>      </tr>     </tbody>    </table>    <p>例如当操作执行成功,VoldConnector线程能收到类似“RCV <- {200 3 Command succeeded}”的响应事件。</p>    <p>这里在详细列举远程Vold进程的那些”不请自来”的事件,也就是指底层触发的响应码,范围为[600,700)</p>    <table>     <thead>      <tr>       <th>命令</th>       <th>响应吗</th>      </tr>     </thead>     <tbody>      <tr>       <td>DISK_CREATED</td>       <td>640</td>      </tr>      <tr>       <td>DISK_SIZE_CHANGED</td>       <td>641</td>      </tr>      <tr>       <td>DISK_LABEL_CHANGED</td>       <td>642</td>      </tr>      <tr>       <td>DISK_SCANNED</td>       <td>643</td>      </tr>      <tr>       <td>DISK_SYS_PATH_CHANGED</td>       <td>644</td>      </tr>      <tr>       <td>DISK_DESTROYED</td>       <td>649</td>      </tr>      <tr>       <td>VOLUME_CREATED</td>       <td>650</td>      </tr>      <tr>       <td>VOLUME_STATE_CHANGED</td>       <td>651</td>      </tr>      <tr>       <td>VOLUME_FS_TYPE_CHANGED</td>       <td>652</td>      </tr>      <tr>       <td>VOLUME_FS_UUID_CHANGED</td>       <td>653</td>      </tr>      <tr>       <td>VOLUME_FS_LABEL_CHANGED</td>       <td>654</td>      </tr>      <tr>       <td>VOLUME_PATH_CHANGED</td>       <td>655</td>      </tr>      <tr>       <td>VOLUME_INTERNAL_PATH_CHANGED</td>       <td>656</td>      </tr>      <tr>       <td>VOLUME_DESTROYED</td>       <td>659</td>      </tr>      <tr>       <td>MOVE_STATUS</td>       <td>660</td>      </tr>      <tr>       <td>BENCHMARK_RESULT</td>       <td>661</td>      </tr>      <tr>       <td>TRIM_RESULT</td>       <td>662</td>      </tr>     </tbody>    </table>    <p>这些命令主要是针对disk,volume的一系列操作,比如设备创建,状态、路径改变,以及文件类型、uid、标签改变等事件都是底层直接触发。</p>    <h2>二、MountService</h2>    <p>MountService运行在system_server进程,在系统启动到阶段PHASE_WAIT_FOR_DEFAULT_DISPLAY后,进入startOtherServices会启动MountService.</p>    <h3>2.1 启动</h3>    <p>[-> SystemServer.java]</p>    <pre>  <code class="language-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);          ...      });  }</code></pre>    <p>NotificationManagerService依赖于MountService,比如media/usb通知事件,所以需要先启动MountService。此处MOUNT_SERVICE_CLASS=”com.android.server.MountService$Lifecycle”</p>    <h3>2.2 startService</h3>    <p>mSystemServiceManager.startService(MOUNT_SERVICE_CLASS)主要完成3件事:</p>    <ul>     <li>创建MOUNT_SERVICE_CLASS所指类的Lifecycle对象;</li>     <li>将该对象添加SystemServiceManager的 mServices 服务列表;</li>     <li>最后调用Lifecycle的onStart()方法,主要工作量这个过程,如下:</li>    </ul>    <p>[-> MountService.java]</p>    <pre>  <code class="language-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);          }          ...      }      ...  }</code></pre>    <p>创建MountService对象,并向Binder服务的大管家ServiceManager登记,该服务名为“mount”,对应服务对象为mMountService。登记之后,其他地方当需要MountService的服务时便可以通过服务名来向ServiceManager来查询具体的MountService服务。</p>    <h3>2.3 MountService</h3>    <pre>  <code class="language-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);      }  }</code></pre>    <p>主要功能依次是:</p>    <ol>     <li>FgThread线程名为”android.fg”,创建IMountServiceListener回调方法;</li>     <li>创建并启动线程名为”MountService”的handlerThread;</li>     <li>IoThread线程名为”android.io”,创建OBB操作的handler;</li>     <li>创建NativeDaemonConnector对象</li>     <li>创建并启动线程名为”VoldConnector”的线程;</li>     <li>创建并启动线程名为”CryptdConnector”的线程;</li>     <li>注册监听用户添加、删除的广播;</li>    </ol>    <p>该过程总共创建了3个线程:”MountService”,”VoldConnector”,”CryptdConnector”,另外还会使用到系统进程中的两个线程”android.fg”和”android.io”</p>    <h3>2.4 Callbacks</h3>    <pre>  <code class="language-java">class MountService {      ...      private static class Callbacks extends Handler {          private final RemoteCallbackList<IMountServiceListener>                          mCallbacks = new RemoteCallbackList<>();          public Callbacks(Looper looper) {              super(looper);          }          ...      }  }</code></pre>    <p>创建Callbacks时的Looper为FgThread.get().getLooper(),其中 FgThread 采用单例模式,是一个线程名为”android.fg”的HandlerThread。另外,Callbacks对象有一个成员变量 mCallbacks ,如下:</p>    <p>[-> RemoteCallbackList.java]</p>    <pre>  <code class="language-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);              ...          }      }      ...  }</code></pre>    <p>通过 register() 方法添加IMountServiceListener对象信息到 mCallbacks 成员变量。RemoteCallbackList的内部类Callback继承于IBinder.DeathRecipient,很显然这是死亡通知,当binder服务端进程死亡后,回调binderDied方法通知binder客户端进行相应地处理。</p>    <h3>2.5 NativeDaemonConnector</h3>    <p>[-> NativeDaemonConnector.java]</p>    <pre>  <code class="language-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);  }</code></pre>    <ul>     <li>mLooper为FgThread.get().getLooper(),即运行在”android.fg”线程;</li>     <li>mResponseQueue对象中成员变量 mPendingCmds 数据类型为LinkedList,记录着vold进程上报的响应事件,事件个数上限为500。</li>    </ul>    <h3>2.6 NDC.run</h3>    <p>[-> NativeDaemonConnector.java]</p>    <pre>  <code class="language-java">final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdog.Monitor {      public void run() {          mCallbackHandler = new Handler(mLooper, this);            while (true) {              try {                  //监听vold的socket【见小节2.7】                  listenToSocket();              } catch (Exception e) {                  loge("Error in NativeDaemonConnector: " + e);                  SystemClock.sleep(5000);              }          }      }  }</code></pre>    <p>“VoldConnector”线程建立了”vold“的socket的客户端,通过循环方式不断监听Vold服务端发送过来的消息。 另外,同理还有一个线程“CryptdConnector”也采用类似的方式,建立了“cryptd”的socket客户端,监听Vold中另个线程发送过来的消息。</p>    <p>MountService与NDC都启动,那么接下来到系统启动到达阶段PHASE_ACTIVITY_MANAGER_READY,则调用到onBootPhase方法。</p>    <h3>2.7 onBootPhase</h3>    <p>[-> MountService.java ::Lifecycle]</p>    <p>由于MountService的内部Lifecycle已添加SystemServiceManager的 mServices 服务列表;故到系统启动到 PHASE_ACTIVITY_MANAGER_READY 时会回调 mServices 中的 onBootPhase 方法</p>    <pre>  <code class="language-java">public static class Lifecycle extends SystemService {      public void onBootPhase(int phase) {          if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {              mMountService.systemReady();          }      }  }</code></pre>    <p>再调用MountService.systemReady方法,该方法主要是通过mHandler发送消息。</p>    <pre>  <code class="language-java">private void systemReady() {      mSystemReady = true;      mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget();  }</code></pre>    <p>此处mHandler = new MountServiceHandler(hthread.getLooper())可知采用的是线程”MountService”中的Looper。到此system_server主线程通过handler向线程”MountService”发送H_SYSTEM_READY消息,接下来进入线程”MountService”的MountServiceHandler对象(简称MSH)的handleMessage()来处理相关的消息。</p>    <h3>2.8 MSH.handleMessage</h3>    <p>[-> MountService.java ::MountServiceHandler]</p>    <pre>  <code class="language-java">class MountServiceHandler extends Handler {      public void handleMessage(Message msg) {          switch (msg.what) {              case H_SYSTEM_READY: {                  handleSystemReady(); //【见小节2.9】                  break;              }              ...          }      }  }</code></pre>    <h3>2.9 handleSystemReady</h3>    <p>[-> MountService.java]</p>    <pre>  <code class="language-java">private void handleSystemReady() {      synchronized (mLock) {          //【见小节2.10】          resetIfReadyAndConnectedLocked();      }        //计划执行日常的fstrim操作【】      MountServiceIdler.scheduleIdlePass(mContext);  }</code></pre>    <h3>2.10 resetIfReadyAndConnectedLocked</h3>    <p>[-> MountService.java]</p>    <pre>  <code class="language-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);          }      }  }</code></pre>    <h3>2.11 NDC.execute</h3>    <p>[-> NativeDaemonConnector.java]</p>    <pre>  <code class="language-java">public NativeDaemonEvent execute(String cmd, Object... args)          throws NativeDaemonConnectorException {      return execute(DEFAULT_TIMEOUT, cmd, args);  }</code></pre>    <p>其中DEFAULT_TIMEOUT等于1分钟,即命令执行超时时长为1分钟。经过层层调用,executeForList()</p>    <pre>  <code class="language-java">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()]);  }</code></pre>    <p>首先,将带执行的命令mSequenceNumber执行加1操作,再将cmd(例如 3 volume reset )写入到socket的输出流,通过循环与poll机制等待执行底层响应该操作结果,否则直到1分钟超时才结束该方法。即便收到底层的响应码,如果响应码属于[100,200)区间,则继续阻塞等待后续事件上报。</p>    <h3>2.12 ResponseQueue.remove</h3>    <p>[-> MountService.java ::ResponseQueue]</p>    <pre>  <code class="language-java">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;      }  }</code></pre>    <p>mPendingCmds中的内容是如何添加的呢?其实是在NDC.listenToSocket循环监听到消息时添加的,则接下来看看监听过程。 这里用到poll,先来看看 responses = new ArrayBlockingQueue<NativeDaemonEvent>(10) ,这是一个长度为10的可阻塞队列。 这里的poll也是阻塞的方式来轮询事件。</p>    <p>responses.poll</p>    <p>[-> ArrayBlockingQueue.java]</p>    <pre>  <code class="language-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();      }  }</code></pre>    <p>小知识:这里用到了ReentrantLock同步锁,该锁跟synchronized有功能有很相似,用于多线程并发访问。那么ReentrantLock与synchronized相比,ReentrantLock优势:</p>    <ul>     <li>ReentrantLock功能更为强大,比如有时间锁等候,可中断锁等候(lockInterruptibly),锁投票等功能;</li>     <li>ReentrantLock性能更好些;</li>     <li>ReentrantLock提供可轮询的锁请求(tryLock),相对不容易产生死锁;而synchronized只要进入,要么成功获取,要么一直阻塞等待。</li>    </ul>    <p>ReentrantLock的劣势:</p>    <ul>     <li>lock必须在finally块显式地释放,否则如果代码抛出Exception,锁将一直得不到释放;对于synchronized而言,JVM或者ART虚拟机都会确保该锁能自动释放。</li>     <li>synchronized锁,在dump线程转储时会记录锁信息,对于分析调试大有裨益;对于Lock来说,只是普通类,虚拟机无法识别。</li>    </ul>    <h3>2.13 listenToSocket</h3>    <p>[-> NativeDaemonConnector.java]</p>    <pre>  <code class="language-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          ...      }  }</code></pre>    <p>这里有一个动作是mResponseQueue.add(),通过该方法便能触发ResponseQueue.poll阻塞操作继续往下执行。</p>    <h3>2.14 ResponseQueue.add</h3>    <p>[-> NativeDaemonConnector.java]</p>    <pre>  <code class="language-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) { }     }  }</code></pre>    <p>responses.put</p>    <p>[-> ArrayBlockingQueue.java]</p>    <pre>  <code class="language-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();      }  }</code></pre>    <h3>2.15 MS.onDaemonConnected</h3>    <p>[-> MountService.java]</p>    <pre>  <code class="language-java">public void onDaemonConnected() {      mDaemonConnected = true;      mHandler.obtainMessage(H_DAEMON_CONNECTED).sendToTarget();  }</code></pre>    <p>当前主线程发送消息H_DAEMON_CONNECTED给线程“MountService”,该线程收到消息后调用MountServiceHandler的handleMessage()相应分支后,进而调用handleDaemonConnected()方法。</p>    <pre>  <code class="language-java">private void handleDaemonConnected() {      synchronized (mLock) {          resetIfReadyAndConnectedLocked();      }        //类型为CountDownLatch,用于多线程同步,阻塞await()直到计数器为零      mConnectedSignal.countDown();      if (mConnectedSignal.getCount() != 0) {          return;      }        //调用PMS来加载ASECs      mPms.scanAvailableAsecs();        //用于通知ASEC扫描已完成      mAsecsScanned.countDown();  }</code></pre>    <p>这里的PMS.scanAvailableAsecs()经过层层调用,最终核心工作还是通过MountService.getSecureContainerList。</p>    <p>[-> MountService.java]</p>    <pre>  <code class="language-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];      }  }</code></pre>    <h2>三、Vold</h2>    <p>Vold是由开机过程中解析init.rc时启动:</p>    <pre>  <code class="language-java">on post-fs-data      start vold</code></pre>    <p>Vold的service定义如下:</p>    <pre>  <code class="language-java">service vold /system/bin/vold      class core      socket vold stream 0660 root mount      socket cryptd stream 0660 root mount      ioprio be 2</code></pre>    <p>接下来便进入main()方法:</p>    <h3>3.1 main</h3>    <p>[-> system/vold/Main.cpp]</p>    <pre>  <code class="language-java">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;        //解析参数,设置contenxt      parse_args(argc, argv);      ...        fcntl(android_get_control_socket("vold"), F_SETFD, FD_CLOEXEC);      fcntl(android_get_control_socket("cryptd"), F_SETFD, FD_CLOEXEC);        mkdir("/dev/block/vold", 0755);        //用于cryptfs检查,并mount加密的文件系统      klog_set_level(6);        //创建单例对象VolumeManager 【见小节3.2.1】      if (!(vm = VolumeManager::Instance())) {          exit(1);      }        //创建单例对象NetlinkManager 【见小节3.3.1】      if (!(nm = NetlinkManager::Instance())) {          exit(1);      }        if (property_get_bool("vold.debug", false)) {          vm->setDebug(true);      }        // 创建CommandListener对象 【见小节3.4.1】      cl = new CommandListener();      // 创建CryptCommandListener对象 【见小节3.5.1】      ccl = new CryptCommandListener();        //【见小节3.2.2】      vm->setBroadcaster((SocketListener *) cl);      //【见小节3.3.2】      nm->setBroadcaster((SocketListener *) cl);        if (vm->start()) { //【见小节3.2.3】          exit(1);      }        process_config(vm); //【见小节3.2.4】        if (nm->start()) {  //【见小节3.3.3】          exit(1);      }        coldboot("/sys/block");        //启动响应命令的监听器 //【见小节3.4.2】      if (cl->startListener()) {          exit(1);      }        if (ccl->startListener()) {          exit(1);      }        //Vold成为监听线程      while(1) {          sleep(1000);      }        exit(0);  }</code></pre>    <p>该方法的主要功能是创建下面4个对象并启动</p>    <ul>     <li>VolumeManager</li>     <li>NetlinkManager (NetlinkHandler)</li>     <li>CommandListener</li>     <li>CryptCommandListener</li>    </ul>    <p>接下来分别说说几个类:</p>    <h3>3.2 VolumeManager</h3>    <p>3.2.1 创建</p>    <p>[-> VolumeManager.cpp]</p>    <pre>  <code class="language-java">VolumeManager *VolumeManager::Instance() {      if (!sInstance)          sInstance = new VolumeManager();      return sInstance;  }</code></pre>    <p>创建单例模式的VolumeManager对象</p>    <pre>  <code class="language-java">VolumeManager::VolumeManager() {      mDebug = false;      mActiveContainers = new AsecIdCollection();      mBroadcaster = NULL;      mUmsSharingCount = 0;      mSavedDirtyRatio = -1;      //当UMS获取时,则设置dirty ratio为0      mUmsDirtyRatio = 0;  }</code></pre>    <p>3.2.2 vm->setBroadcaster</p>    <pre>  <code class="language-java">void setBroadcaster(SocketListener *sl) {       mBroadcaster = sl;   }</code></pre>    <p>将新创建的 CommandListener 对象sl赋值给vm对象的成员变量 mBroadcaster</p>    <p>3.2.3 vm->start</p>    <pre>  <code class="language-java">int VolumeManager::start() {      //卸载所有设备,以提供最干净的环境      unmountAll();        //创建Emulated内部存储      mInternalEmulated = std::shared_ptr<android::vold::VolumeBase>(              new android::vold::EmulatedVolume("/data/media"));      mInternalEmulated->create();      return 0;  }</code></pre>    <p>mInternalEmulated的据类型为 EmulatedVolume ,设备路径为 /data/media ,id和label为“emulated”,mMountFlags=0。 EmulatedVolume 继承于 VolumeBase</p>    <p>3.2.3.1 unmountAll</p>    <pre>  <code class="language-java">int VolumeManager::unmountAll() {      std::lock_guard<std::mutex> lock(mLock);        //卸载内部存储      if (mInternalEmulated != nullptr) {          mInternalEmulated->unmount();      }      //卸载外部存储      for (auto disk : mDisks) {          disk->unmountAll();      }        FILE* fp = setmntent("/proc/mounts", "r");      if (fp == NULL) {          return -errno;      }        std::list<std::string> toUnmount;      mntent* mentry;      while ((mentry = getmntent(fp)) != NULL) {          if (strncmp(mentry->mnt_dir, "/mnt/", 5) == 0                  || strncmp(mentry->mnt_dir, "/storage/", 9) == 0) {              toUnmount.push_front(std::string(mentry->mnt_dir));          }      }      endmntent(fp);        for (auto path : toUnmount) {          //强制卸载          android::vold::ForceUnmount(path);      }        return 0;  }</code></pre>    <p>此处打开的”/proc/mounts”每一行内容依次是文件名,目录,类型,操作。例如:</p>    <pre>  <code class="language-java">/dev/fuse /mnt/runtime/default/emulated fuse rw,nosuid,nodev,...</code></pre>    <p>该方法的主要工作是卸载:</p>    <ul>     <li>内部存储mInternalEmulated;</li>     <li>外部存储mDisks,比如sdcard等;</li>     <li>“/proc/mounts”中目录包含mnt或者storage的路径;</li>    </ul>    <p>卸载内部存储:</p>    <pre>  <code class="language-java">status_t EmulatedVolume::doUnmount() {      if (mFusePid > 0) {          kill(mFusePid, SIGTERM);          TEMP_FAILURE_RETRY(waitpid(mFusePid, nullptr, 0));          mFusePid = 0;      }        KillProcessesUsingPath(getPath());      //强制卸载fuse路径      ForceUnmount(mFuseDefault);      ForceUnmount(mFuseRead);      ForceUnmount(mFuseWrite);        rmdir(mFuseDefault.c_str());      rmdir(mFuseRead.c_str());      rmdir(mFuseWrite.c_str());        mFuseDefault.clear();      mFuseRead.clear();      mFuseWrite.clear();        return OK;  }</code></pre>    <p>KillProcessesUsingPath 的功能很强大,通过文件path来查看其所在进程,并杀掉相应进程。当以下5处任意一处存在与path相同的地方,则会杀掉相应的进程:</p>    <ul>     <li>proc/<pid>/fd ,打开文件;</li>     <li>proc/<pid>/maps 打开文件映射;</li>     <li>proc/<pid>/cwd 链接文件;</li>     <li>proc/<pid>/root 链接文件;</li>     <li>proc/<pid>/exe 链接文件;</li>    </ul>    <p>3.2.3.2 EV.create</p>    <p>[-> VolumeBase.cpp]</p>    <pre>  <code class="language-java">status_t VolumeBase::create() {      mCreated = true;      status_t res = doCreate();      //通知VolumeCreated事件      notifyEvent(ResponseCode::VolumeCreated,              StringPrintf("%d \"%s\" \"%s\"", mType, mDiskId.c_str(), mPartGuid.c_str()));      //设置为非挂载状态      setState(State::kUnmounted);      return res;  }      void VolumeBase::notifyEvent(int event, const std::string& value) {      if (mSilent) return;      //通过socket向MountService发送创建volume的命令(650)      VolumeManager::Instance()->getBroadcaster()->sendBroadcast(event,              StringPrintf("%s %s", getId().c_str(), value.c_str()).c_str(), false);  }</code></pre>    <p>3.2.4 process_config(vm)</p>    <p>[-> system/vold/Main.cpp]</p>    <pre>  <code class="language-java">static int process_config(VolumeManager *vm) {      //获取Fstab路径      std::string path(android::vold::DefaultFstabPath());      fstab = fs_mgr_read_fstab(path.c_str());      ...        bool has_adoptable = false;      for (int i = 0; i < fstab->num_entries; i++) {          if (fs_mgr_is_voldmanaged(&fstab->recs[i])) {              if (fs_mgr_is_nonremovable(&fstab->recs[i])) {                  LOG(WARNING) << "nonremovable no longer supported; ignoring volume";                  continue;              }                std::string sysPattern(fstab->recs[i].blk_device);              std::string nickname(fstab->recs[i].label);              int flags = 0;                if (fs_mgr_is_encryptable(&fstab->recs[i])) {                  flags |= android::vold::Disk::Flags::kAdoptable;                  has_adoptable = true;              }              if (fs_mgr_is_noemulatedsd(&fstab->recs[i])                      || property_get_bool("vold.debug.default_primary", false)) {                  flags |= android::vold::Disk::Flags::kDefaultPrimary;              }                vm->addDiskSource(std::shared_ptr<VolumeManager::DiskSource>(                      new VolumeManager::DiskSource(sysPattern, nickname, flags)));          }      }      property_set("vold.has_adoptable", has_adoptable ? "1" : "0");      return 0;  }</code></pre>    <p>Fstab路径:首先通过 getprop ro.hardware ,比如高通芯片则为 qcom 那么Fstab路径就是 /fstab.qcom ,那么该文件的具体内容,例如(当然这个不同手机会有所不同):</p>    <table>     <thead>      <tr>       <th>src</th>       <th>mnt_point</th>       <th>type</th>       <th>mnt_flags and options</th>       <th>fs_mgr_flags</th>      </tr>     </thead>     <tbody>      <tr>       <td>/dev/block/bootdevice/by-name/system</td>       <td>/system</td>       <td>ext4</td>       <td>ro,barrier=1,discard</td>       <td>wait,verify</td>      </tr>      <tr>       <td>/dev/block/bootdevice/by-name/userdata</td>       <td>/data</td>       <td>ext4</td>       <td>nosuid,nodev,barrier=1,noauto_da_alloc,discard</td>       <td>wait,check,forceencrypt=footer</td>      </tr>      <tr>       <td>/dev/block/bootdevice/by-name/cust</td>       <td>/cust</td>       <td>ext4</td>       <td>nosuid,nodev,barrier=1</td>       <td>wait,check</td>      </tr>      <tr>       <td>/devices/soc.0/7864900.sdhci/mmc_host*</td>       <td>/storage/sdcard1</td>       <td>vfat</td>       <td>nosuid,nodev</td>       <td>wait,voldmanaged=sdcard1:auto,noemulatedsd,encryptable=footer</td>      </tr>      <tr>       <td>/dev/block/bootdevice/by-name/config</td>       <td>/frp</td>       <td>emmc</td>       <td>defaults defaults</td>       <td> </td>      </tr>      <tr>       <td>/devices/platform/msm_hsusb*</td>       <td>/storage/usbotg</td>       <td>vfat</td>       <td>nosuid,nodev</td>       <td>wait,voldmanaged=usbotg:auto,encryptable=footer</td>      </tr>     </tbody>    </table>    <h3>3.3 NetlinkManager</h3>    <p>3.3.1 创建</p>    <p>[-> NetlinkManager.cpp]</p>    <pre>  <code class="language-java">NetlinkManager *NetlinkManager::Instance() {      if (!sInstance)          sInstance = new NetlinkManager();      return sInstance;  }</code></pre>    <p>3.3.2 nm->setBroadcaster</p>    <pre>  <code class="language-java">void setBroadcaster(SocketListener *sl) {      mBroadcaster = sl;  }</code></pre>    <p>3.3.3 nm->start</p>    <pre>  <code class="language-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;        //创建event 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【见小节3.3.4】      mHandler = new NetlinkHandler(mSock);      //启动NetlinkHandler【见小节3.3.5】      if (mHandler->start()) {          goto out;      }        return 0;    out:      close(mSock);      return -1;  }</code></pre>    <p>3.3.4 NetlinkHandler</p>    <p>NetlinkHandler继承于 NetlinkListener , NetlinkListener 继承于 SocketListener 。new NetlinkHandler(mSock)中参数mSock是用于与Kernel进行通信的socket对象。由于这个继承关系,当NetlinkHandler初始化时会调用基类的初始化,最终调用到:</p>    <p>[-> SocketListener.cpp]</p>    <pre>  <code class="language-java">SocketListener::SocketListener(int socketFd, bool listen) {      //listen=false      init(NULL, socketFd, listen, false);  }    void SocketListener::init(const char *socketName, int socketFd, bool listen, bool useCmdNum) {      mListen = listen;      mSocketName = socketName;      //用于监听Kernel发送过程的uevent事件      mSock = socketFd;      mUseCmdNum = useCmdNum;      //初始化同步锁      pthread_mutex_init(&mClientsLock, NULL);      //创建socket通信的client端      mClients = new SocketClientCollection();  }</code></pre>    <p>到此,mListen = false; mSocketName = NULL; mUseCmdNum = false。 另外,这里用到的同步锁,用于控制多线程并发访问。 接着在来看看start过程:</p>    <p>3.3.5 NH->start</p>    <p>[-> NetlinkHandler.cpp]</p>    <pre>  <code class="language-java">int NetlinkHandler::start() {      return this->startListener();  }</code></pre>    <p>[-> SocketListener.cpp]</p>    <pre>  <code class="language-java">int SocketListener::startListener() {      return startListener(4);  }    int SocketListener::startListener(int backlog) {      ...      //mListen =false      if (mListen && listen(mSock, backlog) < 0) {          return -1;      } else if (!mListen)          //创建SocketClient对象,并加入到mClients队列          mClients->push_back(new SocketClient(mSock, false, mUseCmdNum));        //创建匿名管道      if (pipe(mCtrlPipe)) {          return -1;      }        //创建工作线程,线程运行函数threadStart【见小节3.3.6】      if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {          return -1;      }        return 0;  }</code></pre>    <p>mCtrlPipe是匿名管道,这是一个二元数组,mCtrlPipe[0]从管道读数据,mCtrlPipe[1]从管道写数据。</p>    <p>3.3.6 threadStart</p>    <p>[-> SocketListener.cpp]</p>    <pre>  <code class="language-java">void *SocketListener::threadStart(void *obj) {      SocketListener *me = reinterpret_cast<SocketListener *>(obj);      //【见小节3.3.7】      me->runListener();      pthread_exit(NULL); //线程退出      return NULL;  }</code></pre>    <p>3.3.7 SL->runListener</p>    <p>[-> SocketListener.cpp]</p>    <pre>  <code class="language-java">void SocketListener::runListener() {      SocketClientCollection pendingList;      while(1) {          SocketClientCollection::iterator it;          fd_set read_fds;          int rc = 0;          int max = -1;            FD_ZERO(&read_fds);            if (mListen) {              max = mSock;              FD_SET(mSock, &read_fds);          }            FD_SET(mCtrlPipe[0], &read_fds);          if (mCtrlPipe[0] > max)              max = mCtrlPipe[0];            pthread_mutex_lock(&mClientsLock);          for (it = mClients->begin(); it != mClients->end(); ++it) {              // NB: calling out to an other object with mClientsLock held (safe)              int fd = (*it)->getSocket();              FD_SET(fd, &read_fds);              if (fd > max) {                  max = fd;              }          }          pthread_mutex_unlock(&mClientsLock);          SLOGV("mListen=%d, max=%d, mSocketName=%s", mListen, max, mSocketName);          if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {              if (errno == EINTR)                  continue;              SLOGE("select failed (%s) mListen=%d, max=%d", strerror(errno), mListen, max);              sleep(1);              continue;          } else if (!rc)              continue;            if (FD_ISSET(mCtrlPipe[0], &read_fds)) {              char c = CtrlPipe_Shutdown;              TEMP_FAILURE_RETRY(read(mCtrlPipe[0], &c, 1));              if (c == CtrlPipe_Shutdown) {                  break;              }              continue;          }          if (mListen && FD_ISSET(mSock, &read_fds)) {              struct sockaddr addr;              socklen_t alen;              int c;                do {                  alen = sizeof(addr);                  c = accept(mSock, &addr, &alen);                  SLOGV("%s got %d from accept", mSocketName, c);              } while (c < 0 && errno == EINTR);              if (c < 0) {                  SLOGE("accept failed (%s)", strerror(errno));                  sleep(1);                  continue;              }              fcntl(c, F_SETFD, FD_CLOEXEC);              pthread_mutex_lock(&mClientsLock);              mClients->push_back(new SocketClient(c, true, mUseCmdNum));              pthread_mutex_unlock(&mClientsLock);          }            /* Add all active clients to the pending list first */          pendingList.clear();          pthread_mutex_lock(&mClientsLock);          for (it = mClients->begin(); it != mClients->end(); ++it) {              SocketClient* c = *it;              // NB: calling out to an other object with mClientsLock held (safe)              int fd = c->getSocket();              if (FD_ISSET(fd, &read_fds)) {                  pendingList.push_back(c);                  c->incRef();              }          }          pthread_mutex_unlock(&mClientsLock);            /* Process the pending list, since it is owned by the thread,           * there is no need to lock it */          while (!pendingList.empty()) {              /* Pop the first item from the list */              it = pendingList.begin();              SocketClient* c = *it;              pendingList.erase(it);              /* Process it, if false is returned, remove from list */              if (!onDataAvailable(c)) {                  release(c, false);              }              c->decRef();          }      }  }</code></pre>    <h3>3.4 CommandListener</h3>    <p>3.4.1 创建</p>    <p>[-> CommandListener.cpp]</p>    <pre>  <code class="language-java">CommandListener::CommandListener() :                   FrameworkListener("vold", true) {      registerCmd(new DumpCmd());      registerCmd(new VolumeCmd());      registerCmd(new AsecCmd());      registerCmd(new ObbCmd());      registerCmd(new StorageCmd());      registerCmd(new FstrimCmd());  }</code></pre>    <p>3.4.1.1 FrameworkListener</p>    <p>[-> FrameworkListener.cpp]</p>    <pre>  <code class="language-java">FrameworkListener::FrameworkListener(const char *socketName, bool withSeq) :                              SocketListener(socketName, true, withSeq) {      init(socketName, withSeq);  }    void FrameworkListener::init(const char *socketName UNUSED, bool withSeq) {      mCommands = new FrameworkCommandCollection();      errorRate = 0;      mCommandCount = 0;      mWithSeq = withSeq; //true  }</code></pre>    <p>3.4.1.2 SocketListener</p>    <p>[-> SocketListener.cpp]</p>    <pre>  <code class="language-java">SocketListener::SocketListener(const char *socketName, bool listen, bool useCmdNum) {      init(socketName, -1, listen, useCmdNum);  }    void SocketListener::init(const char *socketName, int socketFd, bool listen, bool useCmdNum) {      mListen = listen; //true      mSocketName = socketName; //"vold"      mSock = socketFd; // -1      mUseCmdNum = useCmdNum; //true      pthread_mutex_init(&mClientsLock, NULL);      mClients = new SocketClientCollection();  }</code></pre>    <p>socket名为“vold”</p>    <p>3.4.1.3 registerCmd</p>    <pre>  <code class="language-java">void FrameworkListener::registerCmd(FrameworkCommand *cmd) {      mCommands->push_back(cmd);  }    CommandListener::VolumeCmd::VolumeCmd() :               VoldCommand("volume") {  }</code></pre>    <p>创建这些对象 DumpCmd,VolumeCmd,AsecCmd,ObbCmd,StorageCmd,FstrimCmd,并都加入到mCommands队列。</p>    <p>3.4.2 cl->startListener</p>    <pre>  <code class="language-java">int SocketListener::startListener() {      return startListener(4);  }    int SocketListener::startListener(int backlog) {        if (!mSocketName && mSock == -1) {          ...      } else if (mSocketName) {          //获取“vold”所对应的句柄          if ((mSock = android_get_control_socket(mSocketName)) < 0) {              return -1;          }          fcntl(mSock, F_SETFD, FD_CLOEXEC);      }        //CL开始监听      if (mListen && listen(mSock, backlog) < 0) {          return -1;      }      ...      //创建匿名管道      if (pipe(mCtrlPipe)) {          return -1;      }        //创建工作线程      if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {          return -1;      }        return 0;  }</code></pre>    <h2>四、 案例分析</h2>    <p>MountService根据收到消息会发送VM处理。 例如待SD卡插入后,VM会将(来自NM的“Disk Insert”的)消息发送给MountService,而后MountService则发送“Mount”指令给Vold,指示它挂载这个SD卡。有些应用程序需要检测外部存储卡的插入/拔出事件,这些事件是由MountService通过Intent广播发出的,例如外部存储卡插入后,MountService就会发送ACTION_MEDIA_MOUNTED消息。</p>    <h3>4.1 Kernel上报处理流程</h3>    <p>插入SD卡动作: 通过硬件驱动会引起Kernel向NM发送uevent,NM转发消息给VM,再通过CL发送给MountService;MountService收到后则向Vold发送Mount命令,来挂载SD卡。</p>    <p>整个流程: Kernel Uevent -> volumeManager -> NetlinkManager -> CommandListener -> NativeDaemonConnector -> MountService</p>    <p>Kernel发出Uevnt事件 SocketListener::startListener SocketListener::threadStart SocketListener::runListener NetlinkListener.onDataAvailable NetlinkHandler.onEvent VM.handleBlockEvent Disk.create Disk::notifyEvent SocketListener::sendBroadcast 发送socket事件给上层</p>    <h3>4.2 framework下发处理流程</h3>    <p>MountServic发送socket,执行mount SocketListener::startListener SocketListener::threadStart SocketListener::runListener FrameworkListener::onDataAvailable FrameworkListener::dispatchCommand VolumeCmd.runCommand VolumeBase.mount EmulatedVolume.doMount(内置) PublicVolume.doMount(外置) vfat::Check vfat::Mount fork (/sdcard)</p>    <h3>4.3 startUser流程</h3>    <p>AMS.systemReady goingCallback.run(); onBootPhase(550) MountService.systemReady(); => mSystemReady = true MountService.resetIfReadyAndConnectedLocked mConnector.execute(“volume”, “reset”); RCV <- {650 emulated –> VOLUME_CREATED RCV <- {650 public –> VOLUME_CREATED mConnector.execute(“volume”, “user_added”, user.id, user.serialNumber); mConnector.execute(“volume”, “user_started”, userId);</p>    <pre>  <code class="language-java">mSystemServiceManager.startUser(mCurrentUserId);      MountService.onStartUser          mConnector.execute("volume", "user_started", userId);          mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();              MountServiceHandler.handleMessage -->case H_VOLUME_BROADCAS</code></pre>    <p>NDC监听流程:</p>    <pre>  <code class="language-java">NDC.istenToSocket       NativeDaemonConnector.handleMessage -->          MountService.onEvent              onEventLocked -->                  case VoldResponseCode.VOLUME_CREATED                      MountService.onVolumeCreatedLocked                          MountServiceHandler.handleMessage -->                              case H_VOLUME_MOUNT                                  mConnector.execute("volume", "mount");</code></pre>    <h2>系列文章</h2>    <p><a href="http://www.open-open.com/lib/view/open1469625636493.html">Android存储系统之源码篇</a><br> <a href="http://www.open-open.com/lib/view/open1469625550849.html">Android存储系统之架构篇</a></p>    <p> </p>    <p> </p>    <p>来自:http://gityuan.com/2016/07/17/android-io/</p>    <p> </p>