服务启动
PKMS 服务在 SystemServer.java 的 startBootstrapServices() 中启动;
t.traceBegin("StartPackageManagerService");
try {
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
}
t.traceEnd();
服务启动处理主要在 PackageManagerService 的 main() 中,其创建了 Settings 和 PackageManagerService 对象,并把服务注册到 ServiceManager 中;
public static PackageManagerService main(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
t.traceBegin("create package manager");
//创建Injector对象用于PKMS的运行时环境
Injector injector = new Injector(
context, lock, installer, installLock, new PackageAbiHelperImpl(),
(i, pm) -> new Settings(Environment.getDataDirectory(),
i.getPermissionManagerServiceInternal()
.getPermissionSettings(), lock),
(i, pm) -> (PlatformCompat) ServiceManager
.getService("platform_compat"));
// PKMS构造方法,是整个PKMS启动过程的核心
PackageManagerService m = new PackageManagerService(
injector, onlyCore, factoryTest);
t.traceEnd(); // "create package manager"
// 根据用户类型为所有用户安装/卸载系统包
m.installWhitelistedSystemPackages();
// 注册服务
ServiceManager.addService("package", m);
final PackageManagerNative pmn = m.new PackageManagerNative();
ServiceManager.addService("package_native", pmn);
return m;
}
Settings 对象,主要用来保存有关动态设置的信息,在其构造方法中初始化了几个 File 类,这几个文件主要保存包管理信息;
Settings(File dataDir, PermissionSettings permission, Object lock) {
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);
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");
}
扫描 APK
PKMS 的构造函数主要是对配置文件进行读取,扫描系统中的 APK 并写入到内存或者文件中;
public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest) {
mSettings = injector.getSettings();
t.traceBegin("addSharedUsers");
// 初始化一些 SharedUser 的 name 和 SharedUserSetting 的一一对应关系
// 如对于 name 为 android.uid.system 的 SharedUser,其对应的
// SharedUserSetting(pkgFlags :ApplicationInfo.FLAG_SYSTEM
// pkgPrivateFlags :ApplicationInfo.PRIVATE_FLAG_PRIVILEGED
// uid :Process.SYSTEM_UID)
mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
ApplicationInfo.FLAG_SYSTEM,
ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
t.traceEnd();
// CHECKSTYLE:OFF IndentationCheck
synchronized (mInstallLock) {
// writer
synchronized (mLock) {
t.traceBegin("read user settings");
// 使用 PullParser 方式读取 packages.xml 或 packages-backup.xml,
// 解析文件节点生成对应的对象并保存
mFirstBoot = !mSettings.readLPw(
mInjector.getUserManagerInternal().getUsers(
/* excludePartial= */ true,
/* excludeDying= */ false,
/* excludePreCreated= */ false));
t.traceEnd();
File frameworkDir = new File(Environment.getRootDirectory(),
"framework");
mCacheDir = preparePackageParserCache();
PackageParser2 packageParser = new PackageParser2(mSeparateProcesses,
mOnlyCore, mMetrics, mCacheDir, mPackageParserCallback);
ExecutorService executorService = ParallelPackageParser
.makeExecutorService();
// Prepare apex package info before scanning APKs, these information are
// needed when scanning apk in apex.
// Apex 是用于系统安装包的升级
mApexManager.scanApexPackagesTraced(packageParser, executorService);
// 扫描 system/framework 目录下的 apk 文件
scanDirTracedLI(frameworkDir, systemParseFlags,
systemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0,
packageParser, executorService);
for (int i = 0, size = mDirsToScanAsSystem.size(); i < size; i++) {
final ScanPartition partition = mDirsToScanAsSystem.get(i);
if (partition.getPrivAppFolder() != null) {
// 扫描 system/priv-app 目录下的 apk 文件
scanDirTracedLI(partition.getPrivAppFolder(), systemParseFlags,
systemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag,
0, packageParser, executorService);
}
// 扫描 system/app 目录下的 apk 文件
scanDirTracedLI(partition.getAppFolder(), systemParseFlags,
systemScanFlags | partition.scanFlag, 0,
packageParser, executorService);
}
if (!mOnlyCore) {
// 扫描 data/data/app 目录下的 apk 文件
scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0,
packageParser, executorService);
}
t.traceBegin("write settings");
// 更新 packages.xml
mSettings.writeLPr();
t.traceEnd();
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
SystemClock.uptimeMillis());
} // synchronized (mLock)
} // synchronized (mInstallLock)
// CHECKSTYLE:ON IndentationCheck
}
Apex 是在 Android10 中谷歌为了解决系统升级而提出的一个概念。和 APK 类似,Apex 把 Framework 层中关键的功能搞成一个个的模块,然后可以单独升级这些模块。 这些模块就和一个一个的 APK 类似,就是一个压缩包,后缀名叫 .apex。
Apex 和 Apk 的区别:
- apk 是应用程序的载体,对应用开发者而言,可以 apk 方式对应用功能进行升级。
- apex 是系统功能的载体,对系统开发者(目前看主要是谷歌)而言,可以 apex 方式对系统功能进行升级。 apex 相当于对系统功能进行了更细粒度的划分,可以独立升级这些功能,这些 apex 包将来就发布在谷歌的 playstore 上供我们下载。
scanDirTracedLI() 的主要是扫描 APK 的处理,它又继续调用了 scanDirLI(),大体代码如下:
private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime, PackageParser2 packageParser, ExecutorService executorService) {
final File[] files = scanDir.listFiles();
// 创建一个ParallelPackageParser用于解析操作,其内部会使用线程池进行处理
ParallelPackageParser parallelPackageParser =
new ParallelPackageParser(packageParser, executorService);
// Submit files for parsing in parallel
int fileCount = 0;
for (File file : files) {
final boolean isPackage = (isApkFile(file) || file.isDirectory())
&& !PackageInstallerService.isStageName(file.getName());
if (!isPackage) {
// Ignore entries which are not packages
continue;
}
// 提交安装包文件以进行解析并保存信息
// 这里的包可能是单独的APK文件,也可能是APK目录
// 若是APK目录,则会依次解析目录中包含的APK文件
parallelPackageParser.submit(file, parseFlags);
fileCount++;
}
// Process results one by one
for (; fileCount > 0; fileCount--) {
// 从解析队列中取出已解析的包信息
ParallelPackageParser.ParseResult parseResult =
parallelPackageParser.take();
Throwable throwable = parseResult.throwable;
if (throwable == null) {
try {
// 将前面解析到的Package信息,更新到系统中,
// 并更新某些系统文件信息,且对满足版本要求的应用进行更新操作
addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags,
currentTime, null);
}
}
}
}
PKMS 系统服务的启动大体流程便如此,启动后用户便可与底层交互,实现应用的安装、卸载、包信息获取等功能。