Android存储系统之源码篇
<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>
本文由用户 GZBCoy 自行上传分享,仅供网友学习交流。所有权归原作者,若您的权利被侵害,请联系管理员。
转载本站原创文章,请注明出处,并保留原始链接、图片水印。
本站是一个以用户分享为主的开源技术平台,欢迎各类分享!