Android 6.0 PKMS 深入分析 扫描应用目录

PackageManagerService的构造函数中调用了scanDirLI方法来扫描某个目录的apk文件。我们先来看看这个函数:

一、scanDirLI

[java] view plain copy
  1. private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) {  
  2.     final File[] files = dir.listFiles();  
  3.     if (ArrayUtils.isEmpty(files)) {//目录为空  
  4.         Log.d(TAG, "No files in app dir " + dir);  
  5.         return;  
  6.     }  
  7.   
  8.     if (DEBUG_PACKAGE_SCANNING) {  
  9.         Log.d(TAG, "Scanning app dir " + dir + " scanFlags=" + scanFlags  
  10.                 + " flags=0x" + Integer.toHexString(parseFlags));  
  11.     }  
  12.   
  13.     for (File file : files) {  
  14.         final boolean isPackage = (isApkFile(file) || file.isDirectory())//是Apk文件,或者是目录  
  15.                 && !PackageInstallerService.isStageName(file.getName());  
  16.         if (!isPackage) {//忽略非应用文件  
  17.             // Ignore entries which are not packages  
  18.             continue;  
  19.         }  
  20.         try {//调用scanPackageLI扫描文件  
  21.             scanPackageLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,  
  22.                     scanFlags, currentTime, null);  
  23.         } catch (PackageManagerException e) {// 失败,删除文件数据  
  24.             Slog.w(TAG, "Failed to parse " + file + ": " + e.getMessage());  
  25.   
  26.             // Delete invalid userdata apps  
  27.             if ((parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&  
  28.                     e.error == PackageManager.INSTALL_FAILED_INVALID_APK) {  
  29.                 logCriticalInfo(Log.WARN, "Deleting invalid package at " + file);  
  30.                 if (file.isDirectory()) {  
  31.                     FileUtils.deleteContents(file);  
  32.                 }  
  33.                 file.delete();  
  34.             }  
  35.         }  
  36.     }  
  37. }  

scanDirLI如果目录下的是apk文件或者是目录,会继续调用scanPackageLI函数。

scanDirLI会调用scanPackageLI继续扫描过程,下面我们先来看看这个函数的第一部分

[java] view plain copy
  1. private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,  
  2.         long currentTime, UserHandle user) throws PackageManagerException {  
  3.     if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);  
  4.     parseFlags |= mDefParseFlags;  
  5.     PackageParser pp = new PackageParser();  
  6.     pp.setSeparateProcesses(mSeparateProcesses);  
  7.     pp.setOnlyCoreApps(mOnlyCore);  
  8.     pp.setDisplayMetrics(mMetrics);  
  9.   
  10.     if ((scanFlags & SCAN_TRUSTED_OVERLAY) != 0) {  
  11.         parseFlags |= PackageParser.PARSE_TRUSTED_OVERLAY;  
  12.     }  
  13.   
  14.     final PackageParser.Package pkg;  
  15.     try {  
  16.         pkg = pp.parsePackage(scanFile, parseFlags);  
  17.     } catch (PackageParserException e) {  
  18.         throw PackageManagerException.from(e);  
  19.     }  

第一部分主要调用了PackageParser的parsePackage来解析文件,返回Package。


二、解析APK文件

下面我们来看看这个PackageParser的parsePackage函数:

[java] view plain copy
  1. public Package parsePackage(File packageFile, int flags) throws PackageParserException {  
  2.     if (packageFile.isDirectory()) {  
  3.         return parseClusterPackage(packageFile, flags);  
  4.     } else {  
  5.         return parseMonolithicPackage(packageFile, flags);  
  6.     }  
  7. }  

parsePackage函数对应两个函数,如果是目录调用parseClusterPackage,如果是apk文件就调用parseMonolithicPackage
我们先来看看parseClusterPackage函数

[java] view plain copy
  1. private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {  
  2.     final PackageLite lite = parseClusterPackageLite(packageDir, 0);//获取应用目录的PackageLite对象,这个对象分开保存了目录下的核心应用以及非核心应用的名称  
  3.   
  4.     if (mOnlyCoreApps && !lite.coreApp) {//如果lite中没有核心应用,退出  
  5.         throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,  
  6.                 "Not a coreApp: " + packageDir);  
  7.     }  
  8.   
  9.     final AssetManager assets = new AssetManager();  
  10.     try {  
  11.         // Load the base and all splits into the AssetManager  
  12.         // so that resources can be overriden when parsing the manifests.  
  13.         loadApkIntoAssetManager(assets, lite.baseCodePath, flags);//装载核心应用的资源  
  14.   
  15.         if (!ArrayUtils.isEmpty(lite.splitCodePaths)) {  
  16.             for (String path : lite.splitCodePaths) {  
  17.                 loadApkIntoAssetManager(assets, path, flags);//再装载非核心应用的资源  
  18.             }  
  19.         }  
  20.   
  21.         final File baseApk = new File(lite.baseCodePath);  
  22.         final Package pkg = parseBaseApk(baseApk, assets, flags);//对核心应用解析  
  23.         if (pkg == null) {  
  24.             throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,  
  25.                     "Failed to parse base APK: " + baseApk);  
  26.         }  
  27.   
  28.         if (!ArrayUtils.isEmpty(lite.splitNames)) {  
  29.             final int num = lite.splitNames.length;  
  30.             pkg.splitNames = lite.splitNames;  
  31.             pkg.splitCodePaths = lite.splitCodePaths;  
  32.             pkg.splitRevisionCodes = lite.splitRevisionCodes;  
  33.             pkg.splitFlags = new int[num];  
  34.   
  35.             for (int i = 0; i < num; i++) {  
  36.                 parseSplitApk(pkg, i, assets, flags);//对非核心应用的处理  
  37.             }  
  38.         }  
  39.   
  40.         pkg.codePath = packageDir.getAbsolutePath();  
  41.         return pkg;  
  42.     } finally {  
  43.         IoUtils.closeQuietly(assets);  
  44.     }  
  45. }  

parseClusterPackage函数先调用了parseClusterPackageLite函数对目录下的apk文件进行初步分析,主要区别是核心应用还是非核心应用。核心应用只有一个,非核心应用可以没有,或者多个,非核心应用的作用主要用来保存资源和代码。然后对核心应用调用parseBaseApk分析并生成Package。对非核心应用调用parseSplitApk,分析结果放在前面的Package对象中。

而parseBaseApk只是对AndroidManifest.xml进行解析,我们就不分析了,解析后所有的信息放在Package对象中。


三、scanPackageLI


我们继续分析scanPackageLI函数,下面是处理更改了包名的应用。

[java] view plain copy
  1. PackageSetting ps = null;  
  2.         PackageSetting updatedPkg;  
  3.         // reader  
  4.         synchronized (mPackages) {  
  5.             // Look to see if we already know about this package.  
  6.             String oldName = mSettings.mRenamedPackages.get(pkg.packageName);  
  7.             if (pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(oldName)) {  
  8.                 // This package has been renamed to its original name.  Let's  
  9.                 // use that.  
  10.                 ps = mSettings.peekPackageLPr(oldName);  
  11.             }  
  12.             // If there was no original package, see one for the real package name.  
  13.             if (ps == null) {  
  14.                 ps = mSettings.peekPackageLPr(pkg.packageName);  
  15.             }  

处理安装升级包的系统应用,详细就不分析了,把代码帖出来。

[java] view plain copy
  1.  updatedPkg = mSettings.getDisabledSystemPkgLPr(ps != null ? ps.name : pkg.packageName);  
  2.     if (DEBUG_INSTALL && updatedPkg != null) Slog.d(TAG, "updatedPkg = " + updatedPkg);  
  3. }  
  4. boolean updatedPkgBetter = false;  
  5. // First check if this is a system package that may involve an update  
  6. if (updatedPkg != null && (parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {  
  7.     // If new package is not located in "/system/priv-app" (e.g. due to an OTA),  
  8.     // it needs to drop FLAG_PRIVILEGED.  
  9.     if (locationIsPrivileged(scanFile)) {  
  10.         updatedPkg.pkgFlags |= ApplicationInfo.FLAG_PRIVILEGED;  
  11.     } else {  
  12.         updatedPkg.pkgFlags &= ~ApplicationInfo.FLAG_PRIVILEGED;  
  13.     }  
  14.   
  15.     if (ps != null && !ps.codePath.equals(scanFile)) {  
  16.         // The path has changed from what was last scanned...  check the  
  17.         // version of the new path against what we have stored to determine  
  18.         // what to do.  
  19.         if (DEBUG_INSTALL) Slog.d(TAG, "Path changing from " + ps.codePath);  
  20.         if (pkg.mVersionCode <= ps.versionCode) {  
  21.             // The system package has been updated and the code path does not match  
  22.             // Ignore entry. Skip it.  
  23.             Slog.i(TAG, "Package " + ps.name + " at " + scanFile  
  24.                     + " ignored: updated version " + ps.versionCode  
  25.                     + " better than this " + pkg.mVersionCode);  
  26.             if (!updatedPkg.codePath.equals(scanFile)) {  
  27.                 Slog.w(PackageManagerService.TAG, "Code path for hidden system pkg : "  
  28.                         + ps.name + " changing from " + updatedPkg.codePathString  
  29.                         + " to " + scanFile);  
  30.                 updatedPkg.codePath = scanFile;  
  31.                 updatedPkg.codePathString = scanFile.toString();  
  32.             }  
  33.             updatedPkg.pkg = pkg;  
  34.             throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE, null);  
  35.         } else {  
  36.             // The current app on the system partition is better than  
  37.             // what we have updated to on the data partition; switch  
  38.             // back to the system partition version.  
  39.             // At this point, its safely assumed that package installation for  
  40.             // apps in system partition will go through. If not there won't be a working  
  41.             // version of the app  
  42.             // writer  
  43.             synchronized (mPackages) {  
  44.                 // Just remove the loaded entries from package lists.  
  45.                 mPackages.remove(ps.name);  
  46.             }  
  47.   
  48.             logCriticalInfo(Log.WARN, "Package " + ps.name + " at " + scanFile  
  49.                     + " reverting from " + ps.codePathString  
  50.                     + ": new version " + pkg.mVersionCode  
  51.                     + " better than installed " + ps.versionCode);  
  52.   
  53.             InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),  
  54.                     ps.codePathString, ps.resourcePathString, ps.legacyNativeLibraryPathString,  
  55.                     getAppDexInstructionSets(ps));  
  56.             synchronized (mInstallLock) {  
  57.                 args.cleanUpResourcesLI();  
  58.             }  
  59.             synchronized (mPackages) {  
  60.                 mSettings.enableSystemPackageLPw(ps.name);  
  61.             }  
  62.             updatedPkgBetter = true;  
  63.         }  
  64.     }  
  65. }  
  66.   
  67. if (updatedPkg != null) {  
  68.     // An updated system app will not have the PARSE_IS_SYSTEM flag set  
  69.     // initially  
  70.     parseFlags |= PackageParser.PARSE_IS_SYSTEM;  
  71.   
  72.     // An updated privileged app will not have the PARSE_IS_PRIVILEGED  
  73.     // flag set initially  
  74.     if ((updatedPkg.pkgFlags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {  
  75.         parseFlags |= PackageParser.PARSE_IS_PRIVILEGED;  
  76.     }  
  77. }  

扫描文件的签名

[java] view plain copy
  1. collectCertificatesLI(pp, ps, pkg, scanFile, parseFlags);  

处理应用包名冲突的情况

[java] view plain copy
  1. boolean shouldHideSystemApp = false;  
  2. if (updatedPkg == null && ps != null  
  3.         && (parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0 && !isSystemApp(ps)) {  
  4.     /* 
  5.      * Check to make sure the signatures match first. If they don't, 
  6.      * wipe the installed application and its data. 
  7.      */  
  8.     if (compareSignatures(ps.signatures.mSignatures, pkg.mSignatures)  
  9.             != PackageManager.SIGNATURE_MATCH) {  
  10.         logCriticalInfo(Log.WARN, "Package " + ps.name + " appeared on system, but"  
  11.                 + " signatures don't match existing userdata copy; removing");  
  12.         deletePackageLI(pkg.packageName, nulltruenullnull0nullfalse);  
  13.         ps = null;  
  14.     } else {  
  15.         /* 
  16.          * If the newly-added system app is an older version than the 
  17.          * already installed version, hide it. It will be scanned later 
  18.          * and re-added like an update. 
  19.          */  
  20.         if (pkg.mVersionCode <= ps.versionCode) {  
  21.             shouldHideSystemApp = true;  
  22.             logCriticalInfo(Log.INFO, "Package " + ps.name + " appeared at " + scanFile  
  23.                     + " but new version " + pkg.mVersionCode + " better than installed "  
  24.                     + ps.versionCode + "; hiding system");  
  25.         } else {  
  26.             /* 
  27.              * The newly found system app is a newer version that the 
  28.              * one previously installed. Simply remove the 
  29.              * already-installed application and replace it with our own 
  30.              * while keeping the application data. 
  31.              */  
  32.             logCriticalInfo(Log.WARN, "Package " + ps.name + " at " + scanFile  
  33.                     + " reverting from " + ps.codePathString + ": new version "  
  34.                     + pkg.mVersionCode + " better than installed " + ps.versionCode);  
  35.             InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),  
  36.                     ps.codePathString, ps.resourcePathString, ps.legacyNativeLibraryPathString,  
  37.                     getAppDexInstructionSets(ps));  
  38.             synchronized (mInstallLock) {  
  39.                 args.cleanUpResourcesLI();  
  40.             }  
  41.         }  
  42.     }  
  43. }  

处理应用的代码路径和资源路径

[java] view plain copy
  1. if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {  
  2.     if (ps != null && !ps.codePath.equals(ps.resourcePath)) {  
  3.         parseFlags |= PackageParser.PARSE_FORWARD_LOCK;  
  4.     }  
  5. }  
  6.   
  7. // TODO: extend to support forward-locked splits  
  8. String resourcePath = null;  
  9. String baseResourcePath = null;  
  10. if ((parseFlags & PackageParser.PARSE_FORWARD_LOCK) != 0 && !updatedPkgBetter) {  
  11.     if (ps != null && ps.resourcePathString != null) {  
  12.         resourcePath = ps.resourcePathString;  
  13.         baseResourcePath = ps.resourcePathString;  
  14.     } else {  
  15.         // Should not happen at all. Just log an error.  
  16.         Slog.e(TAG, "Resource path not set for pkg : " + pkg.packageName);  
  17.     }  
  18. else {  
  19.     resourcePath = pkg.codePath;  
  20.     baseResourcePath = pkg.baseCodePath;  
  21. }  
  22.   
  23. // Set application objects path explicitly.  
  24. pkg.applicationInfo.setCodePath(pkg.codePath);  
  25. pkg.applicationInfo.setBaseCodePath(pkg.baseCodePath);  
  26. pkg.applicationInfo.setSplitCodePaths(pkg.splitCodePaths);  
  27. pkg.applicationInfo.setResourcePath(resourcePath);  
  28. pkg.applicationInfo.setBaseResourcePath(baseResourcePath);  
  29. pkg.applicationInfo.setSplitResourcePaths(pkg.splitCodePaths);  

接下来又调用了scanPackageLI函数,第一个参数是Package

[java] view plain copy
  1. PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanFlags  
  2.         | 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的解析就是通过这些变量查找的。


我们在看下这个函数的:

[java] view plain copy
  1. pkgSetting = mSettings.getPackageLPw(pkg, origPackage, realName, suid, destCodeFile,  
  2.         destResourceFile, pkg.applicationInfo.nativeLibraryRootDir,  
  3.         pkg.applicationInfo.primaryCpuAbi,  
  4.         pkg.applicationInfo.secondaryCpuAbi,  
  5.         pkg.applicationInfo.flags, user, false);  

以及把pkgSetting赋给pkg的mExtras成员变量。

[java] view plain copy
  1. pkg.mExtras = pkgSetting;  

下面我们再来看看mSettings.getPackageLPw函数:

[java] view plain copy
  1. PackageSetting getPackageLPw(PackageParser.Package pkg, PackageSetting origPackage,  
  2.         String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,  
  3.         String legacyNativeLibraryPathString, String primaryCpuAbi, String secondaryCpuAbi,  
  4.         int pkgFlags, UserHandle user, boolean add) {  
  5.     final String name = pkg.packageName;  
  6.     PackageSetting p = getPackageLPw(name, origPackage, realName, sharedUser, codePath,  
  7.             resourcePath, legacyNativeLibraryPathString, primaryCpuAbi, secondaryCpuAbi,  
  8.             pkg.mVersionCode, pkgFlags, user, add, true /* allowInstall */);  
  9.     return p;  
  10. }  
调用了getPackageLPw函数
[java] view plain copy
  1.  private PackageSetting getPackageLPw(String name, PackageSetting origPackage,  
  2.          String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,  
  3.          String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString,  
  4.          int vc, int pkgFlags, UserHandle installUser, boolean add,  
  5.          boolean allowInstall) {  
  6.      PackageSetting p = mPackages.get(name);  
  7.      UserManagerService userManager = UserManagerService.getInstance();  
  8.      if (p != null) {  
  9. .......  
  10.      }  
  11.      if (p == null) {//为空时  
  12.          if (origPackage != null) {  
  13.              .......  
  14.          } else {  
  15.              p = new PackageSetting(name, realName, codePath, resourcePath,//新建一个PackageSetting  
  16.                      legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString,  
  17.                      null /* cpuAbiOverrideString */, vc, pkgFlags);  
  18.              ..........  
  19. }  
  20.          if (add) {// 这时传入true  
  21.              // Finish adding new package by adding it and updating shared  
  22.              // user preferences  
  23.              addPackageSettingLPw(p, name, sharedUser);//加入到Settings的mPackages中  
  24.          }  
  25.      } else {  
  26.          if (installUser != null && allowInstall) {  
  27.              // The caller has explicitly specified the user they want this  
  28.              // package installed for, and the package already exists.  
  29.              // Make sure it conforms to the new request.  
  30.              List users = getAllUsers();  
  31.              if (users != null) {  
  32.                  for (UserInfo user : users) {  
  33.                      if ((installUser.getIdentifier() == UserHandle.USER_ALL  
  34.                                  && !isAdbInstallDisallowed(userManager, user.id))  
  35.                              || installUser.getIdentifier() == user.id) {  
  36.                          boolean installed = p.getInstalled(user.id);  
  37.                          if (!installed) {  
  38.                              p.setInstalled(true, user.id);  
  39.                              writePackageRestrictionsLPr(user.id);  
  40.                          }  
  41.                      }  
  42.                  }  
  43.              }  
  44.          }  
  45.      }  
  46.      return p;  
  47.  }  

所以整个文件扫描完后,mSettings的mPackages也会填充。


五、回顾PackageManagerService中的updatePermissionsLPw函数

[java] view plain copy
  1. private void updatePermissionsLPw(String changingPkg,  
  2.         PackageParser.Package pkgInfo, int flags) {  
  3.     // Make sure there are no dangling permission trees.  
  4.     Iterator it = mSettings.mPermissionTrees.values().iterator();  
  5.     while (it.hasNext()) {  
  6.         final BasePermission bp = it.next();  
  7.         if (bp.packageSetting == null) {  
  8.             // We may not yet have parsed the package, so just see if  
  9.             // we still know about its settings.  
  10.             bp.packageSetting = mSettings.mPackages.get(bp.sourcePackage);  
  11.         }  
  12.         if (bp.packageSetting == null) {  
  13.             Slog.w(TAG, "Removing dangling permission tree: " + bp.name  
  14.                     + " from package " + bp.sourcePackage);  
  15.             it.remove();  
  16.         } else if (changingPkg != null && changingPkg.equals(bp.sourcePackage)) {  
  17.             if (pkgInfo == null || !hasPermission(pkgInfo, bp.name)) {  
  18.                 Slog.i(TAG, "Removing old permission tree: " + bp.name  
  19.                         + " from package " + bp.sourcePackage);  
  20.                 flags |= UPDATE_PERMISSIONS_ALL;  
  21.                 it.remove();  
  22.             }  
  23.         }  
  24.     }  
  25.   
  26.     // Make sure all dynamic permissions have been assigned to a package,  
  27.     // and make sure there are no dangling permissions.  
  28.     it = mSettings.mPermissions.values().iterator();  
  29.     while (it.hasNext()) {  
  30.         final BasePermission bp = it.next();  
  31.         if (bp.type == BasePermission.TYPE_DYNAMIC) {  
  32.             if (DEBUG_SETTINGS) Log.v(TAG, "Dynamic permission: name="  
  33.                     + bp.name + " pkg=" + bp.sourcePackage  
  34.                     + " info=" + bp.pendingInfo);  
  35.             if (bp.packageSetting == null && bp.pendingInfo != null) {  
  36.                 final BasePermission tree = findPermissionTreeLP(bp.name);  
  37.                 if (tree != null && tree.perm != null) {  
  38.                     bp.packageSetting = tree.packageSetting;  
  39.                     bp.perm = new PackageParser.Permission(tree.perm.owner,  
  40.                             new PermissionInfo(bp.pendingInfo));  
  41.                     bp.perm.info.packageName = tree.perm.info.packageName;  
  42.                     bp.perm.info.name = bp.name;  
  43.                     bp.uid = tree.uid;  
  44.                 }  
  45.             }  
  46.         }  
  47.         if (bp.packageSetting == null) {  
  48.             // We may not yet have parsed the package, so just see if  
  49.             // we still know about its settings.  
  50.             bp.packageSetting = mSettings.mPackages.get(bp.sourcePackage);  
  51.         }  
  52.         if (bp.packageSetting == null) {  
  53.             Slog.w(TAG, "Removing dangling permission: " + bp.name  
  54.                     + " from package " + bp.sourcePackage);  
  55.             it.remove();  
  56.         } else if (changingPkg != null && changingPkg.equals(bp.sourcePackage)) {  
  57.             if (pkgInfo == null || !hasPermission(pkgInfo, bp.name)) {  
  58.                 Slog.i(TAG, "Removing old permission: " + bp.name  
  59.                         + " from package " + bp.sourcePackage);  
  60.                 flags |= UPDATE_PERMISSIONS_ALL;  
  61.                 it.remove();  
  62.             }  
  63.         }  
  64.     }  
  65.   
  66.     // Now update the permissions for all packages, in particular  
  67.     // replace the granted permissions of the system packages.  
  68.     if ((flags&UPDATE_PERMISSIONS_ALL) != 0) {  
  69.         for (PackageParser.Package pkg : mPackages.values()) {  
  70.             if (pkg != pkgInfo) {  
  71.                 grantPermissionsLPw(pkg, (flags&UPDATE_PERMISSIONS_REPLACE_ALL) != 0,  
  72.                         changingPkg);  
  73.             }  
  74.         }  
  75.     }  
  76.       
  77.     if (pkgInfo != null) {  
  78.         grantPermissionsLPw(pkgInfo, (flags&UPDATE_PERMISSIONS_REPLACE_PKG) != 0, changingPkg);  
  79.     }  
  80. }  

在这个函数最后遍历mPackages调用了grantPermissionsLPw来赋给应用权限。mPackages在前面扫描应用的时候已经填充了。

我们下面再来看下grantPermissionsLPw函数

[java] view plain copy
  1. private void grantPermissionsLPw(PackageParser.Package pkg, boolean replace,  
  2.         String packageOfInterest) {  
  3.     final PackageSetting ps = (PackageSetting) pkg.mExtras;  
  4.     if (ps == null) {  
  5.         return;  
  6.     }  
  7.     final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps;  
  8.     ArraySet origPermissions = gp.grantedPermissions;  
  9.     boolean changedPermission = false;  
  10.   
  11.     if (replace) {  
  12.         ps.permissionsFixed = false;  
  13.         if (gp == ps) {  
  14.             origPermissions = new ArraySet(gp.grantedPermissions);  
  15.             gp.grantedPermissions.clear();  
  16.             gp.gids = mGlobalGids;  
  17.         }  
  18.     }  
  19.   
  20.     if (gp.gids == null) {  
  21.         gp.gids = mGlobalGids;  
  22.     }  
  23.   
  24.     final int N = pkg.requestedPermissions.size();//遍历pkg中需要申请的权限  
  25.     for (int i=0; i
  26.         final String name = pkg.requestedPermissions.get(i);  
  27.         final boolean required = pkg.requestedPermissionsRequired.get(i);  
  28.         final BasePermission bp = mSettings.mPermissions.get(name);//看mPermission对应name的BasePermission  
  29.         if (DEBUG_INSTALL) {  
  30.             if (gp != ps) {  
  31.                 Log.i(TAG, "Package " + pkg.packageName + " checking " + name + ": " + bp);  
  32.             }  
  33.         }  
  34.   
  35.         if (bp == null || bp.packageSetting == null) {  
  36.             if (packageOfInterest == null || packageOfInterest.equals(pkg.packageName)) {  
  37.                 Slog.w(TAG, "Unknown permission " + name  
  38.                         + " in package " + pkg.packageName);  
  39.             }  
  40.             continue;  
  41.         }  
  42.   
  43.         final String perm = bp.name;  
  44.         boolean allowed;  
  45.         boolean allowedSig = false;  
  46.         if ((bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_APPOP) != 0) {  
  47.             // Keep track of app op permissions.  
  48.             ArraySet pkgs = mAppOpPermissionPackages.get(bp.name);  
  49.             if (pkgs == null) {  
  50.                 pkgs = new ArraySet<>();  
  51.                 mAppOpPermissionPackages.put(bp.name, pkgs);  
  52.             }  
  53.             pkgs.add(pkg.packageName);  
  54.         }  
  55.         final int level = bp.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;  
  56.         if (level == PermissionInfo.PROTECTION_NORMAL  
  57.                 || level == PermissionInfo.PROTECTION_DANGEROUS) {  
  58.             // We grant a normal or dangerous permission if any of the following  
  59.             // are true:  
  60.             // 1) The permission is required  
  61.             // 2) The permission is optional, but was granted in the past  
  62.             // 3) The permission is optional, but was requested by an  
  63.             //    app in /system (not /data)  
  64.             //  
  65.             // Otherwise, reject the permission.  
  66.             allowed = (required || origPermissions.contains(perm)  
  67.                     || (isSystemApp(ps) && !isUpdatedSystemApp(ps)));  
  68.         } else if (bp.packageSetting == null) {  
  69.             // This permission is invalid; skip it.  
  70.             allowed = false;  
  71.         } else if (level == PermissionInfo.PROTECTION_SIGNATURE) {  
  72.             allowed = grantSignaturePermission(perm, pkg, bp, origPermissions);  
  73.             if (allowed) {  
  74.                 allowedSig = true;  
  75.             }  
  76.         } else {  
  77.             allowed = false;  
  78.         }  
  79.         if (DEBUG_INSTALL) {  
  80.             if (gp != ps) {  
  81.                 Log.i(TAG, "Package " + pkg.packageName + " granting " + perm);  
  82.             }  
  83.         }  
  84.         if (allowed) {  
  85.             if (!isSystemApp(ps) && ps.permissionsFixed) {  
  86.                 // If this is an existing, non-system package, then  
  87.                 // we can't add any new permissions to it.  
  88.                 if (!allowedSig && !gp.grantedPermissions.contains(perm)) {  
  89.                     // Except...  if this is a permission that was added  
  90.                     // to the platform (note: need to only do this when  
  91.                     // updating the platform).  
  92.                     allowed = isNewPlatformPermissionForPackage(perm, pkg);  
  93.                 }  
  94.             }  
  95.             if (allowed) {//如果grantedPermission没有这个权限,就把这个权限加到grantedPermission,然后gids加入。  
  96.                 if (!gp.grantedPermissions.contains(perm)) {  
  97.                     changedPermission = true;  
  98.                     gp.grantedPermissions.add(perm);  
  99.                     gp.gids = appendInts(gp.gids, bp.gids);  
  100.                 } else if (!ps.haveGids) {  
  101.                     gp.gids = appendInts(gp.gids, bp.gids);  
  102.                 }  
  103.             } else {  
  104.                 if (packageOfInterest == null || packageOfInterest.equals(pkg.packageName)) {  
  105.                     Slog.w(TAG, "Not granting permission " + perm  
  106.                             + " to package " + pkg.packageName  
  107.                             + " because it was previously installed without");  
  108.                 }  
  109.             }  
  110.         } else {  
  111.             if (gp.grantedPermissions.remove(perm)) {  
  112.                 changedPermission = true;  
  113.                 gp.gids = removeInts(gp.gids, bp.gids);  
  114.                 Slog.i(TAG, "Un-granting permission " + perm  
  115.                         + " from package " + pkg.packageName  
  116.                         + " (protectionLevel=" + bp.protectionLevel  
  117.                         + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)  
  118.                         + ")");  
  119.             } else if ((bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_APPOP) == 0) {  
  120.                 // Don't print warning for app op permissions, since it is fine for them  
  121.                 // not to be granted, there is a UI for the user to decide.  
  122.                 if (packageOfInterest == null || packageOfInterest.equals(pkg.packageName)) {  
  123.                     Slog.w(TAG, "Not granting permission " + perm  
  124.                             + " to package " + pkg.packageName  
  125.                             + " (protectionLevel=" + bp.protectionLevel  
  126.                             + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)  
  127.                             + ")");  
  128.                 }  
  129.             }  
  130.         }  
  131.     }  
  132.   
  133.     if ((changedPermission || replace) && !ps.permissionsFixed &&  
  134.             !isSystemApp(ps) || isUpdatedSystemApp(ps)){  
  135.         // This is the first that we have heard about this package, so the  
  136.         // permissions we have now selected are fixed until explicitly  
  137.         // changed.  
  138.         ps.permissionsFixed = true;  
  139.     }  
  140.     ps.haveGids = true;  
  141. }  
这样后应用就有权限了。


你可能感兴趣的:(Android,基础业务分析)