PKMS- Apk的打包 ,安装, 卸载解读

665 阅读15分钟

apk的安装方式

  • 安装系统APK和预置的APK(第一次开机时安装,没有安装界)

    PackageManagerService的构造中会扫描对应目录下的apk,完成安装

  • 网络下载应用安装――通过market应用完成,没有安装界面

    调用PackageManager的installPackage方法执行安装

  • ADB工具安装,没有安装界面

    /repo/system/core/adb/commandline.cpp中install_app方法,该方法调用pm_command通过send_shell_command方法将数据发送到手机端的adbd守护进程中,adbd在收到PC中Console发来的数据之后启动一个Shell,然后执行pm脚本(pm位于/system/bin目录下).

    pm脚本通过app_process执行pm.jar包的main函数(\system\framework\pm.jar) 对应源码: /repo/frameworks/base/cmds/pm/src/com/android/commands/pm/Pm.java

  • 第三方应用安装,有安装界面 以上几种方式均通过PackageInstallObserver来监听安装是否成功。

APK的包组成

生成的apk文件本质还是一个zip文件,只不过被google强行修改来一下后缀名出而已。

app包里面的内容

image.png

  • classes.dex: Dex是DalvikVM executes的缩写,即Android Dalvik执行文件
  • Androidmanifest.xml:Project中androidManifest.xml编译后得到的二进制xml文件
  • META-INF:主要保存各个资源文件的SHA1 hash值,用于校验资源文件是否被修改,防止二次打包时资源文件被替换。该目录下主要包括三个文件:
    • MANIFEST.MF: 保存版本号以及对每个文件(包括资源文件)整体的SHA1 hash
    • CERS.SF: 保存对每个文件头3行的SHA1 hash
    • CERT.RSA: 保存签名和公钥证书  
  • res: Project中res目录下资源文件编译后得到的二进制xml文件
  • resources.arsc:包含了所有资源文件的映射,可以理解为资源索引,通过该文件能找到对应的资源文件
  • lib:ndk编译出来的so库

APK打包流程

大致流程图

  1. 通过aapt2打包res资源文件,生成R.java resources.arsc和res文件(二进制&非二进制和pic保持原样)
  2. 通过Javac编译R.java,Java接口文件,java源文件生成.class文件
  3. 通过d8命令将.class文件和第三方库中的.class文件处理生成classes.dex
  4. 通过aapt2工具将aapt生成的resources.arsc 和res文件,未编译的资源assets文件和classes.dex 一起打包生成apk
  5. 通过zipalign工具将未签名的apk进行对齐处理
  6. 通过apksigner工具对上面的apk进行签名

image.png

工具名称功能介绍
aapt2android资源打包工具
Kotlinc把.kt文件编译成.class文件
javac把.java文件编译成.class文件
d8新一代.class转化成.dex的工具
zipalign字节码对齐工具
apksignerapk签名工具

Apk SignatureScheme V2

Android7.0后引入了一项新的签名方案SignatureScheme v2,它是一个对全文件进行签名的方案。
V1 签名只是校验了apk资源,没有约束zip,签名信息存储在zip/META-INF中 V2 它是一个对全文件进行签名的方案,能提供更快的应用安装时间,对未授权apk文件的更改提供更多保护。

image.png

v2 签名模式在原先 APK 块中增加了一个新的块(签名块),新的块存储了签名,摘要,签名算法,证书链,额外属性等信息,这个块有特定的格式。

为了保护 APK 内容,整个 APK(ZIP文件格式)被分为以下 4 个区块:

  1. ZIP 条目的内容(从偏移量 0 处开始一直到“APK 签名分块”的起始位置)
  2. APK 签名分块
  3. ZIP 中央目录
  4. ZIP 中央目录结尾

其中,应用签名方案的签名信息会被保存在 区块 2(APK Signing Block)中,而区块 1(Contents of ZIP entries)、区块 3(ZIP Central Directory)、区块 4(ZIP End of Central Directory)是受保护的,在签名后任何对区块 1、3、4 的修改都逃不过新的应用签名方案的检查。

APK的安装过程

点击一个未安装的apk后,会弹出安装界面,点击确定之后会进入PackageInstallerActivity的bindUi的方法

private void bindUi() {
    mAlert.setIcon(mAppSnippet.icon);
    mAlert.setTitle(mAppSnippet.label);
    mAlert.setView(R.layout.install_content_view);
    mAlert.setButton(DialogInterface.BUTTON_POSITIVE, getString(R.string.install),
            (ignored, ignored2) -> {
                if (mOk.isEnabled()) {
                    if (mSessionId != -1) {
                        mInstaller.setPermissionsResult(mSessionId, true);
                        finish();
                    } else {
                        startInstall();//进行apk的安装
                    }
                }
            }, null);
    mAlert.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.cancel),
            (ignored, ignored2) -> {
                // Cancel and finish
                setResult(RESULT_CANCELED);
                if (mSessionId != -1) {
                    //如果mSessionId存在,执行setPermissionsResult完成取消安装
                    mInstaller.setPermissionsResult(mSessionId, false);
                }
                finish();
            }, null);
    setupAlert();

    mOk = mAlert.getButton(DialogInterface.BUTTON_POSITIVE);
    mOk.setEnabled(false);

    if (!mOk.isInTouchMode()) {
        mAlert.getButton(DialogInterface.BUTTON_NEGATIVE).requestFocus();
    }
}

进入startInstall方法

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);
    //设置class为InstallInstalling,用来进行activity跳转
    newIntent.setClass(this, InstallInstalling.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 != PackageInstaller.SessionParams.UID_UNKNOWN) {
        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 (mLocalLOGV) Log.i(TAG, "downloaded app uri=" + mPackageURI);
    startActivity(newIntent);
    finish();
}

startInstall方法组装一个intent,并跳转到InstallInstalling这个activity,关闭当前的PackageInstallerActivity。

InstallInstalling主要是用于向包管理器发送包的信息并处理包管理的回调。

进入InstallInstalling类的oncreat方法

protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    ApplicationInfo appInfo = getIntent()
            .getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);
    mPackageURI = getIntent().getData();

    if ("package".equals(mPackageURI.getScheme())) {
        try {
            getPackageManager().installExistingPackage(appInfo.packageName);
            launchSuccess();
        } catch (PackageManager.NameNotFoundException e) {
            launchFailure(PackageInstaller.STATUS_FAILURE,
                    PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
        }
    } else {
        //根据mPackageURI创建一个file
        final File sourceFile = new File(mPackageURI.getPath());
        PackageUtil.AppSnippet as = PackageUtil.getAppSnippet(this, appInfo, sourceFile);

        mAlert.setIcon(as.icon);
        mAlert.setTitle(as.label);
        mAlert.setView(R.layout.install_content_view);
        mAlert.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.cancel),
                (ignored, ignored2) -> {
                    if (mInstallingTask != null) {
                        mInstallingTask.cancel(true);
                    }

                    if (mSessionId > 0) {
                        getPackageManager().getPackageInstaller().abandonSession(mSessionId);
                        mSessionId = 0;
                    }

                    setResult(RESULT_CANCELED);
                    finish();
                }, null);
        setupAlert();
        requireViewById(R.id.installing).setVisibility(View.VISIBLE);
        //1.如果savedInstanceState不为null,获取此前保存的mSessionId和mInstallId,其中mSessionId是安装包的会话id,mInstallId是等待的安装事件的id
        if (savedInstanceState != null) {
            mSessionId = savedInstanceState.getInt(SESSION_ID);
            mInstallId = savedInstanceState.getInt(INSTALL_ID);

            // Reregister for result; might instantly call back if result was delivered while
            // activity was destroyed
            try {
                //2.根据mInstallId向InstallEventReceiver注册以一个观察者launchFinishBasedOnResult会接收到安装事件的回调,无论安装成功或者失败都会关闭当前的activity。
                InstallEventReceiver.addObserver(this, mInstallId,
                        this::launchFinishBasedOnResult);
            } catch (EventResultPersister.OutOfIdsException e) {
                // Does not happen
            }
        } else {
            //3.创建SessionParams,它用来代表安装会话的参数,组装params
            PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
                    PackageInstaller.SessionParams.MODE_FULL_INSTALL);
            params.setInstallAsInstantApp(false);
            params.setReferrerUri(getIntent().getParcelableExtra(Intent.EXTRA_REFERRER));
            params.setOriginatingUri(getIntent()
                    .getParcelableExtra(Intent.EXTRA_ORIGINATING_URI));
            params.setOriginatingUid(getIntent().getIntExtra(Intent.EXTRA_ORIGINATING_UID,
                    UID_UNKNOWN));
            params.setInstallerPackageName(getIntent().getStringExtra(
                    Intent.EXTRA_INSTALLER_PACKAGE_NAME));
            params.setInstallReason(PackageManager.INSTALL_REASON_USER);
            //4.根据mPackageURI对包(APK)进行轻量级的解析,并将解析的参数赋值给params
            File file = new File(mPackageURI.getPath());
            try {
                final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
                final ParseResult<PackageLite> result = ApkLiteParseUtils.parsePackageLite(
                        input.reset(), file, /* flags */ 0);
                if (result.isError()) {
                    Log.e(LOG_TAG, "Cannot parse package " + file + ". Assuming defaults.");
                    Log.e(LOG_TAG,
                            "Cannot calculate installed size " + file + ". Try only apk size.");
                    params.setSize(file.length());
                } else {
                    final PackageLite pkg = result.getResult();
                    params.setAppPackageName(pkg.getPackageName());
                    params.setInstallLocation(pkg.getInstallLocation());
                    params.setSize(
                            PackageHelper.calculateInstalledSize(pkg, params.abiOverride));
                }
            } catch (IOException e) {
                Log.e(LOG_TAG,
                        "Cannot calculate installed size " + file + ". Try only apk size.");
                params.setSize(file.length());
            }

            try {
               //5.向InstallEventReceiver注册一个观察者返回一个新的mInstallId,其中InstallEventReceiver继承自BroadcastReceiver,用于接收安装事件并回掉给EventResultPersister
                mInstallId = InstallEventReceiver
                        .addObserver(this, EventResultPersister.GENERATE_NEW_ID,
                                this::launchFinishBasedOnResult);
            } catch (EventResultPersister.OutOfIdsException e) {
                launchFailure(PackageInstaller.STATUS_FAILURE,
                        PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
            }

            try {
                //6.PackageInstaller的createSession方法内部会通过IPackageInstaller与PackageInstallerService进行进程间通信
                //最终调用的是PackageInstallerService的createSession方法来创建并返回mSessionId
                mSessionId = getPackageManager().getPackageInstaller().createSession(params);
            } catch (IOException e) {
                launchFailure(PackageInstaller.STATUS_FAILURE,
                        PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
            }
        }

        mCancelButton = mAlert.getButton(DialogInterface.BUTTON_NEGATIVE);
    }
}

大致操作如下:

  1. 如果savedInstanceState不为null,获取此前保存的mSessionId和mInstallId,其中mSessionId是安装包的会话id,mInstallId是等待的安装事件的id
  2. 根据mInstallId向InstallEventReceiver注册以一个观察者launchFinishBasedOnResult会接收到安装事件的回调,无论安装成功或者失败都会关闭当前的activity。
  3. 创建SessionParams,它用来代表安装会话的参数,组装params
  4. 根据mPackageURI对包(APK)进行轻量级的解析,并将解析的参数赋值给params
  5. 向InstallEventReceiver注册一个观察者返回一个新的mInstallId,其中InstallEventReceiver继承自BroadcastReceiver,用于接收安装事件并回掉给EventResultPersister
  6. PackageInstaller的createSession方法内部会通过IPackageInstaller与PackageInstallerService进行进程间通信,最终调用的是PackageInstallerService的createSession方法来创建并返回mSessionId

接着进入InstallInstalling类中onResume方法中

protected void onResume() {
    super.onResume();

    // This is the first onResume in a single life of the activity
    if (mInstallingTask == null) {
        PackageInstaller installer = getPackageManager().getPackageInstaller();
        //获取sessionInfo
        PackageInstaller.SessionInfo sessionInfo = installer.getSessionInfo(mSessionId);

        if (sessionInfo != null && !sessionInfo.isActive()) {
            //创建InstallingAsyncTask对象,并调用execute,进入onPostExecute()
            mInstallingTask = new InstallingAsyncTask();
            mInstallingTask.execute();
        } else {
            // we will receive a broadcast when the install is finished
            mCancelButton.setEnabled(false);
            setFinishOnTouchOutside(false);
        }
    }
}

查看InstallingAsyncTask内部类

private final class InstallingAsyncTask extends AsyncTask<Void, Void,
        PackageInstaller.Session> {
    volatile boolean isDone;

    @Override
    protected PackageInstaller.Session doInBackground(Void... params) {
        PackageInstaller.Session session;
        try {
            session = getPackageManager().getPackageInstaller().openSession(mSessionId);
        } catch (IOException e) {
            synchronized (this) {
                isDone = true;
                notifyAll();
            }
            return null;
        }

        session.setStagingProgress(0);

        try {
            File file = new File(mPackageURI.getPath());

            try (InputStream in = new FileInputStream(file)) {
                long sizeBytes = file.length();
                try (OutputStream out = session
                        .openWrite("PackageInstaller", 0, sizeBytes)) {
                    byte[] buffer = new byte[1024 * 1024];
                    while (true) {
                        int numRead = in.read(buffer);

                        if (numRead == -1) {
                            session.fsync(out);
                            break;
                        }

                        if (isCancelled()) {
                            session.close();
                            break;
                        }

                        out.write(buffer, 0, numRead);
                        if (sizeBytes > 0) {
                            float fraction = ((float) numRead / (float) sizeBytes);
                            session.addProgress(fraction);
                        }
                    }
                }
            }

            return session;
        } catch (IOException | SecurityException e) {
            Log.e(LOG_TAG, "Could not write package", e);

            session.close();

            return null;
        } finally {
            synchronized (this) {
                isDone = true;
                notifyAll();
            }
        }
    }

    @Override
    protected void onPostExecute(PackageInstaller.Session session) {
        if (session != null) {
            Intent broadcastIntent = new Intent(BROADCAST_ACTION);
            broadcastIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
            broadcastIntent.setPackage(getPackageName());
            broadcastIntent.putExtra(EventResultPersister.EXTRA_ID, mInstallId);

            PendingIntent pendingIntent = PendingIntent.getBroadcast(
                    InstallInstalling.this,
                    mInstallId,
                    broadcastIntent,
                    PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
            //调用packageInstaller.Session的commit方法,进行安装
            session.commit(pendingIntent.getIntentSender());
            mCancelButton.setEnabled(false);
            setFinishOnTouchOutside(false);
        } else {
            getPackageManager().getPackageInstaller().abandonSession(mSessionId);

            if (!isCancelled()) {
                launchFailure(PackageInstaller.STATUS_FAILURE,
                        PackageManager.INSTALL_FAILED_INVALID_APK, null);
            }
        }
    }
}

doInBackground会根据包的Uri,将apk的信息通过IO流的形式写入到PackageInstaller.Session中,最后在onPostExecute方法中调用PackageInstaller.Session的commit方法,进行安装。

进入PackageInstaller类中查看commit方法

public void commit(@NonNull IntentSender statusReceiver) {
    try {
        //调用PackageInstallerSession的commit方法
        mSession.commit(statusReceiver, false);
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

mSession的类型为IPackageInstallerSession,实现类为PackageInstallerSession。

进入PackageInstallerSession类中的commit方法

public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
    if (hasParentSessionId()) {
        throw new IllegalStateException(
                "Session " + sessionId + " is a child of multi-package session "
                        + getParentSessionId() +  " and may not be committed directly.");
    }
    //调用markAsSealed
    if (!markAsSealed(statusReceiver, forTransfer)) {
        return;
    }
    if (isMultiPackage()) {
        synchronized (mLock) {
            final IntentSender childIntentSender =
                    new ChildStatusIntentReceiver(mChildSessions.clone(), statusReceiver)
                            .getIntentSender();
            boolean sealFailed = false;
            for (int i = mChildSessions.size() - 1; i >= 0; --i) {
                if (!mChildSessions.valueAt(i)
                        .markAsSealed(childIntentSender, forTransfer)) {
                    sealFailed = true;
                }
            }
            if (sealFailed) {
                return;
            }
        }
    }

    dispatchSessionSealed();
}

进入markAsSealed方法

private boolean markAsSealed(@NonNull IntentSender statusReceiver, boolean forTransfer) {
    Objects.requireNonNull(statusReceiver);
    assertCallerIsOwnerOrRoot();

    synchronized (mLock) {
        assertPreparedAndNotDestroyedLocked("commit of session " + sessionId);
        assertNoWriteFileTransfersOpenLocked();

        final boolean isSecureFrpEnabled =
                (Secure.getInt(mContext.getContentResolver(), Secure.SECURE_FRP_MODE, 0) == 1);
        if (isSecureFrpEnabled
                && !isSecureFrpInstallAllowed(mContext, Binder.getCallingUid())) {
            throw new SecurityException("Can't install packages while in secure FRP");
        }

        if (forTransfer) {
            mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, null);
            if (mInstallerUid == mOriginalInstallerUid) {
                throw new IllegalArgumentException("Session has not been transferred");
            }
        } else {
            if (mInstallerUid != mOriginalInstallerUid) {
                throw new IllegalArgumentException("Session has been transferred");
            }
        }

        mRemoteStatusReceiver = statusReceiver;

        // After updating the observer, we can skip re-sealing.
        if (mSealed) {
            return true;
        }

        try {
            sealLocked();
        } catch (PackageManagerException e) {
            return false;
        }
    }

    return true;
}

进行一些校验

进入dispatchSessionSealed方法

private void dispatchSessionSealed() {
    mHandler.obtainMessage(MSG_ON_SESSION_SEALED).sendToTarget();
}

发送一个MSG_ON_SESSION_SEALED的消息

MSG_ON_SESSION_SEALED在handler中的处理

private final Handler.Callback mHandlerCallback = new Handler.Callback() {
    @Override
    public boolean handleMessage(Message msg) {
        switch (msg.what) {
            case MSG_ON_SESSION_SEALED:
                handleSessionSealed();
                break;
            case MSG_STREAM_VALIDATE_AND_COMMIT:
                handleStreamValidateAndCommit();
                break;
            case MSG_INSTALL:
                handleInstall();
                break;
            case MSG_ON_PACKAGE_INSTALLED:
                final SomeArgs args = (SomeArgs) msg.obj;
                final String packageName = (String) args.arg1;
                final String message = (String) args.arg2;
                final Bundle extras = (Bundle) args.arg3;
                final IntentSender statusReceiver = (IntentSender) args.arg4;
                final int returnCode = args.argi1;
                args.recycle();

                sendOnPackageInstalled(mContext, statusReceiver, sessionId,
                        isInstallerDeviceOwnerOrAffiliatedProfileOwner(), userId,
                        packageName, returnCode, message, extras);

                break;
            case MSG_SESSION_VALIDATION_FAILURE:
                final int error = msg.arg1;
                final String detailMessage = (String) msg.obj;
                onSessionValidationFailure(error, detailMessage);
                break;
        }

        return true;
    }
};

进入handleSessionSealed方法

private void handleSessionSealed() {
    assertSealed("dispatchSessionSealed");
    // Persist the fact that we've sealed ourselves to prevent
    // mutations of any hard links we create.
    mCallback.onSessionSealedBlocking(this);
    dispatchStreamValidateAndCommit();
}

进入dispatchStreamValidateAndCommit方法

private void dispatchStreamValidateAndCommit() {
    mHandler.obtainMessage(MSG_STREAM_VALIDATE_AND_COMMIT).sendToTarget();
}

进入handleStreamValidateAndCommit方法

private void handleStreamValidateAndCommit() {
    PackageManagerException unrecoverableFailure = null;
    boolean allSessionsReady = false;
    try {
        allSessionsReady = streamValidateAndCommit();
    } catch (PackageManagerException e) {
        unrecoverableFailure = e;
    }

    if (isMultiPackage()) {
        final List<PackageInstallerSession> childSessions;
        synchronized (mLock) {
            childSessions = getChildSessionsLocked();
        }
        int childCount = childSessions.size();

        ArrayList<PackageInstallerSession> nonFailingSessions = new ArrayList<>(childCount);

        for (int i = childCount - 1; i >= 0; --i) {
            try {
                PackageInstallerSession session = childSessions.get(i);
                //如果会话成功验证并提交,则返回 true。 如果无法准备数据加载器,则返回 false。 只要不抛出异常,就可以多次调用。
                allSessionsReady &= session.streamValidateAndCommit();
                nonFailingSessions.add(session);
            } catch (PackageManagerException e) {
                allSessionsReady = false;
                if (unrecoverableFailure == null) {
                    unrecoverableFailure = e;
                }
            }
        }
        if (unrecoverableFailure != null) {
            onSessionValidationFailure(unrecoverableFailure);
            for (int i = nonFailingSessions.size() - 1; i >= 0; --i) {
                PackageInstallerSession session = nonFailingSessions.get(i);
                session.onSessionValidationFailure(unrecoverableFailure);
            }
        }
    }

    if (!allSessionsReady) {
        return;
    }

    mHandler.obtainMessage(MSG_INSTALL).sendToTarget();
}

进入handleInstall方法

private void handleInstall() {
    if (isInstallerDeviceOwnerOrAffiliatedProfileOwner()) {
        DevicePolicyEventLogger
                .createEvent(DevicePolicyEnums.INSTALL_PACKAGE)
                .setAdmin(mInstallSource.installerPackageName)
                .write();
    }
    //检查是否允许 APEX 更新。 我们在 handleInstall 中执行此检查,因为这是以下位置之一:
    // 在分阶段和非分阶段 APEX 更新流之间共享。
    // 仅在引导完成后调用。
    //后者很重要,因为 isApexUpdateAllowed 检查取决于 ModuleInfoProvider,它仅在设备启动后填充。
    if (isApexSession()) {
        boolean checkApexUpdateAllowed =
                (params.installFlags & PackageManager.INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK)
                    == 0;
        synchronized (mLock) {
            if (checkApexUpdateAllowed && !isApexUpdateAllowed(mPackageName,
                      mInstallSource.installerPackageName)) {
                onSessionValidationFailure(PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
                        "Update of APEX package " + mPackageName + " is not allowed for "
                                + mInstallSource.installerPackageName);
                return;
            }
        }

        if (!params.isStaged) {
            synchronized (mLock) {
                int sessionId = mStagingManager.getSessionIdByPackageName(mPackageName);
                if (sessionId != -1) {
                    onSessionValidationFailure(
                            PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
                            "Staged session " + sessionId + " already contains "
                                    + mPackageName);
                    return;
                }
            }
        }
    }

    if (params.isStaged) {
        mStagingManager.commitSession(mStagedSession);
        dispatchSessionFinished(INSTALL_SUCCEEDED, "Session staged", null);
        return;
    }

    verify();
}

进入verify方法

private void verify() {
    try {
        verifyNonStaged();
    } catch (PackageManagerException e) {
        final String completeMsg = ExceptionUtils.getCompleteMessage(e);
        onSessionVerificationFailure(e.error, completeMsg);
    }
}

进入verifyNonStaged方法

private void verifyNonStaged()
        throws PackageManagerException {
    final PackageManagerService.VerificationParams verifyingSession =
            prepareForVerification();
    if (verifyingSession == null) {
        return;
    }
    if (isMultiPackage()) {
        final List<PackageInstallerSession> childSessions;
        synchronized (mLock) {
            childSessions = getChildSessionsLocked();
        }
        // Spot check to reject a non-staged multi package install of APEXes and APKs.
        if (!params.isStaged && containsApkSession()
                && sessionContains(s -> s.isApexSession())) {
            throw new PackageManagerException(
                PackageManager.INSTALL_FAILED_SESSION_INVALID,
                "Non-staged multi package install of APEX and APK packages is not supported");
        }
        List<PackageManagerService.VerificationParams> verifyingChildSessions =
                new ArrayList<>(childSessions.size());
        boolean success = true;
        PackageManagerException failure = null;
        for (int i = 0; i < childSessions.size(); ++i) {
            final PackageInstallerSession session = childSessions.get(i);
            try {
                final PackageManagerService.VerificationParams verifyingChildSession =
                        session.prepareForVerification();
                if (verifyingChildSession != null) {
                    verifyingChildSessions.add(verifyingChildSession);
                }
            } catch (PackageManagerException e) {
                failure = e;
                success = false;
            }
        }
        if (!success) {
            final IntentSender statusReceiver;
            synchronized (mLock) {
                statusReceiver = mRemoteStatusReceiver;
            }
            sendOnPackageInstalled(mContext, statusReceiver, sessionId,
                    isInstallerDeviceOwnerOrAffiliatedProfileOwner(), userId, null,
                    failure.error, failure.getLocalizedMessage(), null);
            return;
        }
        mPm.verifyStage(verifyingSession, verifyingChildSessions);
    } else {
        mPm.verifyStage(verifyingSession);
    }
}

进入prepareForVerification方法中

private PackageManagerService.VerificationParams prepareForVerification()
        throws PackageManagerException {
    assertNotLocked("makeSessionActive");

    @UserActionRequirement
    int userActionRequirement = USER_ACTION_NOT_NEEDED;
    // TODO(b/159331446): Move this to makeSessionActiveForInstall and update javadoc
    if (!params.isMultiPackage) {
        userActionRequirement = computeUserActionRequirement();
        if (userActionRequirement == USER_ACTION_REQUIRED) {
            sendPendingUserActionIntent();
            return null;
        } // else, we'll wait until we parse to determine if we need to
    }

    boolean silentUpdatePolicyEnforceable = false;
    synchronized (mLock) {
        if (mRelinquished) {
            throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
                    "Session relinquished");
        }
        if (mDestroyed) {
            throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
                    "Session destroyed");
        }
        if (!mSealed) {
            throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
                    "Session not sealed");
        }
        PackageLite result = parseApkLite();
        if (result != null) {
            mPackageLite = result;
            synchronized (mProgressLock) {
                mInternalProgress = 0.5f;
                computeProgressLocked(true);
            }

            extractNativeLibraries(
                    mPackageLite, stageDir, params.abiOverride, mayInheritNativeLibs());

            if (userActionRequirement == USER_ACTION_PENDING_APK_PARSING) {
                if (result.getTargetSdk() < Build.VERSION_CODES.Q) {
                    sendPendingUserActionIntent();
                    return null;
                }
                if (params.requireUserAction == SessionParams.USER_ACTION_NOT_REQUIRED) {
                    silentUpdatePolicyEnforceable = true;
                }
            }
        }
    }
    if (silentUpdatePolicyEnforceable) {
        if (!mSilentUpdatePolicy.isSilentUpdateAllowed(
                getInstallerPackageName(), getPackageName())) {
            // Fall back to the non-silent update if a repeated installation is invoked within
            // the throttle time.
            sendPendingUserActionIntent();
            return null;
        }
        mSilentUpdatePolicy.track(getInstallerPackageName(), getPackageName());
    }
    synchronized (mLock) {
        return makeVerificationParamsLocked();
    }
}

进入sendPendingUserActionIntent方法

//用户确认安装
private void sendPendingUserActionIntent() {
    // User needs to confirm installation;
    // give installer an intent they can use to involve
    // user.
    final Intent intent = new Intent(PackageInstaller.ACTION_CONFIRM_INSTALL);
    intent.setPackage(mPm.getPackageInstallerPackageName());
    intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);

    final IntentSender statusReceiver;
    synchronized (mLock) {
        statusReceiver = mRemoteStatusReceiver;
    }
    sendOnUserActionRequired(mContext, statusReceiver, sessionId, intent);

    // Commit was keeping session marked as active until now; release
    // that extra refcount so session appears idle.
    closeInternal(false);
}

进入makeVerificationParamsLocked方法

private PackageManagerService.VerificationParams makeVerificationParamsLocked() {
    final IPackageInstallObserver2 localObserver;
    if (!hasParentSessionId()) {
        // Avoid attaching this observer to child session since they won't use it.
        localObserver = new IPackageInstallObserver2.Stub() {
            @Override
            public void onUserActionRequired(Intent intent) {
                throw new IllegalStateException();
            }

            @Override
            public void onPackageInstalled(String basePackageName, int returnCode, String msg,
                    Bundle extras) {
                if (returnCode == INSTALL_SUCCEEDED) {
                   //验证完成
                    onVerificationComplete();
                } else {
                    onSessionVerificationFailure(returnCode, msg);
                }
            }
        };
    } else {
        localObserver = null;
    }

    final UserHandle user;
    if ((params.installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {
        user = UserHandle.ALL;
    } else {
        user = new UserHandle(userId);
    }

    mRelinquished = true;

    // TODO(b/169375643): Remove this workaround once b/161121612 is fixed.
    PackageInstaller.SessionParams copiedParams = params.copy();
    if (params.isStaged) {
        // This is called by the pre-reboot verification. Don't enable rollback here since
        // it has been enabled when pre-reboot verification starts.
        copiedParams.installFlags &= ~PackageManager.INSTALL_ENABLE_ROLLBACK;
    }
    return mPm.new VerificationParams(user, stageDir, localObserver, copiedParams,
            mInstallSource, mInstallerUid, mSigningDetails, sessionId, mPackageLite);
}

进入onVerificationComplete方法

private void onVerificationComplete() {
    // Staged sessions will be installed later during boot
    if (isStaged()) {
     mStagingManager.notifyPreRebootVerification_Apk_Complete(mStagedSession);
        return;
    }

    install();
}

进入install方法

private void install() {
    try {
        installNonStaged();
    } catch (PackageManagerException e) {
        final String completeMsg = ExceptionUtils.getCompleteMessage(e);
        onSessionInstallationFailure(e.error, completeMsg);
    }
}

进入installNonStaged方法

private void installNonStaged()
        throws PackageManagerException {
    final PackageManagerService.InstallParams installingSession = makeInstallParams();
    if (installingSession == null) {
        throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
                "Session should contain at least one apk session for installation");
    }
    if (isMultiPackage()) {
        final List<PackageInstallerSession> childSessions;
        synchronized (mLock) {
            childSessions = getChildSessionsLocked();
        }
        List<PackageManagerService.InstallParams> installingChildSessions =
                new ArrayList<>(childSessions.size());
        boolean success = true;
        PackageManagerException failure = null;
        for (int i = 0; i < childSessions.size(); ++i) {
            final PackageInstallerSession session = childSessions.get(i);
            try {
                final PackageManagerService.InstallParams installingChildSession =
                        session.makeInstallParams();
                if (installingChildSession != null) {
                    installingChildSessions.add(installingChildSession);
                }
            } catch (PackageManagerException e) {
                failure = e;
                success = false;
            }
        }
        if (!success) {
            final IntentSender statusReceiver;
            synchronized (mLock) {
                statusReceiver = mRemoteStatusReceiver;
            }
            sendOnPackageInstalled(mContext, statusReceiver, sessionId,
                    isInstallerDeviceOwnerOrAffiliatedProfileOwner(), userId, null,
                    failure.error, failure.getLocalizedMessage(), null);
            return;
        }
        mPm.installStage(installingSession, installingChildSessions);
    } else {
        mPm.installStage(installingSession);
    }
}

进入PackageManagerService类的installStage方法

void installStage(InstallParams params) {
    //创建INIT_COPY类型的消息
    final Message msg = mHandler.obtainMessage(INIT_COPY);
    //给params设置值并赋值给消息
    params.setTraceMethod("installStage").
          setTraceCookie(System.identityHashCode(params));
    msg.obj = params;

    Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStage",
            System.identityHashCode(msg.obj));
    Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
            System.identityHashCode(msg.obj));
    //发送消息
    mHandler.sendMessage(msg);
}

INIT_COPY的处理消息

case INIT_COPY: {
    HandlerParams params = (HandlerParams) msg.obj;
    if (params != null) {
        if (DEBUG_INSTALL) Slog.i(TAG, "init_copy: " + params);
        Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
                System.identityHashCode(params));
        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
        //开始apk的拷贝
        params.startCopy();
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }
    break;

进入startCopy方法

final void startCopy() {
    if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
    handleStartCopy();
    handleReturnCode();
}

handleStartCopy方法是HandlerParams的抽象方法,有如下几个子类

image.png

进入InstallParams中的handleStartCopy方法

public void handleStartCopy() {
    if ((installFlags & PackageManager.INSTALL_APEX) != 0) {
        mRet = INSTALL_SUCCEEDED;
        return;
    }
    //生成PackageInfoLite类
    PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
            mPackageLite, origin.resolvedPath, installFlags, packageAbiOverride);

    // 对于分阶段会话,其验证和安装之间存在延迟。 设备状态可以在此延迟内更改,因此我们需要重新验证某些条件。
    boolean isStaged = (installFlags & INSTALL_STAGED) != 0;
    if (isStaged) {
        mRet = verifyReplacingVersionCode(
                pkgLite, requiredInstalledVersionCode, installFlags);
        if (mRet != INSTALL_SUCCEEDED) {
            return;
        }
    }

    mRet = overrideInstallLocation(pkgLite);
}

进入getMinimalPackageInfo方法

//解析给定的包并返回最少的细节
public static PackageInfoLite getMinimalPackageInfo(Context context, PackageLite pkg,
        String packagePath, int flags, String abiOverride) {
    final PackageInfoLite ret = new PackageInfoLite();
    if (packagePath == null || pkg == null) {
        Slog.i(TAG, "Invalid package file " + packagePath);
        ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK;
        return ret;
    }

    final File packageFile = new File(packagePath);
    final long sizeBytes;
    try {
        sizeBytes = PackageHelper.calculateInstalledSize(pkg, abiOverride);
    } catch (IOException e) {
        if (!packageFile.exists()) {
            ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_URI;
        } else {
            ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK;
        }

        return ret;
    }

    final int recommendedInstallLocation = PackageHelper.resolveInstallLocation(context,
            pkg.getPackageName(), pkg.getInstallLocation(), sizeBytes, flags);

    ret.packageName = pkg.getPackageName();
    ret.splitNames = pkg.getSplitNames();
    ret.versionCode = pkg.getVersionCode();
    ret.versionCodeMajor = pkg.getVersionCodeMajor();
    ret.baseRevisionCode = pkg.getBaseRevisionCode();
    ret.splitRevisionCodes = pkg.getSplitRevisionCodes();
    ret.installLocation = pkg.getInstallLocation();
    ret.verifiers = pkg.getVerifiers();
    ret.recommendedInstallLocation = recommendedInstallLocation;
    ret.multiArch = pkg.isMultiArch();
    ret.debuggable = pkg.isDebuggable();

    return ret;
}

进入verifyReplacingVersionCode方法

//验证替换版本代码
private int verifyReplacingVersionCode(PackageInfoLite pkgLite,
        long requiredInstalledVersionCode, int installFlags) {
    String packageName = pkgLite.packageName;
    synchronized (mLock) {
        AndroidPackage dataOwnerPkg = mPackages.get(packageName);
        if (dataOwnerPkg  == null) {
            PackageSetting ps = mSettings.getPackageLPr(packageName);
            if (ps != null) {
                dataOwnerPkg = ps.pkg;
            }
        }

        if (requiredInstalledVersionCode != PackageManager.VERSION_CODE_HIGHEST) {
            if (dataOwnerPkg == null) {
                Slog.w(TAG, "Required installed version code was "
                        + requiredInstalledVersionCode
                        + " but package is not installed");
                return PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION;
            }

            if (dataOwnerPkg.getLongVersionCode() != requiredInstalledVersionCode) {
                Slog.w(TAG, "Required installed version code was "
                        + requiredInstalledVersionCode
                        + " but actual installed version is "
                        + dataOwnerPkg.getLongVersionCode());
                return PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION;
            }
        }

        if (dataOwnerPkg != null) {
            if (!PackageManagerServiceUtils.isDowngradePermitted(installFlags,
                    dataOwnerPkg.isDebuggable())) {
                try {
                    checkDowngrade(dataOwnerPkg, pkgLite);
                } catch (PackageManagerException e) {
                    Slog.w(TAG, "Downgrade detected: " + e.getMessage());
                    return PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
                }
            }
        }
    }
    return PackageManager.INSTALL_SUCCEEDED;
}

进入overrideInstallLocation方法

private int overrideInstallLocation(PackageInfoLite pkgLite) {
    final boolean ephemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
    if (DEBUG_INSTANT && ephemeral) {
        Slog.v(TAG, "pkgLite for install: " + pkgLite);
    }
    // 表示文件已下载,不需要再次下载
    if (origin.staged) {
        // 设置安装标志位,决定是安装在手机内部存储空间还是 sdcard中
        if (origin.file != null) {
            installFlags |= PackageManager.INSTALL_INTERNAL;
        } else {
            throw new IllegalStateException("Invalid stage location");
        }
    } else if (pkgLite.recommendedInstallLocation
            == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
        /*
         * 如果我们的可用空间太少,请在放弃之前尝试释放缓存
         */
        // TODO: 释放目标设备上的磁盘空间
        final StorageManager storage = StorageManager.from(mContext);
        //返回给定路径被(Environment.getDataDirectory())认为存储空间不足的可用字节数
        final long lowThreshold = storage.getStorageLowBytes(
                Environment.getDataDirectory());
        //返回:-1 计算安装包大小有错误。其他则代表安装包的大小
        final long sizeBytes = PackageManagerServiceUtils.calculateInstalledSize(
                origin.resolvedPath, packageAbiOverride);
        if (sizeBytes >= 0) {
            try {
        
                mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0);
                pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
                        mPackageLite, origin.resolvedPath, installFlags,
                        packageAbiOverride);
            } catch (InstallerException e) {
                Slog.w(TAG, "Failed to free cache", e);
            }
        }

        if (pkgLite.recommendedInstallLocation
                == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
            pkgLite.recommendedInstallLocation
                    = PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
        }
    }
    //安装返回码
    int ret = INSTALL_SUCCEEDED;
    int loc = pkgLite.recommendedInstallLocation;
    if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION) {
        ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
    } else if (loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS) {
        ret = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
    } else if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
        ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
    } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) {
        ret = PackageManager.INSTALL_FAILED_INVALID_APK;
    } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
        ret = PackageManager.INSTALL_FAILED_INVALID_URI;
    } else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) {
        ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
    } else {
        // Override with defaults if needed.
        loc = installLocationPolicy(pkgLite);

        final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;

        if (!onInt) {
            // Override install location with flags
            if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
                // Set the flag to install on external media.
                installFlags &= ~PackageManager.INSTALL_INTERNAL;
            } else {
                // Make sure the flag for installing on external
                // media is unset
                installFlags |= PackageManager.INSTALL_INTERNAL;
            }
        }
    }
    return ret;
}

进入handleReturnCode()方法

void handleReturnCode() {
    processPendingInstall();
}

进入processPendingInstall方法

private void processPendingInstall() {
        //创建安装参数
        InstallArgs args = createInstallArgs(this);
        if (mRet == PackageManager.INSTALL_SUCCEEDED) {
            mRet = args.copyApk();
        }
        if (mRet == PackageManager.INSTALL_SUCCEEDED) {
            F2fsUtils.releaseCompressedBlocks(
                    mContext.getContentResolver(), new File(args.getCodePath()));
        }
        if (mParentInstallParams != null) {
            mParentInstallParams.tryProcessInstallRequest(args, mRet);
        } else {
            PackageInstalledInfo res = createPackageInstalledInfo(mRet);
            processInstallRequestsAsync(
                    res.returnCode == PackageManager.INSTALL_SUCCEEDED,
                    Collections.singletonList(new InstallRequest(args, res)));
        }
    }
}

进入createInstallArgs方法

private InstallArgs createInstallArgs(InstallParams params) {
    if (params.move != null) {
        //处理现有已安装应用程序移动的逻辑
        return new MoveInstallArgs(params);
    } else {
        //处理新应用程序安装的逻辑,包括复制和重命名逻辑
        return new FileInstallArgs(params);
    }
}

进入InstallArgs的copyApk的方法中,发现copyApk是一个抽象方法,有两个子类,进入FileInstallArgs中查看copyApk方法

image.png

int copyApk() {
    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk");
    try {
        return doCopyApk();
    } finally {
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }
}

private int doCopyApk() {
    //表示文件已经下载
    if (origin.staged) {
        if (DEBUG_INSTALL) Slog.d(TAG, origin.file + " already staged; skipping copy");
        //获取安装包路径
        codeFile = origin.file;
        return PackageManager.INSTALL_SUCCEEDED;
    }

    try {
        final boolean isEphemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
        //创建路径
        final File tempDir =
                mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral);
        codeFile = tempDir;
    } catch (IOException e) {
        Slog.w(TAG, "Failed to create copy file: " + e);
        return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
    }
    //将包复制到目标位置(origin.file.getAbsolutePath())
    int ret = PackageManagerServiceUtils.copyPackage(
            origin.file.getAbsolutePath(), codeFile);
    if (ret != PackageManager.INSTALL_SUCCEEDED) {
        Slog.e(TAG, "Failed to copy package");
        return ret;
    }

    final boolean isIncremental = isIncrementalPath(codeFile.getAbsolutePath());
    final File libraryRoot = new File(codeFile, LIB_DIR_NAME);
    NativeLibraryHelper.Handle handle = null;
    try {
        handle = NativeLibraryHelper.Handle.create(codeFile);
        // 将 apk 中的动态库 .so 文件也拷贝到目标路径中。
        ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
                abiOverride, isIncremental);
    } catch (IOException e) {
        Slog.e(TAG, "Copying native libraries failed", e);
        ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
    } finally {
        IoUtils.closeQuietly(handle);
    }

    return ret;
}

进入PackageManagerServiceUtils.copyPackage()方法中

//将包复制到目标位置
public static int copyPackage(String packagePath, File targetDir) {
    if (packagePath == null) {
        return PackageManager.INSTALL_FAILED_INVALID_URI;
    }

    try {
        final File packageFile = new File(packagePath);
        final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
        final ParseResult<PackageLite> result = ApkLiteParseUtils.parsePackageLite(
                input.reset(), packageFile, /* flags */ 0);
        if (result.isError()) {
            Slog.w(TAG, "Failed to parse package at " + packagePath);
            return result.getErrorCode();
        }
        final PackageLite pkg = result.getResult();
        copyFile(pkg.getBaseApkPath(), targetDir, "base.apk");
        if (!ArrayUtils.isEmpty(pkg.getSplitNames())) {
            for (int i = 0; i < pkg.getSplitNames().length; i++) {
                copyFile(pkg.getSplitApkPaths()[i], targetDir,
                        "split_" + pkg.getSplitNames()[i] + ".apk");
            }
        }
        return PackageManager.INSTALL_SUCCEEDED;
    } catch (IOException | ErrnoException e) {
        Slog.w(TAG, "Failed to copy package at " + packagePath + ": " + e);
        return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
    }
}

private static void copyFile(String sourcePath, File targetDir, String targetName)
        throws ErrnoException, IOException {
    if (!FileUtils.isValidExtFilename(targetName)) {
        throw new IllegalArgumentException("Invalid filename: " + targetName);
    }
    Slog.d(TAG, "Copying " + sourcePath + " to " + targetName);

    final File targetFile = new File(targetDir, targetName);
    final FileDescriptor targetFd = Os.open(targetFile.getAbsolutePath(),
            O_RDWR | O_CREAT, 0644);
    Os.chmod(targetFile.getAbsolutePath(), 0644);
    FileInputStream source = null;
    try {
        source = new FileInputStream(sourcePath);
        //将 source.getFD() 的内容复制到targetFd
        FileUtils.copy(source.getFD(), targetFd);
    } finally {
        IoUtils.closeQuietly(source);
    }
}

看到这里 最终安装包在 data/app 目录下以 base.apk 的方式保存,至此安装包的拷贝工作就已经完成。

再次进入processPendingInstall方法

private void processPendingInstall() {
    ...
    if (mRet == PackageManager.INSTALL_SUCCEEDED) {
        F2fsUtils.releaseCompressedBlocks(
                mContext.getContentResolver(), new File(args.getCodePath()));
    }
    //分包
    if (mParentInstallParams != null) {
        mParentInstallParams.tryProcessInstallRequest(args, mRet);
    } else {
        PackageInstalledInfo res = createPackageInstalledInfo(mRet);
        //异步操作,因为包安装可能需要一段时间
        processInstallRequestsAsync(
                res.returnCode == PackageManager.INSTALL_SUCCEEDED,
                Collections.singletonList(new InstallRequest(args, res)));
    }
}

进入processInstallRequestsAsync方法中

private void processInstallRequestsAsync(boolean success,
        List<InstallRequest> installRequests) {
    mHandler.post(() -> {
        List<InstallRequest> apexInstallRequests = new ArrayList<>();
        List<InstallRequest> apkInstallRequests = new ArrayList<>();
        for (InstallRequest request : installRequests) {
            if ((request.args.installFlags & PackageManager.INSTALL_APEX) != 0) {
                apexInstallRequests.add(request);
            } else {
                apkInstallRequests.add(request);
            }
        }
        if (!apexInstallRequests.isEmpty() && !apkInstallRequests.isEmpty()) {
            throw new IllegalStateException(
                    "Attempted to do a multi package install of both APEXes and APKs");
        }
        if (!apexInstallRequests.isEmpty()) {
            if (success) {
                Thread t = new Thread(() -> installApexPackagesTraced(apexInstallRequests),
                        "installApexPackages");
                t.start();
            } else {
                InstallRequest request = apexInstallRequests.get(0);
                notifyInstallObserver(request.installResult, request.args.observer);
            }
            return;
        }
        if (success) {
            for (InstallRequest request : apkInstallRequests) {
     //预安装操作,主要是检查安装包的状态,确保安装环境正常,如果安装环境有问题会清理拷贝文件
                request.args.doPreInstall(request.installResult.returnCode);
            }
            synchronized (mInstallLock) {
                //真正的安装阶段
                installPackagesTracedLI(apkInstallRequests);
            }
            for (InstallRequest request : apkInstallRequests) {
                request.args.doPostInstall(
                        request.installResult.returnCode, request.installResult.uid);
            }
        }
        for (InstallRequest request : apkInstallRequests) {
            restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult,
                    new PostInstallData(request.args, request.installResult, null));
        }
    });
}

进入installPackagesTracedLI方法

private void installPackagesTracedLI(List<InstallRequest> requests) {
    try {
        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages");
        installPackagesLI(requests);
    } finally {
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }
}

进入installPackagesLI方法

private void installPackagesLI(List<InstallRequest> requests) {
    final Map<String, ScanResult> preparedScans = new ArrayMap<>(requests.size());
    final Map<String, InstallArgs> installArgs = new ArrayMap<>(requests.size());
    final Map<String, PackageInstalledInfo> installResults = new ArrayMap<>(requests.size());
    final Map<String, PrepareResult> prepareResults = new ArrayMap<>(requests.size());
    final Map<String, VersionInfo> versionInfos = new ArrayMap<>(requests.size());
    final Map<String, PackageSetting> lastStaticSharedLibSettings =
            new ArrayMap<>(requests.size());
    final Map<String, Boolean> createdAppId = new ArrayMap<>(requests.size());
    boolean success = false;
    try {
        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackagesLI");
        for (InstallRequest request : requests) {
            final PrepareResult prepareResult;
            try {
                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "preparePackage");
                //成功准备好的安装软件包所需的数据集。这包括将用于扫描和协调包的数据
                prepareResult =
                        preparePackageLI(request.args, request.installResult);
            } catch (PrepareFailure prepareFailure) {
               ...
            } finally {
                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
            }
           
       ...
}

进入preparePackageLI方法

    @GuardedBy("mInstallLock")
    private PrepareResult preparePackageLI(InstallArgs args, PackageInstalledInfo res)
            throws PrepareFailure {
        final int installFlags = args.installFlags;
        final File tmpPackageFile = new File(args.getCodePath());
        final boolean onExternal = args.volumeUuid != null;
        final boolean instantApp = ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0);
        final boolean fullApp = ((installFlags & PackageManager.INSTALL_FULL_APP) != 0);
        final boolean virtualPreload =
                ((installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
        @ScanFlags int scanFlags = SCAN_NEW_INSTALL | SCAN_UPDATE_SIGNATURE;
        ...
        
        ParsedPackage parsedPackage;
        //PackageParser2:PackageParser 的 v2 用于在服务中启动解析时使用,并且必须包含服务包含的状态。
        try (PackageParser2 pp = new PackageParser2(mSeparateProcesses, false, mMetrics, null,
                mPackageParserCallback)) {
            // 注释1:pp.parsePackage()新包解析
            parsedPackage = pp.parsePackage(tmpPackageFile, parseFlags, false);
            AndroidPackageUtils.validatePackageDexMetadata(parsedPackage);
        } catch (PackageParserException e) {
            throw new PrepareFailure("Failed parse during installPackageLI", e);
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }
        ...
 
        try {
            // 要么使用我们得到的,要么直接从APK解析
            if (args.signingDetails != PackageParser.SigningDetails.UNKNOWN) {
                parsedPackage.setSigningDetails(args.signingDetails);
            } else {
                parsedPackage.setSigningDetails(
                        ParsingPackageUtils.getSigningDetails(parsedPackage, false /* skipVerify */));
            }
        } catch (PackageParserException e) {
            throw new PrepareFailure("Failed collect during installPackageLI", e);
        }
 
        //未使用v2签名
        if (instantApp && parsedPackage.getSigningDetails().signatureSchemeVersion
                < SignatureSchemeVersion.SIGNING_BLOCK_V2) {
            ...
        }
 
        boolean systemApp = false;
        boolean replace = false;
        synchronized (mLock) {
            // 检查是否已安装现有软件包
            if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
            ...
              }
      
            PackageSetting ps = mSettings.mPackages.get(pkgName);
            if (ps != null) {
                if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps);
 
                // 将签名与最新库版本的包设置进行比较。
                PackageSetting signatureCheckPs = ps;
                if (parsedPackage.isStaticSharedLibrary()) {
                    ...
                }
 
                //注释2:快速校验安装包签名
                final KeySetManagerService ksms = mSettings.mKeySetManagerService;
                if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) {
                    if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, parsedPackage)) {
                        throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
                                + parsedPackage.getPackageName() + " upgrade keys do not match the "
                                + "previously installed version");
                    }
                } else {
                    ...
                }
 
                if (ps.pkg != null) {
                    systemApp = ps.pkg.isSystem();
                }
                res.origUsers = ps.queryInstalledUsers(mUserManager.getUserIds(), true);
            }
 
 
            // 注释3:设置相关权限,生成、移植权限 
            int N = ArrayUtils.size(parsedPackage.getPermissions());
            for (int i = N - 1; i >= 0; i--) {
                final ParsedPermission perm = parsedPackage.getPermissions().get(i);
                final BasePermission bp = mPermissionManager.getPermissionTEMP(perm.getName());
 
                ...
            }
        }
        if (args.move != null) {
            // 我们进行了就地移动,因此 dex 已准备就绪
            ...
        } else {
            // 启用 SCAN_NO_DEX 标志以在稍后阶段跳过 dexopt
            scanFlags |= SCAN_NO_DEX;
 
            try {
                final boolean extractNativeLibs = !AndroidPackageUtils.isLibrary(parsedPackage);
                PackageSetting pkgSetting;
                synchronized (mLock) {
                    pkgSetting = mSettings.getPackageLPr(pkgName);
                }
                // 注释4:生成安装包Abi(Application binary interface,应用二进制接口)
                String abiOverride =
                        (pkgSetting == null || TextUtils.isEmpty(pkgSetting.cpuAbiOverrideString)
                        ? args.abiOverride : pkgSetting.cpuAbiOverrideString);
                boolean isUpdatedSystemAppFromExistingSetting = pkgSetting != null
                        && pkgSetting.getPkgState().isUpdatedSystemApp();
                AndroidPackage oldPackage = mPackages.get(pkgName);
                boolean isUpdatedSystemAppInferred = oldPackage != null && oldPackage.isSystem();
                final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths>
                        derivedAbi = mInjector.getAbiHelper().derivePackageAbi(parsedPackage,
                        isUpdatedSystemAppFromExistingSetting || isUpdatedSystemAppInferred,
                        abiOverride, extractNativeLibs);
                derivedAbi.first.applyTo(parsedPackage);
                derivedAbi.second.applyTo(parsedPackage);
            } catch (PackageManagerException pme) {
                Slog.e(TAG, "Error deriving application ABI", pme);
                throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
                        "Error deriving application ABI");
            }
        }
        //注释5:冻结 安装包
        final PackageFreezer freezer =
                freezePackageForInstall(pkgName, installFlags, "installPackageLI");
        boolean shouldCloseFreezerBeforeReturn = true;
        try {
            final AndroidPackage existingPackage;
            String renamedPackage = null;
            boolean sysPkg = false;
            int targetScanFlags = scanFlags;
            int targetParseFlags = parseFlags;
            final PackageSetting ps;
            final PackageSetting disabledPs;
            if (replace) {
                //更新包
                ...
            } else { 
                // 新包安装
                ...
            }
            // 解冻 安装包
            shouldCloseFreezerBeforeReturn = false;
 
            //返回成功准备好的安装包所需的数据集。
            return new PrepareResult(replace, targetScanFlags, targetParseFlags,
                    existingPackage, parsedPackage, replace /* clearCodeCache */, sysPkg,
                    ps, disabledPs);
        } finally {
            res.freezer = freezer;
            if (shouldCloseFreezerBeforeReturn) {
                freezer.close();
            }
        }
    }

再回来看 installPackagesLI方法

    @GuardedBy("mInstallLock")
    private void installPackagesLI(List<InstallRequest> requests) {
        ...
        try {
            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackagesLI");
            for (InstallRequest request : requests) {
                final PrepareResult prepareResult;
                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "preparePackage");
                    //注释1
                    //成功准备好的安装软件包所需的数据集。这包括将用于扫描和协调包的数据。
                    prepareResult =
                            preparePackageLI(request.args, request.installResult);
                ...
                try {
                    //扫描包并返回新解析的包。
                    //出现错误时返回null。
                    final ScanResult result = scanPackageTracedLI(
                            prepareResult.packageToScan, prepareResult.parseFlags,
                            prepareResult.scanFlags, System.currentTimeMillis(),
                            request.args.user, request.args.abiOverride);
                    ...
                } catch (PackageManagerException e) {
                    request.installResult.setError("Scanning Failed.", e);
                    return;
                }
            }
            //包扫描结果和相关请求详细信息用于协调一个或多个包到系统的潜在添加。
            ReconcileRequest reconcileRequest = new ReconcileRequest(preparedScans, installArgs,
                    installResults,
                    prepareResults,
                    mSharedLibraries,
                    Collections.unmodifiableMap(mPackages), versionInfos,
                    lastStaticSharedLibSettings);
            CommitRequest commitRequest = null;
            synchronized (mLock) {
                //ReconciledPackage:提交到内存中的数据结构和磁盘所需的所有数据的容器。
                //TODO:将此处包含的大部分数据移动到PackageSetting中进行提交。
                
                Map<String, ReconciledPackage> reconciledPackages;
                try {
                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages");
                    reconciledPackages = reconcilePackagesLocked(
                            reconcileRequest, mSettings.mKeySetManagerService);
                } catch (ReconcileFailure e) {
                    for (InstallRequest request : requests) {
                        request.installResult.setError("Reconciliation failed...", e);
                    }
                    return;
                } finally {
                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                }
                try {
                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "commitPackages");
                    commitRequest = new CommitRequest(reconciledPackages,
                            mUserManager.getUserIds());
                    commitPackagesLocked(commitRequest);
                    success = true;
                } finally {
                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                }
            }
            //注释2
            executePostCommitSteps(commitRequest);
        } finally {
            ...
        }
    }

进入 executePostCommitSteps方法

    /**
     * 成功安装后,在提交完成并释放包锁后执行剩余步骤。 
     * 这些通常更昂贵或需要调用 installd,这通常会锁定 mLock。
     */
    private void executePostCommitSteps(CommitRequest commitRequest) {
        final ArraySet<IncrementalStorage> incrementalStorages = new ArraySet<>();
        for (ReconciledPackage reconciledPkg : commitRequest.reconciledPackages.values()) {
            final boolean instantApp = ((reconciledPkg.scanResult.request.scanFlags
                            & PackageManagerService.SCAN_AS_INSTANT_APP) != 0);
            
            final AndroidPackage pkg = reconciledPkg.pkgSetting.pkg;
            final String packageName = pkg.getPackageName();
            //注释1:安装并准备 APP 数据 
            prepareAppDataAfterInstallLIF(pkg);
            ...
            final boolean performDexopt =
                    (!instantApp || Global.getInt(mContext.getContentResolver(),
                    Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)
                    && !pkg.isDebuggable()
                    && (!onIncremental)
                    && dexoptOptions.isCompilationEnabled();
 
              //优化dex文件(实际为 dex2oat 操作,用来将 apk 中的 dex 文件转换为 oat 文件)
            if (performDexopt) {
                // Compile the layout resources.
                if (SystemProperties.getBoolean(PRECOMPILE_LAYOUTS, false)) {
                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "compileLayouts");
                    mViewCompiler.compileLayouts(pkg);
                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                }
 
                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
                ScanResult result = reconciledPkg.scanResult;
 
 
                PackageSetting realPkgSetting = result.existingSettingCopied
                        ? result.request.pkgSetting : result.pkgSetting;
                if (realPkgSetting == null) {
                    realPkgSetting = reconciledPkg.pkgSetting;
                }
 
                // Unfortunately, the updated system app flag is only tracked on this PackageSetting
                boolean isUpdatedSystemApp = reconciledPkg.pkgSetting.getPkgState()
                        .isUpdatedSystemApp();
 
                realPkgSetting.getPkgState().setUpdatedSystemApp(isUpdatedSystemApp);
 
                mPackageDexOptimizer.performDexOpt(pkg, realPkgSetting,
                        null /* instructionSets */,
                        getOrCreateCompilerPackageStats(pkg),
                        mDexManager.getPackageUseInfoOrDefault(packageName),
                        dexoptOptions);
                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
            }
 
            // Notify BackgroundDexOptService that the package has been changed.
            // If this is an update of a package which used to fail to compile,
            // BackgroundDexOptService will remove it from its denylist.
            // TODO: Layering violation
            BackgroundDexOptService.notifyPackageChanged(packageName);
 
            notifyPackageChangeObserversOnUpdate(reconciledPkg);
        }
        NativeLibraryHelper.waitForNativeBinariesExtraction(incrementalStorages);
    }

进入prepareAppDataAfterInstallLIF方法

    /**
     * 在安装或升级后立即为给定的应用程序准备应用程序数据。 
     * 此方法仅会小心地接触为其安装的用户,并强制 restorecon 处理任何 seinfo 更改。
     * 
     * 验证目录是否存在以及所有已安装的应用程序的所有权和标签是否正确。
     * 如果所有权不匹配,它将尝试通过擦除数据来恢复系统应用程序; 第三方应用程序数据保持不变。
     * 
     * 注意:为了避免死锁,不要在持有mLock锁的情况下调用这个方法
     */
    private void prepareAppDataAfterInstallLIF(AndroidPackage pkg) {
        final PackageSetting ps;
        synchronized (mLock) {
            ps = mSettings.mPackages.get(pkg.getPackageName());
            mSettings.writeKernelMappingLPr(ps);
        }
 
        UserManagerInternal umInternal = mInjector.getUserManagerInternal();
        StorageManagerInternal smInternal = mInjector.getStorageManagerInternal();
        for (UserInfo user : mUserManager.getUsers(false /*excludeDying*/)) {
            final int flags;
            if (umInternal.isUserUnlockingOrUnlocked(user.id)) {
                flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
            } else if (umInternal.isUserRunning(user.id)) {
                flags = StorageManager.FLAG_STORAGE_DE;
            } else {
                continue;
            }
 
            if (ps.getInstalled(user.id)) {
                // TODO:这里是我们关注的。咱们接着看
                prepareAppDataLIF(pkg, user.id, flags);
 
                if (umInternal.isUserUnlockingOrUnlocked(user.id)) {
                    // 在外部存储上准备应用程序数据;
                    // 目前这用于设置由安装程序正确创建的任何 OBB 目录。
                    int uid = UserHandle.getUid(user.id, UserHandle.getAppId(pkg.getUid()));
                    smInternal.prepareAppDataAfterInstall(pkg.getPackageName(), uid);
                }
            }
        }
    }
    

进入prepareAppDataLeafLIF方法

    private void prepareAppDataLeafLIF(AndroidPackage pkg, int userId, int flags) {
        if (DEBUG_APP_DATA) {
            Slog.v(TAG, "prepareAppData for " + pkg.getPackageName() + " u" + userId + " 0x"
                    + Integer.toHexString(flags));
        }
 
        final PackageSetting ps;
        synchronized (mLock) {
            ps = mSettings.mPackages.get(pkg.getPackageName());
        }
        final String volumeUuid = pkg.getVolumeUuid();
        final String packageName = pkg.getPackageName();
 
        final int appId = UserHandle.getAppId(pkg.getUid());
 
        String pkgSeInfo = AndroidPackageUtils.getSeInfo(pkg, ps);
 
        Preconditions.checkNotNull(pkgSeInfo);
 
        final String seInfo = pkgSeInfo + (pkg.getSeInfoUser() != null ? pkg.getSeInfoUser() : "");
        long ceDataInode = -1;
        try {
            ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags,
                    appId, seInfo, pkg.getTargetSdkVersion());
        } catch (InstallerException e) {
            if (pkg.isSystem()) {
                logCriticalInfo(Log.ERROR, "Failed to create app data for " + packageName
                        + ", but trying to recover: " + e);
                destroyAppDataLeafLIF(pkg, userId, flags);
                try {
                    //注释1: 最终调用 系统服务 Installer 安装
                    ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags,
                            appId, seInfo, pkg.getTargetSdkVersion());
                    logCriticalInfo(Log.DEBUG, "Recovery succeeded!");
                } catch (InstallerException e2) {
                    logCriticalInfo(Log.DEBUG, "Recovery failed!");
                }
            } else {
                Slog.e(TAG, "Failed to create app data for " + packageName + ": " + e);
            }
        }
        
        if (mIsUpgrade || mFirstBoot || (userId != UserHandle.USER_SYSTEM)) {
            mArtManagerService.prepareAppProfiles(pkg, userId,
                /* updateReferenceProfileContent= */ false);
        }
 
        if ((flags & StorageManager.FLAG_STORAGE_CE) != 0 && ceDataInode != -1) {
            synchronized (mLock) {
                if (ps != null) {
                    ps.setCeDataInode(ceDataInode, userId);
                }
            }
        }
 
        prepareAppDataContentsLeafLIF(pkg, ps, userId, flags);
    }

在看看Installer

public class Installer extends SystemService {
    ...
    private volatile IInstalld mInstalld;
    public long createAppData(String uuid, String packageName, int userId, int flags, int appId,
            String seInfo, int targetSdkVersion) throws InstallerException {
        if (!checkBeforeRemote()) return -1;
        try {
            return mInstalld.createAppData(uuid, packageName, userId, flags, appId, seInfo,
                    targetSdkVersion);
        } catch (Exception e) {
            throw InstallerException.from(e);
        }
    }  
    ...
}

调用系统服务 Installer 安装apk

至此整个 apk 的安装过程结束,实际上安装成功之后,还会发送一个 App 安装成功的广播 ACTION_PACKAGE_ADDED。手机桌面应用注册了这个广播,当接收到应用安装成功之后,就将 apk 的启动 icon 显示在桌面上。

大致流程: 20210924175228588.png

apk的卸载流程

大致流程

image.png