android p的使用方法,基于Android P版本PKMS详解二

由以上代码可知,`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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值