第一阶段PKMS扫描完XML文件并保存在PKMS的变量中,PKMS开始第二阶段的工作,扫描系统中的APK。流程如下:
1. PKMS会调用ScanDirLI()函数对分别对system/framework、system/app、system/priv-app、data/app、vendor/app等目录进行扫描。
// Collect vendor overlay packages.
// (Do this before scanning any apps.)
// For security and version matching reason, only consider
// overlay packages if they reside in VENDOR_OVERLAY_DIR.
File vendorOverlayDir = new File(VENDOR_OVERLAY_DIR);
scanDirLI(vendorOverlayDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_TRUSTED_OVERLAY, 0);
// Find base frameworks (resource packages without code).
scanDirLI(frameworkDir, 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");
scanDirLI(privilegedAppDir, 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");
scanDirLI(systemAppDir, 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
}
scanDirLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
// Collect all OEM packages.
final File oemAppDir = new File(Environment.getOemDirectory(), "app");
scanDirLI(oemAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
2. scanDirLI函数扫描目录下的文件,如是APK文件,则调用scanPackageLI()扫描APK
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
long currentTime, UserHandle user) throws PackageManagerException {
if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
parseFlags |= mDefParseFlags;
PackageParser pp = new PackageParser();
pp.setSeparateProcesses(mSeparateProcesses);
pp.setOnlyCoreApps(mOnlyCore);
pp.setDisplayMetrics(mMetrics);
if ((scanFlags & SCAN_TRUSTED_OVERLAY) != 0) {
parseFlags |= PackageParser.PARSE_TRUSTED_OVERLAY;
}
final PackageParser.Package pkg;
try {
//调用pp.parsePackage解析APK获去描述APK信息的PackageParser.Package对象
pkg = pp.parsePackage(scanFile, parseFlags);
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
}
PackageSetting ps = null;
PackageSetting updatedPkg;
// 更新APK的动作
......
// Verify certificates against what was last scanned
collectCertificatesLI(pp, ps, pkg, scanFile, parseFlags);
/*
* 处理系统apk和非系统apk有相同时的情况
*/
boolean shouldHideSystemApp = false;
if (updatedPkg == null && ps != null
&& (parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0 && !isSystemApp(ps)) {
/*
* Check to make sure the signatures match first. If they don't,
* wipe the installed application and its data.
*/
if (compareSignatures(ps.signatures.mSignatures, pkg.mSignatures)
!= PackageManager.SIGNATURE_MATCH) {
logCriticalInfo(Log.WARN, "Package " + ps.name + " appeared on system, but"
+ " signatures don't match existing userdata copy; removing");
deletePackageLI(pkg.packageName, null, true, null, null, 0, null, false);
ps = null;
} else {
/*
* If the newly-added system app is an older version than the
* already installed version, hide it. It will be scanned later
* and re-added like an update.
*/
if (pkg.mVersionCode <= ps.versionCode) {
shouldHideSystemApp = true;
logCriticalInfo(Log.INFO, "Package " + ps.name + " appeared at " + scanFile
+ " but new version " + pkg.mVersionCode + " better than installed "
+ ps.versionCode + "; hiding system");
} else {
/*
* The newly found system app is a newer version that the
* one previously installed. Simply remove the
* already-installed application and replace it with our own
* while keeping the application data.
*/
logCriticalInfo(Log.WARN, "Package " + ps.name + " at " + scanFile
+ " reverting from " + ps.codePathString + ": new version "
+ pkg.mVersionCode + " better than installed " + ps.versionCode);
InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps));
synchronized (mInstallLock) {
args.cleanUpResourcesLI();
}
}
}
}
// The apk is forward locked (not public) if its code and resources
// are kept in different files. (except for app in either system or
// vendor path).
// TODO grab this value from PackageSettings
if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
if (ps != null && !ps.codePath.equals(ps.resourcePath)) {
parseFlags |= PackageParser.PARSE_FORWARD_LOCK;
}
}
// TODO: extend to support forward-locked splits
String resourcePath = null;
String baseResourcePath = null;
if ((parseFlags & PackageParser.PARSE_FORWARD_LOCK) != 0 && !updatedPkgBetter) {
if (ps != null && ps.resourcePathString != null) {
resourcePath = ps.resourcePathString;
baseResourcePath = ps.resourcePathString;
} else {
// Should not happen at all. Just log an error.
Slog.e(TAG, "Resource path not set for pkg : " + pkg.packageName);
}
} else {
resourcePath = pkg.codePath;
baseResourcePath = pkg.baseCodePath;
}
// Set application objects path explicitly.
pkg.applicationInfo.volumeUuid = pkg.volumeUuid;
pkg.applicationInfo.setCodePath(pkg.codePath);
pkg.applicationInfo.setBaseCodePath(pkg.baseCodePath);
pkg.applicationInfo.setSplitCodePaths(pkg.splitCodePaths);
pkg.applicationInfo.setResourcePath(resourcePath);
pkg.applicationInfo.setBaseResourcePath(baseResourcePath);
pkg.applicationInfo.setSplitResourcePaths(pkg.splitCodePaths);
// 调用重载函数scanPackageLI处理pkg
PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanFlags
| SCAN_UPDATE_SIGNATURE, currentTime, user);
/*
* If the system app should be overridden by a previously installed
* data, hide the system app now and let the /data/app scan pick it up
* again.
*/
if (shouldHideSystemApp) {
synchronized (mPackages) {
mSettings.disableSystemPackageLPw(pkg.packageName);
}
}
return scannedPkg;
}
3. scanPakcageLI()主要做了三件小事
3.1调用PackageParser.parsePackage()解析APK,获得一个PackageParser.Package pkg对象,该文件保存了APK的信息。
3.2对APK进行升级以及签名验证。
3.3调用另一个重载方法scanPakcageLI()对pkg对象进行处理。
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
long currentTime, UserHandle user) throws PackageManagerException {
if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
parseFlags |= mDefParseFlags;
PackageParser pp = new PackageParser();
pp.setSeparateProcesses(mSeparateProcesses);
pp.setOnlyCoreApps(mOnlyCore);
pp.setDisplayMetrics(mMetrics);
if ((scanFlags & SCAN_TRUSTED_OVERLAY) != 0) {
parseFlags |= PackageParser.PARSE_TRUSTED_OVERLAY;
}
final PackageParser.Package pkg;
try {
//调用pp.parsePackage解析APK获去描述APK信息的PackageParser.Package对象
pkg = pp.parsePackage(scanFile, parseFlags);
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
}
PackageSetting ps = null;
PackageSetting updatedPkg;
// 更新APK的动作
......
// Verify certificates against what was last scanned
collectCertificatesLI(pp, ps, pkg, scanFile, parseFlags);
/*
* 处理系统apk和非系统apk有相同时的情况
*/
boolean shouldHideSystemApp = false;
if (updatedPkg == null && ps != null
&& (parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0 && !isSystemApp(ps)) {
/*
* Check to make sure the signatures match first. If they don't,
* wipe the installed application and its data.
*/
if (compareSignatures(ps.signatures.mSignatures, pkg.mSignatures)
!= PackageManager.SIGNATURE_MATCH) {
logCriticalInfo(Log.WARN, "Package " + ps.name + " appeared on system, but"
+ " signatures don't match existing userdata copy; removing");
deletePackageLI(pkg.packageName, null, true, null, null, 0, null, false);
ps = null;
} else {
/*
* If the newly-added system app is an older version than the
* already installed version, hide it. It will be scanned later
* and re-added like an update.
*/
if (pkg.mVersionCode <= ps.versionCode) {
shouldHideSystemApp = true;
logCriticalInfo(Log.INFO, "Package " + ps.name + " appeared at " + scanFile
+ " but new version " + pkg.mVersionCode + " better than installed "
+ ps.versionCode + "; hiding system");
} else {
/*
* The newly found system app is a newer version that the
* one previously installed. Simply remove the
* already-installed application and replace it with our own
* while keeping the application data.
*/
logCriticalInfo(Log.WARN, "Package " + ps.name + " at " + scanFile
+ " reverting from " + ps.codePathString + ": new version "
+ pkg.mVersionCode + " better than installed " + ps.versionCode);
InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps));
synchronized (mInstallLock) {
args.cleanUpResourcesLI();
}
}
}
}
// The apk is forward locked (not public) if its code and resources
// are kept in different files. (except for app in either system or
// vendor path).
// TODO grab this value from PackageSettings
if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
if (ps != null && !ps.codePath.equals(ps.resourcePath)) {
parseFlags |= PackageParser.PARSE_FORWARD_LOCK;
}
}
// TODO: extend to support forward-locked splits
String resourcePath = null;
String baseResourcePath = null;
if ((parseFlags & PackageParser.PARSE_FORWARD_LOCK) != 0 && !updatedPkgBetter) {
if (ps != null && ps.resourcePathString != null) {
resourcePath = ps.resourcePathString;
baseResourcePath = ps.resourcePathString;
} else {
// Should not happen at all. Just log an error.
Slog.e(TAG, "Resource path not set for pkg : " + pkg.packageName);
}
} else {
resourcePath = pkg.codePath;
baseResourcePath = pkg.baseCodePath;
}
// Set application objects path explicitly.
pkg.applicationInfo.volumeUuid = pkg.volumeUuid;
pkg.applicationInfo.setCodePath(pkg.codePath);
pkg.applicationInfo.setBaseCodePath(pkg.baseCodePath);
pkg.applicationInfo.setSplitCodePaths(pkg.splitCodePaths);
pkg.applicationInfo.setResourcePath(resourcePath);
pkg.applicationInfo.setBaseResourcePath(baseResourcePath);
pkg.applicationInfo.setSplitResourcePaths(pkg.splitCodePaths);
// 调用重载函数scanPackageLI处理pkg
PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanFlags
| SCAN_UPDATE_SIGNATURE, currentTime, user);
/*
* If the system app should be overridden by a previously installed
* data, hide the system app now and let the /data/app scan pick it up
* again.
*/
if (shouldHideSystemApp) {
synchronized (mPackages) {
mSettings.disableSystemPackageLPw(pkg.packageName);
}
}
return scannedPkg;
}
4.下面分析PackageParser.parsePackage()方法是如何处理APK的。
4.1 判定给定的输入是否为一个目录,如果是目录,则以为着目录下可能存在多个拆分后的APK,这就需要以Cluster的方式进行解析,如果仅仅是一个APK文件,就以 Monolithic的方式
public Package parsePackage(File packageFile, int flags) throws PackageParserException {
if (packageFile.isDirectory()) {
//判定给定的输入是否为一个目录,如果是目录,则以为着目录下可能存在多个拆分后的APK,这就需要以Cluster的方式进行解析
return parseClusterPackage(packageFile, flags);
} else {
//如果仅仅是一个APK文件,就以Monolithic的方式
return parseMonolithicPackage(packageFile, flags);
}
}
4.2 如果是CoreApp。则调用parseMonolithicPackageLite()进行处理,否则调用parseBaseApk( File)
public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
//如果是CoreApp。则调用parseMonolithicPackageLite()进行处理
if (mOnlyCoreApps) {
final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);
if (!lite.coreApp) {
throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
"Not a coreApp: " + apkFile);
}
}
final AssetManager assets = new AssetManager();
try {
final Package pkg = parseBaseApk(apkFile, assets, flags);
pkg.codePath = apkFile.getAbsolutePath();
return pkg;
} finally {
IoUtils.closeQuietly(assets);
}
}
4.3 parseBaseApk( File)函数里首先初始化了一个AssetManager对象,一个DisplayMetrics对象,一个Resources,并且调用collectCertificates函数获取了应用的签名信息,这些对象都是后续解析中需要用到的,因此将这些参数传递给解析函数,解析完成后关闭资源管理器与解析器
函数里首先初始化了一个AssetManager对象,一个DisplayMetrics对象,一个Resources,并且调用collectCertificates函数获取了应用的签名信息,这些对象都是后续解析中需要用到的,因此将这些参数传递给解析函数,解析完成后关闭资源管理器与解析器
private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
throws PackageParserException {
final String apkPath = apkFile.getAbsolutePath();
String volumeUuid = null;
if (apkPath.startsWith(MNT_EXPAND)) {
final int end = apkPath.indexOf('/', MNT_EXPAND.length());
volumeUuid = apkPath.substring(MNT_EXPAND.length(), end);
}
mParseError = PackageManager.INSTALL_SUCCEEDED;
mArchiveSourcePath = apkFile.getAbsolutePath();
if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);
final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);
Resources res = null;
XmlResourceParser parser = null;
try {
res = new Resources(assets, mMetrics, null);
assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
Build.VERSION.RESOURCES_SDK_INT);
parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
final String[] outError = new String[1];
final Package pkg = parseBaseApk(res, parser, flags, outError);
if (pkg == null) {
throw new PackageParserException(mParseError,
apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]);
}
pkg.volumeUuid = volumeUuid;
pkg.applicationInfo.volumeUuid = volumeUuid;
pkg.baseCodePath = apkPath;
pkg.mSignatures = null;
return pkg;
} catch (PackageParserException e) {
throw e;
} catch (Exception e) {
throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
"Failed to read manifest from " + apkPath, e);
} finally {
IoUtils.closeQuietly(parser);
}
}
4.4 最后调用另一个重载函数parseBaseApk()解析,主要解析AndroidMainfest.xml文件,将数据保存在PackageParser.Package对象后返回。
private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags,
String[] outError) throws XmlPullParserException, IOException {
final boolean trustedOverlay = (flags & PARSE_TRUSTED_OVERLAY) != 0;
AttributeSet attrs = parser;
mParseInstrumentationArgs = null;
mParseActivityArgs = null;
mParseServiceArgs = null;
mParseProviderArgs = null;
final String pkgName;
final String splitName;
try {
Pair
packageSplit = parsePackageSplitNames(parser, attrs, flags);
pkgName = packageSplit.first;
splitName = packageSplit.second;
} catch (PackageParserException e) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
return null;
}
int type;
if (!TextUtils.isEmpty(splitName)) {
outError[0] = "Expected base APK, but found split " + splitName;
mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
return null;
}
final Package pkg = new Package(pkgName);
boolean foundApp = false;
TypedArray sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.AndroidManifest);
pkg.mVersionCode = pkg.applicationInfo.versionCode = sa.getInteger(
com.android.internal.R.styleable.AndroidManifest_versionCode, 0);
pkg.baseRevisionCode = sa.getInteger(
com.android.internal.R.styleable.AndroidManifest_revisionCode, 0);
pkg.mVersionName = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifest_versionName, 0);
if (pkg.mVersionName != null) {
pkg.mVersionName = pkg.mVersionName.intern();
}
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(pkgName)) {
outError[0] = "
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;
pkg.coreApp = attrs.getAttributeBooleanValue(null, "coreApp", false);
sa.recycle();
/* 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;
}
// 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 ((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 (tagName.equals("application")) {
if (foundApp) {
if (RIGID_PARSER) {
outError[0] = "
has more than one
";
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return null;
} else {
Slog.w(TAG, "
has more than one
"); XmlUtils.skipCurrentTag(parser); continue; } } foundApp = true; if (!parseBaseApplication(pkg, res, parser, attrs, flags, outError)) { return null; } } else if (tagName.equals("overlay")) { pkg.mTrustedOverlay = trustedOverlay; sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.AndroidManifestResourceOverlay); pkg.mOverlayTarget = sa.getString( com.android.internal.R.styleable.AndroidManifestResourceOverlay_targetPackage); pkg.mOverlayPriority = sa.getInt( com.android.internal.R.styleable.AndroidManifestResourceOverlay_priority, -1); sa.recycle(); if (pkg.mOverlayTarget == null) { outError[0] = "
does not specify a target package"; mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return null; } if (pkg.mOverlayPriority < 0 || pkg.mOverlayPriority > 9999) { outError[0] = "
priority must be between 0 and 9999"; mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return null; } XmlUtils.skipCurrentTag(parser); } else if (tagName.equals("key-sets")) { if (!parseKeySets(pkg, res, parser, attrs, outError)) { return null; } } else if (tagName.equals("permission-group")) { if (parsePermissionGroup(pkg, flags, res, parser, attrs, outError) == null) { return null; } } else if (tagName.equals("permission")) { if (parsePermission(pkg, res, parser, attrs, outError) == null) { return null; } } else if (tagName.equals("permission-tree")) { if (parsePermissionTree(pkg, res, parser, attrs, outError) == null) { return null; } } else if (tagName.equals("uses-permission")) { if (!parseUsesPermission(pkg, res, parser, attrs)) { return null; } } else if (tagName.equals("uses-permission-sdk-m") || tagName.equals("uses-permission-sdk-23")) { if (!parseUsesPermission(pkg, res, parser, attrs)) { return null; } } else if (tagName.equals("uses-configuration")) { ConfigurationInfo cPref = new ConfigurationInfo(); sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.AndroidManifestUsesConfiguration); cPref.reqTouchScreen = sa.getInt( com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqTouchScreen, Configuration.TOUCHSCREEN_UNDEFINED); cPref.reqKeyboardType = sa.getInt( com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqKeyboardType, Configuration.KEYBOARD_UNDEFINED); if (sa.getBoolean( com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqHardKeyboard, false)) { cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD; } cPref.reqNavigation = sa.getInt( com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqNavigation, Configuration.NAVIGATION_UNDEFINED); if (sa.getBoolean( com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqFiveWayNav, false)) { cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV; } sa.recycle(); pkg.configPreferences = ArrayUtils.add(pkg.configPreferences, cPref); XmlUtils.skipCurrentTag(parser); } else if (tagName.equals("uses-feature")) { FeatureInfo fi = parseUsesFeature(res, attrs); pkg.reqFeatures = ArrayUtils.add(pkg.reqFeatures, fi); if (fi.name == null) { ConfigurationInfo cPref = new ConfigurationInfo(); cPref.reqGlEsVersion = fi.reqGlEsVersion; pkg.configPreferences = ArrayUtils.add(pkg.configPreferences, cPref); } XmlUtils.skipCurrentTag(parser); } else if (tagName.equals("feature-group")) { FeatureGroupInfo group = new FeatureGroupInfo(); ArrayList
features = null; final int innerDepth = parser.getDepth(); while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { continue; } final String innerTagName = parser.getName(); if (innerTagName.equals("uses-feature")) { FeatureInfo featureInfo = parseUsesFeature(res, attrs); // FeatureGroups are stricter and mandate that // any
declared are mandatory. featureInfo.flags |= FeatureInfo.FLAG_REQUIRED; features = ArrayUtils.add(features, featureInfo); } else { Slog.w(TAG, "Unknown element under
: " + innerTagName + " at " + mArchiveSourcePath + " " + parser.getPositionDescription()); } XmlUtils.skipCurrentTag(parser); } if (features != null) { group.features = new FeatureInfo[features.size()]; group.features = features.toArray(group.features); } pkg.featureGroups = ArrayUtils.add(pkg.featureGroups, group); } else if (tagName.equals("uses-sdk")) { if (SDK_VERSION > 0) { sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.AndroidManifestUsesSdk); int minVers = 0; String minCode = null; int targetVers = 0; String targetCode = null; TypedValue val = sa.peekValue( com.android.internal.R.styleable.AndroidManifestUsesSdk_minSdkVersion); if (val != null) { if (val.type == TypedValue.TYPE_STRING && val.string != null) { targetCode = minCode = val.string.toString(); } else { // If it's not a string, it's an integer. targetVers = minVers = val.data; } } val = sa.peekValue( com.android.internal.R.styleable.AndroidManifestUsesSdk_targetSdkVersion); if (val != null) { if (val.type == TypedValue.TYPE_STRING && val.string != null) { targetCode = minCode = val.string.toString(); } else { // If it's not a string, it's an integer. targetVers = val.data; } } sa.recycle(); if (minCode != null) { boolean allowedCodename = false; for (String codename : SDK_CODENAMES) { if (minCode.equals(codename)) { allowedCodename = true; break; } } if (!allowedCodename) { if (SDK_CODENAMES.length > 0) { outError[0] = "Requires development platform " + minCode + " (current platform is any of " + Arrays.toString(SDK_CODENAMES) + ")"; } else { outError[0] = "Requires development platform " + minCode + " but this is a release platform."; } mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK; return null; } } else if (minVers > SDK_VERSION) { outError[0] = "Requires newer sdk version #" + minVers + " (current version is #" + SDK_VERSION + ")"; mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK; return null; } if (targetCode != null) { boolean allowedCodename = false; for (String codename : SDK_CODENAMES) { if (targetCode.equals(codename)) { allowedCodename = true; break; } } if (!allowedCodename) { if (SDK_CODENAMES.length > 0) { outError[0] = "Requires development platform " + targetCode + " (current platform is any of " + Arrays.toString(SDK_CODENAMES) + ")"; } else { outError[0] = "Requires development platform " + targetCode + " but this is a release platform."; } mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK; return null; } // If the code matches, it definitely targets this SDK. pkg.applicationInfo.targetSdkVersion = android.os.Build.VERSION_CODES.CUR_DEVELOPMENT; } else { pkg.applicationInfo.targetSdkVersion = targetVers; } } XmlUtils.skipCurrentTag(parser); } else if (tagName.equals("supports-screens")) { sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.AndroidManifestSupportsScreens); pkg.applicationInfo.requiresSmallestWidthDp = sa.getInteger( com.android.internal.R.styleable.AndroidManifestSupportsScreens_requiresSmallestWidthDp, 0); pkg.applicationInfo.compatibleWidthLimitDp = sa.getInteger( com.android.internal.R.styleable.AndroidManifestSupportsScreens_compatibleWidthLimitDp, 0); pkg.applicationInfo.largestWidthLimitDp = sa.getInteger( com.android.internal.R.styleable.AndroidManifestSupportsScreens_largestWidthLimitDp, 0); // This is a trick to get a boolean and still able to detect // if a value was actually set. supportsSmallScreens = sa.getInteger( com.android.internal.R.styleable.AndroidManifestSupportsScreens_smallScreens, supportsSmallScreens); supportsNormalScreens = sa.getInteger( com.android.internal.R.styleable.AndroidManifestSupportsScreens_normalScreens, supportsNormalScreens); supportsLargeScreens = sa.getInteger( com.android.internal.R.styleable.AndroidManifestSupportsScreens_largeScreens, supportsLargeScreens); supportsXLargeScreens = sa.getInteger( com.android.internal.R.styleable.AndroidManifestSupportsScreens_xlargeScreens, supportsXLargeScreens); resizeable = sa.getInteger( com.android.internal.R.styleable.AndroidManifestSupportsScreens_resizeable, resizeable); anyDensity = sa.getInteger( com.android.internal.R.styleable.AndroidManifestSupportsScreens_anyDensity, anyDensity); sa.recycle(); XmlUtils.skipCurrentTag(parser); } else if (tagName.equals("protected-broadcast")) { sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.AndroidManifestProtectedBroadcast); // Note: don't allow this value to be a reference to a resource // that may change. String name = sa.getNonResourceString( com.android.internal.R.styleable.AndroidManifestProtectedBroadcast_name); sa.recycle(); if (name != null && (flags&PARSE_IS_SYSTEM) != 0) { if (pkg.protectedBroadcasts == null) { pkg.protectedBroadcasts = new ArrayList
(); } if (!pkg.protectedBroadcasts.contains(name)) { pkg.protectedBroadcasts.add(name.intern()); } } XmlUtils.skipCurrentTag(parser); } else if (tagName.equals("instrumentation")) { if (parseInstrumentation(pkg, res, parser, attrs, outError) == null) { return null; } } else if (tagName.equals("original-package")) { sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.AndroidManifestOriginalPackage); String orig =sa.getNonConfigurationString( com.android.internal.R.styleable.AndroidManifestOriginalPackage_name, 0); if (!pkg.packageName.equals(orig)) { if (pkg.mOriginalPackages == null) { pkg.mOriginalPackages = new ArrayList
(); pkg.mRealPackage = pkg.packageName; } pkg.mOriginalPackages.add(orig); } sa.recycle(); XmlUtils.skipCurrentTag(parser); } else if (tagName.equals("adopt-permissions")) { sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.AndroidManifestOriginalPackage); String name = sa.getNonConfigurationString( com.android.internal.R.styleable.AndroidManifestOriginalPackage_name, 0); sa.recycle(); if (name != null) { if (pkg.mAdoptPermissions == null) { pkg.mAdoptPermissions = new ArrayList
(); } pkg.mAdoptPermissions.add(name); } XmlUtils.skipCurrentTag(parser); } else if (tagName.equals("uses-gl-texture")) { // Just skip this tag XmlUtils.skipCurrentTag(parser); continue; } else if (tagName.equals("compatible-screens")) { // Just skip this tag XmlUtils.skipCurrentTag(parser); continue; } else if (tagName.equals("supports-input")) { XmlUtils.skipCurrentTag(parser); continue; } else if (tagName.equals("eat-comment")) { // Just skip this tag XmlUtils.skipCurrentTag(parser); continue; } else if (RIGID_PARSER) { outError[0] = "Bad element under
: " + parser.getName(); mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return null; } else { Slog.w(TAG, "Unknown element under
: " + parser.getName() + " at " + mArchiveSourcePath + " " + parser.getPositionDescription()); XmlUtils.skipCurrentTag(parser); continue; } } if (!foundApp && pkg.instrumentation.size() == 0) { outError[0] = "
does not contain an
or
"; mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY; } final int NP = PackageParser.NEW_PERMISSIONS.length; StringBuilder implicitPerms = null; for (int ip=0; ip
= npi.sdkVersion) { break; } if (!pkg.requestedPermissions.contains(npi.name)) { if (implicitPerms == null) { implicitPerms = new StringBuilder(128); implicitPerms.append(pkg.packageName); implicitPerms.append(": compat added "); } else { implicitPerms.append(' '); } implicitPerms.append(npi.name); pkg.requestedPermissions.add(npi.name); } } if (implicitPerms != null) { Slog.i(TAG, implicitPerms.toString()); } final int NS = PackageParser.SPLIT_PERMISSIONS.length; for (int is=0; is
= spi.targetSdk || !pkg.requestedPermissions.contains(spi.rootPerm)) { continue; } for (int in=0; in<spi.newPerms.length; in++) { final String perm = spi.newPerms[in]; if (!pkg.requestedPermissions.contains(perm)) { pkg.requestedPermissions.add(perm); } } } if (supportsSmallScreens < 0 || (supportsSmallScreens > 0 && pkg.applicationInfo.targetSdkVersion >= android.os.Build.VERSION_CODES.DONUT)) { pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS; } if (supportsNormalScreens != 0) { pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS; } if (supportsLargeScreens < 0 || (supportsLargeScreens > 0 && pkg.applicationInfo.targetSdkVersion >= android.os.Build.VERSION_CODES.DONUT)) { pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS; } if (supportsXLargeScreens < 0 || (supportsXLargeScreens > 0 && pkg.applicationInfo.targetSdkVersion >= android.os.Build.VERSION_CODES.GINGERBREAD)) { pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS; } if (resizeable < 0 || (resizeable > 0 && pkg.applicationInfo.targetSdkVersion >= android.os.Build.VERSION_CODES.DONUT)) { pkg.applicationInfo.flags |= ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS; } if (anyDensity < 0 || (anyDensity > 0 && pkg.applicationInfo.targetSdkVersion >= android.os.Build.VERSION_CODES.DONUT)) { pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES; } return pkg; }
PackageParser.Package类图如下:
5. scanPakcageLI()对pkg对象进行处理,主要完成以下几件事情
5.1 为Package分配UserId或所属的ShareUserId
5.2 向Installd发送命令,为非系统APK创建已PackageName命名的目录
5.3 提取Native动态库,并获取CPUABI信息
5.4 将四大组件的信息保存到PKMS的变量中,方便对外提供统一的组件信息。
private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg, int parseFlags,
int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
final File scanFile = new File(pkg.codePath);
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");
}
if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
} else {
// Only allow system apps to be flagged as core apps.
pkg.coreApp = false;
}
if ((parseFlags&PackageParser.PARSE_IS_PRIVILEGED) != 0) {
pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
}
if (mCustomResolverComponentName != null &&
mCustomResolverComponentName.getPackageName().equals(pkg.packageName)) {
setUpCustomResolverActivity(pkg);
}
/*单独处理名为Android的APK,该APK是framework-res.apk.该APK和系统相关
当多个Activity符合某个Intent的时候,系统会弹出的Activity
铃声选择的Activiy
关机前弹出的对话框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.");
}
// Set up information for our fall-back user intent resolution activity.
mPlatformPackage = pkg;
pkg.mVersionCode = mSdkVersion;
mAndroidApplication = pkg.applicationInfo;
if (!mResolverReplaced) {
mResolveActivity.applicationInfo = mAndroidApplication;
mResolveActivity.name = ResolverActivity.class.getName();
mResolveActivity.packageName = mAndroidApplication.packageName;
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_Holo_Dialog_Alert;
mResolveActivity.exported = true;
mResolveActivity.enabled = true;
mResolveInfo.activityInfo = mResolveActivity;
mResolveInfo.priority = 0;
mResolveInfo.preferredOrder = 0;
mResolveInfo.match = 0;
mResolveComponentName = new ComponentName(
mAndroidApplication.packageName, mResolveActivity.name);
}
}
}
if (DEBUG_PACKAGE_SCANNING) {
if ((parseFlags & PackageParser.PARSE_CHATTY) != 0)
Log.d(TAG, "Scanning package " + pkg.packageName);
}
/*mPackage保存系统中安装的Package
mShareLibraries保存共享库
这里判断安装的package是否重复
*/
if (mPackages.containsKey(pkg.packageName)
|| mSharedLibraries.containsKey(pkg.packageName)) {
throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE,
"Application package " + pkg.packageName
+ " already installed. Skipping duplicate.");
}
// If we're only installing presumed-existing packages, require that the
// scanned APK is both already known and at the path previously established
// for it. Previously unknown packages we pick up normally, but if we have an
// a priori expectation about this package's install presence, enforce it.
// With a singular exception for new system packages. When an OTA contains
// a new system package, we allow the codepath to change from a system location
// to the user-installed location. If we don't allow this change, any newer,
// user-installed version of the application will be ignored.
if ((scanFlags & SCAN_REQUIRE_KNOWN) != 0) {
if (mExpectingBetter.containsKey(pkg.packageName)) {
logCriticalInfo(Log.WARN,
"Relax SCAN_REQUIRE_KNOWN requirement for package " + pkg.packageName);
} else {
PackageSetting known = mSettings.peekPackageLPr(pkg.packageName);
if (known != null) {
if (DEBUG_PACKAGE_SCANNING) {
Log.d(TAG, "Examining " + pkg.codePath
+ " and requiring known paths " + known.codePathString
+ " & " + known.resourcePathString);
}
if (!pkg.applicationInfo.getCodePath().equals(known.codePathString)
|| !pkg.applicationInfo.getResourcePath().equals(known.resourcePathString)) {
throw new PackageManagerException(INSTALL_FAILED_PACKAGE_CHANGED,
"Application package " + pkg.packageName
+ " found at " + pkg.applicationInfo.getCodePath()
+ " but expected at " + known.codePathString + "; ignoring.");
}
}
}
}
// Initialize package source and resource directories
File destCodeFile = new File(pkg.applicationInfo.getCodePath());
File destResourceFile = new File(pkg.applicationInfo.getResourcePath());
SharedUserSetting suid = null;
PackageSetting pkgSetting = null;
if (!isSystemApp(pkg)) {
// Only system apps can use these features.
pkg.mOriginalPackages = null;
pkg.mRealPackage = null;
pkg.mAdoptPermissions = null;
}
// writer
synchronized (mPackages) {
/*获取SharedUserId对应的ShareUserSetting,所有的共享用户保存在Settings.mSharedUsers可参考第一篇对ShareUserSetting的描述
*/
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 ((parseFlags & 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) {
// 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;
}
} else {
if (DEBUG_UPGRADE) Log.v(TAG, "Renaming new package "
+ pkg.packageName + " to old name " + origPackage.name);
}
break;
}
}
}
}
if (mTransferedPackages.contains(pkg.packageName)) {
Slog.w(TAG, "Package " + pkg.packageName
+ " was transferred to another, but its .apk remains");
}
// Just create the setting, don't add it yet. For already existing packages
// the PkgSetting exists already and doesn't have to be created.
pkgSetting = mSettings.getPackageLPw(pkg, origPackage, realName, suid, destCodeFile,
destResourceFile, pkg.applicationInfo.nativeLibraryRootDir,
pkg.applicationInfo.primaryCpuAbi,
pkg.applicationInfo.secondaryCpuAbi,
pkg.applicationInfo.flags, pkg.applicationInfo.privateFlags,
user, false);
if (pkgSetting == null) {
throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
"Creating application package " + pkg.packageName + " failed");
}
if (pkgSetting.origPackage != null) {
// If we are first transitioning from an original package,
// fix up the new package's name now. We need to do this after
// looking up the package under its new name, so getPackageLP
// can take care of fiddling things correctly.
pkg.setPackageName(origPackage.name);
// File a report about this.
String msg = "New package " + pkgSetting.realName
+ " renamed to replace old package " + pkgSetting.name;
reportSettingsProblem(Log.WARN, msg);
// Make a note of it.
mTransferedPackages.add(origPackage.name);
// No longer need to retain this.
pkgSetting.origPackage = null;
}
if (realName != null) {
// Make a note of it.
mTransferedPackages.add(pkg.packageName);
}
if (mSettings.isDisabledSystemPackageLPr(pkg.packageName)) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
}
if ((parseFlags&PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
// Check all shared libraries and map to their actual file path.
// We only do this here for apps not on a system dir, because those
// are the only ones that can fail an install due to this. We
// will take care of the system apps by updating all of their
// library paths after the scan is done.
updateSharedLibrariesLPw(pkg, null);
}
if (mFoundPolicyFile) {
SELinuxMMAC.assignSeinfoValue(pkg);
}
pkg.applicationInfo.uid = pkgSetting.appId;
pkg.mExtras = pkgSetting;
//验证APK的签名
if (shouldCheckUpgradeKeySetLP(pkgSetting, scanFlags)) {
if (checkUpgradeKeySetLP(pkgSetting, pkg)) {
// We just determined the app is signed correctly, so bring
// over the latest parsed certs.
pkgSetting.signatures.mSignatures = pkg.mSignatures;
} else {
if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
"Package " + pkg.packageName + " upgrade keys do not match the "
+ "previously installed version");
} else {
pkgSetting.signatures.mSignatures = pkg.mSignatures;
String msg = "System package " + pkg.packageName
+ " signature changed; retaining data.";
reportSettingsProblem(Log.WARN, msg);
}
}
} else {
try {
verifySignaturesLP(pkgSetting, pkg);
// We just determined the app is signed correctly, so bring
// over the latest parsed certs.
pkgSetting.signatures.mSignatures = pkg.mSignatures;
} catch (PackageManagerException e) {
if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
throw e;
}
// The signature has changed, but this package is in the system
// image... let's recover!
pkgSetting.signatures.mSignatures = pkg.mSignatures;
// However... if this package is part of a shared user, but it
// doesn't match the signature of the shared user, let's fail.
// What this means is that you can't change the signatures
// associated with an overall shared user, which doesn't seem all
// that unreasonable.
if (pkgSetting.sharedUser != null) {
if (compareSignatures(pkgSetting.sharedUser.signatures.mSignatures,
pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) {
throw new PackageManagerException(
INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
"Signature mismatch for shared user : "
+ pkgSetting.sharedUser);
}
}
// File a report about this.
String msg = "System package " + pkg.packageName
+ " signature changed; retaining data.";
reportSettingsProblem(Log.WARN, msg);
}
}
// Verify that this new package doesn't have any content providers
// that conflict with existing packages. Only do this if the
// package isn't already installed, since we don't want to break
// things that are installed.
if ((scanFlags & SCAN_NEW_INSTALL) != 0) {
final int N = pkg.providers.size();
int i;
for (i=0; i<N; i++) {
PackageParser.Provider p = pkg.providers.get(i);
if (p.info.authority != null) {
String names[] = p.info.authority.split(";");
for (int j = 0; j < names.length; j++) {
if (mProvidersByAuthority.containsKey(names[j])) {
PackageParser.Provider other = mProvidersByAuthority.get(names[j]);
final String otherPackageName =
((other != null && other.getComponentName() != null) ?
other.getComponentName().getPackageName() : "?");
throw new PackageManagerException(
INSTALL_FAILED_CONFLICTING_PROVIDER,
"Can't install because provider name " + names[j]
+ " (in package " + pkg.applicationInfo.packageName
+ ") is already used by " + otherPackageName);
}
}
}
}
}
if (pkg.mAdoptPermissions != null) {
// This package wants to adopt ownership of permissions from
// another package.
for (int i = pkg.mAdoptPermissions.size() - 1; i >= 0; i--) {
final String origName = pkg.mAdoptPermissions.get(i);
final PackageSetting orig = mSettings.peekPackageLPr(origName);
if (orig != null) {
if (verifyPackageUpdateLPr(orig, pkg)) {
Slog.i(TAG, "Adopting permissions from " + origName + " to "
+ pkg.packageName);
mSettings.transferPermissionsLPw(origName, pkg.packageName);
}
}
}
}
}
final String pkgName = pkg.packageName;
final long scanFileTime = scanFile.lastModified();
final boolean forceDex = (scanFlags & SCAN_FORCE_DEX) != 0;
pkg.applicationInfo.processName = fixProcessName(
pkg.applicationInfo.packageName,
pkg.applicationInfo.processName,
pkg.applicationInfo.uid);
File dataPath;
if (mPlatformPackage == pkg) {
// The system package is special.
dataPath = new File(Environment.getDataDirectory(), "system");
pkg.applicationInfo.dataDir = dataPath.getPath();
} else {
//为非系统APK创建目录
// This is a normal package, need to make its data directory.
dataPath = Environment.getDataUserPackageDirectory(pkg.volumeUuid,
UserHandle.USER_OWNER, pkg.packageName);
boolean uidError = false;
if (dataPath.exists()) {
int currentUid = 0;
try {
StructStat stat = Os.stat(dataPath.getPath());
currentUid = stat.st_uid;
} catch (ErrnoException e) {
Slog.e(TAG, "Couldn't stat path " + dataPath.getPath(), e);
}
// If we have mismatched owners for the data path, we have a problem.
if (currentUid != pkg.applicationInfo.uid) {
boolean recovered = false;
if (currentUid == 0) {
// The directory somehow became owned by root. Wow.
// This is probably because the system was stopped while
// installd was in the middle of messing with its libs
// directory. Ask installd to fix that.
int ret = mInstaller.fixUid(pkg.volumeUuid, pkgName,
pkg.applicationInfo.uid, pkg.applicationInfo.uid);
if (ret >= 0) {
recovered = true;
String msg = "Package " + pkg.packageName
+ " unexpectedly changed to uid 0; recovered to " +
+ pkg.applicationInfo.uid;
reportSettingsProblem(Log.WARN, msg);
}
}
if (!recovered && ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0
|| (scanFlags&SCAN_BOOTING) != 0)) {
// If this is a system app, we can at least delete its
// current data so the application will still work.
int ret = removeDataDirsLI(pkg.volumeUuid, pkgName);
if (ret >= 0) {
// TODO: Kill the processes first
// Old data gone!
String prefix = (parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0
? "System package " : "Third party package ";
String msg = prefix + pkg.packageName
+ " has changed from uid: "
+ currentUid + " to "
+ pkg.applicationInfo.uid + "; old data erased";
reportSettingsProblem(Log.WARN, msg);
recovered = true;
// And now re-install the app.
ret = createDataDirsLI(pkg.volumeUuid, pkgName, pkg.applicationInfo.uid,
pkg.applicationInfo.seinfo);
if (ret == -1) {
// Ack should not happen!
msg = prefix + pkg.packageName
+ " could not have data directory re-created after delete.";
reportSettingsProblem(Log.WARN, msg);
throw new PackageManagerException(
INSTALL_FAILED_INSUFFICIENT_STORAGE, msg);
}
}
if (!recovered) {
mHasSystemUidErrors = true;
}
} else if (!recovered) {
// If we allow this install to proceed, we will be broken.
// Abort, abort!
throw new PackageManagerException(INSTALL_FAILED_UID_CHANGED,
"scanPackageLI");
}
if (!recovered) {
pkg.applicationInfo.dataDir = "/mismatched_uid/settings_"
+ pkg.applicationInfo.uid + "/fs_"
+ currentUid;
pkg.applicationInfo.nativeLibraryDir = pkg.applicationInfo.dataDir;
pkg.applicationInfo.nativeLibraryRootDir = pkg.applicationInfo.dataDir;
String msg = "Package " + pkg.packageName
+ " has mismatched uid: "
+ currentUid + " on disk, "
+ pkg.applicationInfo.uid + " in settings";
// writer
synchronized (mPackages) {
mSettings.mReadMessages.append(msg);
mSettings.mReadMessages.append('\n');
uidError = true;
if (!pkgSetting.uidError) {
reportSettingsProblem(Log.ERROR, msg);
}
}
}
}
pkg.applicationInfo.dataDir = dataPath.getPath();
if (mShouldRestoreconData) {
Slog.i(TAG, "SELinux relabeling of " + pkg.packageName + " issued.");
mInstaller.restoreconData(pkg.volumeUuid, pkg.packageName,
pkg.applicationInfo.seinfo, pkg.applicationInfo.uid);
}
} else {
if (DEBUG_PACKAGE_SCANNING) {
if ((parseFlags & PackageParser.PARSE_CHATTY) != 0)
Log.v(TAG, "Want this data dir: " + dataPath);
}
//invoke installer to do the actual installation
int ret = createDataDirsLI(pkg.volumeUuid, pkgName, pkg.applicationInfo.uid,
pkg.applicationInfo.seinfo);
if (ret < 0) {
// Error from installer
throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
"Unable to create data dirs [errorCode=" + ret + "]");
}
if (dataPath.exists()) {
pkg.applicationInfo.dataDir = dataPath.getPath();
} else {
Slog.w(TAG, "Unable to create data directory: " + dataPath);
pkg.applicationInfo.dataDir = null;
}
}
pkgSetting.uidError = uidError;
}
final String path = scanFile.getPath();
final String cpuAbiOverride = deriveAbiOverride(pkg.cpuAbiOverride, pkgSetting);
//获取CpuABi信息,可进行优化
if ((scanFlags & SCAN_NEW_INSTALL) == 0) {
derivePackageAbi(pkg, scanFile, cpuAbiOverride, true /* extract libs */);
// Some system apps still use directory structure for native libraries
// in which case we might end up not detecting abi solely based on apk
// structure. Try to detect abi based on directory structure.
if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp() &&
pkg.applicationInfo.primaryCpuAbi == null) {
setBundledAppAbisAndRoots(pkg, pkgSetting);
setNativeLibraryPaths(pkg);
}
} else {
if ((scanFlags & SCAN_MOVE) != 0) {
// We haven't run dex-opt for this move (since we've moved the compiled output too)
// but we already have this packages package info in the PackageSetting. We just
// use that and derive the native library path based on the new codepath.
pkg.applicationInfo.primaryCpuAbi = pkgSetting.primaryCpuAbiString;
pkg.applicationInfo.secondaryCpuAbi = pkgSetting.secondaryCpuAbiString;
}
// Set native library paths again. For moves, the path will be updated based on the
// ABIs we've determined above. For non-moves, the path will be updated based on the
// ABIs we determined during compilation, but the path will depend on the final
// package path (after the rename away from the stage path).
setNativeLibraryPaths(pkg);
}·
if (DEBUG_INSTALL) Slog.i(TAG, "Linking native library dir for " + path);
final int[] userIds = sUserManager.getUserIds();
synchronized (mInstallLock) {
// Make sure all user data directories are ready to roll; we're okay
// if they already exist
if (!TextUtils.isEmpty(pkg.volumeUuid)) {
for (int userId : userIds) {
if (userId != 0) {
mInstaller.createUserData(pkg.volumeUuid, pkg.packageName,
UserHandle.getUid(userId, pkg.applicationInfo.uid), userId,
pkg.applicationInfo.seinfo);
}
}
}
// Create a native library symlink only if we have native libraries
// and if the native libraries are 32 bit libraries. We do not provide
// this symlink for 64 bit libraries.
if (pkg.applicationInfo.primaryCpuAbi != null &&
!VMRuntime.is64BitAbi(pkg.applicationInfo.primaryCpuAbi)) {
final String nativeLibPath = pkg.applicationInfo.nativeLibraryDir;
for (int userId : userIds) {
if (mInstaller.linkNativeLibraryDirectory(pkg.volumeUuid, pkg.packageName,
nativeLibPath, userId) < 0) {
throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
"Failed linking native library dir (user=" + userId + ")");
}
}
}
}
// This is a special case for the "system" package, where the ABI is
// dictated by the zygote configuration (and init.rc). We should keep track
// of this ABI so that we can deal with "normal" applications that run under
// the same UID correctly.
if (mPlatformPackage == pkg) {
pkg.applicationInfo.primaryCpuAbi = VMRuntime.getRuntime().is64Bit() ?
Build.SUPPORTED_64_BIT_ABIS[0] : Build.SUPPORTED_32_BIT_ABIS[0];
}
// If there's a mismatch between the abi-override in the package setting
// and the abiOverride specified for the install. Warn about this because we
// would've already compiled the app without taking the package setting into
// account.
if ((scanFlags & SCAN_NO_DEX) == 0 && (scanFlags & SCAN_NEW_INSTALL) != 0) {
if (cpuAbiOverride == null && pkgSetting.cpuAbiOverrideString != null) {
Slog.w(TAG, "Ignoring persisted ABI override " + cpuAbiOverride +
" for package: " + pkg.packageName);
}
}
pkgSetting.primaryCpuAbiString = pkg.applicationInfo.primaryCpuAbi;
pkgSetting.secondaryCpuAbiString = pkg.applicationInfo.secondaryCpuAbi;
pkgSetting.cpuAbiOverrideString = cpuAbiOverride;
// Copy the derived override back to the parsed package, so that we can
// update the package settings accordingly.
pkg.cpuAbiOverride = cpuAbiOverride;
if (DEBUG_ABI_SELECTION) {
Slog.d(TAG, "Resolved nativeLibraryRoot for " + pkg.applicationInfo.packageName
+ " to root=" + pkg.applicationInfo.nativeLibraryRootDir + ", isa="
+ pkg.applicationInfo.nativeLibraryRootRequiresIsa);
}
// Push the derived path down into PackageSettings so we know what to
// clean up at uninstall time.
pkgSetting.legacyNativeLibraryPathString = pkg.applicationInfo.nativeLibraryRootDir;
if (DEBUG_ABI_SELECTION) {
Log.d(TAG, "Abis for package[" + pkg.packageName + "] are" +
" primary=" + pkg.applicationInfo.primaryCpuAbi +
" secondary=" + pkg.applicationInfo.secondaryCpuAbi);
}
if ((scanFlags&SCAN_BOOTING) == 0 && pkgSetting.sharedUser != null) {
// We don't do this here during boot because we can do it all
// at once after scanning all existing packages.
//
// We also do this *before* we perform dexopt on this package, so that
// we can avoid redundant dexopts, and also to make sure we've got the
// code and package path correct.
adjustCpuAbisForSharedUserLPw(pkgSetting.sharedUser.packages,
pkg, forceDex, (scanFlags & SCAN_DEFER_DEX) != 0, true /* boot complete */);
}
if ((scanFlags & SCAN_NO_DEX) == 0) {
int result = mPackageDexOptimizer.performDexOpt(pkg, null /* instruction sets */,
forceDex, (scanFlags & SCAN_DEFER_DEX) != 0, false /* inclDependencies */,
(scanFlags & SCAN_BOOTING) == 0);
if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
throw new PackageManagerException(INSTALL_FAILED_DEXOPT, "scanPackageLI");
}
}
if (mFactoryTest && pkg.requestedPermissions.contains(
android.Manifest.permission.FACTORY_TEST)) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FACTORY_TEST;
}
ArrayList
clientLibPkgs = null;
// writer
synchronized (mPackages) {
if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
// Only system apps can add new shared libraries.
if (pkg.libraryNames != null) {
for (int i=0; i<pkg.libraryNames.size(); i++) {
String name = pkg.libraryNames.get(i);
boolean allowed = false;
if (pkg.isUpdatedSystemApp()) {
// New library entries can only be added through the
// system image. This is important to get rid of a lot
// of nasty edge cases: for example if we allowed a non-
// system update of the app to add a library, then uninstalling
// the update would make the library go away, and assumptions
// we made such as through app install filtering would now
// have allowed apps on the device which aren't compatible
// with it. Better to just have the restriction here, be
// conservative, and create many fewer cases that can negatively
// impact the user experience.
final PackageSetting sysPs = mSettings
.getDisabledSystemPkgLPr(pkg.packageName);
if (sysPs.pkg != null && sysPs.pkg.libraryNames != null) {
for (int j=0; j<sysPs.pkg.libraryNames.size(); j++) {
if (name.equals(sysPs.pkg.libraryNames.get(j))) {
allowed = true;
allowed = true;
break;
}
}
}
} else {
allowed = true;
}
if (allowed) {
if (!mSharedLibraries.containsKey(name)) {
mSharedLibraries.put(name, new SharedLibraryEntry(null, pkg.packageName));
} else if (!name.equals(pkg.packageName)) {
Slog.w(TAG, "Package " + pkg.packageName + " library "
+ name + " already exists; skipping");
}
} else {
Slog.w(TAG, "Package " + pkg.packageName + " declares lib "
+ name + " that is not declared on system image; skipping");
}
}
if ((scanFlags&SCAN_BOOTING) == 0) {
// If we are not booting, we need to update any applications
// that are clients of our shared library. If we are booting,
// this will all be done once the scan is complete.
clientLibPkgs = updateAllSharedLibrariesLPw(pkg);
}
}
}
}
// We also need to dexopt any apps that are dependent on this library. Note that
// if these fail, we should abort the install since installing the library will
// result in some apps being broken.
if (clientLibPkgs != null) {
if ((scanFlags & SCAN_NO_DEX) == 0) {
for (int i = 0; i < clientLibPkgs.size(); i++) {
PackageParser.Package clientPkg = clientLibPkgs.get(i);
int result = mPackageDexOptimizer.performDexOpt(clientPkg,
null /* instruction sets */, forceDex,
(scanFlags & SCAN_DEFER_DEX) != 0, false,
(scanFlags & SCAN_BOOTING) == 0);
if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
throw new PackageManagerException(INSTALL_FAILED_DEXOPT,
"scanPackageLI failed to dexopt clientLibPkgs");
}
}
}
}
// Request the ActivityManager to kill the process(only for existing packages)
// so that we do not end up in a confused state while the user is still using the older
// version of the application while the new one gets installed.
if ((scanFlags & SCAN_REPLACING) != 0) {
killApplication(pkg.applicationInfo.packageName,
pkg.applicationInfo.uid, "replace pkg");
}
// Also need to kill any apps that are dependent on the library.
if (clientLibPkgs != null) {
for (int i=0; i<clientLibPkgs.size(); i++) {
PackageParser.Package clientPkg = clientLibPkgs.get(i);
killApplication(clientPkg.applicationInfo.packageName,
clientPkg.applicationInfo.uid, "update lib");
}
}
// Make sure we're not adding any bogus keyset info
KeySetManagerService ksms = mSettings.mKeySetManagerService;
ksms.assertScannedPackageValid(pkg);
//下面代码将四大组件存放在PKMS的变量中,方便对外提供统一的组件信息。
// writer
synchronized (mPackages) {
// We don't expect installation to fail beyond this point
// Add the new setting to mSettings
mSettings.insertPackageSettingLPw(pkgSetting, pkg);
// Add the new setting to mPackages
mPackages.put(pkg.applicationInfo.packageName, pkg);
// Make sure we don't accidentally delete its data.
final Iterator
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 ((parseFlags&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);
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 ((parseFlags & 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 ((parseFlags&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);
}
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 ((parseFlags&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);
}
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 ((parseFlags&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);
}
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 ((parseFlags&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);
}
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);
if (cur == null) {
mPermissionGroups.put(pg.info.name, pg);
if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
if (r == null) {
r = new StringBuilder(256);
} else {
r.append(' ');
}
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 ((parseFlags&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);
}
N = pkg.permissions.size();
r = null;
for (i=0; i
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
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 ((parseFlags&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 ((parseFlags&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);
}
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;
// TODO: Update instrumentation.nativeLibraryDir as well ? Does it
// need other information about the application, like the ABI and what not ?
a.info.nativeLibraryDir = pkg.applicationInfo.nativeLibraryDir;
mInstrumentation.put(a.getComponentName(), a);
if ((parseFlags&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
()); } ArrayMap
map = mOverlays.get(pkg.mOverlayTarget); map.put(pkg.packageName, pkg); PackageParser.Package orig = mPackages.get(pkg.mOverlayTarget); if (orig != null && !createIdmapForPackagePairLI(orig, pkg)) { throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "scanPackageLI failed to createIdmap"); } } } else if (mOverlays.containsKey(pkg.packageName) && !pkg.packageName.equals("android")) { // This is a regular package, with one or more known overlay packages. createIdmapsForPackageLI(pkg); } } return pkg; }
至此,PKMS扫描APK结束。