由以上代码可知,`PKMS` 扫描了很多目录,下面列举几个重点说明:
✨ /system/framework :该目录中的文件都是系统库,例如:framework.jar、services.jar、framework-res.apk 等。不过 scanDirTracedLI 只扫描 APK 文件,所以 framework-res.apk 是该目录中唯一被扫描的文件。
✨ /system/app :该目录下全是默认的系统应用。例如:Browser.apk、SettingsProvider.apk 等。
✨ /vendor/app :该目录中的文件由厂商提供,即全是厂商特定的 APK 文件。
### 4.2.1 scanDirTracedLI
`PKMS` 扫描目录统一调用 `scanDirTracedLI` 方法:
```java {.line-numbers}
public void scanDirTracedLI(File scanDir,
final int parseFlags, int scanFlags, long currentTime) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
try {
scanDirLI(scanDir, parseFlags, scanFlags, currentTime);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
```
重点转移到 `scanDirLI` 方法:
```java {.line-numbers}
private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime) {
final File[] files = scanDir.listFiles();
if (ArrayUtils.isEmpty(files)) {
Log.d(TAG, "No files in app dir " + scanDir);
return;
}
...
// ParallelPackageParser 是 Android O 新增的一个类,可以理解它其实就是一个队列,
// 收集系统 apk 文件,然后从这个队列里面一个个取出 apk ,调用 PackageParser 解析!
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 文件,如果不是则跳过继续扫描
if (!isPackage) {
// Ignore entries which are not packages
continue;
}
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) {
/*
* Android P 调用 scanPackageChildLI,
* Android O 调用 scanPackageLI,
*
* 调用 scanPackageChildLI 方法扫描一个特定的 apk 文件,
* 返回值是 PackageParser 的内部类 Package,
* 该类的实例代表一个 APK 文件,所以它就是和 apk 文件对应的数据结构。
*/
scanPackageChildLI(parseResult.pkg, parseFlags, scanFlags,
currentTime, null);
}
} catch (PackageManagerException e) {
errorCode = e.error;
Slog.w(TAG, "Failed to scan " + parseResult.scanFile + ": " + e.getMessage());
}
} else if (throwable instanceof PackageParser.PackageParserException) {
PackageParser.PackageParserException e = (PackageParser.PackageParserException)
throwable;
errorCode = e.error;
Slog.w(TAG, "Failed to parse " + parseResult.scanFile + ": " + e.getMessage());
} else {
throw new IllegalStateException("Unexpected exception occurred while parsing "
+ parseResult.scanFile, throwable);
}
// Delete invalid userdata apps
// 如果是非系统 apk 并且解析失败
if ((scanFlags & SCAN_AS_SYSTEM) == 0 &&
errorCode != PackageManager.INSTALL_SUCCEEDED) {
logCriticalInfo(Log.WARN,
"Deleting invalid package at " + parseResult.scanFile);
// 非系统 Package 扫描失败,删除文件
removeCodePathLI(parseResult.scanFile);
}
}
}
}
```
看下 `ParallelPackageParser` 这个类:
> frameworks/base/services/core/java/com/android/server/pm/ParallelPackageParser.java
```java {.line-numbers}
/**
* Helper class for parallel parsing of packages using {@link PackageParser}.
*
Parsing requests are processed by a thread-pool of {@link #MAX_THREADS}.
* At any time, at most {@link #QUEUE_CAPACITY} results are kept in RAM
*/
class ParallelPackageParser implements AutoCloseable {
private static final int QUEUE_CAPACITY = 10;
private static final int MAX_THREADS = 4;
private final String[] mSeparateProcesses;
private final boolean mOnlyCore;
private final DisplayMetrics mMetrics;
private final File mCacheDir;
private final PackageParser.Callback mPackageParserCallback;
private volatile String mInterruptedInThread;
// BlockingQueue 是一个 FIFO(先进先出)的 Queue(队列),是设计用来实现生产者-消费者队列的。
// 它提供了可阻塞的插入和移除方法,当队列容器已满,生产者线程会被阻塞,直到队列未满;
// 当队列容器为空时,消费者线程会被阻塞,直至队列非空时为止。
// ArrayBlockingQueue 是由数组实现的有界阻塞队列,创建的时候需要指定 capacity(容量,可以存储的最大的元素个数,因为它不会自动扩容)以及是否为公平锁。
private final BlockingQueue mQueue = new ArrayBlockingQueue<>(QUEUE_CAPACITY);
// 线程池
private final ExecutorService mService = ConcurrentUtils.newFixedThreadPool(MAX_THREADS,
"package-parsing-thread", Process.THREAD_PRIORITY_FOREGROUND);
ParallelPackageParser(String[] separateProcesses, boolean onlyCoreApps,
DisplayMetrics metrics, File cacheDir, PackageParser.Callback callback) {
mSeparateProcesses = separateProcesses;
mOnlyCore = onlyCoreApps;
mMetrics = metrics;
mCacheDir = cacheDir;
mPackageParserCallback = callback;
}
static class ParseResult {
PackageParser.Package pkg; // Parsed package
File scanFile; // File that was parsed
Throwable throwable; // Set if an error occurs during parsing
@Override
public String toString() {
return "ParseResult{" +
"pkg=" + pkg +
", scanFile=" + scanFile +
", throwable=" + throwable +
'}';
}
}
/**
* Take the parsed package from the parsing queue, waiting if necessary until the element
* appears in the queue.
* @return parsed package
*/
public ParseResult take() {
try {
if (mInterruptedInThread != null) {
throw new InterruptedException("Interrupted in " + mInterruptedInThread);
}
return mQueue.take();
} catch (InterruptedException e) {
// We cannot recover from interrupt here
Thread.currentThread().interrupt();
throw new IllegalStateException(e);
}
}
/**
* 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();
}
});
}
@VisibleForTesting
protected PackageParser.Package parsePackage(PackageParser packageParser, File scanFile,
int parseFlags) throws PackageParser.PackageParserException {
return packageParser.parsePackage(scanFile, parseFlags, true /* useCaches */);
}
...
}
```
`ParallelPackageParser` 是一个并行的 `PackageParser.Package` 解析器,内部使用线程池来完成并行的工作。具体解析操作后面再另行分析,这里先按照解析成功继续分析:
```java {.line-numbers}
/**
* Scans a package and returns the newly parsed package.
* @throws PackageManagerException on a parse error.
*/
private PackageParser.Package scanPackageChildLI(PackageParser.Package pkg,
final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
@Nullable UserHandle user)
throws PackageManagerException {
// If the package has children and this is the first dive in the function
// we scan the package with the SCAN_CHECK_ONLY flag set to see whether all
// packages (parent and children) would be successfully scanned before the
// actual scan since scanning mutates internal state and we want to atomically
// install the package and its children.
if ((scanFlags & SCAN_CHECK_ONLY) == 0) {
if (pkg.childPackages != null && pkg.childPackages.size() > 0) {
scanFlags |= SCAN_CHECK_ONLY;
}
} else {
scanFlags &= ~SCAN_CHECK_ONLY;
}
// Scan the parent
PackageParser.Package scannedPkg = addForInitLI(pkg, parseFlags,
scanFlags, currentTime, user);
// Scan the children
final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
for (int i = 0; i < childCount; i++) {
PackageParser.Package childPackage = pkg.childPackages.get(i);
addForInitLI(childPackage, parseFlags, scanFlags,
currentTime, user);
}
if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
return scanPackageChildLI(pkg, parseFlags, scanFlags, currentTime, user);
}
return scannedPkg;
}
```
### 4.2.2 addForInitLI
```java {.line-numbers}
/**
* Adds a new package to the internal data structures during platform initialization.
*
After adding, the package is known to the system and available for querying.
*
For packages located on the device ROM [eg. packages located in /system, /vendor,
* etc...], additional checks are performed. Basic verification [such as ensuring
* matching signatures, checking version codes, etc...] occurs if the package is
* identical to a previously known package. If the package fails a signature check,
* the version installed on /data will be removed. If the version of the new package
* is less than or equal than the version on /data, it will be ignored.
*
Regardless of the package location, the results are applied to the internal
* structures and the package is made available to the rest of the system.
*
NOTE: The return value should be removed. It's the passed in package object.
*/
private PackageParser.Package addForInitLI(PackageParser.Package pkg,
@ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
@Nullable UserHandle user)
throws PackageManagerException {
final boolean scanSystemPartition = ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0)
// M:operator app also is removable and not system flag
|| sPmsExt.isRemovableSysApp(pkg.packageName);
final String renamedPkgName;
final PackageSetting disabledPkgSetting;
final boolean isSystemPkgUpdated;
final boolean pkgAlreadyExists;
PackageSetting pkgSetting;
...
// 判断系统应用是否需要更新
synchronized (mPackages) {
renamedPkgName = mSettings.getRenamedPackageLPr(pkg.mRealPackage);
final String realPkgName = getRealPackageName(pkg, renamedPkgName);
if (realPkgName != null) {
ensurePackageRenamed(pkg, renamedPkgName);
}
final PackageSetting originalPkgSetting = getOriginalPackageLocked(pkg, renamedPkgName);
final PackageSetting installedPkgSetting = mSettings.getPackageLPr(pkg.packageName);
pkgSetting = originalPkgSetting == null ? installedPkgSetting : originalPkgSetting;
pkgAlreadyExists = pkgSetting != null;
final String disabledPkgName = pkgAlreadyExists ? pkgSetting.name : pkg.packageName;
disabledPkgSetting = mSettings.getDisabledSystemPkgLPr(disabledPkgName);
isSystemPkgUpdated = disabledPkgSetting != null;
...
final SharedUserSetting sharedUserSetting = (pkg.mSharedUserId != null)
? mSettings.getSharedUserLPw(pkg.mSharedUserId,
0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true)
: null;
...
if (scanSystemPartition) {
// Potentially prune child packages. If the application on the /system
// partition has been updated via OTA, but, is still disabled by a
// version on /data, cycle through all of its children packages and
// remove children that are no longer defined.
// 更新子应用
if (isSystemPkgUpdated) {
...
}
...
}
}
final boolean newPkgChangedPaths =
pkgAlreadyExists && !pkgSetting.codePathString.equals(pkg.codePath);
final boolean newPkgVersionGreater =
//M: change ">" to ">=" can restore the same version apk, test step:
//1) xunfei app is in operator path and version is 6
//2) then adb install the upgrade verison 8
//3) uninstall it(version 8)
//4) install it version 6 again
//5) adb reboot
//6)result: can found xunfei apk verision 6
pkgAlreadyExists && pkg.getLongVersionCode() >= pkgSetting.versionCode;
final boolean isSystemPkgBetter = scanSystemPartition && isSystemPkgUpdated
&& newPkgChangedPaths && newPkgVersionGreater;
if (isSystemPkgBetter) {
// The version of the application on /system is greater than the version on
// /data. Switch back to the application on /system.
// It's safe to assume the application on /system will correctly scan. If not,
// there won't be a working copy of the application.
// 更新安装包到 system 分区中
synchronized (mPackages) {
// just remove the loaded entries from package lists
mPackages.remove(pkgSetting.name);
}
...
// 创建安装参数 InstallArgs
final InstallArgs args = createInstallArgsForExisting(
packageFlagsToInstallFlags(pkgSetting), pkgSetting.codePathString,
pkgSetting.resourcePathString, getAppDexInstructionSets(pkgSetting));
args.cleanUpResourcesLI();
synchronized (mPackages) {
mSettings.enableSystemPackageLPw(pkgSetting.name);
}
}
...
// Verify certificates against what was last scanned. If it is an updated priv app, we will
// force re-collecting certificate.
final boolean forceCollect = PackageManagerServiceUtils.isApkVerificationForced(
disabledPkgSetting);
// Full APK verification can be skipped during certificate collection, only if the file is
// in verified partition, or can be verified on access (when apk verity is enabled). In both
// cases, only data in Signing Block is verified instead of the whole file.
final boolean skipVerify = ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0) ||
(forceCollect && canSkipFullPackageVerification(pkg));
// 安装包校验
collectCertificatesLI(pkgSetting, pkg, forceCollect, skipVerify);
// Reset profile if the application version is changed
maybeClearProfilesForUpgradesLI(pkgSetting, pkg);
/*
* A new system app appeared, but we already had a non-system one of the
* same name installed earlier.
*
*/
boolean shouldHideSystemApp = false;
// A new application appeared on /system, but, we already have a copy of
// the application installed on /data.
if (scanSystemPartition && !isSystemPkgUpdated && pkgAlreadyExists
&& !pkgSetting.isSystem()) {
if (!pkg.mSigningDetails.checkCapability(pkgSetting.signatures.mSigningDetails,
PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)
&& !pkgSetting.signatures.mSigningDetails.checkCapability(
pkg.mSigningDetails,
PackageParser.SigningDetails.CertCapabilities.ROLLBACK)) {
...
try (PackageFreezer freezer = freezePackage(pkg.packageName,
"scanPackageInternalLI")) {
// 如果两个 apk 签名不匹配,则调用 deletePackageLIF 方法清除 apk 文件及其数据
deletePackageLIF(pkg.packageName, null, true, null, 0, null, false, null);
}
pkgSetting = null;
} else if (newPkgVersionGreater) {
// The application on /system is newer than the application on /data.
// Simply remove the application on /data [keeping application data]
// and replace it with the version on /system.
...
// 更新系统 apk 程序
InstallArgs args = createInstallArgsForExisting(
packageFlagsToInstallFlags(pkgSetting), pkgSetting.codePathString,
pkgSetting.resourcePathString, getAppDexInstructionSets(pkgSetting));
synchronized (mInstallLock) {
args.cleanUpResourcesLI();
}
} else {
// The application on /system is older than the application on /data. Hide
// the application on /system and the version on /data will be scanned later
// and re-added like an update.
shouldHideSystemApp = true;
...
}
}
final PackageParser.Package scannedPkg = scanPackageNewLI(pkg, parseFlags, scanFlags
| SCAN_UPDATE_SIGNATURE, currentTime, user);
// 如果新安装的系统APP 会被旧的APP数据覆盖,所以需要隐藏隐藏系统应用程序,并重新扫描 /data/app 目录
if (shouldHideSystemApp) {
synchronized (mPackages) {
mSettings.disableSystemPackageLPw(pkg.packageName, true);
}
}
return scannedPkg;
}
```
### 4.2.3 scanPackageNewLI
开始解析 `PackageParser.Package:
> frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
```java {.line-numbers}
...
PackageParser.Package mPlatformPackage;
...
// TODO: scanPackageNewLI() and scanPackageOnly() should be merged. But, first, commiting
// the results / removing app data needs to be moved up a level to the callers of this
// method. Also, we need to solve the problem of potentially creating a new shared user
// setting. That can probably be done later and patch things up after the fact.
@GuardedBy("mInstallLock")
private PackageParser.Package scanPackageNewLI(@NonNull PackageParser.Package pkg,
final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
@Nullable UserHandle user) throws PackageManagerException {
final String renamedPkgName = mSettings.getRenamedPackageLPr(pkg.mRealPackage);
final String realPkgName = getRealPackageName(pkg, renamedPkgName);
if (realPkgName != null) {
ensurePackageRenamed(pkg, renamedPkgName);
}
final PackageSetting originalPkgSetting = getOriginalPackageLocked(pkg, renamedPkgName);
final PackageSetting pkgSetting = mSettings.getPackageLPr(pkg.packageName);
final PackageSetting disabledPkgSetting =
mSettings.getDisabledSystemPkgLPr(pkg.packageName);
...
// 根据上述各种 PackageSetting 调整扫描 flag
scanFlags = adjustScanFlags(scanFlags, pkgSetting, disabledPkgSetting, user, pkg);
synchronized (mPackages) {
// 应用扫描策略
applyPolicy(pkg, parseFlags, scanFlags, mPlatformPackage);
// 断言 package 有效
assertPackageIsValid(pkg, parseFlags, scanFlags);
SharedUserSetting sharedUserSetting = null;
if (pkg.mSharedUserId != null) {
// SIDE EFFECTS; may potentially allocate a new shared user
sharedUserSetting = mSettings.getSharedUserLPw(
pkg.mSharedUserId, 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true /*create*/);
...
}
boolean scanSucceeded = false;
try {
final ScanRequest request = new ScanRequest(pkg, sharedUserSetting,
pkgSetting == null ? null : pkgSetting.pkg, pkgSetting, disabledPkgSetting,
originalPkgSetting, realPkgName, parseFlags, scanFlags,
(pkg == mPlatformPackage), user);
final ScanResult result = scanPackageOnlyLI(request, mFactoryTest, currentTime);
if (result.success) {
// 将 pkg 中的数据保存到对应的 PMS 变量中,用于以后的管理查询调用等
commitScanResultsLocked(request, result);
}
scanSucceeded = true;
...
}
}
return pkg;
}
```
### 4.2.4 commitScanResultsLocked
> frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
```java {.line-numbers}
/**
* Commits the package scan and modifies system state.
*
WARNING: The method may throw an excpetion in the middle
* of committing the package, leaving the system in an inconsistent state.
* This needs to be fixed so, once we get to this point, no errors are
* possible and the system is not left in an inconsistent state.
*/
@GuardedBy("mPackages")
private void commitScanResultsLocked(@NonNull ScanRequest request, @NonNull ScanResult result)
throws PackageManagerException {
final PackageParser.Package pkg = request.pkg;
final PackageParser.Package oldPkg = request.oldPkg;
final @ParseFlags int parseFlags = request.parseFlags;
final @ScanFlags int scanFlags = request.scanFlags;
final PackageSetting oldPkgSetting = request.oldPkgSetting;
...
final UserHandle user = request.user;
...
final PackageSetting pkgSetting = result.pkgSetting;
...
if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
if (oldPkgSetting != null) {
synchronized (mPackages) {
mSettings.mPackages.put(oldPkgSetting.name, oldPkgSetting);
}
}
} else {
final int userId = user == null ? 0 : user.getIdentifier();
// Modify state for the given package setting
commitPackageSettings(pkg, oldPkg, pkgSetting, user, scanFlags,
(parseFlags & PackageParser.PARSE_CHATTY) != 0 /*chatty*/);
...
}
}
```
### 4.2.5 commitPackageSettings
> frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
```java {.line-numbers}
...
// 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();
...
// Mapping from instrumentation class names to info about them.
final ArrayMap mInstrumentation =
new ArrayMap();
...
// Broadcast actions that are only available to the system.
@GuardedBy("mProtectedBroadcasts")
final ArraySet mProtectedBroadcasts = new ArraySet<>();
...
ApplicationInfo mAndroidApplication;
final ActivityInfo mResolveActivity = new ActivityInfo();
...
ComponentName mResolveComponentName;
...
/**
* Adds a scanned package to the system. When this method is finished, the package will
* be available for query, resolution, etc...
*/
private void commitPackageSettings(PackageParser.Package pkg,
@Nullable PackageParser.Package oldPkg, PackageSetting pkgSetting, UserHandle user,
final @ScanFlags int scanFlags, boolean chatty) {
final String pkgName = pkg.packageName;
// 可配置的 ResloverActivity
if (mCustomResolverComponentName != null &&
mCustomResolverComponentName.getPackageName().equals(pkg.packageName)) {
setUpCustomResolverActivity(pkg);
}
// 针对包名为 "android" 的 apk 进行处理
if (pkg.packageName.equals("android")) {
synchronized (mPackages) {
if ((scanFlags & SCAN_CHECK_ONLY) == 0) {
// Set up information for our fall-back user intent resolution activity.
mPlatformPackage = pkg;
pkg.mVersionCode = mSdkVersion;
pkg.mVersionCodeMajor = 0;
mAndroidApplication = pkg.applicationInfo;
// 配置系统默认的 ResloverActivity
if (!mResolverReplaced) {
mResolveActivity.applicationInfo = mAndroidApplication;
mResolveActivity.name = ResolverActivity.class.getName();
mResolveActivity.packageName = mAndroidApplication.packageName;
mResolveActivity.processName = "system:ui";
...
mResolveComponentName = new ComponentName(
mAndroidApplication.packageName, mResolveActivity.name);
}
}
}
}
...
synchronized (mPackages) {
...
// 在此之前,四大组件的信息都是 Package 对象的私有变量,通过下面的代码,
// 将他们注册到 PackageManagerService 里面,
// 这样 PackageManagerService 就有了所有的组件信息
int N = pkg.providers.size();
StringBuilder r = null;
int i;
// 注册 pkg 里面的 provider 到 PackageManagerService 上的 mProvider 上
for (i=0; i
PackageParser.Provider p = pkg.providers.get(i);
p.info.processName = fixProcessName(pkg.applicationInfo.processName,
p.info.processName);
mProviders.addProvider(p);
...
}
...
N = pkg.services.size();
r = null;
// 注册 pkg 中的 service 到 PackageManagerService 的 mServices 上
for (i=0; i
PackageParser.Service s = pkg.services.get(i);
s.info.processName = fixProcessName(pkg.applicationInfo.processName,
s.info.processName);
mServices.addService(s);
...
}
...
N = pkg.receivers.size();
r = null;
// 注册 pkg 里面的 receiver 到 PackageManagerService 上的 mReceivers 上
for (i=0; i
PackageParser.Activity a = pkg.receivers.get(i);
a.info.processName = fixProcessName(pkg.applicationInfo.processName,
a.info.processName);
mReceivers.addActivity(a, "receiver");
...
}
...
N = pkg.activities.size();
r = null;
// 注册 pkg 里面的 activity 到 PackageManagerService 上的 mActivities 上
for (i=0; i
PackageParser.Activity a = pkg.activities.get(i);
a.info.processName = fixProcessName(pkg.applicationInfo.processName,
a.info.processName);
mActivities.addActivity(a, "activity");
...
}
...
N = pkg.instrumentation.size();
r = null;
// 注册 pkg 里面的 instrumentation 到 PackageManagerService 的 mInstrumentation 中
// Instrumentation 用来跟踪本应用内的 application 及 activity 的生命周期
for (i=0; i
PackageParser.Instrumentation a = pkg.instrumentation.get(i);
a.info.packageName = pkg.applicationInfo.packageName;
...
mInstrumentation.put(a.getComponentName(), a);
...
}
...
// 如果有包内广播
if (pkg.protectedBroadcasts != null) {
N = pkg.protectedBroadcasts.size();
synchronized (mProtectedBroadcasts) {
for (i = 0; i < N; i++) {
mProtectedBroadcasts.add(pkg.protectedBroadcasts.get(i));
}
}
}
...
}
...
}
```
## 4.3 PMS_DATA_SCAN_START
> frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
```java {.line-numbers}
...
/** Directory where installed applications are stored */
private static final File sAppInstallDir =
new File(Environment.getDataDirectory(), "app");
...
/** Directory where code and non-resource assets of forward-locked applications are stored */
private static final File sDrmAppPrivateInstallDir =
new File(Environment.getDataDirectory(), "app-private");
...
/**
* Tracks high priority intent filters for protected actions. During boot, certain
* filter actions are protected and should never be allowed to have a high priority
* intent filter for them. However, there is one, and only one exception -- the
* setup wizard. It must be able to define a high priority intent filter for these
* actions to ensure there are no escapes from the wizard. We need to delay processing
* of these during boot as we need to look at all of the system packages in order
* to know which component is the setup wizard.
*/
private final List mProtectedFilters = new ArrayList<>();
/**
* Whether or not processing protected filters should be deferred.
*/
private boolean mDeferProtectedFilters = true;
...
final @Nullable String mSetupWizardPackage;
final @Nullable String mStorageManagerPackage;
final @Nullable String mSystemTextClassifierPackage;
...
private final PackageUsage mPackageUsage = new PackageUsage();
private final CompilerStats mCompilerStats = new CompilerStats();
...
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
...
synchronized (mInstallLock) {
// writer
synchronized (mPackages) {
...
if (!mOnlyCore) {
// 第三阶段开始,扫描非系统 package
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());
// 扫描 /data/app 目录
scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
// 扫描 /data/app-private 目录
scanDirTracedLI(sDrmAppPrivateInstallDir, mDefParseFlags
| PackageParser.PARSE_FORWARD_LOCK,
scanFlags | SCAN_REQUIRE_KNOWN, 0);
// Remove disable package settings for updated system apps that were
// removed via an OTA. If the update is no longer present, remove the
// app completely. Otherwise, revoke their system privileges.
// 这里检查用户目录下升级文件是否还存在,然后进行处理
for (String deletedAppName : possiblyDeletedUpdatedSystemApps) {
PackageParser.Package deletedPkg = mPackages.get(deletedAppName);
// 从 mSettings.mDisabledSysPackages 变量中移除去此应用
mSettings.removeDisabledSystemPackageLPw(deletedAppName);
final String msg;
// 用户目录中也没有升级包,则肯定是残留的应用信息,则把它的数据目录删除掉
if (deletedPkg == null) {
// should have found an update, but, we didn't; remove everything
msg = "Updated system package " + deletedAppName
+ " no longer exists; removing its data";
// Actual deletion of code and data will be handled by later
// reconciliation step
} else {
// found an update; revoke system privileges
// 如果在用户空间找到了文件,则说明系统目录下的文件可能被删除了,
// 因此,把应用的系统属性去掉,以普通应用的方式运行
msg = "Updated system package + " + deletedAppName
+ " no longer exists; revoking system privileges";
// Don't do anything if a stub is removed from the system image. If
// we were to remove the uncompressed version from the /data partition,
// this is where it'd be done.
final PackageSetting deletedPs = mSettings.mPackages.get(deletedAppName);
deletedPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;
deletedPs.pkgFlags &= ~ApplicationInfo.FLAG_SYSTEM;
}
// 报告系统发生了不一致的情况
logCriticalInfo(Log.WARN, msg);
}
/*
* Make sure all system apps that we expected to appear on
* the userdata partition actually showed up. If they never
* appeared, crawl back and revive the system version.
*/
// 处理 mExpectingBetter 列表,这个列表的应用是带有升级包的系统的应用,
// 前面把他们从 mPackages 列表中清除了并放到 mExpectingBetter 列表,
// 最后也对他们进行扫描处理,但不会放到 mPackages 中。
for (int i = 0; i < mExpectingBetter.size(); i++) {
final String packageName = mExpectingBetter.keyAt(i);
if (!mPackages.containsKey(packageName)) {
final File scanFile = mExpectingBetter.valueAt(i);
logCriticalInfo(Log.WARN, "Expected better " + packageName
+ " but never showed up; reverting to system");
final @ParseFlags int reparseFlags;
final @ScanFlags int rescanFlags;
// 确保应用位于下面的系统应用目录中,如果不在,则不需要处理
if (FileUtils.contains(privilegedAppDir, scanFile)) {
reparseFlags =
mDefParseFlags |
PackageParser.PARSE_IS_SYSTEM_DIR;
rescanFlags =
scanFlags
| SCAN_AS_SYSTEM
| SCAN_AS_PRIVILEGED;
} else if (FileUtils.contains(systemAppDir, scanFile)) {
reparseFlags =
mDefParseFlags |
PackageParser.PARSE_IS_SYSTEM_DIR;
rescanFlags =
scanFlags
| SCAN_AS_SYSTEM;
...
} else {
Slog.e(TAG, "Ignoring unexpected fallback path " + scanFile);
// 如果应用不在上面这些目录,继续循环,不要处理
continue;
}
mSettings.enableSystemPackageLPw(packageName);
try {
// 重新扫描一下这个文件,会添加一个 标签
scanPackageTracedLI(scanFile, reparseFlags, rescanFlags, 0, null);
} catch (PackageManagerException e) {
Slog.e(TAG, "Failed to parse original system package: "
+ e.getMessage());
}
}
}
// Uncompress and install any stubbed system applications.
// This must be done last to ensure all stubs are replaced or disabled.
decompressSystemApplications(stubSystemApps, scanFlags);
final int cachedNonSystemApps = PackageParser.sCachedPackageReadCount.get()
- cachedSystemApps;
// 计算扫描时间及数量
final long dataScanTime = SystemClock.uptimeMillis() - systemScanTime - startTime;
final int dataPackagesCount = mPackages.size() - systemPackagesCount;
...
}
mExpectingBetter.clear();
// Resolve the storage manager.
mStorageManagerPackage = getStorageManagerPackageName();
// Resolve protected action filters. Only the setup wizard is allowed to
// have a high priority filter for these actions.
// 只有开机向导具有高优先级
mSetupWizardPackage = getSetupWizardPackageName();
if (mProtectedFilters.size() > 0) {
...
for (ActivityIntentInfo filter : mProtectedFilters) {
if (filter.activity.info.packageName.equals(mSetupWizardPackage)) {
...
// skip setup wizard; allow it to keep the high priority filter
continue;
}
...
filter.setPriority(0);
}
}
mSystemTextClassifierPackage = getSystemTextClassifierPackageName();
mDeferProtectedFilters = false;
mProtectedFilters.clear();
// Now that we know all of the shared libraries, update all clients to have
// the correct library paths.
updateAllSharedLibrariesLPw(null);
for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) {
// NOTE: We ignore potential failures here during a system scan (like
// the rest of the commands above) because there's precious little we
// can do about it. A settings error is reported, though.
final List changedAbiCodePath =
adjustCpuAbisForSharedUserLPw(setting.packages, null /*scannedPackage*/);
if (changedAbiCodePath != null && changedAbiCodePath.size() > 0) {
for (int i = changedAbiCodePath.size() - 1; i >= 0; --i) {
final String codePathString = changedAbiCodePath.get(i);
try {
mInstaller.rmdex(codePathString,
getDexCodeInstructionSet(getPreferredInstructionSet()));
} catch (InstallerException ignored) {
}
}
}
// Adjust seInfo to ensure apps which share a sharedUserId are placed in the same
// SELinux domain.
setting.fixSeInfoLocked();
}
// Now that we know all the packages we are keeping,
// read and update their last usage times.
mPackageUsage.read(mPackages);
mCompilerStats.read();
// 至此,第三阶段结束
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
SystemClock.uptimeMillis());
...
}
}
...
}
```
### 4.3.1 scanPackageTracedLI
> frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
```java {.line-numbers}
/**
* Traces a package scan.
* @see #scanPackageLI(File, int, int, long, UserHandle)
*/
public PackageParser.Package scanPackageTracedLI(File scanFile, final int parseFlags,
int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage [" + scanFile.toString() + "]");
try {
return scanPackageLI(scanFile, parseFlags, scanFlags, currentTime, user);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
/**
* Scans a package and returns the newly parsed package.
* Returns {@code null} in case of errors and the error code is stored in mLastScanError
*/
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
long currentTime, UserHandle user) throws PackageManagerException {
if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
PackageParser pp = new PackageParser();
pp.setSeparateProcesses(mSeparateProcesses);
pp.setOnlyCoreApps(mOnlyCore);
pp.setDisplayMetrics(mMetrics);
pp.setCallback(mPackageParserCallback);
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
final PackageParser.Package pkg;
try {
// 解析 Package
pkg = pp.parsePackage(scanFile, parseFlags);
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
// Static shared libraries have synthetic package names
if (pkg.applicationInfo.isStaticSharedLibrary()) {
renameStaticSharedLibraryPackage(pkg);
}
return scanPackageChildLI(pkg, parseFlags, scanFlags, currentTime, user);
}
```
本阶段主要工作:
- 扫描 /data/app 目录下的apk;
- 扫描 /data/app-private 目录下的apk;
## 4.4 PMS_SCAN_END
> frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
```java {.line-numbers}
...
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
...
synchronized (mInstallLock) {
// writer
synchronized (mPackages) {
...
// 第四阶段开始
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
SystemClock.uptimeMillis());
...
// If the platform SDK has changed since the last time we booted,
// we need to re-grant app permission to catch any new ones that
// appear. This is really a hack, and means that apps can in some
// cases get permissions that the user didn't initially explicitly
// allow... it would be nice to have some better way to handle
// this situation.
// 当sdk版本不一致时,需要更新权限
final boolean sdkUpdated = (ver.sdkVersion != mSdkVersion);
...
mPermissionManager.updateAllPermissions(
StorageManager.UUID_PRIVATE_INTERNAL, sdkUpdated, mPackages.values(),
mPermissionCallback);
ver.sdkVersion = mSdkVersion;
...
// If this is first boot after an OTA, and a normal boot, then
// we need to clear code cache directories.
// Note that we do *not* clear the application profiles. These remain valid
// across OTAs and are used to drive profile verification (post OTA) and
// profile compilation (without waiting to collect a fresh set of profiles).
// 当这是ota后的首次启动,或者正常启动则需要清除目录的缓存代码
if (mIsUpgrade && !onlyCore) {
Slog.i(TAG, "Build fingerprint changed; clearing code caches");
for (int i = 0; i < mSettings.mPackages.size(); i++) {
final PackageSetting ps = mSettings.mPackages.valueAt(i);
if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, ps.volumeUuid)) {
// No apps are running this early, so no need to freeze
clearAppDataLIF(ps.pkg, UserHandle.USER_ALL,
StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE
| Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
}
}
ver.fingerprint = Build.FINGERPRINT;
}
checkDefaultBrowser();
// clear only after permissions and other defaults have been updated
// 当权限和其他默认项都完成更新,则清理相关信息
mExistingSystemPackages.clear();
mPromoteSystemApps = false;
// All the changes are done during package scanning.
ver.databaseVersion = Settings.CURRENT_DATABASE_VERSION;
// can downgrade to reader
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "write settings");
// 信息写回 packages.xml 文件
mSettings.writeLPr();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
// 至此,第四阶段完成
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
SystemClock.uptimeMillis());
...
}
}
...
}
```
到此阶段,apk 已安装完成,本阶段主要工作:
- 将 SCAN 阶段的信息写回 /data/system/packages.xml;
## 4.5 PMS_READY
> frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
```java {.line-numbers}
...
final PackageInstallerService mInstallerService;
...
// DexManager handles the usage of dex files (e.g. secondary files, whether or not a package
// is used by other apps).
private final DexManager mDexManager;
...
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
...
synchronized (mInstallLock) {
// writer
synchronized (mPackages) {
...
// 第五阶段开始
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
SystemClock.uptimeMillis());
...
// 创建 PackageInstallerService 服务
mInstallerService = new PackageInstallerService(context, this);
...
// Read and update the usage of dex files.
// Do this at the end of PM init so that all the packages have their
// data directory reconciled.
// At this point we know the code paths of the packages, so we can validate
// the disk file and build the internal cache.
// The usage file is expected to be small so loading and verifying it
// should take a fairly small time compare to the other activities (e.g. package
// scanning).
final Map> userPackages = new HashMap<>();
final int[] currentUserIds = UserManagerService.getInstance().getUserIds();
for (int userId : currentUserIds) {
userPackages.put(userId, getInstalledPackages(/*flags*/ 0, userId).getList());
}
mDexManager.load(userPackages);
...
} // synchronized (mPackages)
} // synchronized (mInstallLock)
// Now after opening every single application zip, make sure they
// are all flushed. Not really needed, but keeps things nice and
// tidy.
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "GC");
Runtime.getRuntime().gc();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
// The initial scanning above does many calls into installd while
// holding the mPackages lock, but we're mostly interested in yelling
// once we have a booted system.
mInstaller.setWarnIfHeld(mPackages);
...
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
```
### 4.5.1 创建 PKIS 服务
> frameworks/base/services/core/java/com/android/server/pm/PackageInstallerService.java
```java {.line-numbers}
public class PackageInstallerService extends IPackageInstaller.Stub {
private static final String TAG = "PackageInstaller";
...
private final Context mContext;
private final P