应用学习

一、PMS的常用功能

  • 1、安装、卸载应用
  • 2、查询permission相关信息
  • 3、查询Application相关信息(application、activity、receiver、service、provider及相应属性等)
  • 4、查询已安装应用
  • 5、增加、删除permission
  • 6、清除用户数据、缓存、代码等

二、接口的讲解

  1.PackaeManager.java------>ApplicationPackageManager.java---->PackageManagerService.java

    queryIntentActivities(intent, PackageManager.MATCH_ALL);              :  查询包含这个Intent的Activity

              resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY)   :   查询是否有满足这个Intent的Activity

              clearPackagePreferredActivities()                                                         :    清除默认的修改

    addPreferredActivity()                                                                           :    修改默认的配置

    if (r.match > bestMatch) bestMatch = r.match;

    replacePreferredActivity()                                                                    :     替换Intent 匹配相同的Activity

                getPackageUid(String packageName)                                                 :     获取相应包的UID

    getPermissionInfo(String packageName, int flags (大部分默认为0))    :      通过包名获取权限

    getApplicationInfo(String packageName,int flags)                                :      检索出一个应用程序的所有信息

               getActivityInfo(ComponentName component,int flags) :   检索出一个特定的Activity类的所有信息

    getPackageInfo(String packageName, int flags)     :       包名获取该包名对应的应用程序的PackageInfo对象

    getInstalledPackages(int flags(一般传值为0))  :   返回设备上所有已经安装的应用程序集合  

     入参params flags 附加选项的标志位,你可以理解为筛选条件,可以使用的标志位为:
     GET_ACTIVITIES :(packageInfo的标志)表示 返回包(packageInfo)中包含的所有Activity信息
     GET_GIDS :(packageInfo的标志)表示 返回关联的GID(groupId)
     GET_CONFIGURATIONS :(packageInfo的标志)表示 配置选项信息
     GET_INSTRUMENTATION :(PackageInfo的标志)表示 是否使用了instrumentation
     GET_PERMISSIONS :(PackageInfo的标志)表示 是否使用了permissions
     GET_PROVIDERS :(PackageInfo的标志)表示 是否使用了providers
     GET_RECEIVERS :(PackageInfo的标志)表示 是否使用了recevier
     GET_SERVICES :(PackageInfo的标志)表示 是否使用了service
     GET_SIGNATURES :(PackageInf的标志) 表示是否使用包的签名信息
     GET_UNINSTALLED_PACKAGES:参数标志位,表示检索出所有有数据的目录的应用程序(主要是卸载的)的信息
     Context.getPackageManager()               :   获取PackageManager对象的方法
     获取PackageManagerService的两种方法:
     方法一:
      IBinder b = ServiceManager.getService("package");
      sPackageManager = IPackageManager.Stub.asInterface(b);

                    方法二:
     ActivityThread.getPackageManager()
     public void  checkCallingOrSelfPermission(String permission)     // 检查自己或者其它调用者是否有 permission 权限

  三、PackageManagerService的重要成员支持类以及变量

    1.PackageParser : 这个类主要用于解析APK,解析其AndroidManifest.xml文件得到package的所有信息。  PackageParser.Package这个类用于容纳解析出的信息。
    2. Settings:这个类表示它服务处理设置和读取包的各种状态,它是动态的,比如userId,shareUser、permission、signature以及origPackg相关信息
    3. Installer : 这个类协助安装过程
    4. final PackageInstallerService mInstallerService: 一个应用的安装时间比较长,Android就是用PackageInstallerService来管理应用的安装过程
    5. final Installer mInstaller  : 它是Install的实例,用于和Demon进行install交互。实际上系统上进行APK格式转换、建立数据目录等工作,都是install进程来完成的。
    6. final Settings mSettings  : Setting的实例,保存一些PackageManagner动态设置信息
    7. final ArrayMap<String, PackageParser.Package> mPackages : 代表系统已经安装的package
    8. final private ArrayMap<String, File> mExpectingBetter :  被升级过的应用列表
    9. final SparseArray<HashSet<String>> mSystemPermissions : 系统权限的集合
    10. final HashMap<String, String> mSharedLibraries : 当前已知的共享库
    11. final boolean mOnlyCore  :  用于判断是否只扫描系统库

  四、PackageManagerService相关类的学习
    1.Settings.java类成员变量
     a.private final File mSettingsFilename  :  代表的是"/data/system/packages.xml"文件
     b.private final File mBackupSettingsFilename:代表的是"/data/system/packages_backup/xml"文件,这个文件不一定存在,如果存在,因为他是备份文件,如果它不存在,则说明上次更新packages.xml文件出错了。
    c.private final File mPackageListFilename:代表的是"/data/system/packages.list"文件
final ArrayMap<String, PackageSetting> mPackages = new ArrayMap<>(): 是一个ArrayMap的结构,key是包名,value是PackageSetting。PackageSetting主要包含了一个APP的基本信息,如安装位置,lib位置等信息。
    d.final ArrayMap<String, SharedUserSetting> mSharedUsers =new ArrayMap<String, SharedUserSetting>():在Android中每一个应用都有一个UID,两个相同的UID的应用可以运行在同一个进程中,所以为了让两个应用运行在一个进程中,往往会在AndroidManifest.xml文件中设置shareUserId这个属性,这个属性就是一个字符串,但是我们知道Linux系统中一个uid是一个整型,所以为了将字符串和整形对应起来,就有了的ShareUserSetting类型,刚才说key是shareUserId这个属性的值,那么值就是SharedUserSetting类型了,ShareUserdSetting中除了name(其实就是key),uid对应Linux系统的uid,还有一个列表字段,记录了当前系统中有相同的shareUserId的应用。
    e.final ArrayMap<String, BasePermission> mPermissions=new ArrayMap<String, BasePermission>():代表的是主要保存的是"/system/etc/permissions/platform.xml"中的permission标签内容,因为Android系统是基于Linux系统,所以也有用户组的概念,在platform.xml中定义了一些权限,并且制定了哪些用户具有这些权限,一旦一个应用属于某一个用户组,那么它就拥有了这个用户组的所有权限

      

                                      ShareUserSetting的架构

        
                            Settings的架构
    五、PMS的方法介绍
      1.  scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime)  :  这里可以忽略某些app的安装
         final File[] files = dir.listFiles();
       ......
      // Submit files for parsing in parallel
      int fileCount = 0;
      for (File file : files) {
      final boolean isPackage = (isApkFile(file) || file.isDirectory()) && !PackageInstallerService.isStageName(file.getName());
      if (!isPackage || PackageManagerServiceInjector.ignoreApk(file.getPath())) {
        continue;
      }
      if (RegionalizationEnvironment.isSupported()) {
      if (RegionalizationEnvironment.isExcludedApp(file.getName())) {
        Log.d(TAG, "Regionalization Excluded:" + file.getName());
        continue;
        }
       }      
      parallelPackageParser.submit(file, parseFlags);      //这里可以过滤掉不想要的app
      fileCount++;
      }
      ......
      2.Android侦听应用(Package)变化的方法侦听广播
       当Package状态发生变化时,系统会广播如下一些Action的Intent:
       应用安装:
       public static final String ACTION_PACKAGE_ADDED = "android.intent.action.PACKAGE_ADDED";

       应用更新:
       public static final String ACTION_PACKAGE_REPLACED = "android.intent.action.PACKAGE_REPLACED";
       应用的新版本替代旧版本被安装
       public static final String ACTION_MY_PACKAGE_REPLACED = "android.intent.action.MY_PACKAGE_REPLACED";
       应用的新版本替代旧版本被安装,只发给被更新的应用自己
       public static final String ACTION_PACKAGE_CHANGED = "android.intent.action.PACKAGE_CHANGED";

       应用卸载:
       public static final String ACTION_PACKAGE_REMOVED = "android.intent.action.PACKAGE_REMOVED";
       应用被卸载时发出,正在被卸载的应用自身不会收到
       public static final String ACTION_PACKAGE_FULLY_REMOVED = "android.intent.action.PACKAGE_FULLY_REMOVED";
       应用被完全卸载时发出(数据被删除)
 
        a.系统如何实现只发给某个应用,ACTION_MY_PACKAGE_REPLACED的处理
         sendSystemPackageUpdatedBroadcastsInternal() -->看到在广播ACTION_MY_PACKAGE_REPLACED的时候,是通过Intent.setPackage(String packageName)实现定向发送
       b.ACTION_PACKAGE_CHANGED使用场景
        sendPackageChangedBroadcast(.....)
      c.ACTION_PACKAGE_REMOVED和ACTION_PACKAGE_FULLY_REMOVED的使用场景
       sendPackageRemovedBroadcastInternal(.....)
    ------------- https://blog.csdn.net/zhanglianyu00/article/details/62888359 参考链接-------------
    3.private void processPendingInstall(final InstallArgs args, final int currentStatus)  :  工作是对安装包进行扫描优化,把应用转换成oat格式,然后装载到内存中去
      然后再调用private void installPackageLI(InstallArgs args, PackageInstalledInfo res)  :  然后去解析apk
    ---------------------  http://www.heqiangfly.com/2016/05/12/android-source-code-analysis-package-manager-installation/  ----------------参考链接
                 ---------------------  http://www.codexiu.cn/android/blog/8414/  ----------------参考链接
          
                               安装的流程图    
     六、PackageParse的方法介绍
      包解析器PackageParser就将一个静态的文件,转换成了内存中的数据结构Package,它包含了一个包的所有信息,如包名、包路径、权限、四大组件等,其数据来源主要就是AndroidManifest.xml文件。
      Package parseBaseApk(File apkFile, AssetManager assets, int flags):解析AndroidManifast.xml文件
       解析流程:
       
  1. PackageParser.parsePackages()是包解析器的入口函数,它首先会判定给定的输入是否为一个目录,如果是目录,则以为着目录下可能存在多个拆分后的APK,这就需要以Cluster的方式进行解析;如果仅仅是一个APK文件,就以Monolithic的方式解析;

  2. 解析APK,需要先得到一个中间数据结构PacakgeLite,包名、版本、拆分包等信息都会保存在这个数据结构中;由于一个包可能有多个拆分的APK,所以PackageLite可能关联到多个APK,每一个APK都对应到ApkLite这个数据结构,也是一些基本信息的封装。之所以以Lite为后缀命名,是因为这两个数据结构都比较轻量,只保存APK中很少信息;

  3. 一个APK真正的信息都写在AndroidManifest.xml这个文件中,PackageParser.parseBaseApk()这个函数就是用来解析该文件。其解析过程与AndroidManifest.xml的文件结构一一对应,譬如先解析<application>标签的内容,然后解析其下的<activity>,<service>等标签。

   4.扫描文件的流程:
    
 
    5.scanPackageLI : 主要做以下操作:
    a. //初始化PackageParser对象,用于解析包
      PackageParser pp = new PackageParser();
    b.  //解析包得到一个PackageParser.Package对象
      pkg = pp.parsePackage(scanFile, parseFlags);
    c.   //判定系统APK是否需要更新
      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);
      }
    d.  获取APK的签名信息
        collectCertificatesLI(pp, ps, pkg, scanFile, parseFlags);
    f调用另外一个scanPackageLI()函数,对包进行扫描
      PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanFlags | SCAN_UPDATE_SIGNATURE, currentTime, user);
    6.scanPackageDirtyLI() :    这个是扫描文件关键函数
     a.//针对包名为“android”的APK进行处理
      if (pkg.packageName.equals("android")) {
        ...
        mPlatformPackage = pkg; pkg.mVersionCode = mSdkVersion;
        mAndroidApplication = pkg.applicationInfo;
        ...
      }
     b. //锁上mPacakges对象,意味着要对这个数据结构进行写操作,里面保存的就是已经解析出来的包信息
       synchronized (mPackages) {
       // 如果有定义ShareUserId,则创建一个ShareUserSetting对象
       if (pkg.mSharedUserId != null) {
          suid = mSettings.getSharedUserLPw(pkg.mSharedUserId, 0, 0, true);
          if (suid == null) {
          throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Creating application package " + pkg.packageName + " for shared user failed");
        }
      }
    七、APK安装的流程
      1.拷贝文件到制定目录
      2.解压apk,创建对应的目录
      3.解析apk的AndroidManifast.xml
      4.显示快捷方式
 
    八、应用权限管理
    1.系统权限的机制分为 : 权限解析、权限分配、鉴权、动态添加权限
     2.常见的类的理解
     PermissionInfo : PackageParser.Permission中包含一个对应的PermissionInfo,权限信息的表示,其中包含权限等级的定义(NORMAL, DANGER, SIGNERATURE),另外实现了序列化,用户于进程间通信
      BasePermission : 系统权限的基本表示单元是BasePermission,Settings中维护了一个总的权限映射表mPermissions,所有的权限都会添加到mPermissions列表中,其中key是权限的名字,value是具体的BasePermission实例
     PackageParser.Permission : PackageParser.Permission在上面分析PackageParser解析apk过程中有提及过,解析apk的AndroidManifest.xml文件中的<permission>标签后得到的权限表示
     PackageParser.Permission : PackageParser.Permission在上面分析PackageParser解析apk过程中有提及过,解析apk的AndroidManifest.xml文件中的<permission>标签后得到的权限表示
     GrantedPermissions  : 类里面定义了一个字符串列表grantedPermissions保存pkg已经被赋予的所有权限
     PackageSettingBase : 保存为了如pkg的codePath, resourcePath, signature等信息,同时PackageSettingBase是GrantedPermissions的子类,因为也包含了pkg被赋予的权限列表
     PackageSetting : PackageSetting继承了PackageSettingBase类,并新增如PackageParser.Package和SharedUserSetting
     SharedUserSetting : 
    3.权限相关API
     addPermission(PermissionInfo info) :  动态新增一个新权限
     removePermission(String name) : 删除一个权限
     checkPermission(String permName, String pkgName , int user) : 校验权限是否通过
     getAllPermissionGroups (int flag) : 获取系统中所有的权限组
     getPermissionGroupInfo(String name,int flag) : 查询某个权限组的内容。系统中都有哪些权限组可通过getAllPermissionGroups来查询
     queryPermissionsByGroup(String group,int flag) : 查询一个权限组下面都有些什么权限
     getPermissionInfo(String name, String packageName,int falg) : 根据权限名获取这个权限对象
       4.应用权限授权
      
    5. updatePermissionsLPw(String changingPkg, PackageParser.Package pkgInfo, int flags) : 来更新所有APK的授权状态
    6. grantPermissionsLPw(PackageParser.Package pkg, boolean replace, String packageOfInterest) :  完成授权的准备工作,需要保证所有的扫描出来的权限都有归属,才能开始授权
    7.主要学习的内容作为记录
      包扫描的过程:经过这个过程,Android就能将一个APK文件的静态信息转化为可以管理的数据结构
     
        包查询的过程:Intent的定义和解析是包查询的核心,通过包查询服务可以获取到一个包的信息
        包安装的过程:这个过程是包管理者接纳一个新入成员的体现
     
 
    参考网址 : https://duanqz.github.io/2017-01-04-Package-Manage-Mechanism#%E6%8A%80%E6%9C%AF%E6%9C%AD%E8%AE%B0
    八、应用组件查询的API
      1.List<ApplicationInfo> getInstalledApplications(int flags) : 获取当前系统上安装的所有的应用程序
      2.ApplicationInfo getApplicationInfo(String packageName,int flags) : 获取当前应用的信息
      3.PackageInfo getPackageInfo(String packageName, int flags) : 包名获取一个包的信息
      4.ActivityInfo getActivityInfo(ComponentName component,int flags) :  根据Activity的名称来获取ActivityInfo
      5.int [] getPackageGids(String packageName) : 读取和包名相关的Group id
原文地址:https://www.cnblogs.com/liunx1109/p/11215865.html