1. Android Storage 存储架构分析1 1.1. StorageManagerService初始化 以下StorageManagerService简称SMS。
SMS的初始化在SystemServer中。
System Server 引入
1.1.1. startOtherService DisplayReady后启动 SMS:
1 2 3 4 5 6 7 8 traceBeginAndSlog("MakeDisplayReady" ); traceBeginAndSlog("StartStorageManagerService" ); ... mSystemServiceManager.startService(STORAGE_MANAGER_SERVICE_CLASS); storageManager = IStorageManager.Stub.asInterface( ServiceManager.getService("mount" ));
SMS 在 ServiceManager中的代理名称为 mount, 可以使用dumpsys mount命令打印SMS的内存信息,执行SMS的dump函数
1.1.1.1. startService 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public <T extends SystemService > T startService (Class<T> serviceClass) {try { final String name = serviceClass.getName(); Slog.i(TAG, "Starting " + name); Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartService " + name); if (!SystemService.class.isAssignableFrom(serviceClass)) { throw new RuntimeException ("Failed to create " + name + ": service must extend " + SystemService.class.getName()); } final T service; try { Constructor<T> constructor = serviceClass.getConstructor(Context.class); service = constructor.newInstance(mContext); ... startService(service); return service; } finally { Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); } }
startService 后, 会响应 SystemService 子类, 也就是 StroageManagerService内部类 Lifecycle 的onStart函数, 并传入了 SystemServiceManager的context。
1.1.1.2. SMS#Lifecycle-onStart 1 2 3 4 5 6 7 8 @Override public void onStart () { mStorageManagerService = new StorageManagerService (getContext()); publishBinderService("mount" , mStorageManagerService); mStorageManagerService.start(); }
此处通过publishBinderService注册代理名称,与1处呼应。
1.1.1.3. StorageManagerService-构造函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 public StorageManagerService (Context context) { sSelf = this ; mContext = context; mCallbacks = new Callbacks (FgThread.get().getLooper()); mPms = (PackageManagerService) ServiceManager.getService("package" ); HandlerThread hthread = new HandlerThread (TAG); hthread.start(); mHandler = new StorageManagerServiceHandler (hthread.getLooper()); mObbActionHandler = new ObbActionHandler (IoThread.get().getLooper()); .... .... mSettingsFile = new AtomicFile ( new File (Environment.getDataSystemDirectory(), "storage.xml" )); synchronized (mLock) { readSettingsLocked(); } LocalServices.addService(StorageManagerInternal.class, mStorageManagerInternal); (A) mConnector = new NativeDaemonConnector (this , "vold" , MAX_CONTAINERS * 2 , VOLD_TAG, 25 , null ); (B) mConnector.setDebug(true ); mConnector.setWarnIfHeld(mLock); mConnectorThread = new Thread (mConnector, VOLD_TAG); mCryptConnector = new NativeDaemonConnector (this , "cryptd" , MAX_CONTAINERS * 2 , CRYPTD_TAG, 25 , null ); mCryptConnector.setDebug(true ); mCryptConnectorThread = new Thread (mCryptConnector, CRYPTD_TAG); final IntentFilter userFilter = new IntentFilter (); userFilter.addAction(Intent.ACTION_USER_ADDED); userFilter.addAction(Intent.ACTION_USER_REMOVED); mContext.registerReceiver(mUserReceiver, userFilter, null , mHandler); synchronized (mLock) { addInternalVolumeLocked(); } if (WATCHDOG_ENABLE) { Watchdog.getInstance().addMonitor(this ); } }
1.1.1.3.1. (A) StorageManagerInternal - LocalServices 为了提升通信的效率,google将service分成binder service 和 local service。
如果service只在本进程使用,则可以将这个service 发布为localservice。避免进程间通信。只能在本进程中使用。
( A ) StorageManagerInternal 为抽象类,借助StorageManagerInternal类来实现具体的功能, 该类控制挂载相关的策略。 (mount read write default)。 本地服务 Local Service 用于应用程序内部。
它可以启动并运行,直至有人停止了它或它自己停止。在这种方式下,它以调用Context.startService()启动,以调用Context.stopService()结束。它可以调用Service.stopSelf() 或 Service.stopSelfResult()来自己停止。不论调用了多少次startService()方法,你只需要调用一次stopService()来停止服务。 用于实现应用程序自己的一些耗时任务,比如查询升级信息,并不占用应用程序比如Activity所属线程,而是单开线程后台执行,这样用户体验比较好。
这里将StorageManagerInternal 加到LocalServices中,可以保证SystemServer进程的其他service都能较为方便的使用其中的方法。 如AppOpsService AMS PKMS 等.
1.1.1.3.2. (B)NativeDaemonConnector 构造时传入 第一个参数为 StorageManagerService本身, 自身作为INativeDaemonConnectorCallbacks, Socket名称为“vold”, 没有传入looper,则使用的FgThread.get().getLooper(), Android.fg 的 looper线程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket, int responseQueueSize, String logTag, int maxLogSize, PowerManager.WakeLock wl, Looper looper) { mCallbacks = callbacks; mSocket = socket; mResponseQueue = new ResponseQueue (responseQueueSize); mWakeLock = wl; if (mWakeLock != null ) { mWakeLock.setReferenceCounted(true ); } mLooper = looper; mSequenceNumber = new AtomicInteger (0 ); TAG = logTag != null ? logTag : "NativeDaemonConnector" ; mLocalLog = new LocalLog (maxLogSize); }
1.2. 通信篇- SMS与vold通信 1 2 Os.socket(OsConstants.AF_UNIX, SOCKET_STREAM , 0 ) socket.connect(address);
连接成功后,通过INativeDaemonConnectorCallbacks 响应 onDaemonConnected。
SMS发送 H_DAEMON_CONNECTED, 由HandlerThread创建的子线程进行处理:
该子线程处理的消息包括:
H_SYSTEM_READY
H_DAEMON_CONNECTED
H_FSTRIM
H_SHUTDOWN
H_VOLUME_MOUNT
H_VOLUME_UNMOUNT
H_VOLUME_BROADCAST
H_INTERNAL_BROADCAST
H_PARTITION_FORGET
H_RESET
1.2.1. 与vold通信 - listenToSocket 重点看下 listenToSocket 的消息循环:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 while (true ) { int count = inputStream.read(buffer, start, BUFFER_SIZE - start); fdList = socket.getAncillaryFileDescriptors(); count += start; start = 0 ; 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 { final NativeDaemonEvent event = NativeDaemonEvent.parseRawEvent(rawEvent, fdList); log("RCV <- {" + event + "}" ); if (event.isClassUnsolicited()) { if (mCallbacks.onCheckHoldWakeLock(event.getCode()) && mWakeLock != null ) { mWakeLock.acquire(); releaseWl = true ; } Message msg = mCallbackHandler.obtainMessage( event.getCode(), uptimeMillisInt(), 0 , event.getRawEvent()); if (mCallbackHandler.sendMessage(msg)) { releaseWl = false ; } } else { mResponseQueue.add(event.getCmdNumber(), event); } } 。。。 start = i + 1 ; } } <span id="jump" >this </span> if (start == 0 ) { log("RCV incomplete" ); } if (start != count) { final int remaining = BUFFER_SIZE - start; System.arraycopy(buffer, start, buffer, 0 , remaining); start = remaining; } else { start = 0 ; } }
1.2.1.1. (C) 与vold 通信的 主Handler DaemonConnector 绑定了 mCallbackHandler :
1 mCallbackHandler = new Handler (mLooper, this );
看Handler的构造函数中的第二个参数 callback
Callback是跟Handler 存在绑定关系的,Looper里存的是大的MessageQueue。 使用Handler发送消息时,只能对应callback的 HandleMessage处理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @Override public boolean handleMessage (Message msg) { final String event = (String) msg.obj; final int start = uptimeMillisInt(); final int sent = msg.arg1; try { if (!mCallbacks.onEvent(msg.what, event, NativeDaemonEvent.unescapeArgs(event))) { log(String.format("Unhandled event '%s'" , event)); } } finally { final int end = uptimeMillisInt(); if (start > sent && start - sent > WARN_EXECUTE_DELAY_MS) { loge(String.format("NDC event {%s} processed too late: %dms" , event, start - sent)); } if (end > start && end - start > WARN_EXECUTE_DELAY_MS) { loge(String.format("NDC event {%s} took too long: %dms" , event, end - start)); } } return true ; }
其中 StorageManagerService 的 onEvent 处理了下列事件:
DISK_CREATED
DISK_SIZE_CHANGED
DISK_LABEL_CHANGED
DISK_SCANNED
DISK_SYS_PATH_CHANGED
DISK_DESTROYED
VOLUME_CREATED
VOLUME_STATE_CHANGED
VOLUME_FS_TYPE_CHANGED
VOLUME_FS_UUID_CHANGED
VOLUME_FS_LABEL_CHANGED
VOLUME_PATH_CHANGED
VOLUME_INTERNAL_PATH_CHANGED
VOLUME_DESTROYED
MOVE_STATUS
BENCHMARK_RESULT
TRIM_RESULT
1.2.1.2. StorageManagerService#Callbacks StorageManagerService#Callbacks 中也有一个 Android.fg 线程Looper的Handler。 通过上面的onEvent处理,在对应特殊事件时, 回调回 Callbacks 中。
VOLUME_STATE_CHANGED : onVolumeStateChangedLocked
DISK_DESTROYED : notifyDiskDestroyed
DISK_SCANNED : onDiskScannedLocked
通过SMS#Callbacks内部类通知到各个注册的StorageEventListener。其他的情况也有可能会回调,根据实际情况进行处理:如 onUnlockUser SMS#Callbacks 内部类处理的消息:
MSG_STORAGE_STATE_CHANGED
MSG_VOLUME_STATE_CHANGED
MSG_VOLUME_RECORD_CHANGED
MSG_VOLUME_FORGOTTEN
MSG_DISK_SCANNED
MSG_DISK_DESTROYED
消息全部与卷状态有关,且优先级比子线程处理的消息高,此处通过内部类Callbacks 绑定了许多的callback。 这些callback是通过 StorageEventListener register关联的:
1.2.1.3. (D) 控制类Event处理 1.2.1.3.1. ResponseQueue类 mResponseQueue
ResponseQueue#PendingCmd
PendingCmd 成员 BlockingQueue responses;
如果BlockQueue是空的,从BlockingQueue取东西的操作将会被阻断进入等待状态,直到BlockingQueue进了东西才会被唤醒.同样,如果BlockingQueue是满的,任何试图往里存东西的操作也会被阻断进入等待状态,直到BlockingQueue里有空间才会被唤醒继续操作. 利用了BlockingQueque如果为空,从中取东西会阻塞的特性。
1 mResponseQueue.add(event.getCmdNumber(), event);
在发送一条命令时,一般对端会返回一条控制命令(成功或失败)回来,返回的控制命令最终会放在BlockingQueue中。 这样在命令返回之前,由于队列是空的,所以会将当前代码阻塞住,返回的控制命令被填入到队列中,代码才会继续往下走,通过这样的机制去判断相对应的发往对端的命令执行的时间。 每一条命令的 cmdNumber 是绑定的往对端vold发命令时的命令码, 往对端发的命令码对应的返回命令可能有多条(如asec list命令),这样保证了对应每一条发往对端 (native 进程)的命令都绑定了一个 BlockingQueue.
cmdNumber 15相关的通信过程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 105 -19 13 :39 :51.916 3185 3212 D VoldConnector: SND -> {15 asec list}A105-19 13 :39 :51.926 3185 3266 D VoldConnector: RCV <- {111 15 com.UCMobile-2 } A105-19 13 :39 :51.927 3185 3266 D VoldConnector: RCV <- {111 15 com.taobao.taobao-1 } A105-19 13 :39 :51.930 3185 3266 D VoldConnector: RCV <- {111 15 com.youku.phone-2 } A105-19 13 :39 :51.934 3185 3266 D VoldConnector: RCV <- {111 15 com.tencent.mobileqq-2 } A105-19 13 :39 :51.935 3185 3266 D VoldConnector: RCV <- {111 15 com.sina.weibo-2 } A105-19 13 :39 :51.936 3185 3266 D VoldConnector: RCV <- {111 15 com.kiloo.subwaysurf-2 } A105-19 13 :39 :51.936 3185 3266 D VoldConnector: RCV <- {111 15 com.youdao.huihui.deals-2 } A105-19 13 :39 :51.937 3185 3266 D VoldConnector: RCV <- {111 15 com.facebook.katana-2 } A105-19 13 :39 :51.937 3185 3266 D VoldConnector: RCV <- {111 15 com.duowan.mobile-2 } A105-19 13 :39 :51.938 3185 3266 D VoldConnector: RCV <- {111 15 com.imangi.templerun2-2 } A105-19 13 :39 :51.939 3185 3266 D VoldConnector: RCV <- {111 15 com.taobao.taobao-2 } A105-19 13 :39 :51.940 3185 3266 D VoldConnector: RCV <- {111 15 com.happyelements.AndroidAnimal-2 } A105-19 13 :39 :51.944 3185 3266 D VoldConnector: RCV <- {111 15 com.kiloo.subwaysurf-1 } A105-19 13 :39 :51.945 3185 3266 D VoldConnector: RCV <- {111 15 com.wandoujia.phoenix2.usbproxy-1 } A105-19 13 :39 :51.946 3185 3266 D VoldConnector: RCV <- {200 15 asec operation succeeded}
对应的往native进程发送命令的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 public NativeDaemonEvent[] executeForList(long timeoutMs, String cmd, Object... args) throws NativeDaemonConnectorException { final long startTime = SystemClock.elapsedRealtime(); final ArrayList<NativeDaemonEvent> events = Lists.newArrayList(); 。。。 log("SND -> {" + logCmd + "}" ); synchronized (mDaemonLock) { try { mOutputStream.write(rawCmd.getBytes(StandardCharsets.UTF_8)); } catch (IOException e) { throw new NativeDaemonConnectorException ("problem sending command" , e); } } } NativeDaemonEvent event = null ; do { event = mResponseQueue.remove(sequenceNumber, timeoutMs, logCmd); if (event == null ) { loge("timed-out waiting for response to " + logCmd); throw new NativeDaemonTimeoutException (logCmd, event); } if (VDBG) log("RMV <- {" + event + "}" ); events.add(event); } while (event.isClassContinue()); final long endTime = SystemClock.elapsedRealtime(); if (endTime - startTime > WARN_EXECUTE_DELAY_MS) { loge("NDC Command {" + logCmd + "} took too long (" + (endTime - startTime) + "ms)" ); } if (event.isClassClientError()) { throw new NativeDaemonArgumentException (logCmd, event); } if (event.isClassServerError()) { throw new NativeDaemonFailureException (logCmd, event); } return events.toArray(new NativeDaemonEvent [events.size()]); }
对应的event消息码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 public static final int VolumeListResult = 110 ;public static final int AsecListResult = 111 ;public static final int StorageUsersListResult = 112 ;public static final int CryptfsGetfieldResult = 113 ;public static final int ShareStatusResult = 210 ;public static final int AsecPathResult = 211 ;public static final int ShareEnabledResult = 212 ;public static final int OpFailedNoMedia = 401 ;public static final int OpFailedMediaBlank = 402 ;public static final int OpFailedMediaCorrupt = 403 ;public static final int OpFailedVolNotMounted = 404 ;public static final int OpFailedStorageBusy = 405 ;public static final int OpFailedStorageNotFound = 406 ;public static final int DISK_CREATED = 640 ;public static final int DISK_SIZE_CHANGED = 641 ;public static final int DISK_LABEL_CHANGED = 642 ;public static final int DISK_SCANNED = 643 ;public static final int DISK_SYS_PATH_CHANGED = 644 ;public static final int DISK_DESTROYED = 649 ;public static final int VOLUME_CREATED = 650 ;public static final int VOLUME_STATE_CHANGED = 651 ;public static final int VOLUME_FS_TYPE_CHANGED = 652 ;public static final int VOLUME_FS_UUID_CHANGED = 653 ;public static final int VOLUME_FS_LABEL_CHANGED = 654 ;public static final int VOLUME_PATH_CHANGED = 655 ;public static final int VOLUME_INTERNAL_PATH_CHANGED = 656 ;public static final int VOLUME_DESTROYED = 659 ;public static final int MOVE_STATUS = 660 ;public static final int BENCHMARK_RESULT = 661 ;public static final int TRIM_RESULT = 662 ;