本文基于Android9.0
主要从以下几个方面着手:
- PMS启动
- PMS关键几个成员变量
- PMS安装APK
- PMS卸载APK
这里我简单的将其分为以下几个步骤:
- SystemServer通过PMS的main方法启动PMS
- PMS构造方法中初始化Settings
- 扫描各个系统目录下APP相关信息
PMS启动是在SystemServer中,startBootsTrapService方法中
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
这里会转到PMS的main方法:
public static PackageManagerService main(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
// Self-check for initial settings.
PackageManagerServiceCompilerMapping.checkProperties();
//PMS构造方法
PackageManagerService m = new PackageManagerService(context, installer,
factoryTest, onlyCore);
m.enableSystemUserPackages();
ServiceManager.addService("package", m);
final PackageManagerNative pmn = m.new PackageManagerNative();
ServiceManager.addService("package_native", pmn);
return m;
}
PMS构造方法:
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
......
//Settings的初始化
mSettings = new Settings(mPermissionManager.getPermissionSettings(), mPackages);
......
}
mSettings是全局的,它主要协助PMS保存系统中安装APP包名,权限,四大组件等相关信息的存储,Settings会在/data/system目录下创建相关的文件来保存这些APP相关的信息。
Settings构造函数:
/base/services/core/java/com/android/server/pm/Settings.java
Settings(PermissionSettings permissions, Object lock) {
this(Environment.getDataDirectory(), permissions, lock);
}
Settings(File dataDir, PermissionSettings permission, Object lock) {
mLock = lock;
mPermissions = permission;
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);
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");
}
各个文件的具体内容不做详细的展开。
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
......
scanDirTracedLI(new File(VENDOR_OVERLAY_DIR),
mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM_DIR,
scanFlags
| SCAN_AS_SYSTEM
| SCAN_AS_VENDOR,
0);
scanDirTracedLI(new File(PRODUCT_OVERLAY_DIR),
mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM_DIR,
scanFlags
| SCAN_AS_SYSTEM
| SCAN_AS_PRODUCT,
0);
/// M: Support RSC overlay dir
sPmsExt.scanDirLI(PmsExt.INDEX_RSC_OVERLAY, mDefParseFlags, scanFlags, 0);
mParallelPackageParserCallback.findStaticOverlayPackages();
// Find base frameworks (resource packages without code).
scanDirTracedLI(frameworkDir,
mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM_DIR,
scanFlags
| SCAN_NO_DEX
| SCAN_AS_SYSTEM
| SCAN_AS_PRIVILEGED,
0);
......
}
从Android 9,0的代码来看,扫描路径的顺序为:
- /vendor/overlay
- /product/overlay
- /system/framework
- /system/priv-app
- /system/app
- /vendor/priv-app
- /vendor/app
- /odm/priv-app
- /odm/app
- /oem/priv-app
- /oem/app
- /product/priv-app
- /product/app
- /data/app
- /data/private-app
到这里PMS启动的大致流程就结束了。
四大组件:
// All available activities, for your resolving pleasure.
final ActivityIntentResolver mActivities =
new ActivityIntentResolver();
// All available receivers, for your resolving pleasure.
final ActivityIntentResolver mReceivers =
new ActivityIntentResolver();
// All available services, for your resolving pleasure.
final ServiceIntentResolver mServices = new ServiceIntentResolver();
// All available providers, for your resolving pleasure.
final ProviderIntentResolver mProviders = new ProviderIntentResolver();
以上四个变量,分别用于存储APP中的所有四大组件相关信息。
// Keys are String (package name), values are Package. This also serves
// as the lock for the global state. Methods that must be called with
// this lock held have the prefix "LP".
@GuardedBy("mPackages")
final ArrayMap mPackages =
new ArrayMap();
mPackages用于存储系统中安装的所有APP的包相关信息。
@GuardedBy("mPackages")
final Settings mSettings;
mSettings前面已经讲过,是辅助PMS管理包相关信息的。
Settings的构造函数已经看过了,功能也已经明了,那么 接下来看看其他几个成员都是在哪儿填充数据的。
mPackages:
方法调用的顺序是:
scanDirTracedLI--》scanDirLI--》scanPackageChildLI--》addForInitLI --》mPakcages.put
相关时序图:
到这里,扫描已经安装的APP信息的时候,就会把Package相关内容,存储到mPackages中。
四大组件:mActivites,mReceivers,mServices,mProviders
方法调用基本流程:
scanDirTracedLI--》scanDirLI--》scanPackageChildLI--》addForInitLI --》scanPackageNewLI-->commitScanResultsLocked-->commitPackageSettings-->mProviders.addProvider(p); mServices.addService(s);mReceivers.addActivity(a, "receiver");mActivities.addActivity(a, "activity");
相关流程图,接上面mPackage路程图继续往后跟踪:
四大组件相关信息,在PMS启动的时候,扫描安装的APP时,就存储了相关的信息了。
扫描是在方法scanDirLi方法中:
private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime) {
//列出当前扫描目录(system/framework、system/app、vendor/app等)下所有的文件
final File[] files = scanDir.listFiles();
.....
//解析安装包,也就是APK文件,是通过ParallelPackageParser对象
try (ParallelPackageParser parallelPackageParser = new ParallelPackageParser(
mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir,
mParallelPackageParserCallback)) {
// Submit files for parsing in parallel
int fileCount = 0;
for (File file : files) {
final boolean isPackage = (isApkFile(file) || file.isDirectory())
&& !PackageInstallerService.isStageName(file.getName());
//如果发现并非是APK文件,则直接跳过当前文件,只处理APK文件
if (!isPackage) {
// Ignore entries which are not packages
continue;
}
//将每个APK文件的信息提交到阻塞队列(BlockingQueue)
parallelPackageParser.submit(file, parseFlags);
fileCount++;
}
// Process results one by one
for (; fileCount > 0; fileCount--) {
//从队列中取出之前存入的包数据
ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
Throwable throwable = parseResult.throwable;
int errorCode = PackageManager.INSTALL_SUCCEEDED;
if (throwable == null) {
// TODO(toddke): move lower in the scan chain
// Static shared libraries have synthetic package names
if (parseResult.pkg.applicationInfo.isStaticSharedLibrary()) {
renameStaticSharedLibraryPackage(parseResult.pkg);
}
try {
if (errorCode == PackageManager.INSTALL_SUCCEEDED) {
//执行扫描的后续工作,转到PMS,处理PMS对象中的相关内容
scanPackageChildLI(parseResult.pkg, parseFlags, scanFlags,
currentTime, null);
}
} catch (PackageManagerException e) {
errorCode = e.error;
Slog.w(TAG, "Failed to scan " + parseResult.scanFile + ": " + e.getMessage());
}
......
}
ParallelPackageParser的submit方法,其实就是通过PackageParser解析完APK文件之后,放入mQueue这个阻塞队列中:
//ParallelPackageParser.java
/**
* Submits the file for parsing
* @param scanFile file to scan
* @param parseFlags parse falgs
*/
public void submit(File scanFile, int parseFlags) {
mService.submit(() -> {
ParseResult pr = new ParseResult();
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parallel parsePackage [" + scanFile + "]");
try {
PackageParser pp = new PackageParser();
pp.setSeparateProcesses(mSeparateProcesses);
pp.setOnlyCoreApps(mOnlyCore);
pp.setDisplayMetrics(mMetrics);
pp.setCacheDir(mCacheDir);
pp.setCallback(mPackageParserCallback);
pr.scanFile = scanFile;
pr.pkg = parsePackage(pp, scanFile, parseFlags);
} catch (Throwable e) {
pr.throwable = e;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
try {
mQueue.put(pr);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
// Propagate result to callers of take().
// This is helpful to prevent main thread from getting stuck waiting on
// ParallelPackageParser to finish in case of interruption
mInterruptedInThread = Thread.currentThread().getName();
}
});
}
具体怎么解析APK文件,请继续跟踪,查看PackageParser.java的parsePakcage方法;扫描过程到这里就结束了。
安装APK流程比较简单,直接上流程图:
安装APK的整个流程, 基本都是在PMS中,安装时,会先进行拷贝,将安装文件拷贝到特定目录,然后从特定目录进行解析包名等信息进行安装,并不是从原本APK文件所在路径直接安装的,具体细节请参考上面流程图跟踪解析。
卸载APK是从deletePackageX开始的,具体就不做详细跟踪,情况跟安装APK类似,在卸载APK时,会将要卸载的APK中所保安的四大组件从mProviders,mServices,mReceivers,mActivities中删除,相关权限也会删除,packages.xml等文件也会作相应更新。
附上卸载时序图:
到这里PMS大致的总结就先到这儿。