深入PMS源码(一)—— PMS的启动过程和执行流程

1、PMS简介

作为Android开发者,或多或少的都接触过Android的framework层架构,这也是开发者从使用Android到了解安卓的过程,framework层的核心功能有AMS、PMS、WMS等,这三个也是系统中最基础的使用,笔者之前分析过Android进阶知识树——Android系统的启动过程Android进阶知识树——应用进程的启动过程,在Android程序启动完成后回启动一系列的核心服务,AMS、PMS、WMS就是在此过程中启动的,之后的系列文章之后会一次介绍他们,本篇主要介绍PMS关于PMS文章共氛围3篇,本篇最为首篇也是PMS的主要逻辑部分;

  • PMS主要功能
  1. 管理设备上安装的所有应用程序,并在系统启动时加载应用程序;
  2. 根据请求的Intent匹配到对应的Activity、Provider、Service,提供包含包名和Component的信息对象;
  3. 调用需要权限的系统函数时,检查程序是否具备相应权限从而保证系统安全;
  4. 提供应用程序的安装、卸载的接口;
  • PMS包管理
  1. 应用程序层:使用getPackageManager()获取包的管理对象PackageManager,PMS使用的也是Binder通信,PackageManager是从ServiceManager中获取注册的Binder对象,具体的实现为PackageManagerService,PMS实现对所有程序的安装和加载;
  2. PMS服务层:PMS运行在SystemServer进程中,主要使用/system/etc/permissions.xml和/data/system/packages.xml管理包信息;
  3. 数据文件管理:PMS负责对系统的配置文件、apk安装文件、apk的数据文件执行管理、读写、创建和删除等功能;
    (1)程序文件:所有系统程序的文件处于/system/app/目录下,第三方程序文件处于/data/app/目录下,在程序安装过程中PMS会将要安装的apk文件复制到/data/app/目录下,以包名命名apk文件并添加“-x”后缀,在文件更新时会修改后缀编号;
    (2)/data/dalvik-cache/ 目录保存了程序中的执行代码,在应用程序运行前PMS会从apk中提取dex文件并保存在该目录下,以便之后能快速运行;
    (3)对framework库文件,PMS会将其中所有的apk、jar文件中提取dex文件,将dex文件保存在/data/dalvik-cache/目录下;
    (4)应用程序所使用的数据文件:数据以键值对保存、数据库保存、File保存所产生的文件都保存带/data/data/xxx/目录下,PMS在程序卸载会删除相应文件;
  • /data/system/packages.xml :系统的配置文件,记录所有的应用程序的包管理信息,PMS根据此文件管理所有程序
  1. last-platform-version:记录系统最后一次修改的版本信息;
  2. permissions:保存系统中所有的权限信息列表,系统权限以androd开头、自定义权限以包名开头;
  3. sigs:签名标签,一个程序只能有一个签名但可以有多个证书,包含count属性表示证书数量;
  4. cert:表示签名证书,包含index、key属性,index表示证书的下标;
  5. perms:表示一个程序中声明使用的权限列表,存在package标签之下;
  6. package:包含一个应用程序的对应关系:
    (1)name:应用程序的包名
    (2)codePath:程序apk文件所在的路径
    (3)nativeLibraryPath:程序中使用的native文件路径,一般指程序包下的lib文件中导入的依赖
    (4)flags:表示应用程序的类型
    (5)it、ut:分别表示程序首次安装的install time、更新时间update time
    (6)userId:表示应用程序在Linux下的用户id
    (7)shareId:表示应用程序所共享的Linux用户Id,与userId互斥
    (8)installer:安装器的名称,在调用PackageManager.installPackage()方法时设置的名称

2、PMS的启动过程

在Android系统启动过程中,程序会执行到SystemServer中,然后调用startBootstrapServices()方法启动核心服务,在startBootstrapServices()方法中完成PMS的启动:

private void startBootstrapServices() {
   
       mPackageManagerService = PackageManagerService.main(mSystemContext, installer,mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore); // 1、调用main()创建PMS对象,注册Binder
    
mPackageManager = mSystemContext.getPackageManager(); //2、初始化PackageManager对象
      }
  1. 调用PackageManagerService.main()方法,在main()方法中创建PMS的对象,并向ServiceManager注册Binder
public static PackageManagerService main(Context context, Installer installer, boolean factoryTest, boolean onlyCore) {
   
        // 1、创建PMS对象
        PackageManagerService m = new PackageManagerService(context, installer,factoryTest, onlyCore);
        m.enableSystemUserPackages();
        ServiceManager.addService("package", m); // 2、注册PMS对象到ServiceManager中
        final PackageManagerNative pmn = m.new PackageManagerNative(); // 3、 创建PMN对象
        ServiceManager.addService("package_native", pmn); // 4、注册PMN对象
        return m;
    }

  1. 调用ContextImpl.getPackageManager()获取PackageManager对象,getPackageManager()中使用ActivityThread.getPackageManager()获取前面创建并注册的Binder对象,然后创建ApplicationPackageManager实例
 @Override
public PackageManager getPackageManager() {
   
  IPackageManager pm = ActivityThread.getPackageManager(); // 3、初始化PackageManagerService的代理Binder对象
     if (pm != null) {
   
     return (mPackageManager = new ApplicationPackageManager(this, pm)); //创建Packagemanager的实例
     }
  return null;
}
  1. 程序在获取PMS对象时会调用ActivityThread.getPackageManager(),从ServiceManager中获取Binder,并获取BInder代理对象PMS实例
public static IPackageManager getPackageManager() {
   
    if (sPackageManager != null) {
   
        return sPackageManager;
    }
    IBinder b = ServiceManager.getService("package);  // 获取注册Binder
    sPackageManager = IPackageManager.Stub.asInterface(b); // 获取IPackageManager代理对象,即PMS
    return sPackageManager;
}

从上面的3个过程可以得出以下结论:

  1. PMS使用Binder通信机制,最终IPackageManager接口的实现类为PackageManagerService类;
  2. 系统中获取的PackageManager对象具体实现的子类是ApplicationPackageManager对象;

3、PMS构造函数

由上面的分析知道,在系统启动后程序执行PMS的构造函数创建对象,整个系统对程序的管理就从这里开始,先介绍下相关类和属性信息:

  • PMS中属性
  1. ArrayMap<String, PackageParser.Package> mPackages:在扫描程序文件目录时会将信息保存在Package对象中,然后将所有程序包名极其的package保存在此集合中;
  2. Settings mSettings:保存整个系统信息的Setting对象;
  3. ActivityIntentResolver mActivities:遍历所有程序的目录,并解析所有的注册清单文件,将提取所有的Intent-filter数据保存在对应的集合中;
  4. ActivityIntentResolver mReceivers:同上
  5. ServiceIntentResolver mServices:同上
  6. ProviderIntentResolver mProviders:同上
  • PackageParser:解析apk文件的主要类,执行解析操作;
  • PackageParser.Package:PackageParser的内部类,保存apk文件中的解析信息,每个应用程序对应一个Package对象,属性信息如下:
  1. String packageName:程序包名
  2. String codePath: 软件包的路径
  3. ApplicationInfo applicationInfo :applicationInfo对象
  4. final ArrayList permissions:申请权限的集合
  5. final ArrayList activities:Activity标签解析的结合
  6. final ArrayList receivers:Receiver标签解析的结合
  7. final ArrayList providers :Provider标签解析的结合
  8. final ArrayList services :Service标签解析的结合
  9. Bundle mAppMetaData = null:注册清单中设置的信息
  10. int mVersionCode:版本Code
  11. String mVersionName:版本名称
  12. int mCompileSdkVersion:Sdk版本
  • Settings:PMS内部主要保存信息的类,主要属性如下:
  1. mSettingsFilename:配置系统目录下的package.xml文件
mSystemDir = new File(dataDir, "system"); // 
mSettingsFilename = new File(mSystemDir, "packages.xml"); //获取系统目录下package.xml文件
  1. mBackupSettingsFilename:配置系统目录下的packages-backup.xml文件,一般在创建和修改package文件前,会先创建packages-backup保存原来信息,在操作读写后会删除此文件;
mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
  1. mPackageListFilename:配置系统目录下的packages.list文件,保存了所有应用程序列表,每一行对应一个应用程序
mPackageListFilename = new File(mSystemDir, "packages.list”);
如:com.android.hai 10032 1 data/data/com.android.hai ,第一项:应用程序包名、第二项:Linux用户Id、第三项:1表示可以debug,0表示不能debug、第四项:程序数据文件目录
  1. ArrayMap<String, PackageSetting> mPackages:解析package.xml文件中的每个程序信息保存在PackageSetting对象中,将所有程序的PackageSetting都填充到集合中
  2. mDisabledSysPackages:保存那些没有经过正常程序卸载的应用程序列表,按照正常卸载程序时,PMS会自动删除package.xml文件中的信息,使用adb命令或其他方法删除时package文件信息则不会删除,系统启动时PMS会检查package文件,并检查对应的应用程序的文件目录,从而判断是否意外删除,如果意外删除则加入mDisabledSysPackages集合;
  3. mUserIds:保存Linux下所有的用户Id列表
  4. mPendingPackages:在解析每个PackageSetting时如果是使用sharedId,则将此Setting加入此集合,等相应的share-user标签后再补充Setting
  5. mPastSignatures:保存所有的签名文件信息
  6. mPermissions:保存所有的权限信息
  7. ArraySet mInstallerPackages:已安装的应用软件包

3.1、PMS的工作过程

  • 构造函数
public PackageManagerService(Context context, Installer installer, // PMS的构造函数
        boolean factoryTest, boolean onlyCore) {
   
sUserManager = new UserManagerService(context, this, // 创建UserManagerService
new UserDataPreparer(mInstaller, mInstallLock, mContext, mOnlyCore), mPackages);
mSettings = new Settings(mPermissionManager.getPermissionSettings(), mPackages); //1、创建保存系统信息的Settings对象

mHandlerThread = new ServiceThread(TAG,Process.THREAD_PRIORITY_BACKGROUND, true );
mHandlerThread.start();
mHandler = new PackageHandler(mHandlerThread.getLooper()); // 2、使用HandlerThread初始化PackageHandler对象

mFirstBoot = !mSettings.readLPw(sUserManager.getUsers(false)); // 3、调用readLPw()读取并解析配置package.xml
}

final int packageSettingCount = mSettings.mPackages.size();
for (int i = packageSettingCount - 1; i >= 0; i--) {
   
    PackageSetting ps = mSettings.mPackages.valueAt(i); // 4、遍历所有的程序的packageSettings对象
    if (!isExternal(ps) && (ps.codePath == null || !ps.codePath.exists())
            && mSettings.getDisabledSystemPkgLPr(ps.name) != null) {
    // 判断文件已经被删除的或程序已被卸载
        mSettings.mPackages.removeAt(i); // 移除对应的PackageSettings对象
        mSettings.enableSystemPackageLPw(ps.name); // 从mDisabledSysPackages集合中也移除此程序的Settings对象
    }
}
File frameworkDir = new File(Environment.getRootDirectory(), "framework”); // 5、获取系统的framework文件
Iterator<PackageSetting> pkgSettingIter = mSettings.mPackages.values().iterator();
while (pkgSettingIter.hasNext()) {
   
    PackageSetting ps = pkgSettingIter.next();
    if (isSystemApp(ps)) {
    // 6、保存已经安装的系统的应用程序
        mExistingSystemPackages.add(ps.name);
    }
}
scanDirTracedLI(frameworkDir, // 7、扫描framework文件目录
        mDefParseFlags
        | PackageParser.PARSE_IS_SYSTEM_DIR,
        scanFlags
        | SCAN_NO_DEX
        | SCAN_AS_SYSTEM
        | SCAN_AS_PRIVILEGED,
        0);
final File systemAppDir = new File(Environment.getRootDirectory(), "app");
scanDirTracedLI(systemAppDir, // 8、扫描系统app文件
        mDefParseFlags
        | PackageParser.PARSE_IS_SYSTEM_DIR,
        scanFlags
        | SCAN_AS_SYSTEM,
        0);
。。。。。。扫描各种目录下的文件信息
scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0); //9、扫描安装app目录/data/app/

mSettings.writeLPr(); // 10、写入配置文件
Runtime.getRuntime().gc();

在启动程序后,PMS的所有工作基本都在构造函数中执行的,具体的执行过程见上面代码注释,这里列出几点主要的执行步骤:

  1. 创建Settings对象,将PMS中的mPackage集合传入,此集合保存所有apk的解析数据
  2. 调用readLPw()方法解析系统配置文件package.xml
  3. 调用scanDirTracedLI()扫描系统app
  4. 调用scanDirTracedLI()扫描/data/app/下安装的第三方啊app
  5. 执行mSettings.writeLPr()将扫描后的结果,重新写入配置文件

上面的几个主要过程即可实现PMS对所有安装程序的执行和管理,下面从源码的角度分析下PMS具体的执行细节;

3.2、解析配置文件package.xml

  • readLPw()
 boolean readLPw(@NonNull List<UserInfo> users) {
   
        FileInputStream str = null; 
        if (mBackupSettingsFilename.exists()) {
    // 1、如果package-backUp.xml 文件存在,读取package-back.xml文件
                str = new FileInputStream(mBackupSettingsFilename); // 一般当写入配置时发生意外才会存在此文件
        }
     
str = new FileInputStream(mSettingsFilename); // 2、正常情况下读取package.xml文件信息
XmlPullParser parser = Xml.newPullParser(); // 3、使用PullParser解析xml文件
parser.setInput(str, StandardCharsets.UTF_8.name());

while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
        && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
    // 4、循环读取xml的节点数据
                    String tagName = parser.getName(); // 读取每个标签名称
3044                if (tagName.equals("package")) {
   
3045                    readPackageLPw(parser);  // 解析package标签中信息保存在PackageSetting对象中
3046                } else if (tagName.equals("permissions")) {
   
3047                    mPermissions.readPermissions(parser);  // 解析系统所有的权限信息,保存在PermissionSettings中
3048                } else if (tagName.equals("shared-user")) {
   
3051                    readSharedUserLPw(parser); // 如果使用share-user,解析此标签
                    }
 // 在解析package标签时,如果程序使用的shareUserId,则将此setting对象加入此集合,等相应共享的程序加载完成后再完善信息
 final int N = mPendingPackages.size();
3172        for (int i = 0; i < N; i++) {
    //  5、遍历mPendingPackage集合中的PackageSetting对象,逐步完善每个对象
3173            final PackageSetting p = mPendingPackages.get(i);
3174            final int sharedUserId = p.getSharedUserId();
3175            final Object idObj = getUserIdLPr(sharedUserId); // 获取次shareUserId对应的程序
3176            if (idObj instanceof SharedUserSetting) {
   
3177                final SharedUserSetting sharedUser = (SharedUserSetting) idObj;
3178                p.sharedUser = sharedUser
  • 3
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值