0%

Android Storage 存储架构分析1

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");
//在DisplayReady后启动 SMS
traceBeginAndSlog("StartStorageManagerService");
...
mSystemServiceManager.startService(STORAGE_MANAGER_SERVICE_CLASS);
// "com.android.server.StorageManagerService$Lifecycle";
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) {
//T模板 为 SystemService的子类
try {
final String name = serviceClass.getName();
// name为 StorageManagerService#LifeCircle
Slog.i(TAG, "Starting " + name);
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartService " + name);
// Create the service.
if (!SystemService.class.isAssignableFrom(serviceClass)) {
throw new RuntimeException("Failed to create " + name
+ ": service must extend " + SystemService.class.getName());
}
final T service;
try {
//寻找 StorageManagerService#LifeCircle的构造器,创建实例,传入参数为mContext, mContext为 SystemServiceManager的context
Constructor<T> constructor = serviceClass.getConstructor(Context.class);
service = constructor.newInstance(mContext);

...
//启动对应的service, 响应子类的onStart方法
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() {
//SMS的初始化
mStorageManagerService = new StorageManagerService(getContext());
// 往ServiceManager中注册的服务代理名称为mount。
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;
//前台线程, StorageManagerService 的Callback内部类
mCallbacks = new Callbacks(FgThread.get().getLooper());
// 直接拿到PackagaManagerService的实例。 Service之间是可以互相访问的
// XXX: This will go away soon in favor of IMountServiceObserver
mPms = (PackageManagerService) ServiceManager.getService("package");
// 主handler , 通过HandlerThread创建的新的线程
HandlerThread hthread = new HandlerThread(TAG);
hthread.start();
mHandler = new StorageManagerServiceHandler(hthread.getLooper());
// obb相关的handler
// Add OBB Action Handler to StorageManagerService thread.
mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper());
....
//省略Fstrim相关
....
// data/system/storage.xml文件
mSettingsFile = new AtomicFile(
new File(Environment.getDataSystemDirectory(), "storage.xml"));
synchronized (mLock) {
readSettingsLocked();
}
// StorageManagerInternal 实例加到了LocalServices中
LocalServices.addService(StorageManagerInternal.class, mStorageManagerInternal); (A)
/*
* Create the connection to vold with a maximum queue of twice the
* amount of containers we'd ever expect to have. This keeps an
* "asec list" from blocking a thread repeatedly.
*/
// MAX_CONTAINERS*2 阻止 aesc list block 反复block线程
// asec mount 数量最大为 MAX_CONTAINERS
// NativeDaemonConnector (B)
mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25, null); (B)
mConnector.setDebug(true);
mConnector.setWarnIfHeld(mLock);
// 执行mConnector的run方法, listenToSocket
mConnectorThread = new Thread(mConnector, VOLD_TAG);
// Reuse parameters from first connector since they are tested and safe
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();
}
// Add ourself to the Watchdog monitors if enabled.
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;
// 消息队列,从vold接收来的消息处理,可能延迟
mResponseQueue = new ResponseQueue(responseQueueSize);
// 传入的wakelock为 null
mWakeLock = wl;
if (mWakeLock != null) {
mWakeLock.setReferenceCounted(true);
}
mLooper = looper;
// 原子性操作,多线程不会错乱, SND index | RCV index
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 是从对端发送过来的
fdList = socket.getAncillaryFileDescriptors();
// Add our starting point to the count and reset the start.
count += start;
start = 0;
//一次可能接收到多个命令包过来
for (int i = 0; i < count; i++) {
if (buffer[i] == 0) {
// Note - do not log this raw message since it may contain
// sensitive data
//命令包过来的原始信息,支持UTF-8 编码格式的中文
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 + "}");
// 与卷挂载Disk状态相关的event处理 600-700
if (event.isClassUnsolicited()) {
// TODO: migrate to sending NativeDaemonEvent instances
// StorageManagerService 这个地方总是false。 因为前面传的wakelock 也是null,不走入
if (mCallbacks.onCheckHoldWakeLock(event.getCode())
&& mWakeLock != null) {
mWakeLock.acquire();
releaseWl = true;
}
// mCallbackHandler, 是绑定的传入的looper,此前由于并没有传入looper对象,此处使用的是android.fg线程,往此线程发送消息,则其中的消息循环的处理绑定的handler对应的callback的handleMessage中。(C)
Message msg = mCallbackHandler.obtainMessage(
event.getCode(), uptimeMillisInt(), 0, event.getRawEvent());
if (mCallbackHandler.sendMessage(msg)) {
releaseWl = false;
}
}
// 控制类的event 放在 ResponseQueue中 (D)
else {
mResponseQueue.add(event.getCmdNumber(), event);
}
}
。。。
start = i + 1;
}
}
<span id="jump">this</span>
if (start == 0) {
log("RCV incomplete");
}
// We should end at the amount we read. If not, compact then
// buffer and read again.
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 {
// 此处的mCallbacks 为 StorageManagerService
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 {
// mResponseQueue接收对端发送回来的消息,如果该队列为空,此处remove会block住,直到队列不为空,才继续往下走。
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);
// 100-200 范围内的可以循环
// 如上面的asec list 的消息码为111。
} while (event.isClassContinue());

// 根据mResponseQueue的情况得出 native 进程端处理的时间
final long endTime = SystemClock.elapsedRealtime();
if (endTime - startTime > WARN_EXECUTE_DELAY_MS) {
loge("NDC Command {" + logCmd + "} took too long (" + (endTime - startTime) + "ms)");
}
// 500-600 ClientError
if (event.isClassClientError()) {
throw new NativeDaemonArgumentException(logCmd, event);
}
// 400-600 ServerError
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;

/*
* 200 series - Requestion action has been successfully completed.
*/
public static final int ShareStatusResult = 210;
public static final int AsecPathResult = 211;
public static final int ShareEnabledResult = 212;

/*
* 400 series - Command was accepted, but the requested action
* did not take place.
*/
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;

/*
* 600 series - Unsolicited broadcasts.
*/
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;