PMS源码解析——apk的安装流程(Android12)

1,787 阅读13分钟

Android的知识体系搭建

一 概述

之前我们介绍了 PMS 的工作原理。主要包括 PMS 的启动流程,和 PMS 启动时扫描安装应用,并获取四大组件信息的流程

今天我们再来说说 PMS 的另外一个工作流程,那就是 PMS 安装 apk 的流程

首先,Android 的安装会通过一个 InstallStart 进行跳转,到达一个 PackageInstallerActivity

二 PackageInstallerActivity

2.1 onCreate

protected void onCreate(Bundle icicle) {
	getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);

	super.onCreate(null);

	if (icicle != null) {
		mAllowUnknownSources = icicle.getBoolean(ALLOW_UNKNOWN_SOURCES_KEY);
	}

	// 获取 PackageManager
	mPm = getPackageManager();
	// 获取 IPackageManager
	mIpm = AppGlobals.getPackageManager();
	// 获取权限管理 AppOpsManager
	mAppOpsManager = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE);
	// 通过 PackageManager 获得 PackageInstaller
	mInstaller = mPm.getPackageInstaller();
	// 获取 多用户系统管理用户的类 UserManager
	mUserManager = (UserManager) getSystemService(Context.USER_SERVICE);

	final Intent intent = getIntent();

	...

	// 安装包的 Uri
	final Uri packageUri;

	if (PackageInstaller.ACTION_CONFIRM_INSTALL.equals(intent.getAction())) {
		final int sessionId = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1);
		// 通过 mInstaller 获取一个 PackageInstaller.SessionInfo
		final PackageInstaller.SessionInfo info = mInstaller.getSessionInfo(sessionId);

		mSessionId = sessionId;
		packageUri = Uri.fromFile(new File(info.resolvedBaseCodePath));
		mOriginatingURI = null;
		mReferrerURI = null;
	}
	...
}

PackageInstallerActivity 的逻辑主要在onCreateonResume中,在 onCreate 中,主要是获取一个PackageInstaller.SessionInfo,并构造一个 Uri

2.2 onResume

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

	if (mAppSnippet != null) {
		//  在我们覆盖这个布局之前,加载假布局并禁用OK按钮
		bindUi();
		// 检查是否允许安装该软件包,如果允许就启动安装。如果不允许
	    // 则显示相应的对话框。
		checkIfAllowedAndInitiateInstall();
	}
	...
}

在 onResume 中,则进行了 UI 绑定,会展示我们想要安装的 apk 的一些基本信息。

2.3 bindUi

bindUi 就是将我们要安装的应用展示出来,并给用户弹窗选择

private void bindUi() {

	// 展示要安装apk的基础信息
	mAlert.setIcon(mAppSnippet.icon);
	mAlert.setTitle(mAppSnippet.label);
	mAlert.setView(R.layout.install_content_view);
	// 两个按钮
	mAlert.setButton(DialogInterface.BUTTON_POSITIVE, getString(R.string.install),
			(ignored, ignored2) -> {
				if (mOk.isEnabled()) {
					if (mSessionId != -1) {
						mInstaller.setPermissionsResult(mSessionId, true);
						finish();
					} else {
						startInstall();
					}
				}
			}, null);
	mAlert.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.cancel),
			(ignored, ignored2) -> {
				// Cancel and finish
				setResult(RESULT_CANCELED);
				if (mSessionId != -1) {
					mInstaller.setPermissionsResult(mSessionId, false);
				}
				finish();
			}, null);
	setupAlert();

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

在安装界面展示应用的一些简介信息 mAppSnippet,如果用户选择同意,就开始安装 startInstall,否则就关闭页面。

2.4 startInstall

startInstall 的逻辑就是启动一个子 Activity 来实际安装应用程序,它就是 InstallInstalling

    private void startInstall() {
        Intent newIntent = new Intent();
        newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
                mPkgInfo.applicationInfo);
        newIntent.setData(mPackageURI);
        // 设置目标 Activity
        newIntent.setClass(this, InstallInstalling.class);

        String installerPackageName = getIntent().getStringExtra(
                Intent.EXTRA_INSTALLER_PACKAGE_NAME);

		... // 传参

        newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);

        startActivity(newIntent);
        finish();
    }

三 InstallInstalling

InstallInstalling 安装应用有两个阶段

  1. 发送安装包给 PackageManager 并处理来自 PackageManager 的结果
  2. 处理结果回调,InstallSuccess 或 InstallFailed

3.1 onCreate

同样我们从 onCreate 开始,

protected void onCreate(@Nullable Bundle savedInstanceState) {

	super.onCreate(savedInstanceState);

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

	// 通过 scheme 来判断当前的第一阶段还是第二阶段
	if ("package".equals(mPackageURI.getScheme())) {
		try {
			// 如果是第二阶段,就跳转到处理结果的函数,成功或者失败
			getPackageManager().installExistingPackage(appInfo.packageName);
			launchSuccess();
		} catch (PackageManager.NameNotFoundException e) {
			launchFailure(PackageInstaller.STATUS_FAILURE,
					PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
		}
	} else {
		// 如果是第一阶段,就将安装包信息发送给 PackageManager
		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),
				...
				}, null);
		setupAlert();
		requireViewById(R.id.installing).setVisibility(View.VISIBLE);

		if (savedInstanceState != null) {
			mSessionId = savedInstanceState.getInt(SESSION_ID);
			mInstallId = savedInstanceState.getInt(INSTALL_ID);

			// 为结果注册观察者;如果结果被交付,可能会立即回调,同时
			// 活动被破坏
			try {
				InstallEventReceiver.addObserver(this, mInstallId,
						this::launchFinishBasedOnResult);
			} catch (EventResultPersister.OutOfIdsException e) {
				// Does not happen
			}
		} else {
			PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
					PackageInstaller.SessionParams.MODE_FULL_INSTALL);
			final Uri referrerUri = getIntent().getParcelableExtra(Intent.EXTRA_REFERRER);
			... // 填充参数

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

			try {
				// 获取 PackageManager 的 PackageInstaller,拿到 PackageInstallerService
				// 发送安装参数
				mSessionId = getPackageManager().getPackageInstaller().createSession(params);
			} catch (IOException e) {
				launchFailure(PackageInstaller.STATUS_FAILURE,
						PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
			}
		}

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

在 onCreate 中有两个分支,进行安装还是安装成功,

  • 如果是安装成功,就会启动 InstallSuccess (一个对应的 Activity)。
  • 进行安装就会进行参数填充

最后通过 getPackageManager().getPackageInstaller().createSession(params) 创建了一个 Session。

3.2 onResume

protected void onResume() {
	super.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);
		}
	}
}
  • InstallingAsyncTask
  • PackageInstallerService

四 InstallingAsyncTask

InstallingAsyncTask 继承自 AsyncTask,首先是将文件西悉尼写到 session,然后提交到 session。代码很长,我们主关注主流程的提交即可。

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

	@Override
	protected PackageInstaller.Session doInBackground(Void... params) {
		PackageInstaller.Session session;
		try {
			// 1. 通过 mSessionId 获取对应的 session
			session = getPackageManager().getPackageInstaller().openSession(mSessionId);
		} ...

		session.setStagingProgress(0);

		try {
			// 将文件信息写入 session
			...

			return session;
		}  ...
	}

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

			PendingIntent pendingIntent = PendingIntent.getBroadcast(
					InstallInstalling.this,
					mInstallId,
					broadcastIntent,
					PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);


			// IPackageInstallerSession 其实就是 PackageInstallerService
			session.commit(pendingIntent.getIntentSender());
			mCancelButton.setEnabled(false);
			setFinishOnTouchOutside(false);
		} else {
			...
		}
	}
}

五 PackageInstallerService

5.1 createSession

[frameworks/base/services/core/java/com/android/server/pm/PackageInstallerService.java]

public int createSession(SessionParams params, String installerPackageName,
		String callingAttributionTag, int userId) {
	try {
		return createSessionInternal(params, installerPackageName, callingAttributionTag,
				userId);
	} catch (IOException e) {
		throw ExceptionUtils.wrap(e);
	}
}

createSession 是创建一个系统唯一的 session,这个 session 表示一次安装过程,这样哪怕后续安装中断了,都可用凭借这个 session 进行恢复安装。

接下来我们看看提交的逻辑。

六 PackageInstallerSession

6.1 commit

session 提交之后会经过大量的 Handler 转发,所以我们找到它最终调用的 handleInstall

public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
	...
	dispatchSessionSealed();
}

6.2 dispatchSessionSealed

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

6.3 handleSessionSealed

private void handleSessionSealed() {
	...
	dispatchStreamValidateAndCommit();
}

6.4 handleStreamValidateAndCommit

private void handleStreamValidateAndCommit() {
	try {
		// 发送消息 MSG_INSTALL
		if (allSessionsReady && streamValidateAndCommit()) {
			mHandler.obtainMessage(MSG_INSTALL).sendToTarget();
		}
	} catch (PackageManagerException e) {
		destroy();
		String msg = ExceptionUtils.getCompleteMessage(e);
		dispatchSessionFinished(e.error, msg, null);
		maybeFinishChildSessions(e.error, msg);
	}
}

6.5 handleInstall

private void handleInstall() {

	/**
	 * 如果一个Session 需要用户操作,则停止整个Session集的安装
	 */
	if (sendPendingUserActionIntentIfNeeded()) {
		return;
	}

	// isStaged 为 true 的时候表示下次系统启动的时候才真正安装
	// 一般用于(系统的)apex安装
	if (params.isStaged) {
		mStagedSession.verifySession();
	} else {
		verify();
	}
}

isStaged 为 true 表示现在不安装,下次启动启动的时候安装,一般用于安装系统的 apex 包。和我们应用安装无关。

在 handleInstall 中,会调用 verify,之后都是一些安装的校验,包括且不限于包名,签名,Hash 值等等,这里就不详细探讨了。关于安装包的校验,这里就不多扩展了,我们看一下调用流程即可。

6.6 verifySession

public void verifySession() {
	verify();
}

6.7 verify

private void verify() {
	try {

		...

		verifyNonStaged();
	} catch (PackageManagerException e) {
		...
	}
}


6.8 verifyNonStaged

private void verifyNonStaged()
		throws PackageManagerException {
	mSessionProvider.getSessionVerifier().verify(this, (error, msg) -> {
		mHandler.post(() -> {
			...

			// 调用完成并且成功,调用 onVerificationComplete
			if (error == INSTALL_SUCCEEDED) {
				onVerificationComplete();
			} else {
				// 校验不通过
				onSessionVerificationFailure(error, msg);
			}
		});
	});
}

6.9 onVerificationComplete

private void onVerificationComplete() {

	// 校验完成,开始安装。
	install();
}

当校验完成之后,就会调用 install 开始安装

6.10 install

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

6.11 installNonStaged

private void installNonStaged()
		throws PackageManagerException {
	final PackageManagerService.InstallParams installingSession = makeInstallParams();
	if (installingSession == null) {
		throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
				"Session should contain at least one apk session for installation");
	}

	if (isMultiPackage()) {
		...
		mPm.installStage(installingSession, installingChildSessions);
	} else {
		mPm.installStage(installingSession);
	}
}

在安装函数 installNonStaged 中,不论是批量安装的 isMultiPackage,还是单个安装,最终都会执行到 PMS 的 installStage

七 PMS

7.1 installStage

   void installStage(InstallParams params) {
        final Message msg = mHandler.obtainMessage(INIT_COPY);
        params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
        msg.obj = params;
        mHandler.sendMessage(msg);
    }

PMS 的 installStage 中,首先就会通过 Handler 发送一条消息 INIT_COPY,开始拷贝安装包

7.2 doHandleMessage

void doHandleMessage(Message msg) {
	switch (msg.what) {
		case INIT_COPY: {
			HandlerParams params = (HandlerParams) msg.obj;
			if (params != null) {
				params.startCopy();
			}
			break;
		}

在 doHandleMessage 中,会调用 startCopy 拷贝安装包,这个 params,就是之前传入的

八 HandlerParams

private abstract class HandlerParams {
	 final void startCopy() {
		handleStartCopy();
		handleReturnCode();
	}
}

这个 HandlerParams 是一个抽象类,它的 startCopy 调用了两个函数 handleStartCopyhandleReturnCode,这两个都是抽象方法,由子类实现。

而这个子类在之前传入的参数的[7.1]中我们已经看到了,它就是 InstallParams。

九 PMS.InstallParams

9.1 handleStartCopy

    public void handleStartCopy() {
        if ((mInstallFlags & PackageManager.INSTALL_APEX) != 0) {
            mRet = INSTALL_SUCCEEDED;
            return;
        }

        // 获取一个包信息
        PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mPm.mContext,
                mPackageLite, mOriginInfo.mResolvedPath, mInstallFlags, mPackageAbiOverride);

        // 验证和安装之间有一个延迟。设备的状态可能在这个延迟内发生变化
        // 所以我们需要重新验证。
        boolean isStaged = (mInstallFlags & INSTALL_STAGED) != 0;
        if (isStaged) {
            Pair<Integer, String> ret = mInstallPackageHelper.verifyReplacingVersionCode(
                    pkgLite, mRequiredInstalledVersionCode, mInstallFlags);
            mRet = ret.first;
            if (mRet != INSTALL_SUCCEEDED) {
                return;
            }
        }

        final boolean ephemeral = (mInstallFlags & PackageManager.INSTALL_INSTANT_APP) != 0;

        if (!mOriginInfo.mStaged && pkgLite.recommendedInstallLocation
                == InstallLocationUtils.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
            // 如果 staged 为 false,但是可用空间太小,就释放缓存再尝试一次
            pkgLite.recommendedInstallLocation = mPm.freeCacheForInstallation(
                    pkgLite.recommendedInstallLocation, mPackageLite,
                    mOriginInfo.mResolvedPath, mPackageAbiOverride, mInstallFlags);
        }

        // 覆盖安装
        mRet = overrideInstallLocation(pkgLite.packageName, pkgLite.recommendedInstallLocation,
                pkgLite.installLocation);
    }

handleStartCopy 准确来说是为拷贝做的一些准备,真正的拷贝是由 handleReturnCode 完成的。

9.2 handleReturnCode

void handleReturnCode() {
	processPendingInstall();
}

9.3 processPendingInstall

private void processPendingInstall() {

	// 创建安装参数
	InstallArgs args = createInstallArgs(this);
	if (mRet == PackageManager.INSTALL_SUCCEEDED) {
		// 拷贝 apk
		mRet = args.copyApk();
	}
	...

	// 下面两个函数,最后都会调用到 processInstallRequestsAsync
	if (mParentInstallParams != null) {
		mParentInstallParams.tryProcessInstallRequest(args, mRet);
	} else {
		PackageInstalledInfo res = new PackageInstalledInfo(mRet);
		processInstallRequestsAsync(
				res.mReturnCode == PackageManager.INSTALL_SUCCEEDED,
				Collections.singletonList(new InstallRequest(args, res)));
	}
}
  • 这里的 args 是一个 InstallArgs,这是一个抽象类,我们直接看它的实现 FileInstallArgs。PMS 就是通过它完成的 apk 的拷贝。
  • 然后通过 InstallParams 的 processInstallRequestsAsync 处理拷贝后的流程。

十 FileInstallArgs

10.1 copyApk

[frameworks/base/services/core/java/com/android/server/pm/FileInstallArgs.java]

int copyApk() {
		return doCopyApk();
}

10.2 doCopyApk

private int doCopyApk() {

	try {
		final boolean isEphemeral = (mInstallFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
		// 分配权限,创建目录 /data/app
		final File tempDir =
				mPm.mInstallerService.allocateStageDirLegacy(mVolumeUuid, isEphemeral);
		mCodeFile = tempDir;
	} catch (IOException e) {
		...
	}

	// 拷贝apk
	int ret = PackageManagerServiceUtils.copyPackage(
			mOriginInfo.mFile.getAbsolutePath(), mCodeFile);
	if (ret != PackageManager.INSTALL_SUCCEEDED) {
		Slog.e(TAG, "Failed to copy package");
		return ret;
	}

	final boolean isIncremental = isIncrementalPath(mCodeFile.getAbsolutePath());
	final File libraryRoot = new File(mCodeFile, LIB_DIR_NAME);
	NativeLibraryHelper.Handle handle = null;
	try {
		// 拷贝 so 库
		handle = NativeLibraryHelper.Handle.create(mCodeFile);
		ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
				mAbiOverride, isIncremental);
	} catch (IOException e) {
		Slog.e(TAG, "Copying native libraries failed", e);
		ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
	} finally {
		IoUtils.closeQuietly(handle);
	}

	return ret;
}

十一 PackageManagerServiceUtils

11.1 copyPackage

    [frameworks/base/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java]
    public static int copyPackage(String packagePath, File targetDir) {

        try {
            final File packageFile = new File(packagePath);
           ...

            // 调用 copyFile 函数开始拷贝
            copyFile(pkg.getBaseApkPath(), targetDir, "base.apk");
            if (!ArrayUtils.isEmpty(pkg.getSplitNames())) {
                for (int i = 0; i < pkg.getSplitNames().length; i++) {
                    copyFile(pkg.getSplitApkPaths()[i], targetDir,
                            "split_" + pkg.getSplitNames()[i] + ".apk");
                }
            }
            return PackageManager.INSTALL_SUCCEEDED;
        }
    }

11.2 copyFile

private static void copyFile(String sourcePath, File targetDir, String targetName)
		throws ErrnoException, IOException {

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

最后在 copyFile 函数进行了拷贝,权限为 0644,即用户具有读写权限,组用户和其它用户具有只读权限。

接下来我们回到 [9.2] 继续看后面的流程 processInstallRequestsAsync

十二 PMS

12.1 processInstallRequestsAsync

[frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java]

// 排队进行异步操作,因为软件包的安装可能需要一点时间
private void processInstallRequestsAsync(boolean success,
		List<InstallRequest> installRequests) {
	...

	if (success) {
		for (InstallRequest request : apkInstallRequests) {
			request.args.doPreInstall(request.installResult.returnCode);
		}
		synchronized (mInstallLock) {
			installPackagesTracedLI(apkInstallRequests);
		}
		for (InstallRequest request : apkInstallRequests) {
			request.args.doPostInstall(
					request.installResult.returnCode, request.installResult.uid);
		}
	}
	for (InstallRequest request : apkInstallRequests) {
		restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult,
				new PostInstallData(request.args, request.installResult, null));
	}

}


十三 InstallPackageHelper

13.1 processInstallRequests

[frameworks/base/services/core/java/com/android/server/pm/InstallPackageHelper.java]

public void processInstallRequests(boolean success, List<InstallRequest> installRequests) {
	List<InstallRequest> apexInstallRequests = new ArrayList<>();
	List<InstallRequest> apkInstallRequests = new ArrayList<>();
	for (InstallRequest request : installRequests) {
		if ((request.mArgs.mInstallFlags & PackageManager.INSTALL_APEX) != 0) {
			apexInstallRequests.add(request);
		} else {
			apkInstallRequests.add(request);
		}
	}
	// 支持APEXs和APKs的多包安装可能需要一些思考以确保安装的原子性。
	if (!apexInstallRequests.isEmpty()) {
		if (success) {
			// 由于 installApexPackages 需要与外部服务(apexd)对话,
			// 所以我们 安排以异步方式运行它。一旦完成,它将恢复安装。
			Thread t = new Thread(() -> installApexPackagesTraced(apexInstallRequests),
					"installApexPackages");
			t.start();
		} else {
			// 非阶段性APEX安装在之前的某个地方失败了
			// processInstallRequestAsync。在这种情况下,只需要通知观察者失败
			InstallRequest request = apexInstallRequests.get(0);
			mPm.notifyInstallObserver(request.mInstallResult,
					request.mArgs.mObserver);
		}
		return;
	}
	if (success) {
		// 预安装,做一些检查,如果存在异常情况,就清楚拷贝的 apk 文件
		for (InstallRequest request : apkInstallRequests) {
			request.mArgs.doPreInstall(request.mInstallResult.mReturnCode);
		}
		// 真正的安装
		synchronized (mPm.mInstallLock) {
			installPackagesTracedLI(apkInstallRequests);
		}
		// 安装后的操作
		for (InstallRequest request : apkInstallRequests) {
			request.mArgs.doPostInstall(
					request.mInstallResult.mReturnCode, request.mInstallResult.mUid);
		}
	}
	for (InstallRequest request : apkInstallRequests) {
		restoreAndPostInstall(request.mArgs.mUser.getIdentifier(),
				request.mInstallResult,
				new PostInstallData(request.mArgs,
						request.mInstallResult, null));
	}
}


processInstallRequests 就是真正安装的流程。它分为 4 个步骤

  1. doPreInstall 安装预处理,判断校验的结果,如果不通过就清楚 apk 文件。
  2. installPackagesTracedLI 真正的安装逻辑。
  3. doPostInstall 安装后的处理操作。

十四 PMS

14.1 doPreInstall

[frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java]

int doPreInstall(int status) {
	if (status != PackageManager.INSTALL_SUCCEEDED) {
		cleanUp();
	}
	return status;
}

如果校验状态不通过,就通过 cleanUp 清除安装文件。

14.2 installPackagesTracedLI

[frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java]

private void installPackagesTracedLI(List<InstallRequest> requests) {
	...
	installPackagesLI(requests);
}

14.3 installPackagesLI

[frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java]

private void installPackagesLI(List<InstallRequest> requests) {
	...

		for (InstallRequest request : requests) {
			// 获取所有的请求,并扫描、校对或提交
			final PrepareResult prepareResult;
			try {
				// 先预处理
				prepareResult =
						preparePackageLI(request.mArgs, request.mInstallResult);
			} ...

			...

			try {
				// 扫描
				final ScanResult result = scanPackageTracedLI(
						prepareResult.mPackageToScan, prepareResult.mParseFlags,
						prepareResult.mScanFlags, System.currentTimeMillis(),
						request.mArgs.mUser, request.mArgs.mAbiOverride);
				...
		}
		...
			try {
				// 调解安装包
				reconciledPackages = ReconcilePackageUtils.reconcilePackages(
						reconcileRequest, mSharedLibraries,
						mPm.mSettings.getKeySetManagerService(), mPm.mSettings);
			} ...

			try {
				// 提交安装包
				commitRequest = new CommitRequest(reconciledPackages,
						mPm.mUserManager.getUserIds());
				commitPackagesLocked(commitRequest);
				success = true;
			} ...
		}
		// 提交
		executePostCommitSteps(commitRequest);
	} finally {
		if (success) {
			for (InstallRequest request : requests) {
				final InstallArgs args = request.mArgs;
				if (args.mDataLoaderType != DataLoaderType.INCREMENTAL) {
					continue;
				}
				if (args.mSigningDetails.getSignatureSchemeVersion() != SIGNING_BLOCK_V4) {
					continue;
				}
				// 如果是增量安装,我们在安装前绕过验证器。
				// 在验证了软件包是有效的后,向验证器发送一个通知,
				// 其中包括 base.apk的根哈希值
				...

				VerificationUtils.broadcastPackageVerified(verificationId, originUri,
						PackageManager.VERIFICATION_ALLOW, rootHashString,
						args.mDataLoaderType, args.getUser(), mContext);
			}
		} else {
			for (ScanResult result : preparedScans.values()) {
				if (createdAppId.getOrDefault(result.mRequest.mParsedPackage.getPackageName(),
						false)) {
					cleanUpAppIdCreation(result);
				}
			}
			// 创建一个安装失败的描述性的原因。
			for (InstallRequest request : requests) {
				if (request.mInstallResult.mFreezer != null) {
					request.mInstallResult.mFreezer.close();
				}
				if (request.mInstallResult.mReturnCode == PackageManager.INSTALL_SUCCEEDED) {
					request.mInstallResult.mReturnCode = PackageManager.INSTALL_UNKNOWN;
				}
			}
		}
	}
}

installPackagesLI 就是安装的主要流程,它分为 4 步

  1. preparePackageLI:预处理安装包
  2. scanPackageTracedLI:扫描安装包
  3. reconcilePackages:调解安装包
  4. commitPackagesLocked:提交安装包

14.4 preparePackageLI

preparePackageLI 是安装前的预处理,它里面会对安装包做各种判断,例如版本校验,签名校验等等。

private PrepareResult preparePackageLI(InstallArgs args, PackageInstalledInfo res)
        throws PrepareFailure {

    ...

    // PackageParser2 解析安装包,我们在 PMS 解析安装应用中已经讲过它的原理了
    // 它可以解析安装应用的四大组件
    final ParsedPackage parsedPackage;
    try (PackageParser2 pp = mPm.mInjector.getPreparingPackageParser()) {
        parsedPackage = pp.parsePackage(tmpPackageFile, parseFlags, false);
        AndroidPackageUtils.validatePackageDexMetadata(parsedPackage);
    } ...

	...


    // 如果有现成的就使用,否则从APK中解析
    if (args.mSigningDetails != SigningDetails.UNKNOWN) {
        parsedPackage.setSigningDetails(args.mSigningDetails);
    } else {
    	// 解析
        final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
        final ParseResult<SigningDetails> result = ParsingPackageUtils.getSigningDetails(
                input, parsedPackage, false /*skipVerify*/);
        parsedPackage.setSigningDetails(result.getResult());
    }



    boolean systemApp = false;
    boolean replace = false;
    synchronized (mPm.mLock) {
        // 检查是否存在同样的安装包
        if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
            String oldName = mPm.mSettings.getRenamedPackageLPr(pkgName);
            if (parsedPackage.getOriginalPackages().contains(oldName)
                    && mPm.mPackages.containsKey(oldName)) {
                ...
            } else if (mPm.mPackages.containsKey(pkgName)) {
                //存在软件包,就替换
                replace = true;
                if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing package: " + pkgName);
            }

            if (replace) {
                // 防止应用程序退出运行时权限的版本,
                // 所以新的 targetSdk 不能小于旧的
                AndroidPackage oldPackage = mPm.mPackages.get(pkgName);
                final int oldTargetSdk = oldPackage.getTargetSdkVersion();
                final int newTargetSdk = parsedPackage.getTargetSdkVersion();
                if (oldTargetSdk > Build.VERSION_CODES.LOLLIPOP_MR1
                        && newTargetSdk <= Build.VERSION_CODES.LOLLIPOP_MR1) {
                    ...
                }
                ...
            }
        }

        ...

        if (signatureCheckPs != null) {


            // 签名检查
            final KeySetManagerService ksms = mPm.mSettings.getKeySetManagerService();
            final SharedUserSetting signatureCheckSus = mPm.mSettings.getSharedUserSettingLPr(
                    signatureCheckPs);
            if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, signatureCheckSus,
                    scanFlags)) {
                if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, parsedPackage)) {
                    throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
                            + parsedPackage.getPackageName() + " upgrade keys do not match the "
                            + "previously installed version");
                }
            } else {
                ...
            }
        }



        ...

        // 将检查权限兼容性的逻辑移到PermissionManagerService中
        final int n = ArrayUtils.size(parsedPackage.getPermissions());
        for (int i = n - 1; i >= 0; i--) {
            final ParsedPermission perm = parsedPackage.getPermissions().get(i);
            final Permission bp = mPm.mPermissionManager.getPermissionTEMP(perm.getName());

            // 除了系统,不要允许任何人定义短暂的权限
            if ((perm.getProtectionLevel() & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0
                    && !systemApp) {
                ComponentMutateUtils.setProtectionLevel(perm,
                        perm.getProtectionLevel() & ~PermissionInfo.PROTECTION_FLAG_INSTANT);
            }

            ...
        }
    }

    if (systemApp) {
        if (onExternal) {
            // 系统app不能安装到sd卡
            throw new PrepareFailure(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
                    "Cannot install updates to system apps on sdcard");
        } else if (instantApp) {
            // 系统应用不能被即时应用取代
            throw new PrepareFailure(INSTALL_FAILED_SESSION_INVALID,
                    "Cannot update a system app with an instant app");
        }
    }

    if (args.mMoveInfo != null) {
        // 如果已经做过一次移动,就标记Dex已经准备好
        scanFlags |= SCAN_NO_DEX;
        scanFlags |= SCAN_MOVE;

        synchronized (mPm.mLock) {
            final PackageSetting ps = mPm.mSettings.getPackageLPr(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.
            parsedPackage.setPrimaryCpuAbi(ps.getPrimaryCpuAbi())
                    .setSecondaryCpuAbi(ps.getSecondaryCpuAbi());
        }

    } else {
        // 启用SCAN_NO_DEX标志,以便在以后阶段跳过dexopt
        scanFlags |= SCAN_NO_DEX;

        ...
    }


    final PackageFreezer freezer =
            freezePackageForInstall(pkgName, installFlags, "installPackageLI");
    boolean shouldCloseFreezerBeforeReturn = true;
    try {
        final AndroidPackage oldPackage;
        String renamedPackage;
        boolean sysPkg = false;
        int targetScanFlags = scanFlags;
        int targetParseFlags = parseFlags;
        final PackageSetting ps;
        final PackageSetting disabledPs;
        final SharedUserSetting sharedUserSetting;
        if (replace) {
            // 如果 replace 是 true,表示存在一个旧的安装包
            // 那么就要要验证新安装包是否可用,并且还有先备份一下旧的安装包
            // 如果安装失败,旧需要回滚
            ... //

            synchronized (mPm.mLock) {
                if (DEBUG_INSTALL) {
                    Slog.d(TAG,
                            "replacePackageLI: new=" + parsedPackage + ", old=" + oldPackage);
                }

                ps = mPm.mSettings.getPackageLPr(pkgName11);
                disabledPs = mPm.mSettings.getDisabledSystemPkgLPr(ps);
                sharedUserSetting = mPm.mSettings.getSharedUserSettingLPr(ps);

                // 验证签名是否有效
                final KeySetManagerService ksms = mPm.mSettings.getKeySetManagerService();
                if (ksms.shouldCheckUpgradeKeySetLocked(ps, sharedUserSetting, scanFlags)) {
                    if (!ksms.checkUpgradeKeySetLocked(ps, parsedPackage)) {
                        throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
                                "New package not signed by keys specified by upgrade-keysets: "
                                        + pkgName11);
                    }
                } ...

                // 不允许系统升级,除非升级的哈希值匹配
                if (oldPackage.getRestrictUpdateHash() != null && oldPackage.isSystem()) {
                   ...
                }

                ... // 各种不允许升级的情况判断
            }

            // 更新被删除的内容
            res.mRemovedInfo = new PackageRemovedInfo(mPm);
            res.mRemovedInfo.mUid = oldPackage.getUid();
            res.mRemovedInfo.mRemovedPackage = oldPackage.getPackageName();
            res.mRemovedInfo.mInstallerPackageName = ps.getInstallSource().installerPackageName;
            res.mRemovedInfo.mIsStaticSharedLib =
                    parsedPackage.getStaticSharedLibName() != null;
            ...

            sysPkg = oldPackage.isSystem();
            if (sysPkg) {
                // 根据需要设置系统/特权/oem/供应商/产品的标志
                final boolean privileged = oldPackage.isPrivileged();
                final boolean oem = oldPackage.isOem();
                final boolean vendor = oldPackage.isVendor();
                final boolean product = oldPackage.isProduct();
                final boolean odm = oldPackage.isOdm();
                final boolean systemExt = oldPackage.isSystemExt();
                ...

                targetParseFlags = systemParseFlags;
                targetScanFlags = systemScanFlags;
            } else { // non system replace
                replace = true;
                if (DEBUG_INSTALL) {
                    Slog.d(TAG,
                            "replaceNonSystemPackageLI: new=" + parsedPackage + ", old="
                                    + oldPackage);
                }
            }
        } else { // 新软件包的安装
            ps = null;
            disabledPs = null;
            replace = false;
            oldPackage = null;
            // Remember this for later, in case we need to rollback this install
            String pkgName1 = parsedPackage.getPackageName();

		...

		// 返回
        return new PrepareResult(replace, targetScanFlags, targetParseFlags,
                oldPackage, parsedPackage, replace /* clearCodeCache */, sysPkg,
                ps, disabledPs);
    } finally {
        res.mFreezer = freezer;
        if (shouldCloseFreezerBeforeReturn) {
            freezer.close();
        }
    }
}

接下来扫描 apk 的代码非常长,这里就不列举了,只大概说一下它的作用吧。扫描的主要作用就是为了获取 PackageParser.Package 和 PackageSetting。然后通过 reconcilePackages 对结果进行调和。最后才是 commitPackagesLocked 的提交。

14.5 commitPackagesLocked

private void commitPackagesLocked(final CommitRequest request) {
	// 这个方法中只可能IO失败而导致失败
	for (ReconciledPackage reconciledPkg : request.mReconciledPackages.values()) {
		...

		if (reconciledPkg.mPrepareResult.mReplace) {
			AndroidPackage oldPackage = mPm.mPackages.get(packageName);

			// 设置更新和安装时间
			PackageStateInternal deletedPkgSetting = mPm.snapshotComputer()
					.getPackageStateInternal(oldPackage.getPackageName());
			reconciledPkg.mPkgSetting
					.setFirstInstallTimeFromReplaced(deletedPkgSetting, request.mAllUsers)
					.setLastUpdateTime(System.currentTimeMillis());

			res.mRemovedInfo.mBroadcastAllowList = mPm.mAppsFilter.getVisibilityAllowList(
					mPm.snapshotComputer(), reconciledPkg.mPkgSetting, request.mAllUsers,
					mPm.mSettings.getPackagesLocked());
			if (reconciledPkg.mPrepareResult.mSystem) {
				// 如果安装的是系统应用
				// 移除旧的安装包
				removePackageHelper.removePackageLI(oldPackage, true);
				if (!disableSystemPackageLPw(oldPackage)) {
					// 不需要禁用旧的软件包,直接删除即可
					res.mRemovedInfo.mArgs = new FileInstallArgs(
							oldPackage.getPath(),
							getAppDexInstructionSets(
									AndroidPackageUtils.getPrimaryCpuAbi(oldPackage,
											deletedPkgSetting),
									AndroidPackageUtils.getSecondaryCpuAbi(oldPackage,
											deletedPkgSetting)), mPm);
				} else {
					res.mRemovedInfo.mArgs = null;
				}
			} else {
				try {
					//  设置将在调用updateSettingsLI()时被写入
					deletePackageHelper.executeDeletePackageLIF(
							reconciledPkg.mDeletePackageAction, packageName,
							true, request.mAllUsers, false);
				} catch (SystemDeleteException e) {
					...
				}
				// 成功地删除了旧包;继续进行替换。
				// 更新前先将代码路径的内存拷贝
				PackageSetting ps1 = mPm.mSettings.getPackageLPr(
						reconciledPkg.mPrepareResult.mExistingPackage.getPackageName());
				if ((reconciledPkg.mInstallArgs.mInstallFlags & PackageManager.DONT_KILL_APP)
						== 0) {
					Set<String> oldCodePaths = ps1.getOldCodePaths();
					if (oldCodePaths == null) {
						oldCodePaths = new ArraySet<>();
					}
					Collections.addAll(oldCodePaths, oldPackage.getBaseApkPath());
					Collections.addAll(oldCodePaths, oldPackage.getSplitCodePaths());
					ps1.setOldCodePaths(oldCodePaths);
				} else {
					ps1.setOldCodePaths(null);
				}

				...
			}
		}

		// 正式提交
		AndroidPackage pkg = commitReconciledScanResultLocked(
				reconciledPkg, request.mAllUsers);

		...
	}
	ApplicationPackageManager.invalidateGetPackagesForUidCache();
}

commitPackagesLocked 就是正式提交安装的 apk 了,里面的代码虽然很多,但是做的事情其实很容易猜到。

  1. 修改安装时间
  2. 移除旧的安装包

接下来我们回到 [14.3] 看看安装的四个步骤中的最后一个,执行安装命令executePostCommitSteps

14.6 executePostCommitSteps

[frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java]

private void executePostCommitSteps(CommitRequest commitRequest) {
	final ArraySet<IncrementalStorage> incrementalStorages = new ArraySet<>();
	for (ReconciledPackage reconciledPkg : commitRequest.reconciledPackages.values()) {
		...

		// 安装后准备app数据
		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);
		}
		...

		// dex 优化
		if (performDexopt) {
			...
			mPackageDexOptimizer.performDexOpt(pkg, realPkgSetting,
					null /* instructionSets */,
					getOrCreateCompilerPackageStats(pkg),
					mDexManager.getPackageUseInfoOrDefault(packageName),
					dexoptOptions);
			Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
		}

		// 通知BackgroundDexOptService该软件包已经被改变
		BackgroundDexOptService.notifyPackageChanged(packageName);
		// 通知观察者广播
		notifyPackageChangeObserversOnUpdate(reconciledPkg);
	}
	waitForNativeBinariesExtraction(incrementalStorages);
}

到现在,我们安装的 apk 已经经历了如下步骤

  1. 拷贝到 /data/app
  2. 各种校验
  3. 预处理的扫描和解析安装文件
  4. 移除了旧的安装包

在接下来的 executePostCommitSteps 中,系统则主要做了三件事

  1. 准备安装后的 App 数据 AppData
  2. 对安装包做 dex 优化
  3. 安装完成,通知观察者,并把安装包显示到桌面中。

14.7 doPostInstall

[frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java]

int doPostInstall(int status, int uid) {
	if (status == PackageManager.INSTALL_SUCCEEDED) {
		cleanUp(move.fromUuid);
	} else {
		cleanUp(move.toUuid);
	}
	return status;
}

十五 总结

到这里,PMS 安装应用的流程我们就整理完毕了,最后再来做一个简单的归纳总结。

PMS 作为 Android 中的包管理服务,安装应用的流程如下。

  1. 首先启动一个安装应用的界面 Activity。用户可用在这个界面选择是否安装,并且这个界面还有此时安装的应用的信息(图标,名字,权限等等)。
  2. 如果用户选择同意,就会通过 PMS 创建一个 session,这个 session 的 id 是系统唯一的。
  3. PMS 会通过 Handler 的消息机制,最后调用到 handleInstall 这个函数,它就是应用安装的开始。
  4. 应用的安装会分为两种,一种是 Stage 为 true,这种会在下次启动启动时安装,一种则是普通应用的安装。
  5. 安装的流程大致分为以下几步
    1. 校验安装包
    2. 拷贝 apk
    3. 扫描 apk 解析安装文件
    4. 对安装包做 dex 优化
    5. 通知观察者。

最后用一张整体的UML图结尾吧。

PMS的安装流程~1.png