《深入理解androidII》PackageManagerService学习草稿

最近将uiautomator的工作转移出去了,等待下一个任务的到来间隙,学习学习framework的知识,找来《深入理解android II》开始学,都是一些笔记。方便自己理解。


PKMS


System.Server中调用PackageManagerService.main()方法,该方法中创建PackageManagerService对象,调用PackageMangerService的构造函数,而且还将该对象加入到ServiceManager对象中。

PackageManagerService构造方法中会首先判断sdk的版本是否小于等于0,然后判断是否是英文版本,创建DisplayMetrics对象.创建Settings类,在存储运行过程中设置一些参数。然后调用Settings.addSharedUserLPw方法。


addSharedUserLPw方法传过来的参数为(字符串,uid值,flag),uid代表了进程的权限问题。方法中做了哪些处理?首先在系统已有的SharedUserSettings表中检索一下是否已经存在符合传入参数的SharedUserSettings对象。如果不存在,则以name,flag创建一个对象,设置该对象userId值为uid,然后将该SharedUserSettings对象保存到对应的数组中。


然后分析SharedUserSettings类。保存具有相同sharedUserId的包名。继承自GrantedPermissions权限


做完以后创建SharedUserSettings对象后,回到PackageManagerService构造函数中。后续的工作就是创建Installer,WM,Display,然后创建用户程序的安装和卸载的线程。然后创建各种目录。data/data,data/user,data/app-private.然后到readPermissions()和Settings.readLPw();


readPermissions()方法为解析etc/permissions目录下的所有xml文件,里面包括各种各样的权限信息。实际调用readPermissionsFromXml()

platform.xml文件中有4种标签:

<一>linux层gid和android层permission映射关系

<permission>

<group/>

</permission>

<二>用于向指定uid赋予相应的权限

<assgin-permission/>

<三>指定系统库

<library/>


readPermissionsFromXml()方法

int[] mGlobalGids保存<group>标签中gid的值

HashMap<String,String> mshareLibrarie保存library标签中库名,库文件的位置

SparseArray<HashSet<String>>  mSystemPermissions<assgin-permission>标签里值,uid,权限字符串为里面的HashSet值。以uid指向很多权限。

HashMap<String,FeatureInfo> mAvailableFeatures解析<feature>标签

HashMap mSettings.mPermissions解析<permission>标签


Settings构造方法中会在data/system文件夹下生成5个文件

package.xml:package相关的信息,当系统进行程序安装,卸载和更新时都会更新该文件

package-backup.xml:

package-stop.xml:从系统自带的设置程序中进入到应用程序页面,然后强制关闭某个应用,这些应用的信息保存在该文件中

package-stop-backup.xml:先在该文件中写,然后完成后复制改名为package-stop.xml

package.list:系统中所有非系统自带的apk信息。


Settings.readLPw就是解析上面的xml文件,然后保存到对应的数据结构中。


扫描package开始:

/system/frameworks

/data/dalvik-cache

获得java启动类库,判断启动库里的jar文件是否需要做优化和mshareLibrarie是否需要,如果需要做优化,则删除dalivk-cache到的缓存信息,优化后重新得到。


进入第二阶段:

linux中inotify机制:文件系统变化通知机制,对每个目录都是先创建文件夹监控对象,然后启动监控,然后scanDirLI扫描开始。

/system/framworks/:扫描里面的framework-res.apk

/system/app :browser.apk、settingsProvider.apk等系统应用

/vendor/app:第三方应用

以上三个目录为系统package。


scanDirLI()方法分析:PKMS中的方法,只扫描apk文件,扫描的时候调用scanPackageLI返回PackageParser.Package对象,代表APK的数据结构。扫描过程中遇到扫描失败的情况还得判断它是否属于系统的APK,如果是非系统的apk就地删除。

scanPackageLI()方法分析:PKMS中的方法。调用PackageParser.parsePackage()真正解析apk文件,返回的是PackageParser.Package对象,将文件里的内容映射到数据结构中,还有package升级的工作。然后再调第二个scanPackageLI,传入的参数为Package,第一个scanPackageLI传入的是File。

PackageParser类分析:解析AndroidManifest.xml文件。首先调用parsePackage()获得该xml配置文件,然后再调用同名函数解析xml里的各个节点,这就设计到xml解析方法的知识。PP子类中Package保存整个AndroidManifest.xml里所有信息,以内部变量的信息保存其他子类对象,以数组信息保存在该类中。PP中的子类继承自Component<ActivityIntentInfo>的原因是我们需要通过intent查询到相应的activity这个需求。通过这样的继承关系就能做到这点,如果单纯的就建一个Activity裸类达不到这样的效果。PP中的PackageLite让我想到了SQLite,它也是一个轻量级的数据结构,保存package一些简单的信息用的。理解为SQLite也不过分。


第二个PKMS.scanPackageLI()分析:完成的工作是将package加入到系统中。首先单独处理packageName为“android”的framework-res.apk。framework-res.apk中配置档文件包含的信息如下:(都是一些与系统相关的信息)

ChooserActivity:当多个activity符合同一个intent会有一个选择框弹出

RingtonePickerActivity:铃声选择activity

ShutdownActivity:关机前弹出的选择对话框

PKMS专门设置成员变量来保存该package中的信息:

mPlatformPackage:保存该package信息

mAndroidAppliaction:保存ApplicationInfo信息

mResolveActivity:保存ChooseActivity信息的ActivityInfo信息

mResolveInfo:ResolveInfo类型。保存由系统解析intent后剩下的信息,例如解析完intent后的activity信息。该对象的变量activityInfo指向mResolveActivity。之前所说的PP。activity就是通过过滤完intent得到ResolveInfo对象后得到生下来的activity对象。

接着scanPackageLI所要做的操作是对androidManifest.xml里的信息做一些验证,看是否符合系统的要求。然后将该package里的四大组件公有化。



扫描完系统的apk后,要对非系统的apk进行扫描,也就是/data/app、/data/app-private非系统package目录里扫描apk信息然后加入到系统中。

进行完扫描工作完成后,第二阶段的工作完成,然后将扫描的到的信息集中整理,将某些信息保存到相应的文件中。这样pkms的构造函数里的工作就全部完成啦。


构造函数的工作分3个阶段

1.扫描system/etc/permissions包下的xml信息

2.扫描包信息,最耗时,所以才会造成系统启动速度慢。

3.将扫描的到的信息整理,写到相应的文件中。



APK Installation分析

文件:commandline.c

首先在int adb_commandline()中调用install_app函数。该函数做了3件事情:

1.对apk安装进行验证

2.调用pm_command()安装

3.安装完毕后,删除/data/local/tmp里的文件,因为安装完成以后apk位于/data/app目录下。


pm_command():将要安装的参数信息发送给手机端的adbd.会用一个叫pm脚本,该脚本通过app_process进程去执行pm.jar包中的main函数。然后来看看pm.java的main函数做了哪些工作。

通过aidl接口获得PKMS的binder客户端,IPackageManager.Stub.asInterface(ServiceManager.getService("package"));然后调用runInstall()方法,该方法首先做一些参数分析,然后将Verification程序加入进来,最后调用PKMS客户端来执行installPackageWithVerification函数。而该函数只是简单的创建

InstallParams


几个对象后,发送一个message,信息内容是INIT_COPY。就交给了之前创建mHandler对象

            mHandlerThread.start();
            mHandler = new PackageHandler(mHandlerThread.getLooper());

也就是该消息的处理会方法mHandlerThread线程中处理。Looper信息队列中接受到信息后,会调用Handler的handlerMessage处理,也就是PKMS的方法。在该方法中调用PKMS里的doHandlerMessage()来处理。

doHandlerMessage()先从mes中获得信息的实体,也就是installParams对象。然后获得要安装的个数。最后连接DefaultContainerService.apk。该apk里DefalutContainerService提供安装的服务。所以先查看该服务是否已经启动,如果已经启动将所有要安装的apk索引保存在一个变量mPendingInstalls中。然后mHandler发送安装请求。INIT_COPY变成了MCS_BOUND,然后开始安装。

HandlerParams抽象类,含3个子类:

InstallParams:处理apk安装

moveParams处理apk移动

measureParams查询apk所占控件大小

InstallArgs抽象类,含2个子类:

FileInstallArgs:针对内部存储/data/local/tmp中apk.

SDInstallArgs:sd 卡的/sdcard/tmp中的apk


在上面的处理MCS_BOUND信息中,调用了InstallParams的startCopy()方法,该方法是其父类HandlerParams里的方法,该方法就是安装apk的方法,会尝试4次安装,如果提示不成功,则提示安装失败。在该方法中使用2个handlerParams的子类的实现方法详细解析这2个方法。

了解startCopy()中handleStartCopy()和handleReturnCode()

handleStartCopy()方法相当复杂,总结如下:

1.调用DefaultContainerService.getMinimalPackageInfo(),得到PackageInfoLite,描述apk结构,里面有重要信息推荐安装路径recommendedInstallLocation,该对象继承Parcelable,所以可通过Binder在进程间传递.

DefaultContainerService.getMinimalPackageInfo()方法里也会创建PackageLite对象和PackageInfoLite对象,将PackageLite里的一些信息赋值给PackageInfoLite。所以感觉上来说PackageInfoLite是PackageLite的简洁版,可能还含有其他信息。然后调用recommendAppInstallLocation函数来获得一个合理的安装位置赋值给PackageInfoLiete里的recommendedInstallLocation变量。该方法做了大量工作,就是各种验证路径,检查推荐的路径是否合法,内部控件和sd卡是否有足够控件,最后做一个合理的判断,返回。

2.调用installLocationPolicy检查推荐的路径是否合法。系统的package是不允许安装在sd卡上。

3.createInstallArgs会根据不同的安装位置创建不同的InstallArgs,如果是内部存储返回FileInstallArgs,否则是SDInstallArgs。

4.在正式安装前,对apk进行检查

5.调用InstallArgs的copyApk来安装应用。

copyApk中有createCopyFile()该方法为在/data/app目录下创建一个临时文件,临时文件名为tmp结尾的随机文件,因为inotify的机制会扫描apk结尾的文件,触发。所以为了不让它触发,才会生成这样一个文件。然后调用IMediaContainerService中的copyResource方法。将/data/local/tmp里的apk复制到/data/app下的之前生成的tmp文件中。


handleReturnCode()方法:

1.调用InstallArgs的doPreInstall函数。内部存储的就调用FileInstallArgs,否则就是SDInstallArgs,调用其doPreInstall函数

2.调用pkms的installPackageLI()进行安装,在该函数内部调用InstallArgs的doRename对文件进行改名。然后扫描该apk文件,至此就把apk的所有内容都登记到PKMS的内部中啦。

----doRename:vmdl-随机数字.tmp变为包名-索引.apk。

3.调用InstallArgs的doPostInstall()

4.然后向mHandler中发送消息,提示安装完成,信息内容为POST_INSTALL。携带token,通过它可从mRunningInstalls数组中找到PostInstallData对象。


然后mHandler又要开始处理POST_INSTALL消息。向pm发送一个安装的结果信息。


APK安装流程总结。














评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值