0%

GPT物理分区结构

方案简要框图:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@startuml
skinparam backgroundColor #EEEBDC
skinparam handwritten true
start
:通过分区表xml管理\n手机中的物理分区信息;
:将分区表信息打包到ota的原始target文件中;
:制作升级包时,将分区表的信息解析,\n并根据项目对分区的配置,产生分区配置文件\n打包到ota升级包中;
:recovery子系统进行ota升级,先置成check模式,\n将升级包中的分区配置文件解压,\n通过调整分区工具检查分区是否发生里变化;
if (根据项目情况,以及分区变动的规则检查分区是否发生了变更,\n分区变动了,由用户选择是否继续) then (用户选择继续升级)
:根据分区变动的位置确定哪些分区需要备份,\n对这些分区根据不同的分区备份策略进行备份;
:将根据分区变动规则及\n配置文件中配置的分区信息产生最终分区调整信息;
:将分区调整信息写入到磁盘中记录分区的关键地址中;
:根据不同的分区备份方案选择合适的分区恢复方案对数据进行恢复;
:进行后续的没有分区变动的ota升级流程;
stop
elseif (分区变动了) then (用户选择不继续)
:退出升级;
stop
else (分区没有变动, 不会给用户提示)
:进行没有分区变动的ota升级流程;
stop
@enduml

根据目标镜像动态自适应调整物理分区的技术,在升级过程中不会丢失用户数据。可供项目人员灵活配置哪些分区需要特殊处理,用户在升级时可以察觉到分区是否发生了变动。Ota升级时调整分区的场景完善的断电保护方案。小存储设备上可以留给用户更多的使用存储空间

首先对于基于安卓的通用升级方案来说,是不能在ota升级的时候,根据目标版本动态修改物理分区的,这种方案存在以下弊端:

1.目前的升级方案中,不会调整物理分区,假设目标版本的某分区因新加功能或者解决bug,调整架构等需要的空间增大了。如果项目初始阶段,分区的空间分配的比较小,量产发布给用户后,因为某分区的空间不足,往往会因不能动态的调整物理分区大小而使升级时会受限。
2.由于项目需要,在发布版本给用户以后,可能需要新增分区或者删减分区,这种需求也会因为升级程序无法动态的调整物理分区而受限。
3.对于ROM 磁盘比较小的设备,由于不能动态调整分区。厂家一般采用的方案是,项目初始阶段就分配好了各分区的大小。系统分区(如system分区或modem分区等)通常留有比较大的余量为后面的升级作准备。用户是看不到也不能使用这些系统分区的。这些系统分区留有的余量只能用作升级使用,不能达到很好的利用率。对于本来就很珍贵的ROM空间,造成了浪费。

针对以上缺点,本发明的方案可以在升级时自动的识别分区的改动,并进行针对性的调整。不会丢失数据,用户可以感知到调整了物理分区。用户可以毫无顾虑的进行系统升级。对于厂家而言,减小了分区配置的难度。同时也不需要协调各分区相应模块的研发人员必须按照一定的分区大小的标准进行开发。系统升级的难度变小,厂家可以更从容的推送升级包给用户,减小了用户强升某系统版本因分区不足导致的设备变砖风险。较小了维护成本以及退修返修的概率。对于ROM比较小的设备,合理利用了ROM空间。增大了用户的可使用空间。

1. 编译系统修改

ota升级包含两个大步骤,本地对当前版本打包的过程
将升级包推送到手机中,手机进recovery子系统执行系统升级的流程。
Ota的target-files中保存了完整的用于升级的各镜像的原始信息。
通过该原始包来制作ota的整包和差分包。
在展讯平台上通过xml文件管理手机设备中的物理分区。
在存储容量比较小的设备上,为了留给用户尽量多的内部存储空间,需要将system分区的空间尽量减小。在编译时将xml中关于system分区大小的部分修正为自适应分区后的大小。(推送给用户的版本一般是只读的,debug版本需要留给system分区一定的余量方便研发人员调试)
编译target-files文件时,需要将xml拷贝到target-files压缩文件中。拷贝时检索xml中是否含有Product、ProductList、 Partitions等关键字(预定的关键tag信息,分区的信息是里面的元素),同时包含这些关键字才进行拷贝。

2. 解析xml分区表生成配置文件

阅读全文 »

1. Android 8.1

1.1. 涉及的文件

  • StorageStats.java

  • AppStorageSettings.java

  • InstalledAppDetails.java

  • StorageStatsManager.java

  • StorageStatsService.java

  • PackageManagerService.java

1.2. 相关代码

计算方式:

totalSize = stats.(codeSize + externalCodeSize + dataSize + externalDataSize + cacheSize +externalCacheSize );

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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100

public void updateUi(Context context) {
if (mLastResult == null) {
...
} else {
long codeSize = mLastResult.getCodeBytes();
long dataSize =
mDataCleared ? 0 : mLastResult.getDataBytes() - mLastResult.getCacheBytes();
if (mLastCodeSize != codeSize) {
mLastCodeSize = codeSize;
mAppSize.setSummary(getSizeStr(context, codeSize));
}
if (mLastDataSize != dataSize) {
mLastDataSize = dataSize;
mDataSize.setSummary(getSizeStr(context, dataSize));
}
long cacheSize = (mDataCleared || mCachedCleared) ? 0 : mLastResult.getCacheBytes();
if (mLastCacheSize != cacheSize) {
mLastCacheSize = cacheSize;
mCacheSize.setSummary(getSizeStr(context, cacheSize));
}
// codeBytes + dataBytes + cacheBytes
long totalSize = codeSize + dataSize + cacheSize;
if (mLastTotalSize != totalSize) {
mLastTotalSize = totalSize;
mTotalSize.setSummary(getSizeStr(context, totalSize));
}
}
}

updateUiWithSize(mSizeController.getLastResult());

@Override
public void onLoadFinished(Loader<AppStorageStats> loader, AppStorageStats result) {
mSizeController.setResult(result);
updateUiWithSize(result);
}


@Override
public AppStorageStats loadInBackground() {
AppStorageStats result = null;
try {
result = mSource.getStatsForPackage(mInfo.volumeUuid, mInfo.packageName, mUser);
} catch (NameNotFoundException | IOException e) {
Log.w(TAG, "Package may have been removed during query, failing gracefully", e);
}
return result;
}

mInfo = packageManager.getApplicationInfo(mPackageName, 0);

// 访问 StorageStatsService的 queryStatsForPackage
public StorageStats queryStatsForPackage(String volumeUuid, String packageName, int userId,
String callingPackage) {
...

final ApplicationInfo appInfo;
try {
appInfo = mPackage.getApplicationInfoAsUser(packageName,
PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
}

// 以SharedUserSetting 区分, 查找shareUser, 且ps.getInstalled(userId) = true的,
if (defeatNullable(mPackage.getPackagesForUid(appInfo.uid)).length == 1) {
// 只有一个时, 直接调用 queryStatsForUid函数
// Only one package inside UID means we can fast-path
return queryStatsForUid(volumeUuid, appInfo.uid, callingPackage);
} else {
// Multiple packages means we need to go manual
final int appId = UserHandle.getUserId(appInfo.uid);
final String[] packageNames = new String[] { packageName };
final long[] ceDataInodes = new long[1];
String[] codePaths = new String[0];

if (appInfo.isSystemApp() && !appInfo.isUpdatedSystemApp()) {
// We don't count code baked into system image
// 不计算system下的app size
} else {
codePaths = ArrayUtils.appendElement(String.class, codePaths, appInfo.getCodePath());
}

final PackageStats stats = new PackageStats(TAG);
try {
mInstaller.getAppSize(volumeUuid, packageNames, userId, 0,
appId, ceDataInodes, codePaths, stats);
}
return translate(stats);
}
}

private static StorageStats translate(PackageStats stats) {
final StorageStats res = new StorageStats();
// 最终是计算的这三个部分.
res.codeBytes = stats.codeSize + stats.externalCodeSize;
res.dataBytes = stats.dataSize + stats.externalDataSize;
res.cacheBytes = stats.cacheSize + stats.externalCacheSize;
return res;
}

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
@Override
public StorageStats queryStatsForUid(String volumeUuid, int uid, String callingPackage) {
final int userId = UserHandle.getUserId(uid);
final int appId = UserHandle.getAppId(uid);

if (userId != UserHandle.getCallingUserId()) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS, TAG);
}

if (Binder.getCallingUid() == uid) {
// No permissions required when asking about themselves
} else {
enforcePermission(Binder.getCallingUid(), callingPackage);
}

final String[] packageNames = defeatNullable(mPackage.getPackagesForUid(uid));
final long[] ceDataInodes = new long[packageNames.length];
String[] codePaths = new String[0];

//上面做过检验, defeatNullable(mPackage.getPackagesForUid(appInfo.uid)).length == 1), 即
// packageNames.length = 1;
for (int i = 0; i < packageNames.length; i++) {
try {
final ApplicationInfo appInfo = mPackage.getApplicationInfoAsUser(packageNames[i],
PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
if (appInfo.isSystemApp() && !appInfo.isUpdatedSystemApp()) {
// We don't count code baked into system image
} else {
codePaths = ArrayUtils.appendElement(String.class, codePaths,
appInfo.getCodePath());
}
} catch (NameNotFoundException e) {
throw new ParcelableException(e);
}
}

final PackageStats stats = new PackageStats(TAG);
try {
mInstaller.getAppSize(volumeUuid, packageNames, userId, getDefaultFlags(),
appId, ceDataInodes, codePaths, stats);
} catch (InstallerException e) {
throw new ParcelableException(new IOException(e.getMessage()));
}
return translate(stats);
}

最终执行的代码为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
codePaths = appInfo.getCodePath());
mInstaller.getAppSize(volumeUuid, packageNames, userId, getDefaultFlags(),
appId, ceDataInodes, codePaths, stats);

public void getAppSize(String uuid, String[] packageNames, int userId, int flags, int appId,
long[] ceDataInodes, String[] codePaths, PackageStats stats)
throws InstallerException {
if (!checkBeforeRemote()) return;
try {
final long[] res = mInstalld.getAppSize(uuid, packageNames, userId, flags,
appId, ceDataInodes, codePaths);
stats.codeSize += res[0];
stats.dataSize += res[1];
stats.cacheSize += res[2];
...
stats.externalCodeSize += res[3];
stats.externalDataSize += res[4];
stats.externalCacheSize += res[5];
} catch (Exception e) {
throw InstallerException.from(e);
}
}
阅读全文 »

1. PackageManagerService的启动过程

本篇主要介绍pkms的构造函数所做的工作.

1.1. BOOT_PROGRESS_PMS_START 阶段

1.1.1. 初始化Settings类

初始化Settings类对象并添加6个ShareUserId

1
2
3
4
5
6
7
8
9
10
11
12
13
mSettings = new Settings(mPackages);
mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);

SharedUserSettings将“android:sharedUserId”属性的名称和对应的uid关联起来,同时持有所有声明相同sharedUserId的APK的PackageSettings,因此PKMS可以为同一类APK设置相同的权限。

1.1.1.1. Settings类的作用

首先可以看下Settings的构造函数

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
Settings(File dataDir, Object lock) {
//该 lock 为mPackages 的ArrayMap
mLock = lock;

mRuntimePermissionsPersistence = new RuntimePermissionPersistence(mLock);

mSystemDir = new File(dataDir, "system");
mSystemDir.mkdirs();
FileUtils.setPermissions(mSystemDir.toString(),
FileUtils.S_IRWXU|FileUtils.S_IRWXG
|FileUtils.S_IROTH|FileUtils.S_IXOTH,
-1, -1);
// Settings 工具类, 初始化/data/system下的几个目录
mSettingsFilename = new File(mSystemDir, "packages.xml");
mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
mPackageListFilename = new File(mSystemDir, "packages.list");
FileUtils.setPermissions(mPackageListFilename, 0640, SYSTEM_UID, PACKAGE_INFO_GID);

final File kernelDir = new File("/config/sdcardfs");
mKernelMappingFilename = kernelDir.exists() ? kernelDir : null;

// Deprecated: Needed for migration
mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");
mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
}
阅读全文 »

1. 开篇

涉及的主要文件:

com.android.server.print

系统打印服务, 打印服务是一种插件( plug-in components),它能够通过一些标准协议和打印机通讯。这些服务像一座桥,处于系统和打印机之间。因此,打印机和打印协议的具体实现从系统中分离的,能够独立开发和更新。该处讲解的是和打印插件关联的系统服务.

/frameworks/base/services/print/java/com/android/server/print/

1
2
3
4
5
6
7
8
9
10
11
12
13
/home/newdisk/local/SPREADTRUM/liguang.zhang/remote_disk/sp8.1_trunk/frameworks/base/services/print/java/com/android/server/print$ lltotal 220
drwxr-xr-x 1 2516 2000 4096 Jun 25 14:20 ./
drwxr-xr-x 1 2516 2000 4096 Nov 8 2017 ../
# PrintService插件管理类.
-rw-r--r-- 1 2516 2000 41807 Jun 25 16:21 PrintManagerService.java
# 负责和PrintService插件进行bind, 以及插件的状态进行关联
-rw-r--r-- 1 2516 2000 34039 Jun 25 14:20 RemotePrintService.java
# 推荐选择默认的打印插件
-rw-r--r-- 1 2516 2000 8869 Jun 25 14:20 RemotePrintServiceRecommendationService.java
# 打印机后台处理程序,打印任务工作状态相关.
-rw-r--r-- 1 2516 2000 34260 Nov 8 2017 RemotePrintSpooler.java
# 和用户安装的打印服务相关的管理,通过userState中转转发和PrintManagerService进行交互
-rw-r--r-- 1 2516 2000 85628 Jun 25 15:47 UserState.java

2. PrintManagerService初始化

PrintManagerService(简写PMS) 初始化

SystemServer中启动PMS

1
2
3
4
5
6
7
8
9
10
11
12
13
            if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_PRINTING)) {
traceBeginAndSlog("StartPrintManager");
mSystemServiceManager.startService(PRINT_MANAGER_SERVICE_CLASS);
traceEnd();
}
// onStart注册'print'的服务
public void onStart() {
publishBinderService(Context.PRINT_SERVICE, mPrintManagerImpl);
}
// 监听DISABLED_PRINT_SERVICES 字段, 表示禁用的打印服务插件, 如果该字段变化,则需要重新更新UserState的关联的打印插件.
registerContentObservers();
// 监听PACKAGE ADD/REMOVE/MODIFY等的广播, 用来更新打印插件服务的状态
registerBroadcastReceivers();
阅读全文 »

1. PackageManagerService的启动过程

本篇主要介绍PKMS扫描包的流程


1.1. BOOT_PROGRESS_PMS_SYSTEM_SCAN_START 阶段

1.1.1. 开始扫描apk

先扫描这两个目录的

1
2
/vendor/overlay
/system/framework

再扫描这几个目录下面的:

1
2
3
4
/system/priv-app
/system/app
/vendor/app
/oem/app

最后扫描这几个目录下面的:

阅读全文 »

文件加密FBE&DirectBoot模式介绍

1. File based Encryption

Android 7.0及以上版本提供基于文件的加密方式(FBE). 这种方式允许使用不同的密钥对不同的文件进行加密, 并且可以独立进行解密.
Android 7.0为基于文件的加密引入了新的功能, 命名为Direct Boot. 它允许加密设备直接启动至锁定屏幕的状态. 在以前的版本中, 使用全局磁盘加密(FDE)的设备,
用户需要在任何数据能够被访问前提供认证凭证(图形/密码/指纹), 来预防设备可能被进行的任何基本操作.
如: 闹钟无法执行, 辅助功能服务无法使用, 电话无法接受通话请求, 除了最基本的紧急通话操作.
使用基于文件加密的设备, 应用可以了解当前加密的情况, 同时被允许执行限定范围内的操作. 这些操作能够在用户提供认证凭证前执行, 同时依然能够保护私有用户信息.
在使用FBE的设备上, 设备的每个用户对于设备应用均拥有两个存储空间:

  • 凭证加密存储区间(Credential Encrypted (CE)), 这是缺省的存储空间, 并且只有当用户解锁设备后才可用.
  • 设备加密存储空间(Device Encrypted (DE)), 该存储空间在Direct Boot模式和用户解锁设备后均可用.

1.1. FDE Vs FBE:

  • FBE: FILE BASED ENCRYPTION:
    • 每一个用户一个CE key,CE key的加密信息存储在data分区的相应文件夹中。
    • 每个用户对应一个DE key,除此之外,还有一个全局的DE key用来为与用户非强关联的文件夹设置加密。
    • 设备未解锁之前,可以使用CE区域以外的文件夹。
    • 加密针对文件夹级别,加密机制利用了Ext4 文件系统的加密特性。
    • 这种区分能够使工作模型更为安全, 因为它允许在同一时间能够保护多个用户,并不是基于一个启动时密码。
  • FDE(FULL DISK ENCTYPTION)
    • 只有一个key,key的加密信息存储在磁盘尾部区域。
    • 设备未解锁之前,data目录是以tmpfs格式挂载的data分区处于完全不可使用状态。
    • 加密针对的是分区级别,加密机制利用了dm-crypt加密特性。

1.2. Dependencies

设备必须满足以下的要求来安全使用AOSP的FBE实现:

  • Kernel支持ext4加密(相关的kernel config为: EXT4_FS_ENCRYPTION)
  • Keymaster支持1.0/2.0的HAL版本. 0.3版本的keymaster hal并不提供相关需要的属性支持, 而且不能保证加密密钥的安全保护机制.
  • Keymaster/Keystore 和 GateKeeper必须在可信任执行环境(TEE)中实现, 用以提供对DE密钥的保护, 该情况下, 未认证的系统OS(自行输入到设备上的OS)将不能简单的访问DE密钥.
  • kernel中提供的加密性能必须达到使用AES-XTS时最低为50MB/s来保证良好的用户体验.
  • Verified Boot机制下 Keymaster root of trust 必须绑定至keymaster的初始化过程中. 这将保证设备加密证书不会被未验证的操作系统访问到
  • bootloader passes the following information to the TEE after boot/recovery partition verification and
    TEE initialization to bind the Keymaster root of trust:
    • the public key that was used to sign the boot partition

1.3. 加密规则 Encryption policy

阅读全文 »

1. ADB处理的流程

通过adb install命令安装指定apk时,会先将该apk上传到/data/local/tmp或者/sdcard/tmp目录下,然后调用pm脚本,通过Binder通信,调用PackageManagerService的接口安装apk。
通过PackageInstaller.apk安装指定apk时,最终也会调用PackageManagerService的接口实现apk的安装。
以上两种情况最终都会发送INIT-COPY消息,由PackageManagerService启动过程中初始化的mHandler的handleMessage方法处理该消息,开始apk的安装。

1.1. adb 拷贝流程分析

adb 安装apk支持的命令

1
2
3
4
5
6
7
8
"  adb install [-lrtsdg] <file>\n"
" - push this package file to the device and install it\n"
" (-l: forward lock application)\n" // foward_lock
" (-r: replace existing application)\n" // upgrade apk
" (-t: allow test packages)\n"
" (-s: install application on sdcard)\n" // apptosd
" (-d: allow version code downgrade (debuggable packages only))\n" // downgrade
" (-g: grant all runtime permissions)\n" // 赋予所有的运行时权限
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
static int install_app_legacy(TransportType transport, const char* serial, int argc, const char** argv) {
static const char *const DATA_DEST = "/data/local/tmp/%s";
static const char *const SD_DEST = "/sdcard/tmp/%s";
const char* where = DATA_DEST;
int i;
struct stat sb;

for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-s")) {
where = SD_DEST;
}
}
...
int result = -1;
std::vector<const char*> apk_file = {argv[last_apk]};
std::string apk_dest = android::base::StringPrintf(
where, adb_basename(argv[last_apk]).c_str());
// adb 将pc上的apk包拷贝到手机上的 DATA_DEST/<filename>.apk 或 SD_DEST/<filename>.apk
if (!do_sync_push(apk_file, apk_dest.c_str())) goto cleanup_apk;
argv[last_apk] = apk_dest.c_str(); /* destination name, not source location */
// 调用pm cmd 进行处理
result = pm_command(transport, serial, argc, argv);
cleanup_apk:
// 清理拷贝到手机目录上的apk
delete_file(transport, serial, apk_dest);
return result;
}

发送shell消息到终端, 使用pm install 命令安装对应的apk.期间,如果出现adb connect连接问题,则会进行重连.如果能够发送给终端执行对应的shell命令.等待执行的结果,并通过adb打印到电脑的控制台上.

1.2. pm执行安装流程

生成system/bin/pm 可执行文件

传入参数.执行 runInstall 函数

阅读全文 »

1. Jni层简介

1.1. Jni层的作用

Java层的函数可以调用Native层函数
Native层函数可以调用Java层函数

1.2. 实例分析

MediaScanner为例实例拆解JNI层基础用法

1.2.1. 库名相关

JNI层对应的是libmedia_jni.so, media_jni对应Jni库的名字,Android平台基本采用lib 模块名_jni.so的名字命名。

1
2
3
4
5
6
static {
System.loadLibrary("media_jni");
native_init();
}
// Native函数声明,加native关键字, 实际功能由Jni层完成
private static native final void native_init()

要使用Jni层函数,必须先加载Jni库文件,只要调用Jni函数前加载即可。其次声明该Jni层函数。

加载一般放在 static静态块里,这样类一经创建,就加载对应的Jni库。

阅读全文 »

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. prepareSandboxForApp

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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83

skinparam backgroundColor #EEEBDC

skinparam sequence {
ArrowColor DeepSkyBlue
ActorBorderColor DeepSkyBlue
LifeLineBorderColor blue
LifeLineBackgroundColor #A9DCDF

ParticipantBorderColor DeepSkyBlue
ParticipantBackgroundColor DodgerBlue
ParticipantFontName Impact
ParticipantFontSize 17
ParticipantFontColor #A9DCDF

ActorBackgroundColor aqua
ActorFontColor DeepSkyBlue
ActorFontSize 17
ActorFontName Aapex
}

autoactivate on
pkms -> SMS: prepareSandboxForApp\n(pkg.packageName, appId,\n pkg.mSharedUserId, userId);
SMS->SMS: getSandboxId\n(packageName, sharedUserId);
return sandboxId
note left: packageName || "shared-" + packageName
SMS -> vold: <b>prepareSandboxForApp\n(packageName, appId, \n sandboxId, userId)
vold -> VM: prepareSandboxForApp
alt hasIsolatedStorage
VM->VM: hasIsolatedStorage
note left:"sys.isolated_storage_snapshot" true || "persist.sys.isolated_storage" true
else
VM-->pkms:end
end

VM->VM:verify package
return
VM->VM:<b>prepareSandboxes\n(userId, {packageName}, visibleVolLabels)
VM->VM:prepareSubDirs
note left:<b>sandboxRoot:\n/mnt/runtime/write/<vlable>Android/sandbox/
return

VM->VM:prepareSandboxTargets\n(userId, visibleVolLabels)
note left:<b>mntTargetRoot:\n/mnt/user/<userid>/package\n\
<b>sandboxTarget:\n/mnt/user/<userid>/package/<vlabel>/<userid>\n\
<b>primaryPath</b>(/stor**age/emulated/<userid>) <b>-></b> $mntTargetRoot/self/primary
return

VM->VM:mountPkgSpecificDirsForRunningProcs\n(userId, packageNames, \n visibleVolLabels, -1)
note left:obbMountDir:\n\
/mnt/user/<userId>/obb_mount\n\
<b>read /proc/<pid>/ns/mnt \n\
setns(nsFd.get(), CLONE_NEWNS
VM->VM:getMountModeForRunningProc
note left: <b>stat("/storage", &storageSb) \n\
vs stat("/mnt/runtime/full", &mntFullSb) -> <b>REMOUNT_MODE_FULL \n\
vs stat("/mnt/runtime/write", &mntWriteSb) -> <b>REMOUNT_MODE_LEGACY \n\
obbMountFile: "/mnt/user/<userid>/obb_mount/package" <b> \n\
<b>obbMountFile exist -> REMOUNT_MODE_INSTALLER \n\
vs /mnt/user/<userid>/package-><b>REMOUNT_MODE_WRITE
return mountmode

alt mountMode == remountMode
VM->VM:handleMountModeInstaller
return 0
end

alt REMOUNT_MODE_FULL || REMOUNT_MODE_LEGACY || REMOUNT_MODE_NONE
VM->pkms:end
else REMOUNT_MODE_INSTALLER || REMOUNT_MODE_WRITE
VM->VM ++ : mount
note left #LightBlue:mntSource: /mnt/runtime/write/<vlabel>/<userid> (for emulated)\n\
mntTarget: /storage/<vlabel>/<userid> (storage/emulated/0) \n\
sandboxSource: $mntSource/Android/sandbox/<sandboxid> \n\
<b>$sandboxSource <b>-></b> $mntTarget \n\
obbSourceDir: $mntSource/Android/obb \n\
obbTargetDir: $mntTarget/Android/obb \n\
REMOUNT_MODE_INSTALLER: $obbSourceDir <b>-></b> $obbTargetDir \n\
REMOUNT_MODE_WRITE: $mntSource/Android/data|media/<package>/ <b>-></b> $mntTarget/Android/data|media/<package>/ \n\
$mntSource/Android/data|media/<package>/ <b>-></b> $mntTarget/Android/data|media/<package>/
return
VM->pkms:end
end
阅读全文 »