zoukankan      html  css  js  c++  java
  • 应用学习

    一、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
  • 相关阅读:
    java springboot连接两个数据源
    Android状态栏高度、虚拟操作栏高度
    Java代码实现两种数据库的数据迁移
    微信小程序生成海报
    【比较耗性能的一个东西】Firefox的LayoutReflow
    JS中关于带操作赋值的一个小问题
    js控制样式一个细节
    javascript中打开客户端,关于void的一个疑问
    项目管理日志05-01-05
    项目管理日志05-01-04
  • 原文地址:https://www.cnblogs.com/liunx1109/p/11215865.html
Copyright © 2011-2022 走看看