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进行安装.