Android应用的安装是通过packageinstaller完成. 在源码中, PackageInstaller位于packages/apps/PackageInstaller中. 根据代码量来看并不是太大.
主要是PackageInstallerActivity类, 安装过程中一切状态转换与判断都在这个Activity中进行.
安装流程
先看一下最常见的安装流程.
PackageInstaller中处理安装前的判断与确认操作
首先processPackageUri检测解析Uri. 提取scheme(目前支持file, content, package三种协议, 便于分析只保留了file部分)
private boolean processPackageUri(final Uri packageUri) {
mPackageURI = packageUri;
final String scheme = packageUri.getScheme();
// .... 专注于file协议
File sourceFile = new File(packageUri.getPath());
// 调用PackageParser的parsePackage方法
PackageParser.Package parsed = PackageUtil.getPackageInfo(sourceFile);
// 获取一个PackageInfo对象(获取权限部分)
mPkgInfo = PackageParser.generatePackageInfo(parsed, null,
PackageManager.GET_PERMISSIONS, 0, 0, null,
new PackageUserState());
// As 就是一个应用程序的标题与图标的数据类
as = PackageUtil.getAppSnippet(this, mPkgInfo.applicationInfo, sourceFile);
PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet);
return true;
}
可以看出 processPackageUrl调用framework的api获取了apk的权限信息与应用名称与图标.
然后就是判断该包是否允许安装, 如果允许则初始化准备安装. 首先在checkIfAllowedAndInitiateInstall中判断是否是未知来源的应用, 一般是开启允许未知来源的. 直接开启初始化安装
initiateInstall仅仅获取一下本机是否安装了该应用, 如果安装获取到该应用的信息
private void initiateInstall() {
String pkgName = mPkgInfo.packageName;
// 源码这里进行了pkgName判断转换, 一般不会遇到
// Check if package is already installed. display confirmation dialog if replacing pkg
try {
// This is a little convoluted because we want to get all uninstalled
// apps, but this may include apps with just data, and if it is just
// data we still want to count it as "installed".
mAppInfo = mPm.getApplicationInfo(pkgName,
PackageManager.GET_UNINSTALLED_PACKAGES);
if ((mAppInfo.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
mAppInfo = null;
}
} catch (NameNotFoundException e) {
mAppInfo = null;
}
startInstallConfirm();
}
最后startInstallConfirm()方法中显示了界面中显示的权限列表以及, 确认取消列表. 查看点击OK的事件, 确定安装事件为:
private void startInstall() {
// Start subactivity to actually install the application
Intent newIntent = new Intent();
newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
mPkgInfo.applicationInfo);
newIntent.setData(mPackageURI);
newIntent.setClass(this, InstallAppProgress.class);
String installerPackageName = getIntent().getStringExtra(
Intent.EXTRA_INSTALLER_PACKAGE_NAME);
if (mOriginatingURI != null) {
newIntent.putExtra(Intent.EXTRA_ORIGINATING_URI, mOriginatingURI);
}
if (mReferrerURI != null) {
newIntent.putExtra(Intent.EXTRA_REFERRER, mReferrerURI);
}
if (mOriginatingUid != VerificationParams.NO_UID) {
newIntent.putExtra(Intent.EXTRA_ORIGINATING_UID, mOriginatingUid);
}
if (installerPackageName != null) {
newIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME,
installerPackageName);
}
if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
}
if(localLOGV) Log.i(TAG, "downloaded app uri="+mPackageURI);
startActivity(newIntent);
finish();
}
好吧, 安装确认后跳转到安装进度页面, 具体安装过程也在这个界面中.
InstallAppProcess开始安装并处理安装进度
onCreate中, 接参数mAppInfo与mPackageURI
// 开启安装线程, 使用了HandlerThread
mInstallThread = new HandlerThread("InstallThread");
mInstallThread.start();
mInstallHandler = new Handler(mInstallThread.getLooper());
// 注册一个安装结束的监听
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BROADCAST_ACTION);
registerReceiver(
mBroadcastReceiver, intentFilter, BROADCAST_SENDER_PERMISSION, null /*scheduler*/);
这个handlerThread进行的任务是 doPackageState
private void doPackageStage(PackageManager pm, PackageInstaller.SessionParams params) {
// 1. 获取一个PackageInstaller
final PackageInstaller packageInstaller = pm.getPackageInstaller();
PackageInstaller.Session session = null;
try {
final String packageLocation = mPackageURI.getPath();
final File file = new File(packageLocation);
// 2. create一个sessionId
final int sessionId = packageInstaller.createSession(params);
final byte[] buffer = new byte[65536];
// 3. 根据sessionId打开一个session回话
session = packageInstaller.openSession(sessionId);
final InputStream in = new FileInputStream(file);
final long sizeBytes = file.length();
// 4. 根据这个session回话, 获取一个OutPutstream, 然后将文件写入到这个OutPutStream中
final OutputStream out = session.openWrite("PackageInstaller", 0, sizeBytes);
try {
int c;
while ((c = in.read(buffer)) != -1) {
out.write(buffer, 0, c);
if (sizeBytes > 0) {
final float fraction = ((float) c / (float) sizeBytes);
session.addProgress(fraction);
}
}
session.fsync(out);
} finally {
IoUtils.closeQuietly(in);
IoUtils.closeQuietly(out);
}
// Create a PendingIntent and use it to generate the IntentSender
Intent broadcastIntent = new Intent(BROADCAST_ACTION);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
InstallAppProgress.this /*context*/,
sessionId,
broadcastIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
// 5. 最后调用session的commit方法进行提交
session.commit(pendingIntent.getIntentSender());
} catch (IOException e) {
onPackageInstalled(PackageInstaller.STATUS_FAILURE);
} finally {
IoUtils.closeQuietly(session);
}
}
结论
PackageInstaller只是在应用安装前进行信息提取, 筛选, 以及apk文件的获取. 最后的安装还是调用Framework的PackageInstaller进行安装.