2.3. PackageInstaller
PackageInstaller是Android提供的默认应用程序安装与卸载管理应用程序。应用包中有两个Activity:PackageInstallerActivity和UninstallerActivity分别用来管理应用程序的安装和卸载。这两个Activity可以通过发送Intent的方式启动。下面的代码片段指出了两个Activity能处理的Intent:
android:configChanges="orientation|keyboardHidden|screenSize" android:excludeFromRecents="true">
android:configChanges="orientation|keyboardHidden|screenSize" android:excludeFromRecents="true" android:theme="@android:style/Theme.DeviceDefault.Dialog.NoActionBar">
通过给PackageInstallerActivity发送"android.intent.action.VIEW"或者是"android.intent.action.INSTALL_PACKAGE" Intent就能启动对一个APK文件的安装过程。例如,我们假设有一个应用程序位于/mnt/sdcard/Test.apk,为了启动对这个应用程序的安装,可以通过文件浏览器点击这个应用包文件,同时也可以通过adb shell登陆机器,然后输入以下命令:
am start -a android.intent.action.VIEW -t application/vnd.android.package-archive -c android.intent.category.DEFAULT -d file:///mnt/sdcard/Test.apk
当输入上述命令后,首先是以Action等参数构造一个Intent,然后am调用ActivityManagerService的startActivity方法。最后的结果是启动PackageInstallerActivity,并将构造的Intent传递给启动的Activity。下面简单的描述下,PackageInstallerActivity安装应用的过程:
首先PackageInstaller会检查应用程序的完成性,尝试着从应用包中提解析AndroidManifest.xml文件,构造ParckageParser.Package对象。如果成功,则继续安装;否则安装退出
然后对发起安装请求的应用属性进行判断:如果是system应用,那么就进入初始化安装步骤;如果是非system应用,那么存在一个验证是否允许安装“unknown source”的步骤。
如果上面的步骤通过,就进入了初始化安装过程。初始化过程主要是检测应用是否安装,以及提取相关的权限信息,用于界面显示。这一过程主要是UI界面相关,略过不表
当用户在安装界面上点击“确定”按钮,PackageInstallerActivity就会启动InstallAppProgress,在此Activity会调用PackageManager的方法public abstract void installPackageWithVerificationAndEncryption(Uri packageURI,
IPackageInstallObserver observer, int flags, String installerPackageName,
VerificationParams verificationParams,
ContainerEncryptionParams encryptionParams)真正进行安装,并显示安装进度。
2.3.1. installPackageWithVerificationAndEncryption
PackageManager的installPackageWithVerificationAndEncryption最终是一个binder调用,是在PackageManagerService中负责实现。在此方法中,获取一个Message对象,其id为INIT_COPY,其obj为InstallParams。其中InstallParams对象根据installPackageWithVerificationAndEncryption的方法参数构造。INIT_COPY消息是在PackageHandler中进行处理。对于此消息的处理流程为:
首先通过connectToService方法绑定IMediaContainerService服务;在绑定成功之后,发送MCS_BOUND消息;IMeidaContainerService的实现是在frameworks/base/packages/DefaultContainerService/src/com/android/def/DefaultContainerService.java中。它负责原始apk文件的解密工作。
在PackageHandler消息中再次对MCS_BOUND消息进行处理。这次就会调用InstallParams的startCopy方法,开启复制过程。startcopy方法又会调用handleStartCopy进行复制工作。主要做了如下工作:
确定APK的安装位置
检查磁盘空间是否足够
以InstallParams构造一份InstallArgs对象。InstallArgs有两个子类:AsecInstallArgs和FileInstallArgs,对于安装于外部sd卡或者是有Forward Lock属性的应用,将会构造AsecInstallArgs,否则构造的是FileInstallArgs对象。
检查APK是否需要验证(一般是不需要)
调用InstallArgs对象的copyApk方法。
所以,handleStartCopy最重要的工作就是由InstallParams的copyApk来完成。假设在这个InstallParams引用是一个FileInstallArgs对象,那么其copy流程如下:
创建临时文件。对于最终安装在/data/app目录下面的应用,其临时文件的共享名为:/data/app/vmdl-XXX.tmp。这个XXX是一个随机数
调用IMediaContainerService的服务接口,从原始APK文件中提取出解密过的APK数据,写入到临时文件中
拷贝jni动态库到相应的目录
在InstallParams的startCopy处理完handleStartCopy之后,会调用handleRetureCode方法,此方法中将会进行触发真正的安装流程。
void handleReturnCode() {
if (mArgs != null) {
processPendingInstall(mArgs, mRet);
if (mTempPackage != null) {
if (!mTempPackage.delete()) {
Slog.w(TAG, "Couldn't delete temporary file: " +
mTempPackage.getAbsolutePath());
}
}
}
}
在handleReturnCode中又调用了processPendingInstall方法,这个方法主要做了以下几件事情:
调用FileInstallArgs对象的doPreInstall方法:如果之前的流程有错误,此方法将会执行清理动作
调用PackageManagerService的installPackageLI方法,开始安装过程
调用FileInstallArgs对象的doPostInstall方法:如果之前的流程有错误,此方法将会执行清理动作
installPackgeLI执行步骤如下:
从临时文件中提取出Package对象:final PackageParser.Package pkg = pp.parsePackage(tmpPackageFile,
null, mMetrics, parseFlags)
提取证书信息,并验证
将临时文件更名为正式apk文件,修改动态库目录名
调用installNewPackageLI安装正式apk文件
scanPackageLI方法负责安装apk
updateSettingsLI负责更新“记账簿”