Android Framework之Pkms详解

PKMS是Android系统中负责安装包管理的服务,它的主要职责如下:

管理系统安装的所有应用程序,包括升级、安装、卸载
根据Intent匹配相应的Activity、Service、Provider和BroadcastReceiver等,并提供相关信息
解析应用权限,在App调用系统接口的时候,检查App是否具有相应的权限

做过系统应用开发的同学应该知道,系统应用在系统调试的时候,要把包导入到手机上然后重启来完成新包的安装,原因是Android每次启动后会扫描固定路径下的系统应用安装包来进行安装。下图中是Android系统中安装应用的几种情景:
在这里插入图片描述
apk应用包文件实际是一个 zip 文件,是被 Google 修改了后缀名称,将 apk 文件后缀改成 zip 可以查看内容:

pedro@x86:$ tree -L 2
.
├── AndroidManifest.xml										APP属性定义文件
├── classes2.dex											Java源码编译后的代码文件
├── classes.dex
├── asserts													声音、字体、网页....资源
├── lib														应用中调用到的库
│   ├── armeabi
│   ├── arm64-v8a
├── META-INF												APK的签名文件(*.RSA*.SF*.MF 文件)
│   ├── androidx.activity_activity.version
│   ├── ...省略...
│   ├── androidx.viewpager2_viewpager2.version
│   ├── androidx.viewpager_viewpager.version
│   ├── CERT.RSA
│   ├── CERT.SF
│   ├── com
│   └── MANIFEST.MF
├── res														APP中使用到的资源目录
│   ├── anim												动画资源
│   ├── animator
│   ├── animator-v21
│   ├── anim-v21
│   ├── color												颜色资源
│   ├── color-v23
│   ├── drawable											可绘制的图片资源
│   ├── drawable-hdpi-v4
│   ├── drawable-ldrtl-hdpi-v17
│   ├── drawable-ldrtl-mdpi-v17
│   ├── drawable-ldrtl-xhdpi-v17
│   ├── drawable-ldrtl-xxhdpi-v17
│   ├── drawable-ldrtl-xxxhdpi-v17
│   ├── drawable-mdpi-v4
│   ├── drawable-v21
│   ├── drawable-v23
│   ├── drawable-v24
│   ├── drawable-watch-v20
│   ├── drawable-xhdpi-v4
│   ├── drawable-xxhdpi-v4
│   ├── drawable-xxxhdpi-v4
│   ├── interpolator
│   ├── interpolator-v21
│   ├── layout												页面布局文件
│   ├── layout-land
│   ├── layout-sw600dp-v13
│   ├── layout-v21
│   ├── layout-v26
│   ├── layout-watch-v20
│   ├── mipmap-anydpi-v26
│   ├── mipmap-hdpi-v4
│   ├── mipmap-mdpi-v4
│   ├── mipmap-xhdpi-v4
│   ├── mipmap-xxhdpi-v4
│   ├── mipmap-xxxhdpi-v4
│   └── xml													应用属性配置文件
└── resources.arsc											编译后的资源文件,如 strings.xml

那为什么要采用apk这种格式呢,Android最初是Java语言开发的,java的压缩格式zip,apk是它的扩展。安装包要体积小,便于发布,流转,那必然要以一种压缩的格式存在。
后续google也推出来新的安装包格式aab(Android app bundle),包的体积比apk的小,安全验证机制也更加完善。
接下来我们来看看整个应用安装的原理过程:
应用安装涉及到如下几个目录:

system/app
系统自带的应用程序,无法删除
data/app
用户程序安装的目录,有删除权限。

安装过程:
1.复制APK安装包到data/app目录下,解压并扫描安装包,把解析结果存储起来,存储在PMS的相关属性和mSettings里,每个应用AndroidManifest里面的各个组件信息。
2.把dex文件(Dalvik字节码)保存到dalvik-cache目录,
3.并data/data目录下创建对应的应用数据目录。

卸载过程:删除安装过程中在上述三个目录下创建的文件及目录。
具体安装细节如下:
2.3.1 PackageInstaller

安装流程首先会调用到 PackageInstaller 中,PackageInstaller 是 Android 提供的安装应用。
2.3.1.1 PackageInstallerActivity.startInstall()

当用户点击确认安装时,PackageInstall 安装应用会调用 PackageInstallerActivity.startInstall() 进行安装流程。

startInstall() 方法组装了一个 Intent,并跳转到 InstallInstalling 这个 Activity,并关闭掉当前的 PackageInstallerActivity。

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, InstallInstalling.class);  // 打开 InstallInstalling Activity
    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(localLOGV) Log.i(TAG, "downloaded app uri="+mPackageURI);
    startActivity(newIntent);  // 开启新的 Activity
    finish();
}

2.3.1.2 InstallInstalling.onCreate()

进入 InstallInstalling Activity,首先进入 onCreate() 函数。

在 onCreate() 函数中,主要完成下面的工作:

对于 Package 协议,判断是否已经安装完成
对于 File,判断是否是继续安装还是全新安装,继续安装情况下,获取之前的 sessionId 和 installId,并且根据 installId 注册安装监听;对于全新安装情况,需要根据传入的 apk 信息组装会话参数 SessionParams 对象,并以此创建新的 sessionId,注册新的观察监听安装事件。

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

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

    // 这里对于 package 协议,调用 PackageManager.installExistingPackage() 函数,判断是否已经安装成功
    if ("package".equals(mPackageURI.getScheme())) {
        try {
            getPackageManager().installExistingPackage(appInfo.packageName);
            launchSuccess();
        } catch (PackageManager.NameNotFoundException e) {
            launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
        }
    } else {
        // 对于 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);

        // 判断 savedInstanceState 是否为空,如果为空的话,表明可能之前进行过安装,此时需要获取之前的会话 id mSessionId 和 等待安装事件 id mInstallId
        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
            // 根据 mInstallId 向 InstallEventReceiver 注册一个观察者,launchFinishBasedOnResult 会接收到安装事件的回调,无论安装成功或者失败都会关闭当前的 Activity(InstallInstalling)
            try {
                InstallEventReceiver.addObserver(this, mInstallId,
                        this::launchFinishBasedOnResult);
            } catch (EventResultPersister.OutOfIdsException e) {
                // Does not happen
            }
        } else {
            // 对于 savedInstanceState 为空的情况,表明可能是一次全新的安装,需要组装会话参数来创建新的会话
            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);

            File file = new File(mPackageURI.getPath());
            try {
                PackageParser.PackageLite pkg = PackageParser.parsePackageLite(file, 0);
                params.setAppPackageName(pkg.packageName);
                params.setInstallLocation(pkg.installLocation);
                params.setSize(
                        PackageHelper.calculateInstalledSize(pkg, false, params.abiOverride));
            } catch (PackageParser.PackageParserException e) {
                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());
            } catch (IOException e) {
                Log.e(LOG_TAG,
                        "Cannot calculate installed size " + file + ". Try only apk size.");
                params.setSize(file.length());
            }

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

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

        mCancelButton = mAlert.getButton(DialogInterface.BUTTON_NEGATIVE);

        mSessionCallback = new InstallSessionCallback();
    }
}

2.3.1.3 InstallInstalling.onResume()

接着在 InstallInstalling 的 onResume() 函数中,创建了 InstallingAsyncTask 异步任务类

对于 AsyncTask 简介:

异步任务开始时,execute() 方法传入的参数类型 , 也是 doInBackground() 方法传入的参数类型
异步任务执行时,进度值类型 , onProgressUpdate() 方法传入的参数类型
异步任务结束时,结果类型 , onPostExecute() 方法传入参数类型 , 或 onCancelled() 方法参数

AsyncTask 常用方法解析 :

doInBackground() : 核心方法,执行异步任务,该方法在子线程中执行
onPreExecute() : 在 doInBackground() 执行前先执行的方法,主线程中执行,可更新 UI 界面
onProgressUpdate() : 调用 publishProgress() 回调的方法,主线程中执行,可更新 UI 界面
onPostExecute() : doInBackground() 执行完毕后再执行的方法,主线程中执行,可更新 UI 界面

对于 InstallingAsyncTask,InstallingAsyncTask 是集成自 AsyncTask 类,完成这里的异步处理任务

在 doInBackground() 异步处理中,将 APK 的信息通过IO 流的形式写入到 PackageInstall.Session 中。

在 onPostExecute() 处理中,APK 的信息全部写入到 PackageInstall.Session 中后,调用 PackageInstaller.Session 的 commit() 方法进行安装。

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

    // This is the first onResume in a single life of the activity
    // 这是该活动的单个生命周期中的第一个 onResume 流程
    if (mInstallingTask == null) {
        PackageInstaller installer = getPackageManager().getPackageInstaller();
        PackageInstaller.SessionInfo sessionInfo = installer.getSessionInfo(mSessionId);

        if (sessionInfo != null && !sessionInfo.isActive()) {
            mInstallingTask = new InstallingAsyncTask();
            mInstallingTask.execute();
        } else {
            // we will receive a broadcast when the install is finished
            // 当安装完成时,我们将收到广播
            mCancelButton.setEnabled(false);
            setFinishOnTouchOutside(false);
        }
    }
}

/**
 * Send the package to the package installer and then register a event result observer that
 * will call {@link #launchFinishBasedOnResult(int, int, String)}
 * 将包发送到包安装程序,然后注册将调用的事件结果观察器 launchFinishBasedOnResult()
 */
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 对象,PackageInstaller.Session
            session = getPackageManager().getPackageInstaller().openSession(mSessionId);
        } catch (IOException e) {
            return null;
        }

        // 初始进度
        session.setStagingProgress(0);

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

            // 读取 apk 文件
            try (InputStream in = new FileInputStream(file)) {
                long sizeBytes = file.length();
                // 打开会话对象 session 的输入流
                try (OutputStream out = session
                        .openWrite("PackageInstaller", 0, sizeBytes)) {
                    // 一次读取数据的大小为 1024 KB
                    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;
                        }

                        // 将读取的数据写入到 Session 中
                        out.write(buffer, 0, numRead);
                        if (sizeBytes > 0) {
                            // 计算并设置写入 Session 的总进度
                            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) {
            // session 不为空的情况下,创建一个 PendingIntent,并且调用 PackageInstall.Session.commit() 函数进行安装
            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);

            session.commit(pendingIntent.getIntentSender());
            mCancelButton.setEnabled(false);
            setFinishOnTouchOutside(false);
        } else {
            // session 为空的情况下,取消 sessionId
            getPackageManager().getPackageInstaller().abandonSession(mSessionId);

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

2.3.1.4 PackageInstallerSession.commit()

调用 PackageInstaller.Session.commit() 函数实际会调用到 PackageInstallerSession.commit() 方法中,PackageInstaller 会通过 sessionId 绑定 PackageInstallerService 的 PackageInstallerSession。

@Override
public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
    if (hasParentSessionId()) {
        throw new IllegalStateException(
                "Session " + sessionId + " is a child of multi-package session "
                        + mParentSessionId +  " and may not be committed directly.");
    }
    // markAsCommitted() 方法中会将包的信息封装为 PackageInstallObserverAdapter
    if (!markAsCommitted(statusReceiver, forTransfer)) {
        return;
    }
    if (isMultiPackage()) {
        final SparseIntArray remainingSessions = mChildSessionIds.clone();
        final IntentSender childIntentSender =
                new ChildStatusIntentReceiver(remainingSessions, statusReceiver)
                        .getIntentSender();
        RuntimeException commitException = null;
        boolean commitFailed = false;
        for (int i = mChildSessionIds.size() - 1; i >= 0; --i) {
            final int childSessionId = mChildSessionIds.keyAt(i);
            try {
                // commit all children, regardless if any of them fail; we'll throw/return
                // as appropriate once all children have been processed
                if (!mSessionProvider.getSession(childSessionId)
                        .markAsCommitted(childIntentSender, forTransfer)) {
                    commitFailed = true;
                }
            } catch (RuntimeException e) {
                commitException = e;
            }
        }
        if (commitException != null) {
            throw commitException;
        }
        if (commitFailed) {
            return;
        }
    }
    // 向 Handler 发送一个类型为 MSG_COMMIT 的消息
    mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
}

private final Handler.Callback mHandlerCallback = new Handler.Callback() {
    @Override
    public boolean handleMessage(Message msg) {
        switch (msg.what) {
            case MSG_COMMIT:
                // 对于 MSG_COMMIT 类型消息,调用 handleCommit() 处理
                handleCommit();
                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 IPackageInstallObserver2 observer = (IPackageInstallObserver2) args.arg4;
                final int returnCode = args.argi1;
                args.recycle();

                try {
                    observer.onPackageInstalled(packageName, returnCode, message, extras);
                } catch (RemoteException ignored) {
                }

                break;
        }

        return true;
    }
};

private void handleCommit() {
    if (isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked()) {
        DevicePolicyEventLogger
                .createEvent(DevicePolicyEnums.INSTALL_PACKAGE)
                .setAdmin(mInstallerPackageName)
                .write();
    }
    if (params.isStaged) {
        mStagingManager.commitSession(this);
        destroyInternal();
        dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Session staged", null);
        return;
    }

    if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) {
        destroyInternal();
        dispatchSessionFinished(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
                "APEX packages can only be installed using staged sessions.", null);
        return;
    }

    // For a multiPackage session, read the child sessions
    // outside of the lock, because reading the child
    // sessions with the lock held could lead to deadlock
    // (b/123391593).
    List<PackageInstallerSession> childSessions = getChildSessions();

    try {
        synchronized (mLock) {
            // 调用 commitNonStagedLocked() 继续安装
            commitNonStagedLocked(childSessions);
        }
    } catch (PackageManagerException e) {
        final String completeMsg = ExceptionUtils.getCompleteMessage(e);
        Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg);
        destroyInternal();
        dispatchSessionFinished(e.error, completeMsg, null);
    }
}

private void commitNonStagedLocked(List<PackageInstallerSession> childSessions)
        throws PackageManagerException {
    final PackageManagerService.ActiveInstallSession committingSession =
            makeSessionActiveLocked();
    if (committingSession == null) {
        return;
    }
    // 对于分包的情况,需要对各个包进行 makeSessionActiveLocked() 处理,并添加到 activeChildSessions 集合中,最后调用 PackageManagerService.installStage() 函数进行安装
    if (isMultiPackage()) {
        List<PackageManagerService.ActiveInstallSession> activeChildSessions =
                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.ActiveInstallSession activeSession =
                        session.makeSessionActiveLocked();
                if (activeSession != null) {
                    activeChildSessions.add(activeSession);
                }
            } catch (PackageManagerException e) {
                failure = e;
                success = false;
            }
        }
        if (!success) {
            try {
                mRemoteObserver.onPackageInstalled(
                        null, failure.error, failure.getLocalizedMessage(), null);
            } catch (RemoteException ignored) {
            }
            return;
        }
        mPm.installStage(activeChildSessions);
    } else {
        // 对于单包的情况,调用 PackageManagerService.installStage() 函数进行安装
        mPm.installStage(committingSession);
    }
}

2.3.2 PackageManagerService

PackageManagerService 提供系统的包管理,下面将调用到 PackageManagerService 的应用安装接口中。
2.3.2.1 PackageManagerService.installStage()

这里调用到 PackageManagerService 流程中。

installStage() 函数通过发送 INIT_COPY 的消息,最终会调用 HandlerParams.startCopy() 进行安装。

对于 HandlerParams 类的描述:

HandlerParams 是一个抽象类,用于描述执行安装拷贝的过程,实现类有两个 MultiPackageInstallParams 和 InstallParams;MultiPackageInstallParams 是处理分包的情况;InstallParams 是处理单包的情况。

startCopy() 函数会以此调用 handleStartCopy() 和 handleReturnCode() 函数处理。

void installStage(ActiveInstallSession activeInstallSession) {
    if (DEBUG_INSTANT) {
        if ((activeInstallSession.getSessionParams().installFlags
                & PackageManager.INSTALL_INSTANT_APP) != 0) {
            Slog.d(TAG, "Ephemeral install of " + activeInstallSession.getPackageName());
        }
    }
    // 创建类型为 INIT_COPY 的消息
    final Message msg = mHandler.obtainMessage(INIT_COPY);
    // 创建 InstallParams,它对应于包的安装数据
    final InstallParams params = new InstallParams(activeInstallSession);
    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));

    // 将InstallParams通过消息发送出去
    mHandler.sendMessage(msg);
}

// PackageManagerService 的内部类 PackageHandler 是消息处理类
class PackageHandler extends Handler {
void doHandleMessage(Message msg) {
switch (msg.what) {
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”);
// 调用 params.startCopy() 进行安装
params.startCopy();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
break;
}
}
}
}

handleStartCopy() 需要执行下面几步:

首先检查文件和 cid 是否已生成,如生成则设置 installFlags

检查空间大小,如果空间不够则释放无用空间

覆盖原有安装位置的文件,并根据返回结果来确定函数的返回值,并设置 installFlags

确定是否有任何已安装的包验证器,如有,则延迟检测。主要分三步:首先新建一个验证 Intent,然后设置相关的信息,之后获取验证器列表,最后向每个验证器发送验证 Intent

handleReturnCode() 执行下面几步:

调用 copyApk() 进行 APK 的拷贝动作,通过文件流的操作,把 APK 拷贝到 /data/app 等目录
调用 processPendingInstall() 继续安装,APK拷贝完成后,进入真正的安装

2.3.2.2 PackageManagerService.processPendingInstall()

processPendingInstall() 设置安装参数,并调用 processInstallRequestsAsync() 函数进行处理。

processInstallRequestsAsync() 函数创建一个新的线程,调用 installPackagesTracedLI() 函数继续安装。

private void processPendingInstall(final InstallArgs args, final int currentStatus) {
if (args.mMultiPackageInstallParams != null) {
args.mMultiPackageInstallParams.tryProcessInstallRequest(args, currentStatus);
} else {
// 1.设置安装参数
PackageInstalledInfo res = createPackageInstalledInfo(currentStatus);
// 2.创建一个新线程,处理安装参数,进行安装
processInstallRequestsAsync(
res.returnCode == PackageManager.INSTALL_SUCCEEDED,
Collections.singletonList(new InstallRequest(args, res)));
}
}


private void processInstallRequestsAsync(boolean success,
List installRequests) {
mHandler.post(() -> {
if (success) {
for (InstallRequest request : installRequests) {
// 1.如果之前安装失败,清除无用信息
request.args.doPreInstall(request.installResult.returnCode);
}
synchronized (mInstallLock) {
// 2. installPackagesTracedLI 是安装过程的核心方法,然后调用 installPackagesLI 进行安装。
installPackagesTracedLI(installRequests);
}
for (InstallRequest request : installRequests) {
// 3.如果之前安装失败,清除无用信息
request.args.doPostInstall(
request.installResult.returnCode, request.installResult.uid);
}
}
for (InstallRequest request : installRequests) {
// 执行安装后的 post install
restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult,
new PostInstallData(request.args, request.installResult, null));
}
});
}

2.3.2.3 PackageManagerService.installPackagesTracedLI()

应用的实际安装是通过 PackageManagerService 的 installPackagesTracedLI() 函数完成的。installPackagesTracedLI() 函数封装了 PackageManagerService 实际安装应用的过程。

private void installPackagesTracedLI(List<InstallRequest> requests) {
    try {
        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages");
        installPackagesLI(requests); // 调用 installPackagesLI() 函数进行安装
    } finally {
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }
}

2.3.2.4 PackageManagerService.installPackagesLI()

应用安装调用到 installPackagesLI() 函数中,此函数中将应用安装流程分为下面五个阶段:

Prepare 准备:分析任何当前安装状态,解析包并对其进行初始验证。
Scan 扫描:根据 prepare 中收集的上下文查询已解析的包。
Reconcile 调和:在彼此和当前系统状态的上下文中验证扫描的包,以确保安装成功。
Commit 提交:提交所有扫描包并更新系统状态。这是安装流程中唯一可以修改系统状态的地方,所有可预测的错误必须在此阶段之前确定。
Install 安装:创建应用数据,并且判断是否要执行 dex 优化。

/**
 * Installs one or more packages atomically. This operation is broken up into four phases:
 * <ul>
 *     <li><b>Prepare</b>
 *         <br/>Analyzes any current install state, parses the package and does initial
 *         validation on it.</li>
 *     <li><b>Scan</b>
 *         <br/>Interrogates the parsed packages given the context collected in prepare.</li>
 *     <li><b>Reconcile</b>
 *         <br/>Validates scanned packages in the context of each other and the current system
 *         state to ensure that the install will be successful.
 *     <li><b>Commit</b>
 *         <br/>Commits all scanned packages and updates system state. This is the only place
 *         that system state may be modified in the install flow and all predictable errors
 *         must be determined before this phase.</li>
 * </ul>
 *
 * Failure at any phase will result in a full failure to install all packages.
 */
@GuardedBy("mInstallLock")
private void installPackagesLI(List<InstallRequest> requests) {
    // 初始化一系列集合,用来保存安装过程中应用文件名及对应扫描结果、安装参数、安装请求、准备结果、版本信息、包信息以及创建应用 ID 的数据
    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) {
            // TODO(b/109941548): remove this once we've pulled everything from it and into
            //                    scan, reconcile or commit.
            final PrepareResult prepareResult;
            try {
                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "preparePackage");
                // Prepare 准备:分析任何当前安装状态,解析包并对其进行初始验证。
                prepareResult = preparePackageLI(request.args, request.installResult);
            } catch (PrepareFailure prepareFailure) {
                request.installResult.setError(prepareFailure.error,
                        prepareFailure.getMessage());
                request.installResult.origPackage = prepareFailure.conflictingPackage;
                request.installResult.origPermission = prepareFailure.conflictingPermission;
                return;
            } finally {
                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
            }
            request.installResult.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
            request.installResult.installerPackageName = request.args.installerPackageName;

            final String packageName = prepareResult.packageToScan.packageName;
            // 保存包名对应的 prepareResult 准备结果以及安装参数等信息
            prepareResults.put(packageName, prepareResult);
            installResults.put(packageName, request.installResult);
            installArgs.put(packageName, request.args);
            try {
                // Scan 扫描:根据 prepare 中收集的上下文查询已解析的包。
                final List<ScanResult> scanResults = scanPackageTracedLI(
                        prepareResult.packageToScan, prepareResult.parseFlags,
                        prepareResult.scanFlags, System.currentTimeMillis(),
                        request.args.user);
                for (ScanResult result : scanResults) {
                    // 保存包名及对应的扫描结果信息
                    if (null != preparedScans.put(result.pkgSetting.pkg.packageName, result)) {
                        request.installResult.setError(
                                PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE,
                                "Duplicate package " + result.pkgSetting.pkg.packageName
                                        + " in multi-package install request.");
                        return;
                    }
                    // 创建应用 ID 并保存
                    createdAppId.put(packageName, optimisticallyRegisterAppId(result));
                    // 保存版本信息
                    versionInfos.put(result.pkgSetting.pkg.packageName,
                            getSettingsVersionForPackage(result.pkgSetting.pkg));
                    if (result.staticSharedLibraryInfo != null) {
                        final PackageSetting sharedLibLatestVersionSetting =
                                getSharedLibLatestVersionSetting(result);
                        if (sharedLibLatestVersionSetting != null) {
                            lastStaticSharedLibSettings.put(result.pkgSetting.pkg.packageName,
                                    sharedLibLatestVersionSetting);
                        }
                    }
                }
            } 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 (mPackages) {
            Map<String, ReconciledPackage> reconciledPackages;
            try {
                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages");
                // Reconcile 调和:在彼此和当前系统状态的上下文中验证扫描的包,以确保安装成功。
                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,
                        sUserManager.getUserIds());
                // Commit 提交:提交所有扫描包并更新系统状态。这是安装流程中唯一可以修改系统状态的地方,所有可预测的错误必须在此阶段之前确定。
                commitPackagesLocked(commitRequest);
                success = true;
            } finally {
                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
            }
        }
        // Install 安装:创建应用数据,并且判断是否要执行 dex 优化。
        executePostCommitSteps(commitRequest);
    } finally {
        if (!success) {
            for (ScanResult result : preparedScans.values()) {
                if (createdAppId.getOrDefault(result.request.pkg.packageName, false)) {
                    cleanUpAppIdCreation(result);
                }
            }
            // TODO(patb): create a more descriptive reason than unknown in future release
            // mark all non-failure installs as UNKNOWN so we do not treat them as success
            for (InstallRequest request : requests) {
                if (request.installResult.returnCode == PackageManager.INSTALL_SUCCEEDED) {
                    request.installResult.returnCode = PackageManager.INSTALL_UNKNOWN;
                }
            }
        }
        for (PrepareResult result : prepareResults.values()) {
            if (result.freezer != null) {
                result.freezer.close();
            }
        }
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }
}

2.3.2.4.1 Prepare 准备

应用安装实际过程第一阶段,先对应用包进行准备工作,包括分析当前安装状态,分析包并对其进行初始验证。

我们先来看一下 Prepare 准备阶段的结果 PrepareResult 类

private static class PrepareResult {
    public final int installReason;
    public final String volumeUuid;
    public final String installerPackageName;
    public final UserHandle user;
    public final boolean replace;
    public final int scanFlags;
    public final int parseFlags;
    @Nullable /* The original Package if it is being replaced, otherwise {@code null} */
    public final PackageParser.Package existingPackage;
    public final PackageParser.Package packageToScan;
    public final boolean clearCodeCache;
    public final boolean system;
    /* The original package name if it was changed during an update, otherwise {@code null}. */
    @Nullable
    public final String renamedPackage;
    public final PackageFreezer freezer;
    public final PackageSetting originalPs;
    public final PackageSetting disabledPs;
    public final PackageSetting[] childPackageSettings;

    private PrepareResult(int installReason, String volumeUuid,
            String installerPackageName, UserHandle user, boolean replace, int scanFlags,
            int parseFlags, PackageParser.Package existingPackage,
            PackageParser.Package packageToScan, boolean clearCodeCache, boolean system,
            String renamedPackage, PackageFreezer freezer, PackageSetting originalPs,
            PackageSetting disabledPs, PackageSetting[] childPackageSettings) {
        this.installReason = installReason;
        this.volumeUuid = volumeUuid;
        this.installerPackageName = installerPackageName;
        this.user = user;
        this.replace = replace;
        this.scanFlags = scanFlags;
        this.parseFlags = parseFlags;
        this.existingPackage = existingPackage;
        this.packageToScan = packageToScan;
        this.clearCodeCache = clearCodeCache;
        this.system = system;
        this.renamedPackage = renamedPackage;
        this.freezer = freezer;
        this.originalPs = originalPs;
        this.disabledPs = disabledPs;
        this.childPackageSettings = childPackageSettings;
    }
}

Prepare 阶段调用的是 preparePackageLI() 函数,下面将简要概括 preparePackageLI() 函数的流程

private PrepareResult preparePackageLI(InstallArgs args, PackageInstalledInfo res)
        throws PrepareFailure {
    final int installFlags = args.installFlags;
    final String installerPackageName = args.installerPackageName;
    final String volumeUuid = args.volumeUuid;
    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;
    if (args.move != null) {
        // moving a complete application; perform an initial scan on the new install location
        scanFlags |= SCAN_INITIAL;
    }
    if ((installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) {
        scanFlags |= SCAN_DONT_KILL_APP;
    }
    if (instantApp) {
        scanFlags |= SCAN_AS_INSTANT_APP;
    }
    if (fullApp) {
        scanFlags |= SCAN_AS_FULL_APP;
    }
    if (virtualPreload) {
        scanFlags |= SCAN_AS_VIRTUAL_PRELOAD;
    }

    if (DEBUG_INSTALL) Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile);

    // Sanity check
    if (instantApp && onExternal) {
        Slog.i(TAG, "Incompatible ephemeral install; external=" + onExternal);
        throw new PrepareFailure(PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
    }

/*
 * 1、调用 PackageParser.parsePackage() 函数解析 APK
 * 2、对于 instantApp,安装时有额外的检查,例如应用的 SDK 版本要大于 Android O,并且需要配置 mSharedUserId
 */
    // Retrieve PackageSettings and parse package
    @ParseFlags final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
            | PackageParser.PARSE_ENFORCE_CODE
            | (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0);

    PackageParser pp = new PackageParser();
    pp.setSeparateProcesses(mSeparateProcesses);
    pp.setDisplayMetrics(mMetrics);
    pp.setCallback(mPackageParserCallback);

    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
    final PackageParser.Package pkg;
    try {
        pkg = pp.parsePackage(tmpPackageFile, parseFlags);
        DexMetadataHelper.validatePackageDexMetadata(pkg);
    } catch (PackageParserException e) {
        throw new PrepareFailure("Failed parse during installPackageLI", e);
    } finally {
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }

    // Instant apps have several additional install-time checks.
    if (instantApp) {
        if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.O) {
            Slog.w(TAG,
                    "Instant app package " + pkg.packageName + " does not target at least O");
            throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
                    "Instant app package must target at least O");
        }
        if (pkg.mSharedUserId != null) {
            Slog.w(TAG, "Instant app package " + pkg.packageName
                    + " may not declare sharedUserId.");
            throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
                    "Instant app package may not declare a sharedUserId");
        }
    }

/*
 * 1、如果应用有静态共享库,需要更名,并且需要安装在内部存储
 * 2、对于多安装包的集群包,需要为集群包添加结果
 * 3、设置应用的 CPU ABI
 */
    if (pkg.applicationInfo.isStaticSharedLibrary()) {
        // Static shared libraries have synthetic package names
        renameStaticSharedLibraryPackage(pkg);

        // No static shared libs on external storage
        if (onExternal) {
            Slog.i(TAG, "Static shared libs can only be installed on internal storage.");
            throw new PrepareFailure(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
                    "Packages declaring static-shared libs cannot be updated");
        }
    }

    // If we are installing a clustered package add results for the children
    if (pkg.childPackages != null) {
        synchronized (mPackages) {
            final int childCount = pkg.childPackages.size();
            for (int i = 0; i < childCount; i++) {
                PackageParser.Package childPkg = pkg.childPackages.get(i);
                PackageInstalledInfo childRes = new PackageInstalledInfo();
                childRes.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
                childRes.pkg = childPkg;
                childRes.name = childPkg.packageName;
                PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
                if (childPs != null) {
                    childRes.origUsers = childPs.queryInstalledUsers(
                            sUserManager.getUserIds(), true);
                }
                if ((mPackages.containsKey(childPkg.packageName))) {
                    childRes.removedInfo = new PackageRemovedInfo(this);
                    childRes.removedInfo.removedPackage = childPkg.packageName;
                    childRes.removedInfo.installerPackageName = childPs.installerPackageName;
                }
                if (res.addedChildPackages == null) {
                    res.addedChildPackages = new ArrayMap<>();
                }
                res.addedChildPackages.put(childPkg.packageName, childRes);
            }
        }
    }

    // If package doesn't declare API override, mark that we have an install
    // time CPU ABI override.
    if (TextUtils.isEmpty(pkg.cpuAbiOverride)) {
        pkg.cpuAbiOverride = args.abiOverride;
    }

    String pkgName = res.name = pkg.packageName;
    if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_TEST_ONLY) != 0) {
        if ((installFlags & PackageManager.INSTALL_ALLOW_TEST) == 0) {
            throw new PrepareFailure(INSTALL_FAILED_TEST_ONLY, "installPackageLI");
        }
    }

/*
 * 1、调用 PackageParser.collectCertificates() 函数从应用中获取证书信息
 * 2、如果是 instantApp,那么签名方案不能小于 V2
 */
    try {
        // either use what we've been given or parse directly from the APK
        if (args.signingDetails != PackageParser.SigningDetails.UNKNOWN) {
            pkg.setSigningDetails(args.signingDetails);
        } else {
            PackageParser.collectCertificates(pkg, false /* skipVerify */);
        }
    } catch (PackageParserException e) {
        throw new PrepareFailure("Failed collect during installPackageLI", e);
    }

    if (instantApp && pkg.mSigningDetails.signatureSchemeVersion
            < SignatureSchemeVersion.SIGNING_BLOCK_V2) {
        Slog.w(TAG, "Instant app package " + pkg.packageName
                + " is not signed with at least APK Signature Scheme v2");
        throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
                "Instant app package must be signed with APK Signature Scheme v2 or greater");
    }

/*
 * 1、通过 replace 变量去判断此应用安装是 安装已经存在的包 还是 全新的安装
 * 2、对于 replace 安装情况下,需要对一些情况进行判断
 */
    // Get rid of all references to package scan path via parser.
    pp = null;
    boolean systemApp = false;
    boolean replace = false;
    synchronized (mPackages) {
        // Check if installing already existing package
        if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
            String oldName = mSettings.getRenamedPackageLPr(pkgName);
            if (pkg.mOriginalPackages != null
                    && pkg.mOriginalPackages.contains(oldName)
                    && mPackages.containsKey(oldName)) {
                // This package is derived from an original package,
                // and this device has been updating from that original
                // name.  We must continue using the original name, so
                // rename the new package here.
                pkg.setPackageName(oldName);
                pkgName = pkg.packageName;
                replace = true;
                if (DEBUG_INSTALL) {
                    Slog.d(TAG, "Replacing existing renamed package: oldName="
                            + oldName + " pkgName=" + pkgName);
                }
            } else if (mPackages.containsKey(pkgName)) {
                // This package, under its official name, already exists
                // on the device; we should replace it.
                replace = true;
                if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing pacakge: " + pkgName);
            }

            // Child packages are installed through the parent package
            if (pkg.parentPackage != null) {
                throw new PrepareFailure(
                        PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
                        "Package " + pkg.packageName + " is child of package "
                                + pkg.parentPackage.parentPackage + ". Child packages "
                                + "can be updated only through the parent package.");
            }

            if (replace) {
                // Prevent apps opting out from runtime permissions
                PackageParser.Package oldPackage = mPackages.get(pkgName);
                final int oldTargetSdk = oldPackage.applicationInfo.targetSdkVersion;
                final int newTargetSdk = pkg.applicationInfo.targetSdkVersion;
                if (oldTargetSdk > Build.VERSION_CODES.LOLLIPOP_MR1
                        && newTargetSdk <= Build.VERSION_CODES.LOLLIPOP_MR1) {
                    throw new PrepareFailure(
                            PackageManager.INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE,
                            "Package " + pkg.packageName + " new target SDK " + newTargetSdk
                                    + " doesn't support runtime permissions but the old"
                                    + " target SDK " + oldTargetSdk + " does.");
                }
                // Prevent persistent apps from being updated
                if (((oldPackage.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0)
                        && ((installFlags & PackageManager.INSTALL_STAGED) == 0)) {
                    throw new PrepareFailure(PackageManager.INSTALL_FAILED_INVALID_APK,
                            "Package " + oldPackage.packageName + " is a persistent app. "
                                    + "Persistent apps are not updateable.");
                }
                // Prevent installing of child packages
                if (oldPackage.parentPackage != null) {
                    throw new PrepareFailure(
                            PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
                            "Package " + pkg.packageName + " is child of package "
                                    + oldPackage.parentPackage + ". Child packages "
                                    + "can be updated only through the parent package.");
                }
            }
        }

/*
 * 1、静态共享库具有不同版本的相同包,我们在内部使用合成包名来允许相同包的多个版本,因此我们需要将签名与最新库版本的包设置进行比较。
 * 2、如果更新,快速检查我们的签名是否正确;稍后我们将在扫描时再次检查这一点,但我们希望在被重新定义的权限绊倒之前提前退出。
 */
        PackageSetting ps = mSettings.mPackages.get(pkgName);
        if (ps != null) {
            if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps);

            // Static shared libs have same package with different versions where
            // we internally use a synthetic package name to allow multiple versions
            // of the same package, therefore we need to compare signatures against
            // the package setting for the latest library version.
            PackageSetting signatureCheckPs = ps;
            if (pkg.applicationInfo.isStaticSharedLibrary()) {
                SharedLibraryInfo libraryInfo = getLatestSharedLibraVersionLPr(pkg);
                if (libraryInfo != null) {
                    signatureCheckPs = mSettings.getPackageLPr(libraryInfo.getPackageName());
                }
            }

            // Quick sanity check that we're signed correctly if updating;
            // we'll check this again later when scanning, but we want to
            // bail early here before tripping over redefined permissions.
            final KeySetManagerService ksms = mSettings.mKeySetManagerService;
            if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) {
                if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, pkg)) {
                    throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
                            + pkg.packageName + " upgrade keys do not match the "
                            + "previously installed version");
                }
            } else {
                try {
                    final boolean compareCompat = isCompatSignatureUpdateNeeded(pkg);
                    final boolean compareRecover = isRecoverSignatureUpdateNeeded(pkg);
                    // We don't care about disabledPkgSetting on install for now.
                    final boolean compatMatch = verifySignatures(
                            signatureCheckPs, null, pkg.mSigningDetails, compareCompat,
                            compareRecover);
                    // The new KeySets will be re-added later in the scanning process.
                    if (compatMatch) {
                        synchronized (mPackages) {
                            ksms.removeAppKeySetDataLPw(pkg.packageName);
                        }
                    }
                } catch (PackageManagerException e) {
                    throw new PrepareFailure(e.error, e.getMessage());
                }
            }

            if (ps.pkg != null && ps.pkg.applicationInfo != null) {
                systemApp = (ps.pkg.applicationInfo.flags &
                        ApplicationInfo.FLAG_SYSTEM) != 0;
            }
            res.origUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
        }

/*
 * 1、这里是对应用包声明的权限的控制,比如防止应用程序将 protection 级别从任何其他类型更改为 dangerous
 */
        int N = pkg.permissions.size();
        for (int i = N - 1; i >= 0; i--) {
            final PackageParser.Permission perm = pkg.permissions.get(i);
            final BasePermission bp =
                    (BasePermission) mPermissionManager.getPermissionTEMP(perm.info.name);

            // Don't allow anyone but the system to define ephemeral permissions.
            if ((perm.info.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0
                    && !systemApp) {
                Slog.w(TAG, "Non-System package " + pkg.packageName
                        + " attempting to delcare ephemeral permission "
                        + perm.info.name + "; Removing ephemeral.");
                perm.info.protectionLevel &= ~PermissionInfo.PROTECTION_FLAG_INSTANT;
            }

            // Check whether the newly-scanned package wants to define an already-defined perm
            if (bp != null) {
                // If the defining package is signed with our cert, it's okay.  This
                // also includes the "updating the same package" case, of course.
                // "updating same package" could also involve key-rotation.
                final boolean sigsOk;
                final String sourcePackageName = bp.getSourcePackageName();
                final PackageSettingBase sourcePackageSetting = bp.getSourcePackageSetting();
                final KeySetManagerService ksms = mSettings.mKeySetManagerService;
                if (sourcePackageName.equals(pkg.packageName)
                        && (ksms.shouldCheckUpgradeKeySetLocked(
                        sourcePackageSetting, scanFlags))) {
                    sigsOk = ksms.checkUpgradeKeySetLocked(sourcePackageSetting, pkg);
                } else {

                    // in the event of signing certificate rotation, we need to see if the
                    // package's certificate has rotated from the current one, or if it is an
                    // older certificate with which the current is ok with sharing permissions
                    if (sourcePackageSetting.signatures.mSigningDetails.checkCapability(
                            pkg.mSigningDetails,
                            PackageParser.SigningDetails.CertCapabilities.PERMISSION)) {
                        sigsOk = true;
                    } else if (pkg.mSigningDetails.checkCapability(
                            sourcePackageSetting.signatures.mSigningDetails,
                            PackageParser.SigningDetails.CertCapabilities.PERMISSION)) {

                        // the scanned package checks out, has signing certificate rotation
                        // history, and is newer; bring it over
                        sourcePackageSetting.signatures.mSigningDetails = pkg.mSigningDetails;
                        sigsOk = true;
                    } else {
                        sigsOk = false;
                    }
                }
                if (!sigsOk) {
                    // If the owning package is the system itself, we log but allow
                    // install to proceed; we fail the install on all other permission
                    // redefinitions.
                    if (!sourcePackageName.equals("android")) {
                        throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PERMISSION, "Package "
                                + pkg.packageName
                                + " attempting to redeclare permission "
                                + perm.info.name + " already owned by "
                                + sourcePackageName)
                                .conflictsWithExistingPermission(perm.info.name,
                                        sourcePackageName);
                    } else {
                        Slog.w(TAG, "Package " + pkg.packageName
                                + " attempting to redeclare system permission "
                                + perm.info.name + "; ignoring new declaration");
                        pkg.permissions.remove(i);
                    }
                } else if (!PLATFORM_PACKAGE_NAME.equals(pkg.packageName)) {
                    // Prevent apps to change protection level to dangerous from any other
                    // type as this would allow a privilege escalation where an app adds a
                    // normal/signature permission in other app's group and later redefines
                    // it as dangerous leading to the group auto-grant.
                    if ((perm.info.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
                            == PermissionInfo.PROTECTION_DANGEROUS) {
                        if (bp != null && !bp.isRuntime()) {
                            Slog.w(TAG, "Package " + pkg.packageName + " trying to change a "
                                    + "non-runtime permission " + perm.info.name
                                    + " to runtime; keeping old protection level");
                            perm.info.protectionLevel = bp.getProtectionLevel();
                        }
                    }
                }
            }
        }
    }

/*
 * 1、对于系统 APP,如果在外部存储上或者被其他应用替代,则会提醒异常
 * 2、生成安装包 Abi (Application binary interface,应用二进制接口,描述应用程序和操作系统之间或其他应用程序的低级接口)
 */
    if (systemApp) {
        if (onExternal) {
            // Abort update; system app can't be replaced with app on sdcard
            throw new PrepareFailure(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
                    "Cannot install updates to system apps on sdcard");
        } else if (instantApp) {
            // Abort update; system app can't be replaced with an instant app
            throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
                    "Cannot update a system app with an instant app");
        }
    }

    if (args.move != null) {
        // We did an in-place move, so dex is ready to roll
        scanFlags |= SCAN_NO_DEX;
        scanFlags |= SCAN_MOVE;

        synchronized (mPackages) {
            final PackageSetting ps = mSettings.mPackages.get(pkgName);
            if (ps == null) {
                res.setError(INSTALL_FAILED_INTERNAL_ERROR,
                        "Missing settings for moved package " + pkgName);
            }

            // We moved the entire application as-is, so bring over the
            // previously derived ABI information.
            pkg.applicationInfo.primaryCpuAbi = ps.primaryCpuAbiString;
            pkg.applicationInfo.secondaryCpuAbi = ps.secondaryCpuAbiString;
        }

    } else {
        // Enable SCAN_NO_DEX flag to skip dexopt at a later stage
        scanFlags |= SCAN_NO_DEX;

        try {
            String abiOverride = (TextUtils.isEmpty(pkg.cpuAbiOverride) ?
                    args.abiOverride : pkg.cpuAbiOverride);
            final boolean extractNativeLibs = !pkg.isLibrary();
            derivePackageAbi(pkg, abiOverride, extractNativeLibs);
        } catch (PackageManagerException pme) {
            Slog.e(TAG, "Error deriving application ABI", pme);
            throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
                    "Error deriving application ABI");
        }
    }

    if (!args.doRename(res.returnCode, pkg)) {
        throw new PrepareFailure(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
    }

    try {
        setUpFsVerityIfPossible(pkg);
    } catch (InstallerException | IOException | DigestException | NoSuchAlgorithmException e) {
        throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
                "Failed to set up verity: " + e);
    }


    if (!instantApp) {
        startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg);
    } else {
        if (DEBUG_DOMAIN_VERIFICATION) {
            Slog.d(TAG, "Not verifying instant app install for app links: " + pkgName);
        }
    }

/*
 * 1、冻结 APK,调用 freezePackageForInstall() 函数冻结 APK,准备进行安装
 * 2、通过 replace 参数判断是替换安装还是安装新的 APK,对于替换安装,包含系统升级后应用的更新流程
 */
    final PackageFreezer freezer =
            freezePackageForInstall(pkgName, installFlags, "installPackageLI");
    boolean shouldCloseFreezerBeforeReturn = true;
    try {
        final PackageParser.Package existingPackage;
        String renamedPackage = null;
        boolean sysPkg = false;
        String targetVolumeUuid = volumeUuid;
        int targetScanFlags = scanFlags;
        int targetParseFlags = parseFlags;
        final PackageSetting ps;
        final PackageSetting disabledPs;
        final PackageSetting[] childPackages;
        if (replace) {
            targetVolumeUuid = null;
            if (pkg.applicationInfo.isStaticSharedLibrary()) {
                // Static libs have a synthetic package name containing the version
                // and cannot be updated as an update would get a new package name,
                // unless this is the exact same version code which is useful for
                // development.
                PackageParser.Package existingPkg = mPackages.get(pkg.packageName);
                if (existingPkg != null
                        && existingPkg.getLongVersionCode() != pkg.getLongVersionCode()) {
                    throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PACKAGE,
                            "Packages declaring "
                                    + "static-shared libs cannot be updated");
                }
            }

            final boolean isInstantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;

            final PackageParser.Package oldPackage;
            final String pkgName11 = pkg.packageName;
            final int[] allUsers;
            final int[] installedUsers;

            synchronized (mPackages) {
                oldPackage = mPackages.get(pkgName11);
                existingPackage = oldPackage;
                if (DEBUG_INSTALL) {
                    Slog.d(TAG,
                            "replacePackageLI: new=" + pkg + ", old=" + oldPackage);
                }

                ps = mSettings.mPackages.get(pkgName11);
                disabledPs = mSettings.getDisabledSystemPkgLPr(ps);

                // verify signatures are valid
                final KeySetManagerService ksms = mSettings.mKeySetManagerService;
                if (ksms.shouldCheckUpgradeKeySetLocked(ps, scanFlags)) {
                    if (!ksms.checkUpgradeKeySetLocked(ps, pkg)) {
                        throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
                                "New package not signed by keys specified by upgrade-keysets: "
                                        + pkgName11);
                    }
                } else {
                    // default to original signature matching
                    if (!pkg.mSigningDetails.checkCapability(oldPackage.mSigningDetails,
                            SigningDetails.CertCapabilities.INSTALLED_DATA)
                            && !oldPackage.mSigningDetails.checkCapability(
                            pkg.mSigningDetails,
                            SigningDetails.CertCapabilities.ROLLBACK)) {
                        throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
                                "New package has a different signature: " + pkgName11);
                    }
                }

                // don't allow a system upgrade unless the upgrade hash matches
                if (oldPackage.restrictUpdateHash != null && oldPackage.isSystem()) {
                    final byte[] digestBytes;
                    try {
                        final MessageDigest digest = MessageDigest.getInstance("SHA-512");
                        updateDigest(digest, new File(pkg.baseCodePath));
                        if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
                            for (String path : pkg.splitCodePaths) {
                                updateDigest(digest, new File(path));
                            }
                        }
                        digestBytes = digest.digest();
                    } catch (NoSuchAlgorithmException | IOException e) {
                        throw new PrepareFailure(INSTALL_FAILED_INVALID_APK,
                                "Could not compute hash: " + pkgName11);
                    }
                    if (!Arrays.equals(oldPackage.restrictUpdateHash, digestBytes)) {
                        throw new PrepareFailure(INSTALL_FAILED_INVALID_APK,
                                "New package fails restrict-update check: " + pkgName11);
                    }
                    // retain upgrade restriction
                    pkg.restrictUpdateHash = oldPackage.restrictUpdateHash;
                }

                // Check for shared user id changes
                String invalidPackageName =
                        getParentOrChildPackageChangedSharedUser(oldPackage, pkg);
                if (invalidPackageName != null) {
                    throw new PrepareFailure(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
                            "Package " + invalidPackageName + " tried to change user "
                                    + oldPackage.mSharedUserId);
                }

                // In case of rollback, remember per-user/profile install state
                allUsers = sUserManager.getUserIds();
                installedUsers = ps.queryInstalledUsers(allUsers, true);


                // don't allow an upgrade from full to ephemeral
                if (isInstantApp) {
                    if (args.user == null || args.user.getIdentifier() == UserHandle.USER_ALL) {
                        for (int currentUser : allUsers) {
                            if (!ps.getInstantApp(currentUser)) {
                                // can't downgrade from full to instant
                                Slog.w(TAG,
                                        "Can't replace full app with instant app: " + pkgName11
                                                + " for user: " + currentUser);
                                throw new PrepareFailure(
                                        PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
                            }
                        }
                    } else if (!ps.getInstantApp(args.user.getIdentifier())) {
                        // can't downgrade from full to instant
                        Slog.w(TAG, "Can't replace full app with instant app: " + pkgName11
                                + " for user: " + args.user.getIdentifier());
                        throw new PrepareFailure(
                                PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
                    }
                }
            }


            // Update what is removed
            res.removedInfo = new PackageRemovedInfo(this);
            res.removedInfo.uid = oldPackage.applicationInfo.uid;
            res.removedInfo.removedPackage = oldPackage.packageName;
            res.removedInfo.installerPackageName = ps.installerPackageName;
            res.removedInfo.isStaticSharedLib = pkg.staticSharedLibName != null;
            res.removedInfo.isUpdate = true;
            res.removedInfo.origUsers = installedUsers;
            res.removedInfo.installReasons = new SparseArray<>(installedUsers.length);
            for (int i = 0; i < installedUsers.length; i++) {
                final int userId = installedUsers[i];
                res.removedInfo.installReasons.put(userId, ps.getInstallReason(userId));
            }

            childPackages = mSettings.getChildSettingsLPr(ps);
            if (childPackages != null) {
                for (PackageSetting childPs : childPackages) {
                    boolean childPackageUpdated = false;
                    PackageParser.Package childPkg = (childPs == null) ? null : childPs.pkg;
                    if (res.addedChildPackages != null) {
                        PackageInstalledInfo childRes = res.addedChildPackages.get(
                                childPkg.packageName);
                        if (childRes != null) {
                            childRes.removedInfo.uid = childPkg.applicationInfo.uid;
                            childRes.removedInfo.removedPackage = childPkg.packageName;
                            if (childPs != null) {
                                childRes.removedInfo.installerPackageName =
                                        childPs.installerPackageName;
                            }
                            childRes.removedInfo.isUpdate = true;
                            childRes.removedInfo.installReasons =
                                    res.removedInfo.installReasons;
                            childPackageUpdated = true;
                        }
                    }
                    if (!childPackageUpdated) {
                        PackageRemovedInfo childRemovedRes = new PackageRemovedInfo(this);
                        childRemovedRes.removedPackage = childPkg.packageName;
                        if (childPs != null) {
                            childRemovedRes.installerPackageName = childPs.installerPackageName;
                        }
                        childRemovedRes.isUpdate = false;
                        childRemovedRes.dataRemoved = true;
                        synchronized (mPackages) {
                            if (childPs != null) {
                                childRemovedRes.origUsers = childPs.queryInstalledUsers(
                                        allUsers,
                                        true);
                            }
                        }
                        if (res.removedInfo.removedChildPackages == null) {
                            res.removedInfo.removedChildPackages = new ArrayMap<>();
                        }
                        res.removedInfo.removedChildPackages.put(childPkg.packageName,
                                childRemovedRes);
                    }
                }
            }


            sysPkg = (isSystemApp(oldPackage));
            if (sysPkg) {
                // Set the system/privileged/oem/vendor/product flags as needed
                final boolean privileged = isPrivilegedApp(oldPackage);
                final boolean oem = isOemApp(oldPackage);
                final boolean vendor = isVendorApp(oldPackage);
                final boolean product = isProductApp(oldPackage);
                final boolean odm = isOdmApp(oldPackage);
                final @ParseFlags int systemParseFlags = parseFlags;
                final @ScanFlags int systemScanFlags = scanFlags
                        | SCAN_AS_SYSTEM
                        | (privileged ? SCAN_AS_PRIVILEGED : 0)
                        | (oem ? SCAN_AS_OEM : 0)
                        | (vendor ? SCAN_AS_VENDOR : 0)
                        | (product ? SCAN_AS_PRODUCT : 0)
                        | (odm ? SCAN_AS_ODM : 0);

                if (DEBUG_INSTALL) {
                    Slog.d(TAG, "replaceSystemPackageLI: new=" + pkg
                            + ", old=" + oldPackage);
                }
                res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
                pkg.setApplicationInfoFlags(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP,
                        ApplicationInfo.FLAG_UPDATED_SYSTEM_APP);
                targetParseFlags = systemParseFlags;
                targetScanFlags = systemScanFlags;
            } else { // non system replace
                replace = true;
                if (DEBUG_INSTALL) {
                    Slog.d(TAG,
                            "replaceNonSystemPackageLI: new=" + pkg + ", old="
                                    + oldPackage);
                }

                String pkgName1 = oldPackage.packageName;
                boolean deletedPkg = true;
                boolean addedPkg = false;
                boolean updatedSettings = false;

                final long origUpdateTime = (pkg.mExtras != null)
                        ? ((PackageSetting) pkg.mExtras).lastUpdateTime : 0;

            }
        } 

/*
 * 1、对于全新的安装,相对于替换安装则少了很多准备工作,进行了一些命名的检查
 */
        else { // new package install
            ps = null;
            childPackages = null;
            disabledPs = null;
            replace = false;
            existingPackage = null;
            // Remember this for later, in case we need to rollback this install
            String pkgName1 = pkg.packageName;

            if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);

            // TODO(patb): MOVE TO RECONCILE
            synchronized (mPackages) {
                renamedPackage = mSettings.getRenamedPackageLPr(pkgName1);
                if (renamedPackage != null) {
                    // A package with the same name is already installed, though
                    // it has been renamed to an older name.  The package we
                    // are trying to install should be installed as an update to
                    // the existing one, but that has not been requested, so bail.
                    throw new PrepareFailure(INSTALL_FAILED_ALREADY_EXISTS,
                            "Attempt to re-install " + pkgName1
                                    + " without first uninstalling package running as "
                                    + renamedPackage);
                }
                if (mPackages.containsKey(pkgName1)) {
                    // Don't allow installation over an existing package with the same name.
                    throw new PrepareFailure(INSTALL_FAILED_ALREADY_EXISTS,
                            "Attempt to re-install " + pkgName1
                                    + " without first uninstalling.");
                }
            }
        }

/*
 * 1、设置标志位,能够在后续的安装中,关闭冻结
 * 2、Prepare 准备阶段返回结果,构建 PrepareResult 对象作为结果
 */
        // we're passing the freezer back to be closed in a later phase of install
        shouldCloseFreezerBeforeReturn = false;

        return new PrepareResult(args.installReason, targetVolumeUuid, installerPackageName,
                args.user, replace, targetScanFlags, targetParseFlags, existingPackage, pkg,
                replace /* clearCodeCache */, sysPkg, renamedPackage, freezer,
                ps, disabledPs, childPackages);
    } finally {
        if (shouldCloseFreezerBeforeReturn) {
            freezer.close();
        }
    }
}

2.3.2.4.2 Scan 扫描

扫描阶段会调用 scanPackageTracedLI() 函数完成。这里的调用栈如下:

scanPackageTracedLI()
scanPackageLI()
scanPackageChildLI()
addForInitLI()
scanPackageNewLI()

scanPackageTracedLI() 中调用 scanPackageLI() 函数;scanPackageLI() 函数会调用 PackageParser.parsePackage() 解析包,然后调用 scanPackageChildLI() 函数继续扫描;scanPackageChildLI() 函数会对于单包和多包的情况调用 addForInitLI() 函数继续处理。在 addForInitLI() 函数中会有各种场景的过滤,例如对于系统分区下的应用,在系统更新后的场景下,会去对包再次进行扫描 ;是否跳过验签;是否是隐藏的系统应用;然后调用 scanPackageNewLI() 函数获取 scanResult 扫描结果对象。

private PackageParser.Package addForInitLI(PackageParser.Package pkg,
@ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
@Nullable UserHandle user)
throws PackageManagerException {
// 判断系统应用是否需要更新
synchronized (mPackages) {
// 更新子应用
if (isSystemPkgUpdated) {

}
if (isSystemPkgBetter) {
// 更新安装包到 system 分区中
synchronized (mPackages) {
// just remove the loaded entries from package lists
mPackages.remove(pkgSetting.name);
}

// 创建安装参数 InstallArgs
final InstallArgs args = createInstallArgsForExisting(
pkgSetting.codePathString,
pkgSetting.resourcePathString, getAppDexInstructionSets(pkgSetting));
args.cleanUpResourcesLI();
synchronized (mPackages) {
mSettings.enableSystemPackageLPw(pkgSetting.name);
}
}
// 安装包校验
collectCertificatesLI(pkgSetting, pkg, forceCollect, skipVerify);

try (PackageFreezer freezer = freezePackage(pkg.packageName,
“scanPackageInternalLI”)) {
// 如果两个 apk 签名不匹配,则调用 deletePackageLIF 方法清除 apk 文件及其数据
deletePackageLIF(pkg.packageName, null, true, null, 0, null, false, null);
}

// 更新系统 apk 程序
InstallArgs args = createInstallArgsForExisting(
pkgSetting.codePathString,
pkgSetting.resourcePathString, getAppDexInstructionSets(pkgSetting));
synchronized (mInstallLock) {
args.cleanUpResourcesLI();
}
}
// 如果新安装的系统APP 会被旧的APP 数据覆盖,所以需要隐藏隐藏系统应用程序,并重新扫描 /data/app 目录
if (shouldHideSystemApp) {
synchronized (mPackages) {
mSettings.disableSystemPackageLPw(pkg.packageName, true);
}
}
}

2.3.2.4.3 Reconcile 调和

PackageManagerService 在对 Package 进行扫描之后,会调用 reconcilePackagesLocked() 函数进行调和。

将当前正在安装应用信息合并到存储所有应用基本信息的 map 中;

如果当前正在覆盖安装非系统应用则需要删除原有的应用,这里只是构造了对应的 action 对象;

如果是覆盖安装,则判断新安装的应用签名与原有应用签名是否一致;如果不是覆盖安装且如果当前应用与其他应用共享 uid 则合并签名;

private static Map<String, ReconciledPackage> reconcilePackagesLocked(
        final ReconcileRequest request, KeySetManagerService ksms, Injector injector)
        throws ReconcileFailure {
     //当前正在安装应用信息,key为对应包名
    final Map<String, ScanResult> scannedPackages = request.scannedPackages;
    final Map<String, ReconciledPackage> result = new ArrayMap<>(scannedPackages.size());
    //request.allPackages表示当前系统中已经安装的应用(key为包名),这里包含了当前正在安装包
    final ArrayMap<String, AndroidPackage> combinedPackages = new ArrayMap<>(request.allPackages.size() + scannedPackages.size());
    combinedPackages.putAll(request.allPackages);
    final Map<String, WatchedLongSparseArray<SharedLibraryInfo>> incomingSharedLibraries = new ArrayMap<>();

    for (String installPackageName : scannedPackages.keySet()) {
        final ScanResult scanResult = scannedPackages.get(installPackageName);
        //将正在安装的应用信息替换map中的原有信息
        combinedPackages.put(scanResult.pkgSetting.name, scanResult.request.parsedPackage);
        //当前正在安装的应用是否存在被共享的so库,只有系统应用才有
        ......
        //获取前面应用安装过程中存储的信息
        final InstallArgs installArgs = request.installArgs.get(installPackageName);
        final PackageInstalledInfo res = request.installResults.get(installPackageName);
        final PrepareResult prepareResult = request.preparedPackages.get(installPackageName);
        final boolean isInstall = installArgs != null;
        //如果当前正在安装应用,但是存储信息为空,则说明某个步骤存在问题
        if (isInstall && (res == null || prepareResult == null)) {
            throw new ReconcileFailure("Reconcile arguments are not balanced for " + installPackageName + "!");
        }
        final DeletePackageAction deletePackageAction;
        // 如果是覆盖安装并且是非系统应用,则需要卸载原有的应用
        if (isInstall && prepareResult.replace && !prepareResult.system) {
            final boolean killApp = (scanResult.request.scanFlags & SCAN_DONT_KILL_APP) == 0;
            final int deleteFlags = PackageManager.DELETE_KEEP_DATA | (killApp ? 0 : PackageManager.DELETE_DONT_KILL_APP);
            deletePackageAction = mayDeletePackageLocked(res.removedInfo, prepareResult.originalPs, prepareResult.disabledPs,deleteFlags, null);
            if (deletePackageAction == null) {
                throw new ReconcileFailure(PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE,"May not delete " + installPackageName + " to replace");
            }
        } else {
            deletePackageAction = null;
        }
        //临时变量赋值
        ......
        //如果是应用升级判断新安装应用签名是与原有的应用签名一致
        if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) {
            if (ksms.checkUpgradeKeySetLocked(signatureCheckPs, parsedPackage)) {
            } else {
                //签名不一致则抛出异常
                ......
            }
            signingDetails = parsedPackage.getSigningDetails();
        } else {
             //如果正在安装应用签名与某些应用共享uid,则合并他们的签名信息
            ......
        }
        result.put(installPackageName, new ReconciledPackage(request, installArgs, scanResult.pkgSetting, res, request.preparedPackages.get(installPackageName), scanResult, deletePackageAction, allowedSharedLibInfos, signingDetails, sharedUserSignaturesChanged, removeAppKeySetData));
    }
    //共享库相关
    ......
    return result;
}

2.3.2.4.4 Commit 提交

PackageManagerService 会调用 commitPackagesLocked() 函数继续安装新的 Package

private void commitPackagesLocked(final CommitRequest request) {
    // TODO: remove any expected failures from this method; this should only be able to fail due
    //       to unavoidable errors (I/O, etc.)
    for (ReconciledPackage reconciledPkg : request.reconciledPackages.values()) {
        final ScanResult scanResult = reconciledPkg.scanResult;
        final ScanRequest scanRequest = scanResult.request;
        final PackageParser.Package pkg = scanRequest.pkg;
        final String packageName = pkg.packageName;
        final PackageInstalledInfo res = reconciledPkg.installResult;

        if (reconciledPkg.prepareResult.replace) {
            PackageParser.Package oldPackage = mPackages.get(packageName);

            // Set the update and install times 设置更新和安装时间
            PackageSetting deletedPkgSetting = (PackageSetting) oldPackage.mExtras;
            setInstallAndUpdateTime(pkg, deletedPkgSetting.firstInstallTime,
                    System.currentTimeMillis());

            if (reconciledPkg.prepareResult.system) {
                // Remove existing system package 删除现有系统包
                removePackageLI(oldPackage, true);
                if (!disableSystemPackageLPw(oldPackage, pkg)) {
                    // We didn't need to disable the .apk as a current system package,
                    // which means we are replacing another update that is already
                    // installed.  We need to make sure to delete the older one's .apk.
                    // 我们使用 apk 作为当前系统包,这意味着我们正在替换已经安装的另一个更新。我们需要确保删除旧版本的 apk。
                    res.removedInfo.args = createInstallArgsForExisting(
                            oldPackage.applicationInfo.getCodePath(),
                            oldPackage.applicationInfo.getResourcePath(),
                            getAppDexInstructionSets(oldPackage.applicationInfo));
                } else {
                    res.removedInfo.args = null;
                }

                // Update the package dynamic state if succeeded
                // Now that the install succeeded make sure we remove data
                // directories for any child package the update removed.
                // 如果成功,更新包的动态状态。现在安装成功了,确保我们删除了更新删除的所有子包的数据目录。
                final int deletedChildCount = (oldPackage.childPackages != null)
                        ? oldPackage.childPackages.size() : 0;
                final int newChildCount = (pkg.childPackages != null)
                        ? pkg.childPackages.size() : 0;
                for (int i = 0; i < deletedChildCount; i++) {
                    PackageParser.Package deletedChildPkg = oldPackage.childPackages.get(i);
                    boolean childPackageDeleted = true;
                    for (int j = 0; j < newChildCount; j++) {
                        PackageParser.Package newChildPkg = pkg.childPackages.get(j);
                        if (deletedChildPkg.packageName.equals(newChildPkg.packageName)) {
                            childPackageDeleted = false;
                            break;
                        }
                    }
                    if (childPackageDeleted) {
                        PackageSetting ps1 = mSettings.getDisabledSystemPkgLPr(
                                deletedChildPkg.packageName);
                        if (ps1 != null && res.removedInfo.removedChildPackages != null) {
                            PackageRemovedInfo removedChildRes = res.removedInfo
                                    .removedChildPackages.get(deletedChildPkg.packageName);
                            removePackageDataLIF(ps1, request.mAllUsers, removedChildRes, 0,
                                    false);
                            removedChildRes.removedForAllUsers = mPackages.get(ps1.name)
                                    == null;
                        }
                    }
                }
            } else {
                try {
                    executeDeletePackageLIF(reconciledPkg.deletePackageAction, packageName,
                            true, request.mAllUsers, true, pkg);
                } catch (SystemDeleteException e) {
                    if (Build.IS_ENG) {
                        throw new RuntimeException("Unexpected failure", e);
                        // ignore; not possible for non-system app
                    }
                }
                // Successfully deleted the old package; proceed with replace. 成功删除旧包;继续更换

                // If deleted package lived in a container, give users a chance to
                // relinquish resources before killing.
                // 如果删除的包位于容器中,则在删除之前给用户一个放弃资源的机会
                if (oldPackage.isForwardLocked() || isExternal(oldPackage)) {
                    if (DEBUG_INSTALL) {
                        Slog.i(TAG, "upgrading pkg " + oldPackage
                                + " is ASEC-hosted -> UNAVAILABLE");
                    }
                    final int[] uidArray = new int[]{oldPackage.applicationInfo.uid};
                    final ArrayList<String> pkgList = new ArrayList<>(1);
                    pkgList.add(oldPackage.applicationInfo.packageName);
                    sendResourcesChangedBroadcast(false, true, pkgList, uidArray, null);
                }

                // Update the in-memory copy of the previous code paths. 更新以前代码路径的内存副本
                PackageSetting ps1 = mSettings.mPackages.get(
                        reconciledPkg.prepareResult.existingPackage.packageName);
                if ((reconciledPkg.installArgs.installFlags & PackageManager.DONT_KILL_APP)
                        == 0) {
                    if (ps1.mOldCodePaths == null) {
                        ps1.mOldCodePaths = new ArraySet<>();
                    }
                    Collections.addAll(ps1.mOldCodePaths, oldPackage.baseCodePath);
                    if (oldPackage.splitCodePaths != null) {
                        Collections.addAll(ps1.mOldCodePaths, oldPackage.splitCodePaths);
                    }
                } else {
                    ps1.mOldCodePaths = null;
                }
                if (ps1.childPackageNames != null) {
                    for (int i = ps1.childPackageNames.size() - 1; i >= 0; --i) {
                        final String childPkgName = ps1.childPackageNames.get(i);
                        final PackageSetting childPs = mSettings.mPackages.get(childPkgName);
                        childPs.mOldCodePaths = ps1.mOldCodePaths;
                    }
                }

                if (reconciledPkg.installResult.returnCode
                        == PackageManager.INSTALL_SUCCEEDED) {
                    PackageSetting ps2 = mSettings.getPackageLPr(pkg.packageName);
                    if (ps2 != null) {
                        res.removedInfo.removedForAllUsers = mPackages.get(ps2.name) == null;
                        if (res.removedInfo.removedChildPackages != null) {
                            final int childCount1 = res.removedInfo.removedChildPackages.size();
                            // Iterate in reverse as we may modify the collection
                            for (int i = childCount1 - 1; i >= 0; i--) {
                                String childPackageName =
                                        res.removedInfo.removedChildPackages.keyAt(i);
                                if (res.addedChildPackages.containsKey(childPackageName)) {
                                    res.removedInfo.removedChildPackages.removeAt(i);
                                } else {
                                    PackageRemovedInfo childInfo = res.removedInfo
                                            .removedChildPackages.valueAt(i);
                                    childInfo.removedForAllUsers = mPackages.get(
                                            childInfo.removedPackage) == null;
                                }
                            }
                        }
                    }
                }
            }
        }
        commitReconciledScanResultLocked(reconciledPkg);
        // 更新系统应用包信息
        updateSettingsLI(pkg, reconciledPkg.installArgs.installerPackageName, request.mAllUsers,
                res, reconciledPkg.installArgs.user, reconciledPkg.installArgs.installReason);

        final PackageSetting ps = mSettings.mPackages.get(packageName);
        if (ps != null) {
            res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
            ps.setUpdateAvailable(false /*updateAvailable*/);
        }
        final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
        for (int i = 0; i < childCount; i++) {
            PackageParser.Package childPkg = pkg.childPackages.get(i);
            PackageInstalledInfo childRes = res.addedChildPackages.get(
                    childPkg.packageName);
            PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
            if (childPs != null) {
                childRes.newUsers = childPs.queryInstalledUsers(
                        sUserManager.getUserIds(), true);
            }
        }
        if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
            updateSequenceNumberLP(ps, res.newUsers);
            updateInstantAppInstallerLocked(packageName);
        }
    }
}

2.3.2.4.5 Install 安装

PackageManagerService 会调用 executePostCommitSteps() 函数进行安装。

executePostCommitSteps() 函数中会调用 prepareAppDataAfterInstallLIF() 进行安装,并且会判断 Package 是否需要进行 Dex 优化。

prepareAppDataAfterInstallLIF() 的调用栈如下:

prepareAppDataAfterInstallLIF()
|
prepareAppDataLIF()
|
prepareAppDataLeafLIF()
|
[Installer.java]
createAppData()

最终会调用到 Installer 模块中。

下面是 executePostCommitSteps() 函数的代码:

private void executePostCommitSteps(CommitRequest commitRequest) {
    for (ReconciledPackage reconciledPkg : commitRequest.reconciledPackages.values()) {
        final boolean instantApp = ((reconciledPkg.scanResult.request.scanFlags
                        & PackageManagerService.SCAN_AS_INSTANT_APP) != 0);
        final PackageParser.Package pkg = reconciledPkg.pkgSetting.pkg;
        final String packageName = pkg.packageName;
        prepareAppDataAfterInstallLIF(pkg);
        if (reconciledPkg.prepareResult.clearCodeCache) {
            clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE
                    | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
        }
        if (reconciledPkg.prepareResult.replace) {
            mDexManager.notifyPackageUpdated(pkg.packageName,
                    pkg.baseCodePath, pkg.splitCodePaths);
        }

        // Prepare the application profiles for the new code paths.
        // This needs to be done before invoking dexopt so that any install-time profile
        // can be used for optimizations.
        // 为新的代码路径准备应用程序概要文件。这需要在调用 dexopt 之前完成,以便可以使用任何安装时配置文件进行优化。
        mArtManagerService.prepareAppProfiles(
                pkg,
                resolveUserIds(reconciledPkg.installArgs.user.getIdentifier()),
                /* updateReferenceProfileContent= */ true);

        // Check whether we need to dexopt the app.
        //
        // NOTE: it is IMPORTANT to call dexopt:
        //   - after doRename which will sync the package data from PackageParser.Package and
        //     its corresponding ApplicationInfo.
        //   - after installNewPackageLIF or replacePackageLIF which will update result with the
        //     uid of the application (pkg.applicationInfo.uid).
        //     This update happens in place!
        //
        // We only need to dexopt if the package meets ALL of the following conditions:
        //   1) it is not an instant app or if it is then dexopt is enabled via gservices.
        //   2) it is not debuggable.
        //
        // Note that we do not dexopt instant apps by default. dexopt can take some time to
        // complete, so we skip this step during installation. Instead, we'll take extra time
        // the first time the instant app starts. It's preferred to do it this way to provide
        // continuous progress to the useur instead of mysteriously blocking somewhere in the
        // middle of running an instant app. The default behaviour can be overridden
        // via gservices.
        final boolean performDexopt =
                (!instantApp || Global.getInt(mContext.getContentResolver(),
                Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)
                && ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0);

        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");
            // Do not run PackageDexOptimizer through the local performDexOpt
            // method because `pkg` may not be in `mPackages` yet.
            //
            // Also, don't fail application installs if the dexopt step fails.
            DexoptOptions dexoptOptions = new DexoptOptions(packageName,
                    REASON_INSTALL,
                    DexoptOptions.DEXOPT_BOOT_COMPLETE
                            | DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE);
            mPackageDexOptimizer.performDexOpt(pkg,
                    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 blacklist.
        // TODO: Layering violation
        // 通知 BackgroundDexOptService 包已经更改。
        // 如果这是一个曾经编译失败的包的更新,BackgroundDexOptService 将把它从黑名单中删除。
        BackgroundDexOptService.notifyPackageChanged(packageName);
    }
}

2.3.3 Installer

PackageManagerService 会调用 Installer 服务,调用 Installer 的 createAppData() 创建应用数据。

Installer 服务是 Android 提供的用于安装的服务,Installer 持有 Installd 守护进程对应的 Binder 服务的代理对象,本质上是通过 Binder 通信调用底层的 Installd 服务真正完成 APK 文件格式的优化和转换、建立相关的数据目录、删除文件、安装应用等工作。

这里简要描述下 Installer 服务与 Installd守护进程。

Installer 与 Installd 通过 Aidl 的方式进行通信,文件为 /android/frameworks/native/cmds/installd/binder/android/os/IInstalld.aidl。Installer 是一个系统服务,在 SystemServer 的 startBootstrapServices() 函数中启动,启动时获取 Installd 服务的代理对象。

问题:为什么需要 Installd?

答:Android 在 PackageManagerService 的服务中提供了包安装的流程,但是为什么还需要 Installd 参与呢?原因是 system_server 以 system 用户的身份运行,PackageManagerService 运行在 system_server 中,那么也就是 system 用户。system 用户并没有访问应用程序目录的权限,但是 Installd 服务是以 root 用户启动的,可以访问 /data/data/ 下的目录,Installd 需要完成一些创建应用数据的任务

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值