Android程序包管理(1)--PKMS启动过程

本文详细介绍Android系统的包管理服务(Package Manager Service, PKMS)启动过程,包括重要文件目录介绍、数据结构说明、启动流程解析等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、PKMS启动过程

1、重要文件目录介绍

1.目录:

/system/ect/permissions/xxx.xml:加载系统feature

/system/ect/permissions/platform.xml:为核心系统进程uid/gid分配默认权限

  • permission/group:用于建立linux层gid和Android层permission之间的映射关系

  • assign-permission:用于向指定的uid赋予相应的权限

  • library:用于指定系统库,应用程序运行时系统自动为这些进程加载这些库

/data/system/packages.xml:所有应用程序与包管理相关信息,保存所有安装程序的基本包信息。当进行程序安装更新卸载是都会更新此文件。

/data/system/packages.list:保存所有应用程序列表,每一行对应于一个应用程序。

/data/system/packages-stopped.xml:保存被用户强行停止的程序信息。

/system/app:系统自带应用程序路径

/data/app:第三方应用程序路径

/data/dalvik-cache/:dex文件输出路径

/system/framework/.apk; .jar:framework中的程序

/data/secure/:加密目录

/data/drm/:drm用户专有目录

/data/app-private/:drm用户专有目录

/data/data/:普通程序数据

2.数据结构:

(1)Settings:

File mSettingsFilename:配置文件名称,指的是packages.xml文件

File mBackupSettingsFilename:配置文件的备份文件

File mPackageListFilename:packages.list文件保存所有程序列表

HashMap<String, PackageSetting> mPackages:填充从packages.xml文件中读取的包管理信息

HashMap<String, PackageSetting> mDisabledSysPackages:保存没有经过标准卸载方式删除的程序列表

HashMap<String, SharedUserSetting> mSharedUsers:保存所有共享id的信息,来源于packages.xml中的

ArrayList<Object> mUserIds:所有用户id

ArrayList<Signature> mPastSignatures:保存所有的签名

HashMap<String, BasePermission> mPermissions:保存所有权限

HashMap<String, BasePermission> mPermissionTrees:对应packages.xml文件中的permission-tree,没有使用

(2)PMS:

HashMap<String, PackageParser.Package> mPackages:保存所有程序包信息.来源于扫描程序目录下所有程序文件

Settings mSettings:上面介绍的类

int[] mGlobalGids:系统中所有linux用户id

SparseArray<HashSet<String>> mSystemPermissions:系统中所有权限的名称

HashMap<String, SharedLibraryEntry> mSharedLibraries:系统所依赖的共享java库,来源于platform.xml中library标签

ActivityIntentResolver mActivities、ActivityIntentResolver mReceivers、ServiceIntentResolver mServices、ProviderIntentResolver mProviders:用于intent-filter匹配.通过读取manifest提取intent-filter下的数据

保存的framework-res.apk信息:

mPlatformPackage:保存该package信息

mAndroidApplication:此package中的ApplicationInfo

mResolveActivity:指向用于表示ChooserActivity信息的ActivityInfo

mResolveInfo:存储系统解析Intent后得到的结果信息,根据该信息得到组件

3.系统apk

(1)framework-res.apk包含以下常用Activity:

ChooserActivity:当多个Activity符合某个intent时弹出此Activity

RingtonePickerActivity:铃声选择Activity

ShutdownActivity:关机前确认对话框

4.uid含义

(1)Process.myUid() = ApplicationInfo.uid = PackageSetting.appid;这里的uid标识具体独立应用。

(2)UserHandle.getUid(int userId, int appId); 这类的uid标识多用户下的用户id。如果是单用户与上面的uid一致,这里传入的appid就是上面的uid。

参考:http://blog.youkuaiyun.com/leirenbaobao/article/details/48318753

http://blog.youkuaiyun.com/Gaugamela/article/details/78689580

2、PKMS启动过程

如下图启动流程:

一、在ServerThread中启动PKMS

1.初始化启动PKMS:系统开机时会经过一列调用到ServerThread.initAndLoop()函数,该函数中会初始化启动各个系统服务,其中就包含PKMS服务。

  • 启动PKMS服务通过调用PackageManagerService.main()方法实现,传入参数需要关注:installer对象负责辅助程序安装.与SocketServer通信;onlyCore代表是否只扫描系统app正常启动为false。

2.执行已经安装的apk的dex优化:执行完初始化启动PKMS之后,接着调用PackageManagerService.performBootDexOpt()执行所有安装的apk的dex优化操作,这里的优化只有在第一次系统启动之后进行。

3.通知系统PKMS启动完成:调用PackageManagerService.systemReady()通知系统PKSM启动完成。

二、在PKSM.main()中启动服务

1.首先构造PackageManagerService对象,传入参数。

2.将这个新建对象添加到ServiceManager中。

三、PackageManagerService构造函数中执行启动操作

1.赋值变量:将传入参数赋值到内部变量中。mNoDexOpt表示是eng版本扫描apk后不做dex优化。

2.创建辅助类Settings:Settings是Android的全局管理者,用于协助PMS保存所有的安装包信息。

  • 在Settings构造函数中构建带读取的配置文件的File对象及相应目录。

    • 创建目录:创建/data/system目录,依次构建文件/data/system/packages.xml、/data/system/packages-backup.xml、/data/system/packages.list、/data/system/packages-stopped.xml、/data/system/packages-stopped-backup.xml。以上文件作用见第一节介绍。
  • 添加共享的uid及name:使用Settings.addSharedUserLPw()预置可以共享的uid及name。

    • 查看是否有缓存:首先会从mSharedUsers获取制定name对应的SharedUserSetting对象,这里不存在对应的SharedUserSetting对象。

    • 新建并保存SharedUserSetting对象:不存在缓存所以新建SharedUserSetting对象保存传入参数uid、name、flag。使用addUserIdLPw()将传入对象以其uid为索引分别存入mUserIds或者mOtherUserIds中。这样做可以直接以uid为索引获取SharedUserSetting提升查询效率。接着存入mSharedUsers以name为key传入该map中。

3.赋值获取变量:赋值installer该对象负责与与SocketServer通信辅助程序安装,获取默认的现实信息保存到mMetrics中。

4.创建消息循环队列:创建PackageHandler消息队列,处理外部的安装请求。

5.创建系统路径及目录存放文件:分别创建/data/data、/data/app、/data/app-lib等数据目录。

6.开始读取系统的权限配置文件:调用readPermissions()从/system/etc/permissions/目录下读取全部xml文件,属性值保存到mSettings.mPermissions中。执行完毕PMS保存系统feature及指定uid的权限。这些文件是有硬件信息编译之后复制到该目录下。

  • 首先遍历该目录下所有文件,先处理除了platform.xml的其他所有文件,这里处理的文件基本是只定义系统的一些feature。遍历执行结束开始真正处理platform.xml。

  • 处理过程主要是解析xml文件中的各个tag并且保存信息到PMS中,platform.xml文件的典型内容如下:

    <permissions>
    
        <!-- 建立权限名与gid的映射关系-->
    
        <permission name="android.permission.READ_EXTERNAL_STORAGE" >
    
            <group gid="sdcard_r" />
    
        </permission>
    
        <!-- 为指定uid赋予权限-->
    
        <assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="media" />
    
         <!-- 系统提供的java库,程序运行必须加载-->
    
        <library name="javax.btobex" file="/system/framework/javax.btobex.jar"/>
    
    </permissions>
    

以上文件解析完成生成相关数据结构:mGlobalGids/mSharedLibraries/mSystemPermission/mAvaliableFeature/mSettings.mPermissions。相关介绍见第一节。

7.读取Settings中创建的三个配置文件:调用mSettings.readLPw()主要工作从/data/system/packages.xml读取所有应用程序中和包管理相关的信息,保存到mSettings.mPackages。一个典型的packages.xml文件如下:

        <package name="cn.nubia.video" codePath="/system/priv-app/NubiaVideo" nativeLibraryPath="/system/priv-app/NubiaVideo/lib" flags="1078508613" ft="8a8bdd70" it="8a8bdd70" ut="8a8bdd70" version="40001" userId="10014">

                <sigs count="1">

                    <cert index="3" />

                </sigs>

                <proper-signing-keyset identifier="2" />

                <signing-keyset identifier="2" />

            </package>
  • 首先根据是否存在packages.xml及其备份文件确定读取备份文件还是源文件。使用XmlPullParser读取文件解析开始。分别解析package、permissions、shared-user等标签。这里以解析package标签为例调用readPackageLPw(parser)。

    • 获取制定属性对应值:name(包名)、userId、realName、codePath、nativeLibraryPath、version…

    • 根据获取到的属性值处理:首先判断userId如果大于0调用addPackageLPw()获取一个该userId对应的PackageSetting对象,该对象描述已安装的pkg的信息。然后保存该对象。接着判断sharedIdStr如果存在则该pkg以共享id运行,新建对象PedingPackage保存信息到mPendingPackages中后续处理。接下来还会判断其他属性并赋值相应信息到该PackageSetting对象省略。

  • 该文件解析结束后处理mPendingPackages中以共享id运行的pkg。

    • 循环遍历获取待处理PedingPackage,使用getPackageLPw()获取目标uid对应的PackageSetting,接着拷贝信息到获取的对象中。
  • 接着读取packages-stopped.xml文件省略该过程。

8.对系统核心java库进行dex操作流程:省略该过程。

9.设置监听系统pkg目录,并且扫描目录下的apk文件:系统pkg目录主要包括:/system/frameworks /system/app /verdor/app

  • 首先新建对象mFrameworkInstallObserver监听该目录。

  • 调用scanDirLI()扫描该目录下的apk文件。

    • 首先循环遍历该目录下所有文件,判断只有apk 文件才扫描。接着调用scanPackageLI()扫描该apk文件并且返回PackageParser.Package对象。

    • 在scanPackageLI()中:首先新建PackageParser对象,解析该apk对应的manifest文件生成对应PackageParser.Package对象。

-+处理package升级问题,旧package信息PackageSetting来自于package.xml省略该过程。

-+调用setApplicationInfoPaths()为Package对象的ApplicationInfo设置其codePath/resPath。

-+调用scanPackageLI()将解析到的信息转换到PKMS中。

-++在scanPackageLI()中:

-+++首先单独处理包名为android的及framework-res.apk信息。为mResolveActivity赋值相应信息该组件用途见第一节。

-+++如果该pkg声明了以共享id运行则获取对应SharedUserSetting对象suid。

-+++调用mSettings.getPackageLPw()获取该pkg对应的packageSetting对象,该pkg如果已安装则存在该对象,未安装过则会新建该对象并分配对应的appid,该appid即uid表示一个特定应用。

-+++将packageSetting对象的appid赋值给ApplicationInfo的uid。这里给出了一个android应用的uid的来源。

-+++调用fixProcessName()确定该应用运行的进程名称。

-+++开始设置该pkg对应的数据目录:判断如果是系统pkg即framework-res.apk直接为其ApplicationInfo设置数据目录为/data/system。

-+++如果是普通pkg,调用getDataPathForPackage()获取其对应的数据目录,如果该目录存在判断其所属uid是否一致处理不一致情况,并且为其ApplicationInfo设置数据目录。该目录不存在则创建,调用createDataDirsLI()执行创建并且为其ApplicationInfo设置数据目录。接着为该pkg确定nativelib所在目录。

-+++提取对应的so文件到制定目录。接着开始对apk进行dex优化操作,然后将Package对象中的四大组件信息登记到PKMS中。

10.依次设置文件夹监听后,删除安装失败的报信息及临时文件。

11.设置对非系统pkg目录监听和扫描,非系统pkg目录包括:/data/app /data/app-private

12.重新为应用赋予权限,最后将已安装的apk信息重新写入package.xml。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值