美文网首页
PackageManagerService架构剖析开篇

PackageManagerService架构剖析开篇

作者: 码上就说 | 来源:发表于2018-07-25 15:59 被阅读182次

    PackageManagerService在Android中的非常重要,主要负责的功能如下:
    1.解析AndroidManifest.xml,主要包括AndroidManifest中节点信息的解析和target-name的分析和提炼,这部分和ActivityManagerService和WindowManagerService都有紧急的联系。关于AndroidManifest.xml中的属性设置,会单独拎出来讲解,本文不扩展讲解。
    2.扫描本地文件,主要针对apk,主要是系统应用、本地安装应用等等。这部分会在下面仔细讲解。
    3.管理本地apk,主要包括安装、删除等等。
    下面称PackageManagerService为PMS

    一、PMS启动

    PMS是系统的关键服务,也是在system_server进程中启动的,同AMS与其他的系统服务,下面是PMS的启动流程:


    PackageManagerService启动流程.jpg

    上面是PMS启动流程,PMS还是从systemServer中启动的系统服务,主要关注一下PMS在构造函数中做了什么,构造函数中一般是初始化PMS中需要使用的线程和读取基本的配置。

    1.1 PMS系统服务注册的地方

    PMS中的main函数中有PMS服务的注册,还是将PMS注册到ServiceManager中,然后service写入/dev/binder中,可以实现用户空间和内核空间的通信,这是binder通信机制相关的知识。

    PackageManagerService.java
    public static PackageManagerService main(Context context, Installer installer,
                boolean factoryTest, boolean onlyCore) {
            // Self-check for initial settings.
            PackageManagerServiceCompilerMapping.checkProperties();
    
            PackageManagerService m = new PackageManagerService(context, installer,
                    factoryTest, onlyCore);
            m.enableSystemUserPackages();
            ServiceManager.addService("package", m);
            final PackageManagerNative pmn = m.new PackageManagerNative();
            ServiceManager.addService("package_native", pmn);
            return m;
        }
    

    除了PMS,这儿还注册了“package_native”的服务,这个服务主要是给native代码调用的,包含3个函数,获取package的相关信息(versionCode、uid、Installer相关信息)。

     PackageManagerService m = new PackageManagerService(context, installer,
                    factoryTest, onlyCore);
    

    这里传入PMS构造中的几个参数需要了解一下。
    1.context,上下文。
    2.installer,类是Installer.java
    frameworks/base/services/core/java/com/android/server/pm/Installer.java

    public class Installer extends SystemService {
    //......
    }
    

    这是一个负责package安装、删除、迁移、更新的系统服务。因为PMS中需要管理package,那么就需要installer实例的协助。
    3.factoryTest,当前是否是测试模式。
    4.onlyCore,onlyCore为true表明当前的设置正在加密或者已经是加密的,说明此时只能运行核心app,刚开始不会扫描非系统app,这个会在扫描流程中详细说明下。

    1.2 PMS构造函数剖析

    PMS的构造函数代码非常多,有800多行,这么多代码,需要仔细剖析一下。这儿按照执行顺序将PMS构造函数分为下面几块:

    1.2.1 设置uid属性

    这里主要设置的是shareUsers属性,放在Settings中的ArrayMap中,先存起来。

    1.2.2 初始化package解析和管理的对象

    主要初始化的类是:
    1.PackageDexOptimizer
    2.DexManager
    3.ArtManagerService
    4.ProtectedPackages

    1.2.3 创建PackageHandler处理package管理中消息
    1.2.4 扫描系统app和系统目录下的jar
    1.2.5 扫描应用app和应用目录下的lib

    这个步骤的执行是有条件的,具体条件是 1.1小节中提到的onlyCore变量,如果onlyCore为false,才会执行扫描操作。

    PackageManagerService.java
    
                // Find base frameworks (resource packages without code).
                scanDirTracedLI(frameworkDir, mDefParseFlags
                        | PackageParser.PARSE_IS_SYSTEM
                        | PackageParser.PARSE_IS_SYSTEM_DIR
                        | PackageParser.PARSE_IS_PRIVILEGED,
                        scanFlags | SCAN_NO_DEX, 0);
    
                // Collected privileged system packages.
                final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
                scanDirTracedLI(privilegedAppDir, mDefParseFlags
                        | PackageParser.PARSE_IS_SYSTEM
                        | PackageParser.PARSE_IS_SYSTEM_DIR
                        | PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0);
    
                // Collect ordinary system packages.
                final File systemAppDir = new File(Environment.getRootDirectory(), "app");
                scanDirTracedLI(systemAppDir, mDefParseFlags
                        | PackageParser.PARSE_IS_SYSTEM
                        | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
    
    

    它们都是调用scanDirTracedLI,除了检索的目录不同,这个函数值得进一步探讨。
    下面挑出final File systemAppDir = new File(Environment.getRootDirectory(), "app");
    这个Environment.getRootDirectory()是什么?

    private static final File DIR_ANDROID_ROOT = getDirectory(ENV_ANDROID_ROOT, "/system");
    private static final File DIR_ANDROID_DATA = getDirectory(ENV_ANDROID_DATA, "/data");
    public static File getRootDirectory() {
            return DIR_ANDROID_ROOT;
        }
    

    说明这个systemAppDir目录就是/system/app/,存放系统应用的地方。
    接下里讨论一下scanDirTracedLI(...)做什么。
    先阐述一下scanDirTracedLI(...)的调用流程:


    scanDirTraceLI流程.jpg

    这儿做的事情很简单,总结起来就是解析/system/app 目录下面的所有apk,然后解析其中的文件,例如解析AndroidManifest.xml,解析assets,解析res等等,分别使用存储结构存储起来,这些数据在后面都会用到,本文只谈大纲,代码的详细分析流程我后面会重新开章节讲解,请见谅。

    二、PMS结构分析

    分析PMS的代码结构,有助于我们从整体架构的角度来分析PMS。

    PackageManagerService.java
    public class PackageManagerService extends IPackageManager.Stub
            implements PackageSender {
    }
    

    IPackageManager.Stub是IPackageManager.aidl自动生成的,正好也说明了PMS是service端的,通过binder交互,这里主要看看IPackageManager.aidl有什么主要的方法。
    我简单的分为下面几类:

    2.1 权限管理方法

        PermissionInfo getPermissionInfo(String name, String packageName, int flags);
        ParceledListSlice queryPermissionsByGroup(String group, int flags);
        PermissionGroupInfo getPermissionGroupInfo(String name, int flags);
        ParceledListSlice getAllPermissionGroups(int flags);
        int checkPermission(String permName, String pkgName, int userId);
        int checkUidPermission(String permName, int uid);
        boolean addPermission(in PermissionInfo info);
        void removePermission(String name);
        void grantRuntimePermission(String packageName, String permissionName, int userId);
        void revokeRuntimePermission(String packageName, String permissionName, int userId);
        void resetRuntimePermissions();
        int getPermissionFlags(String permissionName, String packageName, int userId);
        void updatePermissionFlags(String permissionName, String packageName, int flagMask,
                int flagValues, int userId);
        void updatePermissionFlagsForAllApps(int flagMask, int flagValues, int userId);
        boolean shouldShowRequestPermissionRationale(String permissionName,
                String packageName, int userId);
    

    2.2 通用属性方法

        PackageInfo getPackageInfo(String packageName, int flags, int userId);
        PackageInfo getPackageInfoVersioned(in VersionedPackage versionedPackage,
                int flags, int userId);
        int getPackageUid(String packageName, int flags, int userId);
        int[] getPackageGids(String packageName, int flags, int userId);
        ApplicationInfo getApplicationInfo(String packageName, int flags ,int userId);
        ActivityInfo getActivityInfo(in ComponentName className, int flags, int userId);
        boolean activitySupportsIntent(in ComponentName className, in Intent intent,
                String resolvedType);
        ActivityInfo getReceiverInfo(in ComponentName className, int flags, int userId);
        ServiceInfo getServiceInfo(in ComponentName className, int flags, int userId);
        ProviderInfo getProviderInfo(in ComponentName className, int flags, int userId);
    

    2.3 组件处理方法

        ParceledListSlice queryIntentActivities(in Intent intent,
                String resolvedType, int flags, int userId);
        ParceledListSlice queryIntentActivityOptions(
                in ComponentName caller, in Intent[] specifics,
                in String[] specificTypes, in Intent intent,
                String resolvedType, int flags, int userId);
        ParceledListSlice queryIntentReceivers(in Intent intent,
                String resolvedType, int flags, int userId);
        ResolveInfo resolveService(in Intent intent,
                String resolvedType, int flags, int userId);
        ParceledListSlice queryIntentServices(in Intent intent,
                String resolvedType, int flags, int userId);
        ParceledListSlice queryIntentContentProviders(in Intent intent,
                String resolvedType, int flags, int userId);
        ProviderInfo resolveContentProvider(String name, int flags, int userId);
        void querySyncProviders(inout List<String> outNames,
                inout List<ProviderInfo> outInfo);
        ParceledListSlice queryContentProviders(
                String processName, int uid, int flags, String metaDataKey);
        ComponentName getInstantAppResolverComponent();
        ComponentName getInstantAppResolverSettingsComponent();
        ComponentName getInstantAppInstallerComponent();
    

    2.4 其他方法

    //......
        boolean isFirstBoot();
        boolean isOnlyCoreApps();
        boolean isUpgrade();
        boolean isStorageLow();
    //......
    

    这儿并没有列出所有的方法,这些方法大家了解即可,不需要一个一个方法去抠,只需要抓住核心调用方法,最好和app开发结合起来理解即可。

    PackageSender接口是主要处理receiver的,这些个receiver都是解析AndroidManifest的时候得到的receiver,了解即可。

    interface PackageSender {
        void sendPackageBroadcast(final String action, final String pkg,
            final Bundle extras, final int flags, final String targetPkg,
            final IIntentReceiver finishedReceiver, final int[] userIds);
        void sendPackageAddedForNewUsers(String packageName, boolean isSystem,
            int appId, int... userIds);
    }
    

    三、小结

    本文简单分析了PMS的启动和构造函数,只阐述了大纲,我的思路是接下来会用一个章节讨论一下PMS是如何解析apk的。谢谢大家。

    相关文章

      网友评论

          本文标题:PackageManagerService架构剖析开篇

          本文链接:https://www.haomeiwen.com/subject/vmbvuftx.html