Android6.0 framework层权限相关源码分析

1、概述。
         此处只研究了一下framework层的权限相关的代码和逻辑,至于和linux层的对应后续再跟踪。分析6.0的权限模型,其实就是分
析应用apk被解析安装到手机上时,是如何解析apk的manifest清单文件中的关于权限的一些配置的。此处从两方面着手的安装流程,
一方面是系统解析本身就有的apk,一方面是下载到手机里面的apk,然后点击安装。

2、解析系统应用。
     此处就从SystemServer开始介绍,前面开机如何加载这个服务就不介绍了。
               
          Step1.PackageManagerService.main
                         public static PackageManagerService main(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) {
        PackageManagerService m = new PackageManagerService(context, installer,
                factoryTest, onlyCore);
        ServiceManager.addService("package", m);
        return m;
                    }
                    这个函数创建了一个PMS的实例,然后把这个服务添加到ServicesManager中去。那么创建这个实例的时候就会去走
                  PMS的构造,如下。
                   public PackageManagerService(Context context, Installer installer,
                                                                             boolean factoryTest, boolean onlyCore) {
                              ......
                             mSettings = new Settings(mPackages); //实例化一个Settings类的对象,用于在解析这个apk的过程中存放各种变量
                             ......
                             //加载一些全局的系统的配置,如system/etc/Permissions  文件下面的各个xml的解析(有权限,有特征等等)
                             //然后放到相应的成员变量如:
                               //1、final ArrayMap<String, PermissionEntry> mPermissions = new ArrayMap<>();每个权限名字对应一
                          //PermissionEntry,这个成员变量解析的是<permission>的标签。
                                //2、final SparseArray<ArraySet<String>> mSystemPermissions = new SparseArray<>();每个uid,所对应的所有
                                // 权限,这个成员变量是解析<assign-permission>标签下的权限。
                             SystemConfig systemConfig = SystemConfig.getInstance();
                        ......
                         ArrayMap<String, SystemConfig.PermissionEntry> permConfig  = systemConfig.getPermissions();
               for (int i=0; i<permConfig.size(); i++) {
                   SystemConfig.PermissionEntry perm = permConfig.valueAt(i);
                   BasePermission bp = mSettings.mPermissions.get(perm.name);
                   if (bp == null) {
                       //一个权限对应一个 BasePermission,和是那个应用的权限无关。最终都放到 mSettings.mPermissions
                       bp = new BasePermission(perm.name, "android", BasePermission.TYPE_BUILTIN);
                        mSettings.mPermissions.put(perm.name, bp);
                   }
                   if (perm.gids != null) {
                       bp.setGids(perm.gids, perm.perUser);
                   }
               }
                             ......
                             File frameworkDir = new File(Environment.getRootDirectory(), "framework");
                              File vendorOverlayDir = new File(VENDOR_OVERLAY_DIR);
                             //扫描/vendor/overlay
               scanDirLI(vendorOverlayDir, PackageParser.PARSE_IS_SYSTEM
                                   | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_TRUSTED_OVERLAY, 0);
                 //扫描 /system/framework
                scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM
                                                               | PackageParser.PARSE_IS_SYSTEM_DIR
                                                                  | PackageParser.PARSE_IS_PRIVILEGED,
                                                                                 scanFlags | SCAN_NO_DEX, 0);

             //扫描 /system/priv-app
            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);

             //扫描 /system/app
            final File systemAppDir = new File(Environment.getRootDirectory(), "app");
            scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM
                                                 | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);

            //扫描vendor/app
            File vendorAppDir = new File("/vendor/app");
            scanDirLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM
                                                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);

            // 扫描oem/app
            final File oemAppDir = new File(Environment.getOemDirectory(), "app");
            scanDirLI(oemAppDir, PackageParser.PARSE_IS_SYSTEM
                                                 | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
           //以上会调用scanDirLI函数来设备上的指定目录下的apk文件,注意其传入的参数有各种系统级别的解析才传入的以
           // 来证明是系统应用等等。
           ......
                    }

         Step2.PackageManagerService.scanDirLI
                        private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) {
        final File[] files = dir.listFiles();
        ......
        for (File file : files) {
            //是否是个apk文件或者是个目录。
            final boolean isPackage = (isApkFile(file) || file.isDirectory()) &&
                                              !PackageInstallerService.isStageName(file.getName());
            if (!isPackage) {
                // Ignore entries which are not packages                 
                continue;
            }
             .............
            try {
                //调用scanPackageLI进一步解析
                scanPackageLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,
                        scanFlags, currentTime, null);
            } catch (PackageManagerException e) {...... }
        }
 }
 此函数就是解析传过来的第一个参数,如果是apk文件或者是目录,就对其一一调用 scanPackageLI进行解析。

             Step3.PackageManagerService.  scanPackageLI
                         private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
                                                                                        long currentTime, UserHandle user) throws PackageManagerException {
                               PackageParser pp = new PackageParser();
                                       ......
                                        final PackageParser.Package pkg;
            try {
                  pkg = pp.parsePackage(scanFile, parseFlags);
            } catch (PackageParserException e) {... }
           ......
    
                                                         | SCAN_UPDATE_SIGNATURE, currentTime, user);
            ......
            return scannedPkg;
                         }
                         通过创建PackagePaser实例并调用它的parsePackage来解析pkg文件,注意这个函数的参数也是通过path路劲来解析的,最终还
                 得需要 另外的一个重写的 scanPackageLI方法来实现包解析玩的pkg保存在PMS中。
               
                 Step4.PackageParser.parsePackage
                                   public Package parsePackage(File packageFile, int flags) throws PackageParserException {
        //通过判断是一个apk文件还是一个目录
        if (packageFile.isDirectory()) {
            return parseClusterPackage(packageFile, flags);
        } else {
            return parseMonolithicPackage(packageFile, flags);
        }
    }
     此函数会进一步的判断传入的是一个apk文件还是一个目录,进而在调用不同的解析方法。最终都会调用到parseBaseApk里
    private static int loadApkIntoAssetManager(AssetManager assets, String apkPath, int flags)
            throws PackageParserException {
        if ((flags & PARSE_MUST_BE_APK) != 0 && !isApkPath(apkPath)) {
            throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
                    "Invalid package file: " + apkPath);
        }

        // The AssetManager guarantees uniqueness for asset paths, so if this asset path
        // already exists in the AssetManager, addAssetPath will only return the cookie
        // assigned to it.
        int cookie = assets.addAssetPath(apkPath);
        if (cookie == 0) {
            throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
                    "Failed adding asset path: " + apkPath);
        }
        return cookie;
    }

    private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
            throws PackageParserException {
        ......
        Resources res = null;
        XmlResourceParser parser = null;
        try {
            res = new Resources(assets, mMetrics, null);
            ......
            //zy this method is main to get ANDROID_MANIFEST_FILENAME out
            parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);

            final String[] outError = new String[1];
            final Package pkg = parseBaseApk(res, parser, flags, outError);
           ......
            return pkg;

        } catch (PackageParserException e) {......   } catch (Exception e) {......
        } finally {
            IoUtils.closeQuietly(parser);
        }
    }
                                 这个函数就是先进行一些基本的判断那,如路径合不合法等,并且解析出apk文件中的AndroidManifest.xml文件,然后调用另一
                      个  重载的 parsePackage函数对这个文件进行进一步的解析。
                           private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags,
                                                                         String[] outError) throws XmlPullParserException, IOException {
                                   ......
                                   final Package pkg = new Package(pkgName);//第一次出现这个类,用于封装包的各种信息
                                   ......
                                            int outerDepth = parser.getDepth();
                                   //没有到AndroidManifest.xml文件的结尾处,就一直循环。
                                            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                                                               && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
                                           ......
                                                    String tagName = parser.getName();
                                            if  ( tagName . equals ( "application" ))  {
                                                           ......
 
 
}  else if ( tagName . equals ( "overlay" )) {
......
}  else if ( tagName . equals ( "key-sets" )) {
......
} 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; } }
.......//解析各种标签,然调用本类的相应的方法,完成解析并保存在pkg的变量当中,最后把pkg返回。
}
                                                 return pkg;
                            }
                            这个函数用来完成对AndroidManifest.xml文件的各个标签进行解析,此处我们只关心和权限相关的 uses-permission标签。

              Step5 PackageParser.parseUsesPermission
                               private boolean parseUsesPermission(Package pkg, Resources res, XmlResourceParser parser,
                                       AttributeSet attrs) throws XmlPullParserException, IOException {
                           ......
        if ((maxSdkVersion == 0) || (maxSdkVersion >= Build.VERSION.RESOURCES_SDK_INT)) {
            if (name != null) {
                int index = pkg.requestedPermissions.indexOf(name);
                if (index == -1) {
                    pkg.requestedPermissions.add(name.intern());
                } else {......  }
            }
        }
        return true;
    }  
此函数就是把 Uses-Permission标签下的每一个权限的名字添加到pkg. requestedPermissions的变量当中。
然后一层层返回到step3中
             Step.6 PackageManagerService.scanPackageLI
                         private PackageParser.Package scanPackageLI(PackageParser.Package pkg, int parseFlags,
                                                int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
                                  boolean success = false;
    try {
         final PackageParser.Package res = scanPackageDirtyLI(pkg, parseFlags, scanFlags,
                    currentTime, user);
          success = true;
          return res;
    } finally {......  }
                     }
                     继续调用 scanPackageDirtyLI来完成解析。注意到现在为止pkg里面已经有了大量的信息。
                       private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg, int parseFlags,    
                                                                          int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
                                   ......
                                       //通过pkg创建一个PackageSetting对象,也是临时保存一个指定的package的数据和信息。
                                //如此出会找到这个package的uid、还会通过层层的父类的初始化new PermissionsState()类。
                                 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);
                               ......
                               pkg.applicationInfo.uid = pkgSetting.appId;   //赋值uid
                              pkg.mExtras = pkgSetting;
                              ......
                              synchronized (mPackages) {
                                       //把 pkgSetting保存到Settings的变量 mPackages中, String对应于包名。
                                      //final ArrayMap<String, PackageSetting> mPackages =  new ArrayMap<String, PackageSetting>();
                                        mSettings.insertPackageSettingLPw(pkgSetting, pkg);
                                      //把pkg保存到PMS的成员变量 mPackages  中,Stirng对应于包名。
                                      // final ArrayMap<String, PackageParser.Package> mPackages =  new ArrayMap<String, PackageParser.Package>();
                                      mPackages.put(pkg.applicationInfo.packageName, pkg);
                                      ......
                                     int N = pkg.providers.size();
                                      ......//解析 providers  把相应的provider添加到mProviders当中。
                                               N = pkg.services .size();
                                      ......//解析services  把相应的 services 添加到mS ervices 当中。
                                              N = pkg.receivers .size();
                                      ......//解析receivers  把相应的 receivers  添加到 mR eceivers  当中。
                                               N = pkg.activities .size();
                                      ......//解析activities  把相应的 activities  添加到 mA ctivities  当中。 
                                       N = pkg.permissionGroups .size();
                                      ......//解析permissionGroups 把相应的 permissionGroups 添加到 mPermissionGroups 当中。
                                       N = pkg.permissions .size();
                                      ......//解析permissions 把相应的permissions 添加到permissionMap 当中。
                                      N = pkg.instrumentation.size();
                                         ......//解析 instrumentation 把相应的 instrumentation 添加到 mInstrumentation 当中。
                                       ......
                                 }
                                 return pkg;
                       }
                       此函数现在看来除啦进一步解析pkg外,还把pkg的一些属性添加到PMS的成员变量中。
          
                Step7.PackageManagerService
                                  至此完成了对系统中的相应的目录下的apk的解析,那么它们的权限怎么设定的那?完全没有踪影啊,别急。接下来继续回到
                PMS的构造当中。
                  public PackageManagerService(Context context, Installer installer,
                                                                             boolean factoryTest, boolean onlyCore) {
                  //此处接着Step1的步骤分析。
                   ......
                   int updateFlags = UPDATE_PERMISSIONS_ALL;
                 if (ver.sdkVersion != mSdkVersion) {
                            updateFlags |= UPDATE_PERMISSIONS_REPLACE_PKG | UPDATE_PERMISSIONS_REPLACE_ALL;
                   }
                   updatePermissionsLPw(null, null, StorageManager.UUID_PRIVATE_INTERNAL, updateFlags);/
                        }
                    在构造中解析完系统的apk后调用 updatePermissionsLPw来设定应用的权限。
          
                  Step 8.PackageManagerService.  updatePermissionsLPw
                             
                           private void updatePermissionsLPw(String changingPkg,
                                                                             PackageParser.Package pkgInfo, String replaceVolumeUuid, int flags) {
                                      ......
                                     //下面的这个flags从PMS构造中传入,所以符合条件可以进入,并且replace为false。
                                     if ((flags&UPDATE_PERMISSIONS_ALL) != 0) {
                                             // mPackages,在Step 6中已经完成保存
                                                      for (PackageParser.Package pkg : mPackages.values()) {
                          if (pkg != pkgInfo) { 
                                   final String volumeUuid = getVolumeUuidForPackage(pkg);
                                   final boolean replace = ((flags & UPDATE_PERMISSIONS_REPLACE_ALL) != 0)
                                                                                      && Objects.equals(replaceVolumeUuid, volumeUuid);
                 grantPermissionsLPw(pkg, replace, changingPkg);  
}
                                     }
                                     //从PMS构造中传过来的是null,此处一般手动安装的应用会走,并且 replace  为true。
                 if (pkgInfo != null) {
                         final String volumeUuid = getVolumeUuidForPackage(pkgInfo);
                         final boolean replace = ((flags & UPDATE_PERMISSIONS_REPLACE_PKG) != 0)
                                                                                  && Objects.equals(replaceVolumeUuid, volumeUuid);
                         grantPermissionsLPw(pkgInfo, replace, changingPkg);
                  }
                            }
                      此函数更具传入的参数的不同调用方法中不同地方的 grantPermissionsLPw,并把相应的参数传入.

                 Step 9.PackageManagerService.  grantPermissionsLPw
                            private void grantPermissionsLPw(PackageParser.Package pkg, boolean replace,
                                                                                                                                          String packageOfInterest) {
                                    //在Step 6 已经赋值   pkg.mExtras。
                                      final PackageSetting ps = (PackageSetting) pkg.mExtras;
        if (ps == null) {
            return;
        }
         //此时的 permissionsState不为null,因为在初始化 PackageSetting 时,已经实例化它,但是它的成员变量很多
        //都是null因为实例化它的时候用的是无参数的构造,如: public ArrayMap<String, PermissionData> mPermissions;
        //key对应于权限名字,Values对应于一个用于封装的 PermissionData类
         PermissionsState permissionsState = ps.getPermissionsState();
        PermissionsState origPermissions = permissionsState;
        ......
       //已经在Step 5中完成了解析。
       final int N = pkg.requestedPermissions.size();
       for (int i=0; i<N; i++) {
                final String name = pkg.requestedPermissions.get(i);
               //在Step1中(还有别的地方)已经初始化此项
               final BasePermission bp = mSettings.mPermissions.get(name);
               ......
     final String perm = bp.name;
     boolean allowedSig = false;
     int grant = GRANT_DENIED;
     ......
   //从何处导致的 protectionLevel的不同,暂时还没分析出来!!!!??????
    final int level = bp.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
    switch (level) {              
              case PermissionInfo.PROTECTION_NORMAL: {
                    // 当不是 PROTECTION_DANGEROUS类型的时候都安装为安装权限。
                    grant = GRANT_INSTALL;
                } break;

              case PermissionInfo.PROTECTION_DANGEROUS: {
                     if (pkg.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1) {
                        // 当targtversion小于6.0是赋值这个。
                        grant = GRANT_INSTALL_LEGACY;
                   } else if (origPermissions.hasInstallPermission(bp.name)) {
                        // For legacy apps that became modern, install becomes runtime.
                        grant = GRANT_UPGRADE;
                     } else if (mPromoteSystemApps && isSystemApp(ps)
                                   && mExistingSystemPackages.contains(ps.name)) {
                        grant = GRANT_UPGRADE;
                     } else {
                        // 想是正常的6.0的第一次安装的时候,就会赋值此处。
                        grant = GRANT_RUNTIME;
                     }
               } break;
             
              case PermissionInfo.PROTECTION_SIGNATURE: {
                    // For all apps signature permissions are install time ones.
                    allowedSig = grantSignaturePermission(perm, pkg, bp, origPermissions);
                    if (allowedSig) {
                        grant = GRANT_INSTALL;
                    }
                } break;  
       }
     ......
          }
          if(grant != GRANT_DENIED){
                  ......
                  switch (grant) {
                          case GRANT_INSTALL: {
                        for (int userId : UserManagerService.getInstance().getUserIds()) {
                              if (origPermissions.getRuntimePermissionState(  bp.name, userId) != null) {
                                  origPermissions.revokeRuntimePermission(bp, userId);
                                  origPermissions.updatePermissionFlags(bp, userId,  
                                                                  PackageManager.MASK_PERMISSION_FLAGS, 0);
                                  changedRuntimePermissionUserIds = ArrayUtils.appendInt(
                                                               changedRuntimePermissionUserIds, userId);
                               }
                         }
                         // 允许所有的安装时的权限,通过 grantInstallPermission。此处的逻辑在最后单独分析。
                         int flag = permissionsState.grantInstallPermission(bp);
                         android.util.Log.d("zy_test","GRANT_INSTALL flag = "+flag);
                         if (flag != PermissionsState.PERMISSION_OPERATION_FAILURE) {
                              changedInstallPermission = true;
                         }
                    } break;

                    case GRANT_INSTALL_LEGACY: {
                       //当应用的targetversion<23并且权限是运行时权限,才会走到这里。也是全部允许。
                        int flag = permissionsState.grantInstallPermission(bp);
                        if (flag !=PermissionsState.PERMISSION_OPERATION_FAILURE) {
                            changedInstallPermission = true;
                        }
                    } break;
                     
                    case GRANT_RUNTIME: {
                        for (int userId : UserManagerService.getInstance().getUserIds()) {
                               PermissionState permissionState = origPermissions  .getRuntimePermissionState(bp.name, userId);
                               final int flags = permissionState != null     ? permissionState.getFlags() : 0;
                               //此时 hasRuntimePermission会返回false,由于 origPermissions. mPermissions==null
                               if (origPermissions.hasRuntimePermission(bp.name, userId)) {
                                   //所以不会进入到这里进而允许所有的运行时权限。
                                   if (permissionsState.grantRuntimePermission(bp, userId) ==
                                                                 PermissionsState.PERMISSION_OPERATION_FAILURE) {
                                           changedRuntimePermissionUserIds = ArrayUtils.appendInt(
                                                                                changedRuntimePermissionUserIds, userId);
                                    }
                                }
                                permissionsState.updatePermissionFlags(bp, userId, flags, flags);
                         }
                    } break;

                    case GRANT_UPGRADE: {......}
                    ......
                   }else{
                           ......
                   }
          }
          ......
                           }
                             此函数真正的初始化了每个应用的framework层的权限设置,根据不同的权限类型和应用的targetversion。但是这样的话系统应用
                     很多必要的权限默认也是不允许的,这样体验很不好。
                  
                    Step 10  PackageManagerService.systemReady()
                             systemServer调用完PMS的main方法后,会调用PMS的systemReady。
                             public void systemReady() {
                                       ......
                    for (int userId : grantPermissionsUserIds) {
                         //此处初始化所有用户的一些默认的权限。
                mDefaultPermissionPolicy.grantDefaultPermissions(userId);
        }
        ......
                             }
                               我们只分析和权限相关的, mDefaultPermissionPolicy 是 DefaultPermissionGrantPolicy类的实例,在PMS创建的时候就完成了实
                      例化, 通过调用 grantDefaultPermissions来初始化一些应用的默认权限。
                    
                     Step 11 DefaultPermissionGrantPolicy.  grantDefaultPermissions
                                public void grantDefaultPermissions(int userId) {
                                               grantPermissionsToSysComponentsAndPrivApps(userId);//对PMS.mPackages里面的符合一定条件pkg的权限的初始化。
                                            grantDefaultSystemHandlerPermissions(userId);//对如:Mms、Dialer、Contact等应用的权限的初始化
                                        }
                          此函数分别通过再次调用另外的方法,完成最终的某些应用的权限的初始化,此处就不再深入分析,有兴趣的可以自己在往下看,
                    也  很简单。最终是通过PMS的grantRuntimePermission(,,)来完成对应用的权限的设置。至此我们完成了系统的apk的解析和默
                    认权限的设置,当中忽略了很多细节有兴趣可以自己深入研究,此文只起到抛砖引玉作用。
                        
        3、解析下载好的apk(手动点击安装)
                   手动点击安装和系统的解析很多地方都会走相同的代码,只是一开始的入口方式不同,此处就不重复讨论相同的地方了。且下面的分析
              省略了具体的PackageInstaller对点击安装apk往外发送的广播的处理,直接分析最终的在PMS的实现。
      
                                                                    
                             
                     Step 1.PackageManagerService.installPackage
                          此处就直接从安装的接口调用处开始分析。
                           public void installPackage(String originPath, IPackageInstallObserver2 observer,
                                     int installFlags, String installerPackageName, VerificationParams verificationParams,
                                     String packageAbiOverride) {
             installPackageAsUser(originPath, observer, installFlags, installerPackageName,
                                                      verificationParams, packageAbiOverride, UserHandle.getCallingUserId());
       }
       直接调用了另外的一个函数 installPackageAsUser。
        public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,
                               int installFlags, String installerPackageName, VerificationParams verificationParams,
                                String packageAbiOverride, int userId) {
                                       ......
                                       final Message msg = mHandler.obtainMessage(INIT_COPY);
        msg.obj = new InstallParams(origin, null, observer, installFlags, installerPackageName,
                                   null, verificationParams, user, packageAbiOverride, null);
        mHandler.sendMessage(msg);
                            }
                             此函数主要就是做些基本的判断,如:是否有权限、是否可以默认允许安装时权限。最后往mHandler 发送消息,进行处理。
                 
                       Step 2.PackageManager Service . PackageHandler
                                   PackageHandler.doHandleMessage(.)会被多次调用进行一些必要的处理,如:判断APK路径是否合法,把Apk复制过来,
                        检查签名和包名是否合法等等。最终在某个消息中会调用到,processPendingInstall。
             
                        Step 3.PackageManagerService.processPendingInstall
                                  private void processPendingInstall(final InstallArgs args, final int currentStatus) {
                                           ......
                                          mHandler.post(new Runnable() {
                                                   ......
                                                    if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
                          args.doPreInstall(res.returnCode);
                          synchronized (mInstallLock) {
                                    installPackageLI(args, res);
                            }
                           args.doPostInstall(res.returnCode, res.uid);
                    }
                  ......
                                          });
                                   }
                                  此函数被异步调用,一直在等待安装的flag变为 INSTALL_SUCCEEDED。最后调用 installPackageLI开始真正的安装。 

                       Step 4.PackageManagerService.installPackageLI
                                  private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
                                            ......
                                                      PackageParser pp = new PackageParser();
                                           ......
                                                       final PackageParser.Package pkg;
             try {
                   //此处的解析和前面所说的解析系统应用的刘晨个相同,注意一下某些参数和标志位的区别即可。
                    pkg = pp.parsePackage(tmpPackageFile, parseFlags);
             } catch (PackageParserException e) {
                   return;
             }
             ......
               if (replace) {
                     replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
                                  installerPackageName, volumeUuid, res);
              } else {
                      //第一次安装apk时,会走到这里。
                       installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
                             args.user, installerPackageName, volumeUuid, res);
              }
                                  }
                                         此函数主要是通过 parsePackage解析apk的manifest的一些属性。然后调用 installNewPackageLI方法。
                                 Step 5.PackageManagerService.installNewPackageLI
                                           private void installNewPackageLI(PackageParser.Package pkg, int parseFlags, int scanFlags,
                                                                                                        UserHandle user, String installerPackageName, String volumeUuid,
                                                                                                   PackageInstalledInfo res) {
                                                  ......
                                                   PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanFlags, 
                                                                                                                                                               System.currentTimeMillis(), user);
                                                  updateSettingsLI(newPackage, installerPackageName, volumeUuid, null, null, res, user);
                                                  .......
                                                     }
                                          此函数通过 scanPackageLI进行进一步的解析,此处解析和解析系统应用的Step 6相同,此处不再重复分析。通过它完成
                                  了对apk的解析,最终在调用 updateSettingsLI来实现对此应用权限相关的默认设置。
                                  
                                  Step 6. PackageManagerService.updateSettingsLI
                                              private void updateSettingsLI(PackageParser.Package newPackage, String installerPackageName,
                                                                                                                                String volumeUuid, int[] allUsers, boolean[] perUserInstalled, PackageInstalledInfo res,
                                                                                                                                               UserHandle user) {
                                                         ......
        updatePermissionsLPw(newPackage.packageName, newPackage,  // zy updatePermissionsLPw??
                                                    UPDATE_PERMISSIONS_REPLACE_PKG | (newPackage.permissions.size() > 0
                                                             ? UPDATE_PERMISSIONS_ALL : 0));
      ...
                                              }
                                           函数调用 updatePermissionsLPw来实现权限的默认设置,和解析系统应用的Step 8~9功能相同的。
                                  至此就完成了普通的apk的安装解析和设置权限的流程,可以看出核心功能和解析系统的并无两样。综上可以看到对于M基线的
                                  权限设置,核心是不区分系统应用和普通应用的,只在一些开始解析时传入的flag上有些区别。也就是说在安装解析完后,默认                     
                                  的对于targetversion<23的应用,所有的基本和危险权限默认允许,对于 targetversion=23的,所有的安装权限默认允许,危险权
                                  限全部默认拒绝。至于系统的一些应用默认就允许一些权限,是解析完后转门对应用的权限进行了设置(Step11)。
                   
                          4、权限PermissionsState的机制分析。
                                     在解析系统应用的Step 9中我们,我们只是分析道调用 grantInstallPermission,没有具体的跟踪再往下的逻辑。还有
                                  hasRuntimePermission的实现等。
 
                                 PermissionsState基本囊括了一个应用的所有权限的状态。
                                public final class PermissionsState {
                                                     ......
                                          public ArrayMap<String, PermissionData> mPermissions;//key :权限名字,value :  PermissionData 对单个权限的封装
                                          ......
                                                    public PermissionsState() {
        /* do nothing */ //空的构造,在前面解析系统应用的Step 6中  pkgSetting = mSettings.getPackageLPw(...)
        //内部就调用啦这个构造函数,这就导致成员变量 mPermissions==null.
   }

    public PermissionsState(PermissionsState prototype) {
        copyFrom(prototype);//从另一个 PermissionsState获取数据,此时一般 mPermissions都不是null。
         //此处就不详细分析这个方,就是简单的获取一下。
    }
//查看是否有这个权限,此时的有不仅仅是权限列表有,还需要已经允许(包含运行时和安装时通过 userId区分
public boolean hasPermission(String name, int userId) {
       //如果mPermissions==null,正好对应到系统解析的Step 9中,刚空构造初始化完毕,为允许任何权限的时候。
        if (mPermissions == null) {
            return false;
        }

        PermissionData permissionData = mPermissions.get(name);
        //只有当 PermissionData  != null, 并且权限已经允许时才返回true。
        return permissionData != null && permissionData.isGranted(userId);
    }

   private int grantPermission(BasePermission permission, int userId) {
       //如果已经允许这个权限了,那么就没必要再允许一次了。
        if (hasPermission(permission.name, userId)) {
            return PERMISSION_OPERATION_FAILURE;
        }
        //此处不太懂可能是要和Linux中的gid是相对应。???
        final boolean hasGids = !ArrayUtils.isEmpty(permission.computeGids(userId));
        final int[] oldGids = hasGids ? computeGids(userId) : NO_GIDS;
        //下面这个方法很关键,用来实例化 PermissionData  的.
        PermissionData permissionData = ensurePermissionData(permission);

        //然后通过调用 permissionData  的grant方法来完成权限的允许过程。
        if (!permissionData.grant(userId)) {
            return PERMISSION_OPERATION_FAILURE;
        }

        if (hasGids) {
            final int[] newGids = computeGids(userId);
            if (oldGids.length != newGids.length) {
                return PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
            }
        }

        return PERMISSION_OPERATION_SUCCESS;
    }

     private PermissionData ensurePermissionData(BasePermission permission) {
        if (mPermissions == null) {
            mPermissions = new ArrayMap<>();//当第一次到这 mPermissions 为null时,初始化一个
        }
       //第一次获取某个权限时必定为null。
        PermissionData permissionData = mPermissions.get(permission.name);
        if (permissionData == null) {
            permissionData = new PermissionData(permission);//实例化 PermissionData。
            mPermissions.put(permission.name, permissionData);//添加到 mPermissions当中。
        }
        return permissionData;
    }
private int revokePermission(BasePermission permission, int userId) {
       //如果已经拒绝了就没必要操作了。
        if (!hasPermission(permission.name, userId)) {
            return PERMISSION_OPERATION_FAILURE;
        }
        ......
        PermissionData permissionData = mPermissions.get(permission.name);
        //调用 permissionData   revoke方法来完成拒绝的操作
        if (!permissionData.revoke(userId)) {
            return PERMISSION_OPERATION_FAILURE;
        }
        ......
        return PERMISSION_OPERATION_SUCCESS;
    }
  ......

private static final class PermissionData {
         private final BasePermission mPerm;  //一个权限对应一个 BasePermission 
        // mUserStates ,由于一个权限对应一个PermissionData,所以此处其实 mUserStates 的大小只为1,key = userid,
        //Value =  PermissionState.
        private SparseArray<PermissionState> mUserStates = new SparseArray<>(); 

        public PermissionData(BasePermission perm) {
            mPerm = perm;
        }

        public PermissionData(PermissionData other) {
            this(other.mPerm);
            ......//此处不做分析
        }     
      ......
      //此处仅仅写出了重要的方法,且以允许权限为例。
       public boolean grant(int userId) {
           ......  //前面进行一些判断,是否有必要进行接下来的允许工作
            PermissionState userState = mUserStates.get(userId);//第一次获取的时候必然为null
            if (userState == null) {
               //此处new一个单个权限对应的 PermissionState,以权限的名字为参数。
                userState = new PermissionState(mPerm.name);
                mUserStates.put(userId, userState);//然后放到成员变量 mUserStates中。以userid为key。(反正只有一个)
            }

            userState.mGranted = true; //最后改变这个成员变量来标记是否允许。
            return true;
        }
       public boolean revoke(int userId) {
             ...... //也是一些有没有必要继续执行的判断,应该是加快工作效率的吧

            PermissionState userState = mUserStates.get(userId);
            userState.mGranted = false;//直接把变量 mGranted  至为false
            if (userState.isDefault()) {//如果默认就是ifalse,那么移除这个
                mUserStates.remove(userId);
            }
            return true;
        }
        ......
  }
  
  //单一的某个权限,对它的封装,此处封装的是名字和,状态。
   public static final class PermissionState {
        private final String mName;
        private boolean mGranted;
        private int mFlags;

        public PermissionState(String name) {
            mName = name;
        }

        public PermissionState(PermissionState other) {
            mName = other.mName;
            mGranted = other.mGranted;
            mFlags = other.mFlags;
        }

        public boolean isGranted() {
            return mGranted;
        }

    }
                                        }
                                       至此我们分析完PermissionsState类的主要的一些方法和变量。然后对应到我们的解析系统应用的Step 9当中。
                                       当权限是 安装时权限的时候,调用的 permissionsState.grantInstallPermission(bp)。最终会调用到grantPermis
                               sion的 方法当中。此时首 先判断 hasPermission,由于mPermissions == null,返回的是false。接下来就调用ensure
                               PermissionData(..)和permission  Data.grant(userId)完成最终的允许状态使,PermissionState.mGranted = =true.
                                      当权限是运行时权限的时候,调用hasRuntimePermission(..)。最终也会调用到hasPermission。由于mPerm
                               issions == null。最终返回false。进而不会进入判断,也就不能调用grantRuntimePermission。

                          5、权限的检查、允许和禁止的机制。
                                权限的检查通过AMS里面的一些列封装,最后到PMS当中。
                                检查权限的方法主要有以下几种。
                                @Override
    public int checkPermission(String permName, String pkgName, int userId) {
       //判断用户id是否合法。
        if (!sUserManager.exists(userId)) {
            return PackageManager.PERMISSION_DENIED;
        }

        synchronized (mPackages) {
            final PackageParser.Package p = mPackages.get(pkgName);
            if (p != null && p.mExtras != null) {
                final PackageSetting ps = (PackageSetting) p.mExtras;//取出ps
                final PermissionsState permissionsState = ps.getPermissionsState();//取出 permissionsState 
                if (permissionsState.hasPermission(permName, userId)) { //调用 hasPermission,看看是否已经允许。
                    return PackageManager.PERMISSION_GRANTED;
                }
                //特殊的权限的处理
                if (Manifest.permission.ACCESS_COARSE_LOCATION.equals(permName) && permissionsState
                        .hasPermission(Manifest.permission.ACCESS_FINE_LOCATION, userId)) {
                    return PackageManager.PERMISSION_GRANTED;
                }
            }
        }
        return PackageManager.PERMISSION_DENIED;//以上都不符合,那么默认就是不允许的
   }

 @Override
    public int checkUidPermission(String permName, int uid) {
         ...... //userid、uid是否合法的判断
        synchronized (mPackages) {
             //此处取得的是SettingsBase也就是ps,此文没有具体分析到这一块。
            Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));
            if (obj != null) {
                final SettingBase ps = (SettingBase) obj;
                final PermissionsState permissionsState = ps.getPermissionsState();
                if (permissionsState.hasPermission(permName, userId)) { //还是看是否已经允许
                    return PackageManager.PERMISSION_GRANTED;
                }
               //特殊权限的处理
                if (Manifest.permission.ACCESS_COARSE_LOCATION.equals(permName) && permissionsState
                        .hasPermission(Manifest.permission.ACCESS_FINE_LOCATION, userId)) {
                    return PackageManager.PERMISSION_GRANTED;
                }
            } else {
                ArraySet<String> perms = mSystemPermissions.get(uid);
                if (perms != null) {
                    if (perms.contains(permName)) { //如果是解析来的权限不是自己定义的,那么就允许。
                        return PackageManager.PERMISSION_GRANTED;
                    }
                    if (Manifest.permission.ACCESS_COARSE_LOCATION.equals(permName) && perms
                            .contains(Manifest.permission.ACCESS_FINE_LOCATION)) {
                        return PackageManager.PERMISSION_GRANTED;
                    }
                }
            }
        }

        return PackageManager.PERMISSION_DENIED;  //默认还是拒绝
    }
                               
                                 权限允许的方法:
                                       由于安装时权限是在安装的时候就已经允许的,所以此时的允许权限,其实就是允许运行时权限。在解析系统apk的Step 11
                                  也有说明,调用PMS的grantRuntimePermission.
                                       public void grantRuntimePermission(String packageName, String name, final int userId) {
                                                           ..... //一些权限和userid合法性的检查。
                                                 final int uid;
                                                           final SettingBase sb;
                                                synchronized (mPackages) {
                                                                final PackageParser.Package pkg = mPackages.get(packageName);
            ......
            final BasePermission bp = mSettings.mPermissions.get(name);
            ......
            uid = UserHandle.getUid(userId, pkg.applicationInfo.uid);
            sb = (SettingBase) pkg.mExtras;
            ......
                                                             final int result = permissionsState.grantRuntimePermission(bp, userId);
                                                            ...... //此处做完权限允许操作后,会先更具返回的result经行一些处理。最终再把这些操作信息
                                                            //持久化到文件中在/data/system/users/X/runtime-permissions.xml当中。此处在说另外几个xml
                                                           //packages.xml 、package.list 都存放在data/system/下面,文件里存放了所有apk的包的信息,如:包名
                                                }
                                                 }
                                        grantRuntimePermission最终也会调用到 permissionsState 的 grantPermission方法中。基本流程和上述一样。

                                    权限禁止的方法。
                                           此处也是指禁止运行时的权限,因为安装时的权限是不可控制的。安装时就已经允许。
                                            @Override
                                                       public void revokeRuntimePermission(String packageName, String name, int userId) {
                                                        .......//前面的这些操作和允许运行时权限调用的类似,不再做分析
                                                       if (permissionsState.revokeRuntimePermission(bp, userId) ==
                                                                                                 PermissionsState.PERMISSION_OPERATION_FAILURE) {
                                                                  return;
                                                        }
                                                        ......
                                                      }
                                          最终就是调用PermissonState的revoke方法把mGranted变量置为false。

                       6、解析安装APK时和去学奶奶相关的一些重要的类的成员变量。

                             Settings类的成员变量:
                              final ArrayMap<String, BasePermission> mPermissions =  new ArrayMap<String, BasePermission>():每个权限字符串对应一
                             个BasePermission类。
                              final ArrayMap<String, PackageSetting> mPackages =  new ArrayMap<String, PackageSetting>():每一个包名对应一个 Packag
                             eSetting类。

                             PackageManagerService的成员变量:
                              final ArrayMap<String, PackageParser.Package> mPackages =  new ArrayMap<String, PackageParser.Package>(): 每一个包名
                             对应一个PackageParser.Package对象。(很关键)
                              private static final int GRANT_DENIED = 1;
                                    private static final int GRANT_INSTALL = 2;
                                    private static final int GRANT_INSTALL_LEGACY = 3;
                                      private static final int GRANT_RUNTIME = 4;
                                     private static final int GRANT_UPGRADE = 5;
                             
                             ./system/core/include/private/android_filesystem_config.h   :uid字符串和linux中的uid的对应。
                           
                           7、重启手机后走的流程(不是第一次恢复出厂设置的加载。)
                                    a、关机重启后应用安装问题
                                    如果彻底关机之后再开机,那么系统就会重新安装一遍所有的应用程序的,因为关机之后,我们是可以改变系统中的应用
                             程序的,  例如,增加、删除或者修改系统中的应用程序。如果不重新检查一遍的话,那么就会有问题了。在实际使用中,我们
                             很少会彻底地关 机,一  般意义上的关机只是让系统深度睡眠,这种情况不会导致系统重新安装一遍系统中的应用程序。 系统除
                             了会把应用程序的安装  信息保存在内存中之外,还会保存在一个本地文件中,因为有些应用程序的安装信息无论安装多少次,
                              都是必 须保持一致的,例如,  应用程序的Linux用户ID。如果不保存下来的话,那么每次应用程序重新安装之后,表现可能都
                              会不一致。   /data/system/packages.xml里面  会在构造中调用Settings类的 readLPw进行读取。其实就是会重新解析,但是有些
                              属性配置不会变,会重新重xml里面读取。也会在addPackageLPw中new PackageSetting

                                   b、shared UID相关问题
                                          假设程序A要与程序B共享一个UID,那么程序B不需要配置Shared UID,它会获得一个普 通的UID,需要配置Shared UID
                                   的是程序A,这时候系统会将程序B的UID分配给程序A,这样就达到了共享UID的目的。 两个程序有相同的UID,并不意味着
                                   它们会运行在同一个进程中。一个程序运行在哪一个进程,一般是由它的Package名称和UID来决定的 ,也就是说,UID相同
                                   但是Package名称不同的两个程序是运行两个不同的进程中的。给每一个程序都分配一个UID是用来控制权限的,因此,两
                                   个程序具有相同的UID,就意味它们有相同的权限,可以进行资源共享。关于进程的创建可以看连接:   
                                    http://blog.csdn.net/luoshengyang/article/details/6689748

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值