PackageManagerService的构造函数中调用了scanDirLI方法来扫描某个目录的apk文件。我们先来看看这个函数:
一、scanDirLI
- private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) {
- final File[] files = dir.listFiles();
- if (ArrayUtils.isEmpty(files)) {
- Log.d(TAG, "No files in app dir " + dir);
- return;
- }
-
- if (DEBUG_PACKAGE_SCANNING) {
- Log.d(TAG, "Scanning app dir " + dir + " scanFlags=" + scanFlags
- + " flags=0x" + Integer.toHexString(parseFlags));
- }
-
- for (File file : files) {
- final boolean isPackage = (isApkFile(file) || file.isDirectory())
- && !PackageInstallerService.isStageName(file.getName());
- if (!isPackage) {
-
- continue;
- }
- try {
- scanPackageLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,
- scanFlags, currentTime, null);
- } catch (PackageManagerException e) {
- Slog.w(TAG, "Failed to parse " + file + ": " + e.getMessage());
-
-
- if ((parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
- e.error == PackageManager.INSTALL_FAILED_INVALID_APK) {
- logCriticalInfo(Log.WARN, "Deleting invalid package at " + file);
- if (file.isDirectory()) {
- FileUtils.deleteContents(file);
- }
- file.delete();
- }
- }
- }
- }
scanDirLI如果目录下的是apk文件或者是目录,会继续调用scanPackageLI函数。
scanDirLI会调用scanPackageLI继续扫描过程,下面我们先来看看这个函数的第一部分
- 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 {
- pkg = pp.parsePackage(scanFile, parseFlags);
- } catch (PackageParserException e) {
- throw PackageManagerException.from(e);
- }
第一部分主要调用了PackageParser的parsePackage来解析文件,返回Package。
二、解析APK文件
下面我们来看看这个PackageParser的parsePackage函数:
- public Package parsePackage(File packageFile, int flags) throws PackageParserException {
- if (packageFile.isDirectory()) {
- return parseClusterPackage(packageFile, flags);
- } else {
- return parseMonolithicPackage(packageFile, flags);
- }
- }
parsePackage函数对应两个函数,如果是目录调用parseClusterPackage,如果是apk文件就调用parseMonolithicPackage
我们先来看看parseClusterPackage函数
- private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
- final PackageLite lite = parseClusterPackageLite(packageDir, 0);
-
- if (mOnlyCoreApps && !lite.coreApp) {
- throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
- "Not a coreApp: " + packageDir);
- }
-
- final AssetManager assets = new AssetManager();
- try {
-
-
- loadApkIntoAssetManager(assets, lite.baseCodePath, flags);
-
- if (!ArrayUtils.isEmpty(lite.splitCodePaths)) {
- for (String path : lite.splitCodePaths) {
- loadApkIntoAssetManager(assets, path, flags);
- }
- }
-
- final File baseApk = new File(lite.baseCodePath);
- final Package pkg = parseBaseApk(baseApk, assets, flags);
- if (pkg == null) {
- throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
- "Failed to parse base APK: " + baseApk);
- }
-
- if (!ArrayUtils.isEmpty(lite.splitNames)) {
- final int num = lite.splitNames.length;
- pkg.splitNames = lite.splitNames;
- pkg.splitCodePaths = lite.splitCodePaths;
- pkg.splitRevisionCodes = lite.splitRevisionCodes;
- pkg.splitFlags = new int[num];
-
- for (int i = 0; i < num; i++) {
- parseSplitApk(pkg, i, assets, flags);
- }
- }
-
- pkg.codePath = packageDir.getAbsolutePath();
- return pkg;
- } finally {
- IoUtils.closeQuietly(assets);
- }
- }
parseClusterPackage函数先调用了parseClusterPackageLite函数对目录下的apk文件进行初步分析,主要区别是核心应用还是非核心应用。核心应用只有一个,非核心应用可以没有,或者多个,非核心应用的作用主要用来保存资源和代码。然后对核心应用调用parseBaseApk分析并生成Package。对非核心应用调用parseSplitApk,分析结果放在前面的Package对象中。
而parseBaseApk只是对AndroidManifest.xml进行解析,我们就不分析了,解析后所有的信息放在Package对象中。
三、scanPackageLI
我们继续分析scanPackageLI函数,下面是处理更改了包名的应用。
- PackageSetting ps = null;
- PackageSetting updatedPkg;
-
- synchronized (mPackages) {
-
- String oldName = mSettings.mRenamedPackages.get(pkg.packageName);
- if (pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(oldName)) {
-
-
- ps = mSettings.peekPackageLPr(oldName);
- }
-
- if (ps == null) {
- ps = mSettings.peekPackageLPr(pkg.packageName);
- }
处理安装升级包的系统应用,详细就不分析了,把代码帖出来。
- updatedPkg = mSettings.getDisabledSystemPkgLPr(ps != null ? ps.name : pkg.packageName);
- if (DEBUG_INSTALL && updatedPkg != null) Slog.d(TAG, "updatedPkg = " + updatedPkg);
- }
- boolean updatedPkgBetter = false;
-
- if (updatedPkg != null && (parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
-
-
- if (locationIsPrivileged(scanFile)) {
- updatedPkg.pkgFlags |= ApplicationInfo.FLAG_PRIVILEGED;
- } else {
- updatedPkg.pkgFlags &= ~ApplicationInfo.FLAG_PRIVILEGED;
- }
-
- if (ps != null && !ps.codePath.equals(scanFile)) {
-
-
-
- if (DEBUG_INSTALL) Slog.d(TAG, "Path changing from " + ps.codePath);
- if (pkg.mVersionCode <= ps.versionCode) {
-
-
- Slog.i(TAG, "Package " + ps.name + " at " + scanFile
- + " ignored: updated version " + ps.versionCode
- + " better than this " + pkg.mVersionCode);
- if (!updatedPkg.codePath.equals(scanFile)) {
- Slog.w(PackageManagerService.TAG, "Code path for hidden system pkg : "
- + ps.name + " changing from " + updatedPkg.codePathString
- + " to " + scanFile);
- updatedPkg.codePath = scanFile;
- updatedPkg.codePathString = scanFile.toString();
- }
- updatedPkg.pkg = pkg;
- throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE, null);
- } else {
-
-
-
-
-
-
-
- synchronized (mPackages) {
-
- mPackages.remove(ps.name);
- }
-
- 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, ps.legacyNativeLibraryPathString,
- getAppDexInstructionSets(ps));
- synchronized (mInstallLock) {
- args.cleanUpResourcesLI();
- }
- synchronized (mPackages) {
- mSettings.enableSystemPackageLPw(ps.name);
- }
- updatedPkgBetter = true;
- }
- }
- }
-
- if (updatedPkg != null) {
-
-
- parseFlags |= PackageParser.PARSE_IS_SYSTEM;
-
-
-
- if ((updatedPkg.pkgFlags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {
- parseFlags |= PackageParser.PARSE_IS_PRIVILEGED;
- }
- }
扫描文件的签名
- collectCertificatesLI(pp, ps, pkg, scanFile, parseFlags);
处理应用包名冲突的情况
- boolean shouldHideSystemApp = false;
- if (updatedPkg == null && ps != null
- && (parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0 && !isSystemApp(ps)) {
-
-
-
-
- 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 (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 {
-
-
-
-
-
-
- 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, ps.legacyNativeLibraryPathString,
- getAppDexInstructionSets(ps));
- synchronized (mInstallLock) {
- args.cleanUpResourcesLI();
- }
- }
- }
- }
处理应用的代码路径和资源路径
- if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
- if (ps != null && !ps.codePath.equals(ps.resourcePath)) {
- parseFlags |= PackageParser.PARSE_FORWARD_LOCK;
- }
- }
-
-
- 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 {
-
- Slog.e(TAG, "Resource path not set for pkg : " + pkg.packageName);
- }
- } else {
- resourcePath = pkg.codePath;
- baseResourcePath = pkg.baseCodePath;
- }
-
-
- 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函数,第一个参数是Package
- PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanFlags
- | SCAN_UPDATE_SIGNATURE, currentTime, user);
四、scanPackageDirtyLI
这个函数主要调用了scanPackageDirtyLI,这个函数非常长,我们介绍下主要功能。
1.建立ResolverActivity的内存对象
就是当发出一个Intent,如果有多个Activity响应该Intent的Activity,会弹出一个对话框让用户选择,这个对话框就是ResolverActivity。
2.处理带有original-package标签的应用
3.校验签名
4.检查ContentProvider名称
5.确定应用将来的进程名称
6.创建应用的数据目录
7.安装动态库
8.重新优化dex
9.提取应用中的组件信息
把应用的Activity、Service、Provider、Receiver信息、Permission、PermissionGroup信息都提取出来加入到PackageManagerService的成员变量中。
final ActivityIntentResolver mActivities;
final ActivityIntentResolver mReceivers;
final ActivityIntentResolver mServices;
final ActivityIntentResolver mProviders;
系统中所有的组件信息都会加入到这4个变量中。Android系统运行时对Intent的解析就是通过这些变量查找的。
我们在看下这个函数的:
- pkgSetting = mSettings.getPackageLPw(pkg, origPackage, realName, suid, destCodeFile,
- destResourceFile, pkg.applicationInfo.nativeLibraryRootDir,
- pkg.applicationInfo.primaryCpuAbi,
- pkg.applicationInfo.secondaryCpuAbi,
- pkg.applicationInfo.flags, user, false);
以及把pkgSetting赋给pkg的mExtras成员变量。
- pkg.mExtras = pkgSetting;
下面我们再来看看mSettings.getPackageLPw函数:
- PackageSetting getPackageLPw(PackageParser.Package pkg, PackageSetting origPackage,
- String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
- String legacyNativeLibraryPathString, String primaryCpuAbi, String secondaryCpuAbi,
- int pkgFlags, UserHandle user, boolean add) {
- final String name = pkg.packageName;
- PackageSetting p = getPackageLPw(name, origPackage, realName, sharedUser, codePath,
- resourcePath, legacyNativeLibraryPathString, primaryCpuAbi, secondaryCpuAbi,
- pkg.mVersionCode, pkgFlags, user, add, true );
- return p;
- }
调用了getPackageLPw函数
- private PackageSetting getPackageLPw(String name, PackageSetting origPackage,
- String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
- String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString,
- int vc, int pkgFlags, UserHandle installUser, boolean add,
- boolean allowInstall) {
- PackageSetting p = mPackages.get(name);
- UserManagerService userManager = UserManagerService.getInstance();
- if (p != null) {
- .......
- }
- if (p == null) {
- if (origPackage != null) {
- .......
- } else {
- p = new PackageSetting(name, realName, codePath, resourcePath,
- legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString,
- null , vc, pkgFlags);
- ..........
- }
- if (add) {
-
-
- addPackageSettingLPw(p, name, sharedUser);
- }
- } else {
- if (installUser != null && allowInstall) {
-
-
-
- List users = getAllUsers();
- if (users != null) {
- for (UserInfo user : users) {
- if ((installUser.getIdentifier() == UserHandle.USER_ALL
- && !isAdbInstallDisallowed(userManager, user.id))
- || installUser.getIdentifier() == user.id) {
- boolean installed = p.getInstalled(user.id);
- if (!installed) {
- p.setInstalled(true, user.id);
- writePackageRestrictionsLPr(user.id);
- }
- }
- }
- }
- }
- }
- return p;
- }
所以整个文件扫描完后,mSettings的mPackages也会填充。
五、回顾PackageManagerService中的updatePermissionsLPw函数
- private void updatePermissionsLPw(String changingPkg,
- PackageParser.Package pkgInfo, int flags) {
-
- Iterator it = mSettings.mPermissionTrees.values().iterator();
- while (it.hasNext()) {
- final BasePermission bp = it.next();
- if (bp.packageSetting == null) {
-
-
- bp.packageSetting = mSettings.mPackages.get(bp.sourcePackage);
- }
- if (bp.packageSetting == null) {
- Slog.w(TAG, "Removing dangling permission tree: " + bp.name
- + " from package " + bp.sourcePackage);
- it.remove();
- } else if (changingPkg != null && changingPkg.equals(bp.sourcePackage)) {
- if (pkgInfo == null || !hasPermission(pkgInfo, bp.name)) {
- Slog.i(TAG, "Removing old permission tree: " + bp.name
- + " from package " + bp.sourcePackage);
- flags |= UPDATE_PERMISSIONS_ALL;
- it.remove();
- }
- }
- }
-
-
-
- it = mSettings.mPermissions.values().iterator();
- while (it.hasNext()) {
- final BasePermission bp = it.next();
- if (bp.type == BasePermission.TYPE_DYNAMIC) {
- if (DEBUG_SETTINGS) Log.v(TAG, "Dynamic permission: name="
- + bp.name + " pkg=" + bp.sourcePackage
- + " info=" + bp.pendingInfo);
- if (bp.packageSetting == null && bp.pendingInfo != null) {
- final BasePermission tree = findPermissionTreeLP(bp.name);
- if (tree != null && tree.perm != null) {
- bp.packageSetting = tree.packageSetting;
- bp.perm = new PackageParser.Permission(tree.perm.owner,
- new PermissionInfo(bp.pendingInfo));
- bp.perm.info.packageName = tree.perm.info.packageName;
- bp.perm.info.name = bp.name;
- bp.uid = tree.uid;
- }
- }
- }
- if (bp.packageSetting == null) {
-
-
- bp.packageSetting = mSettings.mPackages.get(bp.sourcePackage);
- }
- if (bp.packageSetting == null) {
- Slog.w(TAG, "Removing dangling permission: " + bp.name
- + " from package " + bp.sourcePackage);
- it.remove();
- } else if (changingPkg != null && changingPkg.equals(bp.sourcePackage)) {
- if (pkgInfo == null || !hasPermission(pkgInfo, bp.name)) {
- Slog.i(TAG, "Removing old permission: " + bp.name
- + " from package " + bp.sourcePackage);
- flags |= UPDATE_PERMISSIONS_ALL;
- it.remove();
- }
- }
- }
-
-
-
- if ((flags&UPDATE_PERMISSIONS_ALL) != 0) {
- for (PackageParser.Package pkg : mPackages.values()) {
- if (pkg != pkgInfo) {
- grantPermissionsLPw(pkg, (flags&UPDATE_PERMISSIONS_REPLACE_ALL) != 0,
- changingPkg);
- }
- }
- }
-
- if (pkgInfo != null) {
- grantPermissionsLPw(pkgInfo, (flags&UPDATE_PERMISSIONS_REPLACE_PKG) != 0, changingPkg);
- }
- }
在这个函数最后遍历mPackages调用了grantPermissionsLPw来赋给应用权限。mPackages在前面扫描应用的时候已经填充了。
我们下面再来看下grantPermissionsLPw函数
- private void grantPermissionsLPw(PackageParser.Package pkg, boolean replace,
- String packageOfInterest) {
- final PackageSetting ps = (PackageSetting) pkg.mExtras;
- if (ps == null) {
- return;
- }
- final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps;
- ArraySet origPermissions = gp.grantedPermissions;
- boolean changedPermission = false;
-
- if (replace) {
- ps.permissionsFixed = false;
- if (gp == ps) {
- origPermissions = new ArraySet(gp.grantedPermissions);
- gp.grantedPermissions.clear();
- gp.gids = mGlobalGids;
- }
- }
-
- if (gp.gids == null) {
- gp.gids = mGlobalGids;
- }
-
- final int N = pkg.requestedPermissions.size();
- for (int i=0; i
- final String name = pkg.requestedPermissions.get(i);
- final boolean required = pkg.requestedPermissionsRequired.get(i);
- final BasePermission bp = mSettings.mPermissions.get(name);
- if (DEBUG_INSTALL) {
- if (gp != ps) {
- Log.i(TAG, "Package " + pkg.packageName + " checking " + name + ": " + bp);
- }
- }
-
- if (bp == null || bp.packageSetting == null) {
- if (packageOfInterest == null || packageOfInterest.equals(pkg.packageName)) {
- Slog.w(TAG, "Unknown permission " + name
- + " in package " + pkg.packageName);
- }
- continue;
- }
-
- final String perm = bp.name;
- boolean allowed;
- boolean allowedSig = false;
- if ((bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_APPOP) != 0) {
-
- ArraySet pkgs = mAppOpPermissionPackages.get(bp.name);
- if (pkgs == null) {
- pkgs = new ArraySet<>();
- mAppOpPermissionPackages.put(bp.name, pkgs);
- }
- pkgs.add(pkg.packageName);
- }
- final int level = bp.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
- if (level == PermissionInfo.PROTECTION_NORMAL
- || level == PermissionInfo.PROTECTION_DANGEROUS) {
-
-
-
-
-
-
-
-
- allowed = (required || origPermissions.contains(perm)
- || (isSystemApp(ps) && !isUpdatedSystemApp(ps)));
- } else if (bp.packageSetting == null) {
-
- allowed = false;
- } else if (level == PermissionInfo.PROTECTION_SIGNATURE) {
- allowed = grantSignaturePermission(perm, pkg, bp, origPermissions);
- if (allowed) {
- allowedSig = true;
- }
- } else {
- allowed = false;
- }
- if (DEBUG_INSTALL) {
- if (gp != ps) {
- Log.i(TAG, "Package " + pkg.packageName + " granting " + perm);
- }
- }
- if (allowed) {
- if (!isSystemApp(ps) && ps.permissionsFixed) {
-
-
- if (!allowedSig && !gp.grantedPermissions.contains(perm)) {
-
-
-
- allowed = isNewPlatformPermissionForPackage(perm, pkg);
- }
- }
- if (allowed) {
- if (!gp.grantedPermissions.contains(perm)) {
- changedPermission = true;
- gp.grantedPermissions.add(perm);
- gp.gids = appendInts(gp.gids, bp.gids);
- } else if (!ps.haveGids) {
- gp.gids = appendInts(gp.gids, bp.gids);
- }
- } else {
- if (packageOfInterest == null || packageOfInterest.equals(pkg.packageName)) {
- Slog.w(TAG, "Not granting permission " + perm
- + " to package " + pkg.packageName
- + " because it was previously installed without");
- }
- }
- } else {
- if (gp.grantedPermissions.remove(perm)) {
- changedPermission = true;
- gp.gids = removeInts(gp.gids, bp.gids);
- Slog.i(TAG, "Un-granting permission " + perm
- + " from package " + pkg.packageName
- + " (protectionLevel=" + bp.protectionLevel
- + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)
- + ")");
- } else if ((bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_APPOP) == 0) {
-
-
- if (packageOfInterest == null || packageOfInterest.equals(pkg.packageName)) {
- Slog.w(TAG, "Not granting permission " + perm
- + " to package " + pkg.packageName
- + " (protectionLevel=" + bp.protectionLevel
- + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)
- + ")");
- }
- }
- }
- }
-
- if ((changedPermission || replace) && !ps.permissionsFixed &&
- !isSystemApp(ps) || isUpdatedSystemApp(ps)){
-
-
-
- ps.permissionsFixed = true;
- }
- ps.haveGids = true;
- }
这样后应用就有权限了。