Android — PackageManagerService APK扫描流程解析
PackageManagerService(PKMS)构造中触发APK扫描的函数调用是:scanDirTracedLI(),它会遍历我们传入的文件路径,然后循环解析其中存在的APK文件,并将信息解析出来存入PKMS内部,供后续的运行时信息管理。PKMS这一部分的函数调用很深,我们这里只看其中的几个关键函数调用,以此来熟悉APK扫描工作的基本内容。
PKMS解析APK文件主要依靠PackageParser实现。PackageParser内部定义了一些内部类,来描述解析过程不同阶段获取的APK/Package信息;主要有:
其中,PackageParser::Package信息是最丰富的。说是解析APK文件,其实主要是解析应用的Androidmanifest.xml配置文件;因为配置文件中描述了所有有关该应用的组件、权限、包名等信息。对它的解析过程,就是我们获取APK信息的过程。
PackageParser::parseBaseApkCommon()负责Androidmanifest.xml的解析:
/**
* This is the common parsing routing for handling parent and child
* packages in a base APK. The difference between parent and child
* parsing is that some tags are not supported by child packages as
* well as some manifest attributes are ignored. The implementation
* assumes the calling code has already handled the manifest tag if needed
* (this applies to the parent only).
*
* @param pkg The package which to populate
* @param acceptedTags Which tags to handle, null to handle all
* @param res Resources against which to resolve values
* @param parser Parser of the manifest
* @param flags Flags about how to parse
* @param outError Human readable error if parsing fails
* @return The package if parsing succeeded or null.
*
* @throws XmlPullParserException
* @throws IOException
*/
private Package parseBaseApkCommon(Package pkg, Set<String> acceptedTags, Resources res,
XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException,
IOException {
mParseInstrumentationArgs = null;
mParseActivityArgs = null;
mParseServiceArgs = null;
mParseProviderArgs = null;
int type;
boolean foundApp = false;
TypedArray sa = res.obtainAttributes(parser,
com.android.internal.R.styleable.AndroidManifest);
String str = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0);
if (str != null && str.length() > 0) {
String nameError = validateName(str, true, false);
if (nameError != null && !"android".equals(pkg.packageName)) {
outError[0] = "<manifest> specifies bad sharedUserId name \""
+ str + "\": " + nameError;
mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID;
return null;
}
pkg.mSharedUserId = str.intern();
pkg.mSharedUserLabel = sa.getResourceId(
com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0);
}
pkg.installLocation = sa.getInteger(
com.android.internal.R.styleable.AndroidManifest_installLocation,
PARSE_DEFAULT_INSTALL_LOCATION);
pkg.applicationInfo.installLocation = pkg.installLocation;
/* Set the global "forward lock" flag */
if ((flags & PARSE_FORWARD_LOCK) != 0) {
pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK;
}
/* Set the global "on SD card" flag */
if ((flags & PARSE_EXTERNAL_STORAGE) != 0) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE;
}
if ((flags & PARSE_IS_EPHEMERAL) != 0) {
pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_EPHEMERAL;
}
// Resource boolean are -1, so 1 means we don't know the value.
int supportsSmallScreens = 1;
int supportsNormalScreens = 1;
int supportsLargeScreens = 1;
int supportsXLargeScreens = 1;
int resizeable = 1;
int anyDensity = 1;
int outerDepth = parser.getDepth();
//这整个while()大循环的工作就是在解析AndroidManifest.xml中声明的<application>/<uses-permission>等标签;
//这里我们只关注最常见的<application>/<uses-permission>标签解析
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
String tagName = parser.getName();
if (acceptedTags != null && !acceptedTags.contains(tagName)) {
Slog.w(TAG, "Skipping unsupported element under <manifest>: "
+ tagName + " at " + mArchiveSourcePath + " "
+ parser.getPositionDescription());
XmlUtils.skipCurrentTag(parser);
continue;
}
//<application>标签
if (tagName.equals(TAG_APPLICATION)) {//解析<application>标签的内容,我们可以在该标签中声明Android四大组件;而这往往是Apk重要的功能实现部分
if (foundApp) {
if (RIGID_PARSER) {
outError[0] = "<manifest> has more than one <application>";
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return null;
} else {
Slog.w(TAG, "<manifest> has more than one <application>");
XmlUtils.skipCurrentTag(parser);
continue;
}
}
foundApp = true;
if (!parseBaseApplication(pkg, res, parser, flags, outError)) {//调用parseBaseApplicaton()函数解析<application>标签
return null;
}
} else if (tagName.equals(TAG_KEY_SETS)) {
if (!parseKeySets(pkg, res, parser, outError)) {
return null;
}
} else if (tagName.equals(TAG_PERMISSION_GROUP)) {
if (parsePermissionGroup(pkg, flags, res, parser, outError) == null) {
return null;
}
} else if (tagName.equals(TAG_PERMISSION)) {//权限解析:<permission>是apk声明的保护自己组件的权限
if (parsePermission(pkg, res, parser, outError) == null) {
return null;
}
} else if (tagName.equals(TAG_PERMISSION_TREE)) {
if (parsePermissionTree(pkg, res, parser, outError) == null) {
return null;
}
} else if (tagName.equals(TAG_USES_PERMISSION)) {//权限解析:<uses-permission>是apk要使用的系统权限声明
if (!parseUsesPermission(pkg, res, parser)) {
return null;
}
} else if (tagName.equals(TAG_USES_PERMISSION_SDK_M)
|| tagName.equals(TAG_USES_PERMISSION_SDK_23)) {
if (!parseUsesPermission(pkg, res, parser)) {
return null;
}
}
......
}
......
return pkg;
}
采用XmlPullParser解析器解析Androidmanifest.xml配置文件;因为配置文件中会描述很多的关于APK的信息,这里我们主要关注对Androidmanifest.xml中<application>标签的解析过程,因为我们添加的Android四大组件相关的内容都会在该标签中描述。
解析<application>要调用parseBaseApplication()函数:
/**
* Parse the {@code application} XML tree at the current parse location in a
* <em>base APK</em> manifest.
* <p>
* When adding new features, carefully consider if they should also be
* supported by split APKs.
*/
private boolean parseBaseApplication(Package owner, Resources res,
XmlResourceParser parser, int flags, String[] outError)
throws XmlPullParserException, IOException {
final ApplicationInfo ai = owner.applicationInfo;
final String pkgName = owner.applicationInfo.packageName;
TypedArray sa = res.obtainAttributes(parser,
com.android.internal.R.styleable.AndroidManifestApplication);
if (!parsePackageItemInfo(owner, ai, outError,
"<application>", sa, false /*nameRequired*/,
com.android.internal.R.styleable.AndroidManifestApplication_name,
com.android.internal.R.styleable.AndroidManifestApplication_label,
com.android.internal.R.styleable.AndroidManifestApplication_icon,
com.android.internal.R.styleable.AndroidManifestApplication_roundIcon,
com.android.internal.R.styleable.AndroidManifestApplication_logo,
com.android.internal.R.styleable.AndroidManifestApplication_banner)) {
sa.recycle();
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
if (ai.name != null) {
ai.className = ai.name;
}
String manageSpaceActivity = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifestApplication_manageSpaceActivity,
Configuration.NATIVE_CONFIG_VERSION);
if (manageSpaceActivity != null) {
ai.manageSpaceActivityName = buildClassName(pkgName, manageSpaceActivity,
outError);
}
boolean allowBackup = sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestApplication_allowBackup, true);
if (allowBackup) {
ai.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP;
// backupAgent, killAfterRestore, fullBackupContent, backupInForeground,
// and restoreAnyVersion are only relevant if backup is possible for the
// given application.
String backupAgent = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifestApplication_backupAgent,
Configuration.NATIVE_CONFIG_VERSION);
if (backupAgent != null) {
ai.backupAgentName = buildClassName(pkgName, backupAgent, outError);
if (DEBUG_BACKUP) {
Slog.v(TAG, "android:backupAgent = " + ai.backupAgentName
+ " from " + pkgName + "+" + backupAgent);
}
......
}
......
}
......
final int innerDepth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
String tagName = parser.getName();
if (tagName.equals("activity")) {
Activity a = parseActivity(owner, res, parser, flags, outError, false,
owner.baseHardwareAccelerated);//解析声明的activity组件
if (a == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
owner.activities.add(a);
} else if (tagName.equals("receiver")) {
Activity a = parseActivity(owner, res, parser, flags, outError, true, false);//解析声明的broadcastreceiver组件
if (a == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
owner.receivers.add(a);
} else if (tagName.equals("service")) {
Service s = parseService(owner, res, parser, flags, outError);//解析声明的service组件
if (s == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
owner.services.add(s);
} else if (tagName.equals("provider")) {//解析声明的provider组件
Provider p = parseProvider(owner, res, parser, flags, outError);
if (p == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
owner.providers.add(p);
}
......
}
modifySharedLibrariesForBackwardCompatibility(owner);
if (hasDomainURLs(owner)) {
owner.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS;
} else {
owner.applicationInfo.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS;
}
return true;
}
PackageParser定义了一些内部类来封装解析得到的四大组件内容,这些类的结构如图所示:
我们从代码中看到了对Application中声明的Android四大组件的解析调用,它们的解析过程类似:都是调用XmlPullParser解析器解析各个节点的内容并保存。我们以解析Activity为例,来看它是如何解析<activity>节点、并保存其各个节点的信息的:
private Activity parseActivity(Package owner, Resources res,
XmlResourceParser parser, int flags, String[] outError,
boolean receiver, boolean hardwareAccelerated)
throws XmlPullParserException, IOException {
TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestActivity);
if (mParseActivityArgs == null) {
mParseActivityArgs = new ParseComponentArgs(owner, outError,
R.styleable.AndroidManifestActivity_name,
R.styleable.AndroidManifestActivity_label,
R.styleable.AndroidManifestActivity_icon,
R.styleable.AndroidManifestActivity_roundIcon,
R.styleable.AndroidManifestActivity_logo,
R.styleable.AndroidManifestActivity_banner,
mSeparateProcesses,
R.styleable.AndroidManifestActivity_process,
R.styleable.AndroidManifestActivity_description,
R.styleable.AndroidManifestActivity_enabled);
}
mParseActivityArgs.tag = receiver ? "<receiver>" : "<activity>";
mParseActivityArgs.sa = sa;
mParseActivityArgs.flags = flags;
Activity a = new Activity(mParseActivityArgs, new ActivityInfo());
if (outError[0] != null) {
sa.recycle();
return null;
}
......
int outerDepth = parser.getDepth();
int type;
while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG
|| parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
if (parser.getName().equals("intent-filter")) {//解析<intent-filter>,得到各个intent信息
ActivityIntentInfo intent = new ActivityIntentInfo(a);
if (!parseIntent(res, parser, true, true, intent, outError)) {
return null;
}
if (intent.countActions() == 0) {
Slog.w(TAG, "No actions in intent filter at "
+ mArchiveSourcePath + " "
+ parser.getPositionDescription());
} else {
a.intents.add(intent);
}
} else if (!receiver && parser.getName().equals("preferred")) {
ActivityIntentInfo intent = new ActivityIntentInfo(a);
if (!parseIntent(res, parser, false, false, intent, outError)) {
return null;
}
if (intent.countActions() == 0) {
Slog.w(TAG, "No actions in preferred at "
+ mArchiveSourcePath + " "
+ parser.getPositionDescription());
} else {
if (owner.preferredActivityFilters == null) {
owner.preferredActivityFilters = new ArrayList<ActivityIntentInfo>();
}
owner.preferredActivityFilters.add(intent);
}
} else if (parser.getName().equals("meta-data")) {
if ((a.metaData = parseMetaData(res, parser, a.metaData,
outError)) == null) {
return null;
}
} else if (!receiver && parser.getName().equals("layout")) {
parseLayout(res, parser, a);
} else {
if (!RIGID_PARSER) {
Slog.w(TAG, "Problem in package " + mArchiveSourcePath + ":");
if (receiver) {
Slog.w(TAG, "Unknown element under <receiver>: " + parser.getName()
+ " at " + mArchiveSourcePath + " "
+ parser.getPositionDescription());
} else {
Slog.w(TAG, "Unknown element under <activity>: " + parser.getName()
+ " at " + mArchiveSourcePath + " "
+ parser.getPositionDescription());
}
XmlUtils.skipCurrentTag(parser);
continue;
} else {
if (receiver) {
outError[0] = "Bad element under <receiver>: " + parser.getName();
} else {
outError[0] = "Bad element under <activity>: " + parser.getName();
}
return null;
}
}
}
if (!setExported) {
a.info.exported = a.intents.size() > 0;
}
return a;
}
解析的过程很直接,我们主要看<intent-filter>节点的内容;我们设置的intent内容都包含在<intent-filter>节点内,PMS对外提供了组件查询的业务,它主要就是根据这里的intent来查找的。
从之前的代码我们可以看到,这个过程解析的结果是以Package实例保存的;它描述了一个单独的APK文件中所声明的绝大部分信息。其中,它有一些集合保存的内容我们需要注意,这一部分之前的图示也有所展示:
// For now we only support one application per package.
public final ApplicationInfo applicationInfo = new ApplicationInfo();
public final ArrayList<Permission> permissions = new ArrayList<Permission>(0);
public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0);
public final ArrayList<Activity> activities = new ArrayList<Activity>(0);
public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);
public final ArrayList<Provider> providers = new ArrayList<Provider>(0);
public final ArrayList<Service> services = new ArrayList<Service>(0);
public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0);
回到Activity标签的解析,解析到了Intent信息会保存到Activity实例内部的intents集合中;这一部分对Service/Provider/Receiver的解析都是一样的;<activity>标签解析完后,返回的activity实例又会被保存到Package类的activities中。其他三大组件的处理也跟此类似,所以这里就略过它们的解析过程了。
parseBaseApplication()函数执行完毕后,我们得到了一个保存有绝大部分APK信息的Package实例;得到了Package实例,我们还需要把它的信息整合到PMS中,让PMS统一管理;这个过程由PMS::scanPackageDirtyLI()处理。scanPackageDirtyLI()函数的处理较长,我们也分段来看它的主要处理流程。
scanPackageDirtyLI():
//一个package不能没有代码路径或者资源路径信息
if (pkg.applicationInfo.getCodePath() == null ||
pkg.applicationInfo.getResourcePath() == null) {
// Bail out. The resource and code paths haven't been set.
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Code and resource paths haven't been set correctly");
}
// Apply policy
if ((policyFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
if (pkg.applicationInfo.isDirectBootAware()) {
// we're direct boot aware; set for all components
for (PackageParser.Service s : pkg.services) {
s.info.encryptionAware = s.info.directBootAware = true;
}
for (PackageParser.Provider p : pkg.providers) {
p.info.encryptionAware = p.info.directBootAware = true;
}
for (PackageParser.Activity a : pkg.activities) {
a.info.encryptionAware = a.info.directBootAware = true;
}
for (PackageParser.Activity r : pkg.receivers) {
r.info.encryptionAware = r.info.directBootAware = true;
}
}
} else {//清掉普通应用不能使用的flag
// Only allow system apps to be flagged as core apps.
pkg.coreApp = false;
// clear flags not applicable to regular apps
pkg.applicationInfo.privateFlags &=
~ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE;
pkg.applicationInfo.privateFlags &=
~ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
}
pkg.mTrustedOverlay = (policyFlags&PackageParser.PARSE_TRUSTED_OVERLAY) != 0;
if ((policyFlags&PackageParser.PARSE_IS_PRIVILEGED) != 0) {
pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
}
if ((policyFlags & PackageParser.PARSE_ENFORCE_CODE) != 0) {
enforceCodePolicy(pkg);
}
if (mCustomResolverComponentName != null &&
mCustomResolverComponentName.getPackageName().equals(pkg.packageName)) {
setUpCustomResolverActivity(pkg);
}
这部分主要是做一些校验、容错处理;内容较为简单;我们接着看第二部分的实现:
scanPackageDirtyLI():
//处理framework-res.apk;里面包含了很多系统资源及一些重要的系统Activity,如果关机对话框/默认应用选择框等
if (pkg.packageName.equals("android")) {
synchronized (mPackages) {
if (mAndroidApplication != null) {
Slog.w(TAG, "*************************************************");
Slog.w(TAG, "Core android package being redefined. Skipping.");
Slog.w(TAG, " file=" + scanFile);
Slog.w(TAG, "*************************************************");
throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE,
"Core android package being redefined. Skipping.");
}
if ((scanFlags & SCAN_CHECK_ONLY) == 0) {
// Set up information for our fall-back user intent resolution activity.
mPlatformPackage = pkg;
pkg.mVersionCode = mSdkVersion;
mAndroidApplication = pkg.applicationInfo;
//记录framework-res.apk中的一些组件信息,供后续使用;也许是系统认为这些信息要被频繁使用的缘故
if (!mResolverReplaced) {
mResolveActivity.applicationInfo = mAndroidApplication;
mResolveActivity.name = ResolverActivity.class.getName();//com.android.internal.app.ResolverActivity
mResolveActivity.packageName = mAndroidApplication.packageName;//"android"
mResolveActivity.processName = "system:ui";
mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
mResolveActivity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NEVER;
mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
mResolveActivity.theme = R.style.Theme_Material_Dialog_Alert;
mResolveActivity.exported = true;
mResolveActivity.enabled = true;
mResolveActivity.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
mResolveActivity.configChanges = ActivityInfo.CONFIG_SCREEN_SIZE
| ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE
| ActivityInfo.CONFIG_SCREEN_LAYOUT
| ActivityInfo.CONFIG_ORIENTATION
| ActivityInfo.CONFIG_KEYBOARD
| ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
mResolveInfo.activityInfo = mResolveActivity;
mResolveInfo.priority = 0;
mResolveInfo.preferredOrder = 0;
mResolveInfo.match = 0;
mResolveComponentName = new ComponentName(
mAndroidApplication.packageName, mResolveActivity.name);
}
}
}
}
if (DEBUG_PACKAGE_SCANNING) {
if ((policyFlags & PackageParser.PARSE_CHATTY) != 0)
Log.d(TAG, "Scanning package " + pkg.packageName);
}
这里专门处理包名为”android”的应用,它其实就是framework-res.apk。其中,PMS会将framework-res.apk中的一些单独保存一份;这也许是由于PMS觉得它以后会经常使用的缘故。
再看scanPackageDirtyLI():
......
// writer
synchronized (mPackages) {
if (pkg.mSharedUserId != null) {
suid = mSettings.getSharedUserLPw(pkg.mSharedUserId, 0, 0, true);
if (suid == null) {
throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
"Creating application package " + pkg.packageName
+ " for shared user failed");
}
if (DEBUG_PACKAGE_SCANNING) {
if ((policyFlags & PackageParser.PARSE_CHATTY) != 0)
Log.d(TAG, "Shared UserID " + pkg.mSharedUserId + " (uid=" + suid.userId
+ "): packages=" + suid.packages);
}
}
// Check if we are renaming from an original package name.
//处理需要更改了包名的应用
PackageSetting origPackage = null;
String realName = null;
if (pkg.mOriginalPackages != null) {//当前package设置了"original-package"
// This package may need to be renamed to a previously
// installed name. Let's check on that...
final String renamed = mSettings.mRenamedPackages.get(pkg.mRealPackage);
if (pkg.mOriginalPackages.contains(renamed)) {
// This package had originally been installed as the
// original name, and we have already taken care of
// transitioning to the new one. Just update the new
// one to continue using the old name.
realName = pkg.mRealPackage;
if (!pkg.packageName.equals(renamed)) {
// Callers into this function may have already taken
// care of renaming the package; only do it here if
// it is not already done.
pkg.setPackageName(renamed);
}
} else {
for (int i=pkg.mOriginalPackages.size()-1; i>=0; i--) {
if ((origPackage = mSettings.peekPackageLPr(
pkg.mOriginalPackages.get(i))) != null) {
// We do have the package already installed under its
// original name... should we use it?
if (!verifyPackageUpdateLPr(origPackage, pkg)) {
// New package is not compatible with original.
origPackage = null;
continue;
} else if (origPackage.sharedUser != null) {
// Make sure uid is compatible between packages.
if (!origPackage.sharedUser.name.equals(pkg.mSharedUserId)) {
Slog.w(TAG, "Unable to migrate data from " + origPackage.name
+ " to " + pkg.packageName + ": old uid "
+ origPackage.sharedUser.name
+ " differs from " + pkg.mSharedUserId);
origPackage = null;
continue;
}
// TODO: Add case when shared user id is added [b/28144775]
} else {
if (DEBUG_UPGRADE) Log.v(TAG, "Renaming new package "
+ pkg.packageName + " to old name " + origPackage.name);
}
break;
}
}
}
}
......
}
这一部分主要处理应用重命名的情况。
紧接着再看PMS对四大组件的处理部分:
......
boolean createIdmapFailed = false;
synchronized (mPackages) {
// We don't expect installation to fail beyond this point
if (pkgSetting.pkg != null) {
// Note that |user| might be null during the initial boot scan. If a codePath
// for an app has changed during a boot scan, it's due to an app update that's
// part of the system partition and marker changes must be applied to all users.
maybeRenameForeignDexMarkers(pkgSetting.pkg, pkg,
(user != null) ? user : UserHandle.ALL);
}
// Add the new setting to mSettings
mSettings.insertPackageSettingLPw(pkgSetting, pkg);
// Add the new setting to mPackages
mPackages.put(pkg.applicationInfo.packageName, pkg);//这里一个APK的解析工作就已经快结束了,将它添加PMS::mPackages中管理
// Make sure we don't accidentally delete its data.
final Iterator<PackageCleanItem> iter = mSettings.mPackagesToBeCleaned.iterator();
while (iter.hasNext()) {
PackageCleanItem item = iter.next();
if (pkgName.equals(item.packageName)) {
iter.remove();
}
}
// Take care of first install / last update times.
if (currentTime != 0) {
if (pkgSetting.firstInstallTime == 0) {
pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = currentTime;
} else if ((scanFlags&SCAN_UPDATE_TIME) != 0) {
pkgSetting.lastUpdateTime = currentTime;
}
} else if (pkgSetting.firstInstallTime == 0) {
// We need *something*. Take time time stamp of the file.
pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = scanFileTime;
} else if ((policyFlags&PackageParser.PARSE_IS_SYSTEM_DIR) != 0) {
if (scanFileTime != pkgSetting.timeStamp) {
// A package on the system image has changed; consider this
// to be an update.
pkgSetting.lastUpdateTime = scanFileTime;
}
}
// Add the package's KeySets to the global KeySetManagerService
ksms.addScannedPackageLPw(pkg);
//PackageManagerService内部私有化package内部声明的四大组件信息,利于管理和查询;这里是ContentProvider
int N = pkg.providers.size();
StringBuilder r = null;
int i;
for (i=0; i<N; i++) {
PackageParser.Provider p = pkg.providers.get(i);
p.info.processName = fixProcessName(pkg.applicationInfo.processName,
p.info.processName, pkg.applicationInfo.uid);
mProviders.addProvider(p);
p.syncable = p.info.isSyncable;
if (p.info.authority != null) {
String names[] = p.info.authority.split(";");
p.info.authority = null;
for (int j = 0; j < names.length; j++) {
if (j == 1 && p.syncable) {
// We only want the first authority for a provider to possibly be
// syncable, so if we already added this provider using a different
// authority clear the syncable flag. We copy the provider before
// changing it because the mProviders object contains a reference
// to a provider that we don't want to change.
// Only do this for the second authority since the resulting provider
// object can be the same for all future authorities for this provider.
p = new PackageParser.Provider(p);
p.syncable = false;
}
if (!mProvidersByAuthority.containsKey(names[j])) {
mProvidersByAuthority.put(names[j], p);
if (p.info.authority == null) {
p.info.authority = names[j];
} else {
p.info.authority = p.info.authority + ";" + names[j];
}
if (DEBUG_PACKAGE_SCANNING) {
if ((policyFlags & PackageParser.PARSE_CHATTY) != 0)
Log.d(TAG, "Registered content provider: " + names[j]
+ ", className = " + p.info.name + ", isSyncable = "
+ p.info.isSyncable);
}
} else {
PackageParser.Provider other = mProvidersByAuthority.get(names[j]);
Slog.w(TAG, "Skipping provider name " + names[j] +
" (in package " + pkg.applicationInfo.packageName +
"): name already used by "
+ ((other != null && other.getComponentName() != null)
? other.getComponentName().getPackageName() : "?"));
}
}
}
if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) {
if (r == null) {
r = new StringBuilder(256);
} else {
r.append(' ');
}
r.append(p.info.name);
}
}
if (r != null) {
if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Providers: " + r);
}
//PackageManagerService内部私有化package内部声明的四大组件信息,利于管理和查询;这里是Service
N = pkg.services.size();
r = null;
for (i=0; i<N; i++) {
PackageParser.Service s = pkg.services.get(i);
s.info.processName = fixProcessName(pkg.applicationInfo.processName,
s.info.processName, pkg.applicationInfo.uid);
mServices.addService(s);
if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) {
if (r == null) {
r = new StringBuilder(256);
} else {
r.append(' ');
}
r.append(s.info.name);
}
}
if (r != null) {
if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Services: " + r);
}
//PackageManagerService内部私有化package内部声明的四大组件信息,利于管理和查询;这里是BroadcastReceiver
N = pkg.receivers.size();
r = null;
for (i=0; i<N; i++) {
PackageParser.Activity a = pkg.receivers.get(i);
a.info.processName = fixProcessName(pkg.applicationInfo.processName,
a.info.processName, pkg.applicationInfo.uid);
mReceivers.addActivity(a, "receiver");
if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) {
if (r == null) {
r = new StringBuilder(256);
} else {
r.append(' ');
}
r.append(a.info.name);
}
}
if (r != null) {
if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Receivers: " + r);
}
//PackageManagerService内部私有化package内部声明的四大组件信息,利于管理和查询;这里是Activity
N = pkg.activities.size();
r = null;
for (i=0; i<N; i++) {
PackageParser.Activity a = pkg.activities.get(i);
a.info.processName = fixProcessName(pkg.applicationInfo.processName,
a.info.processName, pkg.applicationInfo.uid);
mActivities.addActivity(a, "activity");
if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) {
if (r == null) {
r = new StringBuilder(256);
} else {
r.append(' ');
}
r.append(a.info.name);
}
}
if (r != null) {
if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Activities: " + r);
}
//与之前类似,这里是权限组,它是权限的一个修饰Tag,表明apk申请的权限属于哪一个范畴;
//例如,我们手机的应用管理里面,查看一个应用的权限,如"精确位置(基于GPS和网络)",它会有一个标签说明,如"位置信息",它就是
//"精确位置"这个权限的权限组.
N = pkg.permissionGroups.size();
r = null;
for (i=0; i<N; i++) {
PackageParser.PermissionGroup pg = pkg.permissionGroups.get(i);
PackageParser.PermissionGroup cur = mPermissionGroups.get(pg.info.name);
final String curPackageName = cur == null ? null : cur.info.packageName;
final boolean isPackageUpdate = pg.info.packageName.equals(curPackageName);
if (cur == null || isPackageUpdate) {
mPermissionGroups.put(pg.info.name, pg);
if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) {
if (r == null) {
r = new StringBuilder(256);
} else {
r.append(' ');
}
if (isPackageUpdate) {
r.append("UPD:");
}
r.append(pg.info.name);
}
} else {
Slog.w(TAG, "Permission group " + pg.info.name + " from package "
+ pg.info.packageName + " ignored: original from "
+ cur.info.packageName);
if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) {
if (r == null) {
r = new StringBuilder(256);
} else {
r.append(' ');
}
r.append("DUP:");
r.append(pg.info.name);
}
}
}
if (r != null) {
if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Permission Groups: " + r);
}
//PackageManagerService内部私有化package内部自己定义/声明的权限信息,用来保护自己的组件;利于管理和查询
N = pkg.permissions.size();
r = null;
for (i=0; i<N; i++) {
PackageParser.Permission p = pkg.permissions.get(i);
// Assume by default that we did not install this permission into the system.
p.info.flags &= ~PermissionInfo.FLAG_INSTALLED;
// Now that permission groups have a special meaning, we ignore permission
// groups for legacy apps to prevent unexpected behavior. In particular,
// permissions for one app being granted to someone just becase they happen
// to be in a group defined by another app (before this had no implications).
if (pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) {
p.group = mPermissionGroups.get(p.info.group);
// Warn for a permission in an unknown group.
if (p.info.group != null && p.group == null) {
Slog.w(TAG, "Permission " + p.info.name + " from package "
+ p.info.packageName + " in an unknown group " + p.info.group);
}
}
ArrayMap<String, BasePermission> permissionMap =
p.tree ? mSettings.mPermissionTrees
: mSettings.mPermissions;
BasePermission bp = permissionMap.get(p.info.name);
// Allow system apps to redefine non-system permissions
if (bp != null && !Objects.equals(bp.sourcePackage, p.info.packageName)) {
final boolean currentOwnerIsSystem = (bp.perm != null
&& isSystemApp(bp.perm.owner));
if (isSystemApp(p.owner)) {
if (bp.type == BasePermission.TYPE_BUILTIN && bp.perm == null) {
// It's a built-in permission and no owner, take ownership now
bp.packageSetting = pkgSetting;
bp.perm = p;
bp.uid = pkg.applicationInfo.uid;
bp.sourcePackage = p.info.packageName;
p.info.flags |= PermissionInfo.FLAG_INSTALLED;
} else if (!currentOwnerIsSystem) {
String msg = "New decl " + p.owner + " of permission "
+ p.info.name + " is system; overriding " + bp.sourcePackage;
reportSettingsProblem(Log.WARN, msg);
bp = null;
}
}
}
if (bp == null) {
bp = new BasePermission(p.info.name, p.info.packageName,
BasePermission.TYPE_NORMAL);
permissionMap.put(p.info.name, bp);
}
if (bp.perm == null) {
if (bp.sourcePackage == null
|| bp.sourcePackage.equals(p.info.packageName)) {
BasePermission tree = findPermissionTreeLP(p.info.name);
if (tree == null
|| tree.sourcePackage.equals(p.info.packageName)) {
bp.packageSetting = pkgSetting;
bp.perm = p;
bp.uid = pkg.applicationInfo.uid;
bp.sourcePackage = p.info.packageName;
p.info.flags |= PermissionInfo.FLAG_INSTALLED;
if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) {
if (r == null) {
r = new StringBuilder(256);
} else {
r.append(' ');
}
r.append(p.info.name);
}
} else {
Slog.w(TAG, "Permission " + p.info.name + " from package "
+ p.info.packageName + " ignored: base tree "
+ tree.name + " is from package "
+ tree.sourcePackage);
}
} else {
Slog.w(TAG, "Permission " + p.info.name + " from package "
+ p.info.packageName + " ignored: original from "
+ bp.sourcePackage);
}
} else if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) {
if (r == null) {
r = new StringBuilder(256);
} else {
r.append(' ');
}
r.append("DUP:");
r.append(p.info.name);
}
if (bp.perm == p) {
bp.protectionLevel = p.info.protectionLevel;
}
}
if (r != null) {
if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Permissions: " + r);
}
//与之前类似,这里是Instrumentation,管理apk声明的Instrumentation类,它能监控应用各组件之间的交互.
N = pkg.instrumentation.size();
r = null;
for (i=0; i<N; i++) {
PackageParser.Instrumentation a = pkg.instrumentation.get(i);
a.info.packageName = pkg.applicationInfo.packageName;
a.info.sourceDir = pkg.applicationInfo.sourceDir;
a.info.publicSourceDir = pkg.applicationInfo.publicSourceDir;
a.info.splitSourceDirs = pkg.applicationInfo.splitSourceDirs;
a.info.splitPublicSourceDirs = pkg.applicationInfo.splitPublicSourceDirs;
a.info.dataDir = pkg.applicationInfo.dataDir;
a.info.deviceProtectedDataDir = pkg.applicationInfo.deviceProtectedDataDir;
a.info.credentialProtectedDataDir = pkg.applicationInfo.credentialProtectedDataDir;
a.info.nativeLibraryDir = pkg.applicationInfo.nativeLibraryDir;
a.info.secondaryNativeLibraryDir = pkg.applicationInfo.secondaryNativeLibraryDir;
mInstrumentation.put(a.getComponentName(), a);
if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) {
if (r == null) {
r = new StringBuilder(256);
} else {
r.append(' ');
}
r.append(a.info.name);
}
}
if (r != null) {
if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Instrumentation: " + r);
}
if (pkg.protectedBroadcasts != null) {
N = pkg.protectedBroadcasts.size();
for (i=0; i<N; i++) {
mProtectedBroadcasts.add(pkg.protectedBroadcasts.get(i));
}
}
pkgSetting.setTimeStamp(scanFileTime);
// Create idmap files for pairs of (packages, overlay packages).
// Note: "android", ie framework-res.apk, is handled by native layers.
if (pkg.mOverlayTarget != null) {
// This is an overlay package.
if (pkg.mOverlayTarget != null && !pkg.mOverlayTarget.equals("android")) {
if (!mOverlays.containsKey(pkg.mOverlayTarget)) {
mOverlays.put(pkg.mOverlayTarget,
new ArrayMap<String, PackageParser.Package>());
}
ArrayMap<String, PackageParser.Package> map = mOverlays.get(pkg.mOverlayTarget);
map.put(pkg.packageName, pkg);
PackageParser.Package orig = mPackages.get(pkg.mOverlayTarget);
if (orig != null && !createIdmapForPackagePairLI(orig, pkg)) {
createIdmapFailed = true;
}
}
} else if (mOverlays.containsKey(pkg.packageName) &&
!pkg.packageName.equals("android")) {
// This is a regular package, with one or more known overlay packages.
createIdmapsForPackageLI(pkg);
}
}
与前图对应,PMS中有如下几个对象:
// All available activities, for your resolving pleasure.
final ActivityIntentResolver mActivities =
new ActivityIntentResolver();
// All available receivers, for your resolving pleasure.
final ActivityIntentResolver mReceivers =
new ActivityIntentResolver();
// All available services, for your resolving pleasure.
final ServiceIntentResolver mServices = new ServiceIntentResolver();
// All available providers, for your resolving pleasure.
final ProviderIntentResolver mProviders = new ProviderIntentResolver();
它们负责保存所有解析到的APK中声明的四大组件对象。从之前的解析过程中,我们已经知道,每个组件中都保存了它的Intent信息,这也为以后的运行时组件查询提供了依据。
经过了scanPackageDirtyLI(),我们解析到的一个APK的Package实例添加到了PMS中,并且它所有重要组件也已经由PMS统一管理。这样PMS就能很好的管理这个APK的信息了。
到这里,APK扫描所涉及到的主要函数调用分析也就结束了。上面的流程,我们只介绍了一些重要的点,其他的内容我们可以自己去分析代码即可。