Android 8.1 源码_核心篇 — 深入研究 PackageManagerService 系列(2)

56次阅读

共计 17152 个字符,预计需要花费 43 分钟才能阅读完成。

开篇
核心源码

关键类
路径

SystemServer.java
frameworks/base/services/java/com/android/server/SystemServer.java

PackageManagerService.java
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

Process.java
frameworks/base/core/java/android/os/Process.java

SystemConfig.java
frameworks/base/core/java/com/android/server/SystemConfig.java

Settings.java
frameworks/base/services/core/java/com/android/server/pm/Settings.java

简介
PackageManagerService(PMS)是 SystemServer 启动后的第一个核心服务,也是 Android 系统中最常用的服务之一。它负责系统中 Package 的管理,应用程序的安装、卸载、信息查询等。如果你是面向 Android 系统开发的工程师,基础概念我也不需要再多赘述,我们直接跟源码。
构造函数分析 – 扫描 Package
PMS 构造函数第二阶段的工作就是扫描系统中的 APK 了。由于需要逐个扫描文件,因此手机上装的程序越多,PMS 的工作量就越大,系统启动速度也就越慢,这就是为什么你的手机启动速度有快慢的原因。
系统库的 dex 优化
接着上面的 PMS 构造函数继续分析源码:
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
… …

// DEX 优化
mPackageDexOptimizer = new PackageDexOptimizer(installer, mInstallLock, context,
“*dexopt*”);
mDexManager = new DexManager(this, mPackageDexOptimizer, installer, mInstallLock);

synchronized (mPackages) {
mHandlerThread = new ServiceThread(TAG,
Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
mHandlerThread.start();
mHandler = new PackageHandler(mHandlerThread.getLooper());
mProcessLoggingHandler = new ProcessLoggingHandler();
Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);

mDefaultPermissionPolicy = new DefaultPermissionGrantPolicy(this);
mInstantAppRegistry = new InstantAppRegistry(this);

// 为 data/ 目录下的某些子目录生成 File 实例
File dataDir = Environment.getDataDirectory();
// data/app 存放第三方应用
mAppInstallDir = new File(dataDir, “app”);
mAppLib32InstallDir = new File(dataDir, “app-lib”);
mAsecInternalPath = new File(dataDir, “app-asec”).getPath();
// data/app-private 存放 drm 保护的应用
mDrmAppPrivateInstallDir = new File(dataDir, “app-private”);
sUserManager = new UserManagerService(context, this,
new UserDataPreparer(mInstaller, mInstallLock, mContext, mOnlyCore), mPackages);

// 获取 SystemConfig 中解析到的 <permission> 标签标识的 permission 信息,保存到 Settings::mPermissions
ArrayMap<String, SystemConfig.PermissionEntry> permConfig
= systemConfig.getPermissions();

for (int i=0; i<permConfig.size(); i++) {
SystemConfig.PermissionEntry perm = permConfig.valueAt(i);
BasePermission bp = mSettings.mPermissions.get(perm.name);
if (bp == null) {
bp = new BasePermission(perm.name, “android”, BasePermission.TYPE_BUILTIN);
mSettings.mPermissions.put(perm.name, bp);
}
if (perm.gids != null) {
bp.setGids(perm.gids, perm.perUser);
}
}

// 得到除 framework 之外的系统中的共享库列表,从 SystemConfig 获取解析到的数据
ArrayMap<String, String> libConfig = systemConfig.getSharedLibraries();
final int builtInLibCount = libConfig.size();
for (int i = 0; i < builtInLibCount; i++) {
String name = libConfig.keyAt(i);
String path = libConfig.valueAt(i);
addSharedLibraryLPw(path, null, name, SharedLibraryInfo.VERSION_UNDEFINED,
SharedLibraryInfo.TYPE_BUILTIN, PLATFORM_PACKAGE_NAME, 0);
}

mFoundPolicyFile = SELinuxMMAC.readInstallPolicy();

// 读取 packages.xml 的内容,并对 mSettings::mPackages 等成员进行赋值;packages.xml 文件中的内容是上一次扫描 apk 目录的结果;
// 当前这一次扫描的结果是保存在 PackageManagerService::mPackages 列表中;
// 对比上次扫描的结果来检查本次扫描到的应用中是否有被升级包覆盖的系统应用,如果有则从 PackageManagerService::mPackages 中移除;
// 这样,PackageManagerService::mPackages 的记录就和 mSettings::mPackages 的一致了;
// 系统最终会将本次 apk 扫描的结果重新写入 packages.xml 中
mFirstBoot = !mSettings.readLPw(sUserManager.getUsers(false));

// Clean up orphaned packages for which the code path doesn’t exist
// and they are an update to a system app – caused by bug/32321269
final int packageSettingCount = mSettings.mPackages.size();
// 清理那些代码路径不存在的异常 package
for (int i = packageSettingCount – 1; i >= 0; i–) {
PackageSetting ps = mSettings.mPackages.valueAt(i);
if (!isExternal(ps) && (ps.codePath == null || !ps.codePath.exists())
&& mSettings.getDisabledSystemPkgLPr(ps.name) != null) {
mSettings.mPackages.removeAt(i);
mSettings.enableSystemPackageLPw(ps.name);
}
}

if (mFirstBoot) {
requestCopyPreoptedFiles();
}

// 设置模块来代替 framework-res.apk 中缺省的 ResolverActivity
String customResolverActivity = Resources.getSystem().getString(
R.string.config_customResolverActivity);
if (TextUtils.isEmpty(customResolverActivity)) {
customResolverActivity = null;
} else {
mCustomResolverComponentName = ComponentName.unflattenFromString(
customResolverActivity);
}

long startTime = SystemClock.uptimeMillis(); // 记录扫描开始的时间

// 需要系统提前加载的一些 jar
final String bootClassPath = System.getenv(“BOOTCLASSPATH”);
final String systemServerClassPath = System.getenv(“SYSTEMSERVERCLASSPATH”);

if (bootClassPath == null) {
Slog.w(TAG, “No BOOTCLASSPATH found!”);
}

if (systemServerClassPath == null) {
Slog.w(TAG, “No SYSTEMSERVERCLASSPATH found!”);
}
扫描系统 Package
清空 cache 文件后,PMS 终于进入重点段了。接下来看 PMS 第二阶段工作的核心内容,即扫描 Package,相关代码如下:
// PackageManagerService.java

// 定义 frameworkDir 指向 /system/frameworks 目录
File frameworkDir = new File(Environment.getRootDirectory(), “framework”);

final VersionInfo ver = mSettings.getInternalVersion();
mIsUpgrade = !Build.FINGERPRINT.equals(ver.fingerprint);

// when upgrading from pre-M, promote system app permissions from install to runtime
mPromoteSystemApps =
mIsUpgrade && ver.sdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1;

// When upgrading from pre-N, we need to handle package extraction like first boot,
// as there is no profiling data available.
mIsPreNUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N;

mIsPreNMR1Upgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N_MR1;

// save off the names of pre-existing system packages prior to scanning; we don’t
// want to automatically grant runtime permissions for new system apps
// 是否需要提升权限
if (mPromoteSystemApps) {
Iterator<PackageSetting> pkgSettingIter = mSettings.mPackages.values().iterator();
while (pkgSettingIter.hasNext()) {
PackageSetting ps = pkgSettingIter.next();
if (isSystemApp(ps)) {
// 遍历 Settings::mPackages 集合,将系统 APP 加入到 PackageManagerService::mExistingSystemPackages
mExistingSystemPackages.add(ps.name);
}
}
}

mCacheDir = preparePackageParserCache(mIsUpgrade);

// 定义扫描参数
int scanFlags = SCAN_BOOTING | SCAN_INITIAL;
if (mIsUpgrade || mFirstBoot) {
scanFlags = scanFlags | SCAN_FIRST_BOOT_OR_UPGRADE;
}

// 先扫描 /vendor/overlay 目录
scanDirTracedLI(new File(VENDOR_OVERLAY_DIR), mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_TRUSTED_OVERLAY, scanFlags | SCAN_TRUSTED_OVERLAY, 0);

// 调用 scanDirTracedLI 函数扫描 /system/frameworks 目录
scanDirTracedLI(frameworkDir, mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_IS_PRIVILEGED,
scanFlags | SCAN_NO_DEX, 0);

// Collected privileged system packages.
final File privilegedAppDir = new File(Environment.getRootDirectory(), “priv-app”);
// 扫描 /system/priv-app 下的 package
scanDirTracedLI(privilegedAppDir, mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0);

// Collect ordinary system packages.
final File systemAppDir = new File(Environment.getRootDirectory(), “app”);
// 扫描 /system/app 下的 package
scanDirTracedLI(systemAppDir, mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);

// Collect all vendor packages.
File vendorAppDir = new File(“/vendor/app”);
try {
vendorAppDir = vendorAppDir.getCanonicalFile();
} catch (IOException e) {
// failed to look up canonical path, continue with original one
}
// 扫描 /vendor/app 下的 package
scanDirTracedLI(vendorAppDir, mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);

// Collect all OEM packages.
final File oemAppDir = new File(Environment.getOemDirectory(), “app”);
// 扫描 OEM 的 Package
scanDirTracedLI(oemAppDir, mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
由以上代码可知,PMS 将扫描以下几个目录(仅列出重点):
         ✨ /system/frameworks:该目录中的文件都是系统库,例如:framework.jar、services.jar、framework-res.apk。不过 scanDirTracedLI 只扫描 APK 文件,所以 framework-res.apk 是该目录中唯一“受宠”的文件。
         ✨ /system/app:该目录下全是默认的系统应用。例如:Browser.apk、SettingsProvider.apk 等。
         ✨ /vendor/app:该目录中的文件由厂商提供,即全是厂商特定的 APK 文件,目前市面上的厂商都把自己的应用放在 /system/app 目录下。
scanDirTracedLI
PMS 调用 scanDirTracedLI 函数进行扫描,下面分析此函数:
public void scanDirTracedLI(File dir, final int parseFlags, int scanFlags, long currentTime) {
try {
scanDirLI(dir, parseFlags, scanFlags, currentTime); // 调用 scanDirLI 函数
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
我们可以看出,实际是调用了 scanDirLI 函数进行扫描工作!
scanDirLI
下面的重点就是来关注 scanDirLI 函数了:
private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) {
// 列举该目录下的文件
final File[] files = dir.listFiles();
if (ArrayUtils.isEmpty(files)) {
Log.d(TAG, “No files in app dir ” + dir);
return;
}

ParallelPackageParser parallelPackageParser = new ParallelPackageParser(
mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir,
mParallelPackageParserCallback);

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;
}
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) {
// Static shared libraries have synthetic package names
if (parseResult.pkg.applicationInfo.isStaticSharedLibrary()) {
renameStaticSharedLibraryPackage(parseResult.pkg);
}
try {
if (errorCode == PackageManager.INSTALL_SUCCEEDED) {
// 调用 scanPackageLI 函数扫描一个特定的文件,返回值是 PackageParser 的内部类 Package,该类的实例代表一个 APK 文件,所以它就是和 APK 文件对应的数据结构
scanPackageLI(parseResult.pkg, parseResult.scanFile, parseFlags, scanFlags,
currentTime, null);
}
… …
}

// Delete invalid userdata apps
if ((parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
errorCode == PackageManager.INSTALL_FAILED_INVALID_APK) {
// 非系统 Package 扫描失败,删除文件
removeCodePathLI(parseResult.scanFile);
}
}
parallelPackageParser.close();
}
scanPackageLI – 01
PMS 中有三处 scanPackageLI,我们后面会一一分析到,先来看第一个也是最先碰到的 sanPackageLI 函数。
private PackageParser.Package scanPackageLI(PackageParser.Package pkg, File scanFile,
final int policyFlags, int scanFlags, long currentTime, @Nullable UserHandle user)
throws PackageManagerException {
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 = scanPackageInternalLI(pkg, scanFile, policyFlags,
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);
scanPackageInternalLI(childPackage, scanFile, policyFlags, scanFlags,
currentTime, user);
}

if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
return scanPackageLI(pkg, scanFile, policyFlags, scanFlags, currentTime, user);
}

return scannedPkg;
}
scanPackageInternalLI
调用 scanPackageInternalLI():
private PackageParser.Package scanPackageInternalLI(PackageParser.Package pkg, File scanFile,
int policyFlags, int scanFlags, long currentTime, @Nullable UserHandle user)
throws PackageManagerException {
PackageSetting ps = null;
PackageSetting updatedPkg;
// 判断系统 APP 是否需要更新
synchronized (mPackages) {
// 查看是否已经有该安装包,通过 mSetting 查找
String oldName = mSettings.getRenamedPackageLPr(pkg.packageName);
if (pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(oldName)) {
// 如果存在同一个包名的老的安装包,且已经改回原始名称了
ps = mSettings.getPackageLPr(oldName);
}
// 如果没有原始包,则使用真实包名
if (ps == null) {
ps = mSettings.getPackageLPr(pkg.packageName);
}
// 查这个包是否是一个隐藏或者可以更新的系统包
updatedPkg = mSettings.getDisabledSystemPkgLPr(ps != null ? ps.name : pkg.packageName);

// If this is a package we don’t know about on the system partition, we
// may need to remove disabled child packages on the system partition
// or may need to not add child packages if the parent apk is updated
// on the data partition and no longer defines this child package.
if ((policyFlags & PackageParser.PARSE_IS_SYSTEM) != 0) {
// If this is a parent package for an updated system app and this system
// app got an OTA update which no longer defines some of the child packages
// we have to prune them from the disabled system packages.
PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(pkg.packageName);
if (disabledPs != null) {
final int scannedChildCount = (pkg.childPackages != null)
? pkg.childPackages.size() : 0;
final int disabledChildCount = disabledPs.childPackageNames != null
? disabledPs.childPackageNames.size() : 0;
for (int i = 0; i < disabledChildCount; i++) {
String disabledChildPackageName = disabledPs.childPackageNames.get(i);
boolean disabledPackageAvailable = false;
for (int j = 0; j < scannedChildCount; j++) {
PackageParser.Package childPkg = pkg.childPackages.get(j);
if (childPkg.packageName.equals(disabledChildPackageName)) {
disabledPackageAvailable = true;
break;
}
}
if (!disabledPackageAvailable) {
mSettings.removeDisabledSystemPackageLPw(disabledChildPackageName);
}
}
}
}
}
… …

// Note that we invoke the following method only if we are about to unpack an application
// 调用第二个 scanPackageLI 函数
PackageParser.Package scannedPkg = scanPackageLI(pkg, policyFlags, scanFlags
| SCAN_UPDATE_SIGNATURE, currentTime, user);

… …
}
scanPackageLI – 02
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
long currentTime, UserHandle user) throws PackageManagerException {
// 创建一个 PackageParser 对象,用于解析包
PackageParser pp = new PackageParser();

// 设置 PackageParse 的三个属性
pp.setSeparateProcesses(mSeparateProcesses);
pp.setOnlyCoreApps(mOnlyCore);
pp.setDisplayMetrics(mMetrics);

pp.setCallback(mPackageParserCallback);

// 判断扫描模式
if ((scanFlags & SCAN_TRUSTED_OVERLAY) != 0) {
parseFlags |= PackageParser.PARSE_TRUSTED_OVERLAY;
}

// 解析 APK 获取对应 PackageParser.Package 对象 pkg
final PackageParser.Package pkg;

// 调用 PackageParser 的 parsePackage 函数解析 APK 文件
try {
// ???? ???? ???? ???? ???? ???? 真正的解析
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 scanPackageLI(pkg, scanFile, parseFlags, scanFlags, currentTime, user);
}
PackageParser
PackageParser 主要负责 APK 文件的解析,即解析 APK 文件中的 AndroidManifest.xml。
这边我们要重点分析 PackageParser 类!!!
官方解释
Android 安装一个 APK 的时候首先会解析 APK,而解析 APK 则需要用到一个工具类,这个工具类就是 PackageParser。
/**
* Parser for package files (APKs) on disk. This supports apps packaged either
* as a single “monolithic” APK, or apps packaged as a “cluster” of multiple
* APKs in a single directory.
* <p>
* Apps packaged as multiple APKs always consist of a single “base” APK (with a
* {@code null} split name) and zero or more “split” APKs (with unique split
* names). Any subset of those split APKs are a valid install, as long as the
* following constraints are met:
* <ul>
* <li>All APKs must have the exact same package name, version code, and signing
* certificates.
* <li>All APKs must have unique split names.
* <li>All installations must contain a single base APK.
* </ul>
*
* @hide
*/
public class PackageParser {
解释如下:
解析磁盘上的 APK 安装包文件。它既能解析一个 ” 单一 ”APK 文件,也能解析一个 ” 集群 ”APK 文件 (即一个 APK 文件里面包含多个 APK 文件)。
一个 ” 集群 ”APK 有一个 ” 基准 ”APK(base APK) 组成和其他一些 ” 分割 ”APK(“split” APKs) 构成,其中这些 ” 分割 ”APK 用一些数字来分割。
这些 ” 分割 ”APK 的必须都是有效的安装,同时必须满足下面的几个条件:
✨ 所有的 APK 必须具有完全相同的软件包名称,版本代码和签名证书
✨ 所有的 APK 必须具有唯一的拆分名称
✨ 所有安装必须包含一个单一的 APK。

解析步骤
所以我们知道 PackageParse 类,它主要用来解析手机上的 APK 文件 (支持 Single APK 和 MultipleAPK),解析一个 APK 主要是分为两个步骤:
✨ 1、将 APK 解析成 Package:即解析 APK 文件为 Package 对象的过程。
✨ 2、将 Package 转化为 PackageInfo:即由 Package 对象生成 PackageInfo 的过程。

我们接下来看看 parsePackage 方法。
parsePackage
/**
* Parse the package at the given location. Automatically detects if the
* package is a monolithic style (single APK file) or cluster style
* (directory of APKs).
* <p>
* This performs sanity checking on cluster style packages, such as
* requiring identical package name and version codes, a single base APK,
* and unique split names.
* <p>
* Note that this <em>does not</em> perform signature verification; that
* must be done separately in {@link #collectCertificates(Package, int)}.
*
* If {@code useCaches} is true, the package parser might return a cached
* result from a previous parse of the same {@code packageFile} with the same
* {@code flags}. Note that this method does not check whether {@code packageFile}
* has changed since the last parse, it’s up to callers to do so.
*
* @see #parsePackageLite(File, int)
*/
public Package parsePackage(File packageFile, int flags) throws PackageParserException {
return parsePackage(packageFile, flags, false /* useCaches */);
}

public Package parsePackage(File packageFile, int flags, boolean useCaches)
throws PackageParserException {
Package parsed = useCaches ? getCachedResult(packageFile, flags) : null;
if (parsed != null) {
return parsed;
}

long parseTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
if (packageFile.isDirectory()) {
// 集群 APK
parsed = parseClusterPackage(packageFile, flags); // 获得一个 XML 资源解析对象
} else {
// 单一 APK
parsed = parseMonolithicPackage(packageFile, flags); // 获得一个 XML 资源解析对象
}

long cacheTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
cacheResult(packageFile, flags, parsed);
if (LOG_PARSE_TIMINGS) {
parseTime = cacheTime – parseTime;
cacheTime = SystemClock.uptimeMillis() – cacheTime;
if (parseTime + cacheTime > LOG_PARSE_TIMINGS_THRESHOLD_MS) {
Slog.i(TAG, “Parse times for ‘” + packageFile + “‘: parse=” + parseTime
+ “ms, update_cache=” + cacheTime + ” ms”);
}
}
return parsed;
}
parseMonolithicPackage
这边我们以单一 APK 为例去跟踪源码流程:
/**
* Parse the given APK file, treating it as as a single monolithic package.
* <p>
* Note that this <em>does not</em> perform signature verification; that
* must be done separately in {@link #collectCertificates(Package, int)}.
*
* @deprecated external callers should move to
* {@link #parsePackage(File, int)}. Eventually this method will
* be marked private.
*/
@Deprecated
public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
final AssetManager assets = newConfiguredAssetManager();
// ???? ???? ???? ???? ???? ???? 重点分析
final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);

if (mOnlyCoreApps) {
if (!lite.coreApp) {
throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
“Not a coreApp: ” + apkFile);
}
}

try {
// ???? ???? ???? ???? ???? ???? 重点分析
// 调用 parseBaseApk() 方法解析一个 apk 并生成一个 Package 对象
final Package pkg = parseBaseApk(apkFile, assets, flags);
pkg.setCodePath(apkFile.getAbsolutePath());
pkg.setUse32bitAbi(lite.use32bitAbi);
return pkg;
} finally {
IoUtils.closeQuietly(assets);
}
}
【说明】:未分析完,由于篇幅字数限制,剩下代码的分析见【Android 8.1 源码_核心篇 — 深入研究 PackageManagerService 系列(3)】

正文完
 0