PackageManagerService启动流程

         从这里开始将开始介绍下android的几个重要的进程:WindowManagerService(WMS)、ActivityManagerService(AMS)、PackagerManagerService(简称PMS)。好多文章都是从AMS讲起,本文为了减轻读者的压力就先从简单的PMS开始。众所周知,android的三大管家都是独立的进程运行的,基本上都是在ServerThread进程运行之后逐个起来,但是PMS在各个应用在Launcher中的显示更为重要,因为没有PMS,系统的APK根本无法显示出来,因为没有安装。这里有个地方要澄清下,android系统并不是安装的APK的会永远存在,其实不是,每次开机系统都要去扫描/system/etc/permission和/data/system/packages.xml获取应用程序和权限,从而进行APK包的安装流程,最后安装的程序才显示到界面上。PWS的初始化都放到了构析函数中:

        PackageManagerService的初始化工作都是在它的构造函数中完成的,主要分两个大步骤:1、扫描xml文件并解析成对应的数据结构; 2、扫描apk文件并解析成对应的数据结构并执行安装,主要流程如下:

1、建立并启动PackageHandler消息循环,用于处理apk安装卸载APK等请求,如adb installpackage installer安装apk时就会发送消息到PMSPackageHandler中进行处理。

mHandlerThread.start();

mHandlernewPackageHandler(mHandlerThread.getLooper());

手动安装APK调用的是installPackage函数,接着就是通过mHandler发送到handleMessage中进行处理的。这里讲的是开机后的APK自动安装流程。

2、通过调用readPermissions()函数解析/system/etc/permission下的xml文件,主要是platform.xml,建立permission和gid之间的关系,可以指定一个权限与几个组对应,当一个apk被授予这个权限时它也同时属于这几个组,readPermission(parser,perm);给一些底层用户分配一些权限,如shell授予各种permission,把一个权限赋予一个uid,当apk使用这个uid运行时,就具备了这个权限系统增加的一些应用需要link的扩展的jar库。

 3、通过调用mSettings.readLPw函数检查/data/system/packages.xml是否存在,里面记录了系统的permission,以及每个apk的name,codePath,flags,ts,version,userid等,这些信息主要是通过apk安装的时候解析AndroidManifest.xml获取到的,解析完apk后将更新信息写入这个文件并保存,下次开机直接从里面读取相关信息添加到内存相关列表中,当有apk安装,升级,删除等操作时会更新这个文件;格式如下:

<?xml version=‘1.0’ encoding=‘utf-8’ standalone=‘yes’ ?>

<packages>

<last-platform-version internal=“15”external=“15” />

<permission-trees />

<permissions>

<item name=“android.permission.SHUTDOWN”package=“android” protection=“3”/>

<item name=“android.permission.WRITE_CONTACTS”package=“android” protection=“1”/>

<item name=“android.permission.VIBRATE”package=“android” />

</permissions>

<package name=“com.android.contacts”codePath=“/system/app/Contacts.apk”nativeLibraryPath=“/data/data/com.android.contacts/lib”flags=“1” ft=“157e38c3c28”it=“157e38c3c28”ut=“157e38c3c28” version=“15” sharedUserId=“10000”>

<sigs count=“1”>

<cert index=“2”/>

</sigs>

</package>

<package name=“com.android.calendar”codePath=“/system/app/Calendar.apk”nativeLibraryPath=“/data/data/com.android.calendar/lib”flags=“1” ft=“157e38bf9c0”it=“157e38bf9c0”ut=“157e38bf9c0” version=“15” userId=“10005”>

<sigs count=“1”>

<cert index=“0”/>

</sigs>

</package>

<shared-user name=“android.uid.shared”userId=“10000”>

<sigs count=“1”>

<cert index=“2”/>

</sigs>

<perms>

<item name=“android.permission.WRITE_EXTERNAL_STORAGE”/>

<item name=“android.permission.REBOOT”/>

</perms>

</shared-user>

<shared-user name=“android.uid.log”userId=“1007”>

<perms />

</shared-user>

</packages>

《PackageManagerService启动流程》

这里注明下xml的解析用的都是pull xml解析方式,包括布局文件的解析也是,可见安卓系统是多么的喜欢Pull解析方式。

4、启动多个AppDirObserver线程监测/system/framework,/system/app,/data/app/data/app-private目录的事件,主要监听add和remove事件,对于目录监听底层通过innotify机制实现,inotify是一种文件系统的变化通知机制如文件增加、删除等事件可以立刻让用户态得知,它为用户态监视文件系统的变化提供了强大的支持,当有addevent时调用scanPackageLI(File,int,int)处理,当有removeevent时调用removePackageLI处理;其开启的监听线程代码如下:

            mFrameworkInstallObserver =newAppDirObserver(

                  frameworkDir.getPath(),OBSERVER_EVENTS,true,false);

           mFrameworkInstallObserver.startWatching();

           scanDirLI(frameworkDir,PackageParser.PARSE_IS_SYSTEM

                   | PackageParser.PARSE_IS_SYSTEM_DIR,

                    scanMode |SCAN_NO_DEX,0);

           File privilegedAppDir =new File(Environment.getRootDirectory(),“priv-app”);

            mPrivilegedInstallObserver =new AppDirObserver(

                    privilegedAppDir.getPath(),OBSERVER_EVENTS,true,true);

           mPrivilegedInstallObserver.startWatching();

               scanDirLI(privilegedAppDir,PackageParser.PARSE_IS_SYSTEM

                       | PackageParser.PARSE_IS_SYSTEM_DIR

                       | PackageParser.PARSE_IS_PRIVILEGED,scanMode,0);

           File systemAppDir =new File(Environment.getRootDirectory(),“app”);

            mSystemInstallObserver =new AppDirObserver(

                   systemAppDir.getPath(),OBSERVER_EVENTS,true,false);

            mSystemInstallObserver.startWatching();

           scanDirLI(systemAppDir,PackageParser.PARSE_IS_SYSTEM

                   | PackageParser.PARSE_IS_SYSTEM_DIR,scanMode,0);

           File vendorAppDir =new File(“/vendor/app”);

            mVendorInstallObserver =new AppDirObserver(

                  vendorAppDir.getPath(),OBSERVER_EVENTS,true,false);

            mVendorInstallObserver.startWatching();

5、 调用scanDirLI函数启动apk解析,解析目录/system/framework、/system/app、/vendor/app、/data/app、/data/app-private下的APK文件,解析后的数据放到PackageParser.Package中。调用流程如下:scanDirLI->scanPackageLI->PackageParser.parsePackage(),parsePackage函数返回的是一个PackageParser.Package结构类,最后会把引用给PackageSetting的PackageParser.Package pkg变量。这里是整个流程最关键的一步,因为前面所做的事情都是为了把包内容等存储到PackageSetting的PackageParser.Package变量中,为的是接着Lancher的显示或者其他应用程序获取应用信息都是通过这个变量进行获取。另外一个要提到的是AndroidMenifest的versionCode属性,当一个APK即存在于/system/app或者/data/app/中时,那么系统将以versionCode值大的那个APK为准。

比如我们经常用到的获取应用列表的函数queryIntentActivities,就是通过PackageManger调用到PMS的queryIntentActivities函数,而queryIntentActivities函数最终也是获取了PackageSetting的PackageParser.Package变量,从而得到APK的相关信息。

7、通过updatePermissionsLPw函数里面的grantPermissionsLPw函数给apk赋权限,实际上也是把相关的权限值添加到PackageSetting的grantedPermissions变量中,

grantedPermissions是HashSet<String>类型的变量,最后APP或者系统其他地方需要获取某个APK的权限,就可以通过PackageSetting类获取了,这里的数据结构设计得比较巧妙,值得深入学习。

8、解析完所有APK相关xml数据后,scanPackageLI函数接着继续调用mInstaller.install(packageName,uid,uid, seinfo)执行正式的安装流程。

9、 最后在构析函数中调用mSettings.writeLPr();函数将解析出的Package的相关信息更新到相关全局变量和文件。主要是把前面解析出来的信息重新更新到原先的文件,因为这时的APK信息可能跟packages.xml的数据不一样了。

    原文作者:jianzhechen
    原文地址: https://blog.csdn.net/yibanbubadao123/article/details/62046316
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞