Package Installer源码学习分析
title: Package Installer源码学习分析
tags: android,Package Installer,AOSP
grammar_cjkRuby: true
背景
主要功能:
- 安装前验证
- 安装程序
- 卸载程序
主要安装方式:
- Intent 隐式调用
- adb install or pm shell命令
- root权限or 静默安装
这里主要看第一种方式,Package Installer 入口 一般通过Java代码安装应用会创建Intent,并且指定一个activity action,隐式调用。
可以先看看PackageInstaller的AndroidManifest.xml文件
与普通应用的区别没有Android.intent.action.MAIN的activity action 所以不会在Android 系统的程序列表中有任何图标
PackageInstallerActivity InstallAppProgress
UninstallerActivity UninstallAppProgress
Intent隐式调用安装apk ,其中Uri from file: |package: PackageInstallerActivity是负责安装的入口界面,在这个activity中完成安装应用的初始化操作。在onCreat()方法中完成下面主要的核心任务:
- 从Intent对象中获取Package Uri,Scheme等信息。
- 对从Intent中获取的信息进行校验,主要是Scheme信息。
- 根据Scheme信息(file|package)进行处理相应的,获取ApplicationInfo对象,该对象包含应用相关信息。如应用名称,图标。并且显示应用的信息。
- 校验系统是否允许安装“未知来源”的应用
- 进行安装前的准备,并根据具体情况显示校验窗口
initiateInstall()初始化工作并且调用 startInstallConfirm()权限列表,尽管安装之前的校验工作很复杂,但是这并不是Package Installer 的主要任务,安装才是主要的工作,这是在InstallAppProgress中完成的。
在InstallAppProgress中的onCreate方法中获取ApplicationInfo对象的值mAppInfo和mPackageURI接下来会验证scheme是否是file或者package最后调用initView方法开始安装应用。安装应用的核心代码也在initView这个方法中。一开始initView方法根据package name 或者apk 文件的路径获取一些信息,然后判断该程序是否已经安装,如果已经安装就进入更新模式(通过installFlags变量控制)。尽管在initView方法的代码看上去很多,但是真正核心的就下面几行代码
if ("package".equals(mPackageURI.getScheme())) {
try {
//根据packageName更新应用
pm.installExistingPackage(mAppInfo.packageName);
observer.packageInstalled(mAppInfo.packageName,
PackageManager.INSTALL_SUCCEEDED);
} catch (PackageManager.NameNotFoundException e) {
observer.packageInstalled(mAppInfo.packageName,
PackageManager.INSTALL_FAILED_INVALID_APK);
}
} else {
//使用APK的路径安装或者更新应用
pm.installPackageWithVerificationAndEncryption(mPackageURI, observer, installFlags,
installerPackageName, verificationParams, null);//Android 4.2以后有这个方法
}
其中installExistingPackage和installPackageWithVerificationAndEncryption都是PackageManger类的方法,这两个方法都是静默安装应用。但是这两个方法都被设为hide,在普通的Activity中无法使用。由于这两个方法都是异步执行的,PackageInstallObserver是安装事件的监听器,不管安装成功还是失败都会给用户一个反馈。
卸载应用
卸载Android 应用与安装应用类似,也是调用系统几的API,这些API无法在普通应用中调用,使用这些API可以实现静默卸载。Package Installer 在卸载之前都会弹出确认。这个询问对话框就是卸载的入口,对应 UninstallerActivity 类。该Activity也允许普通程序通过Action调用,UninstallerActivity的关键部分是确认按钮对应的事件如下
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == Dialog.BUTTON_POSITIVE) {
((UninstallerActivity) getActivity()).startUninstallProgress();
} else {
((UninstallerActivity) getActivity()).dispatchAborted();
}
}
void startUninstallProgress() {
Intent newIntent = new Intent(Intent.ACTION_VIEW);
newIntent.putExtra(Intent.EXTRA_USER, mDialogInfo.user);
//卸载改Android 应用对于所有用户的程序和数据
newIntent.putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, mDialogInfo.allUsers);
newIntent.putExtra(PackageInstaller.EXTRA_CALLBACK, mDialogInfo.callback);
newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO, mDialogInfo.appInfo);
//允许卸载窗口返回是否卸载成功的标志,可以用startActivityForResult接收
if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
}
newIntent.setClass(this, UninstallAppProgress.class);
startActivity(newIntent);
}
点击确认按钮后会调用startUninstallProgress方法,和安装过程类似,卸载过程是在UninstallAppProgress中完成的。