当前位置: 首页 > news >正文

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 applicationIntent newIntent = new Intent();newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,mPkgInfo.applicationInfo);newIntent.setData(mPackageURI);newIntent.setClass(this, InstallInstalling.class);  // 打开 InstallInstalling ActivityString 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);  // 开启新的 Activityfinish();
}

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 mInstallIdif (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,用于接收安装事件并回调给 EventResultPersistertry {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;@Overrideprotected PackageInstaller.Session doInBackground(Void... params) {PackageInstaller.Session session;try {// 获取之前创建的 Session 对象,PackageInstaller.Sessionsession = 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 KBbyte[] 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();}}}@Overrideprotected 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 为空的情况下,取消 sessionIdgetPackageManager().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() 方法中会将包的信息封装为 PackageInstallObserverAdapterif (!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 processedif (!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() {@Overridepublic 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 successfor (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}. */@Nullablepublic 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 locationscanFlags |= 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 checkif (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 namesrenameStaticSharedLibraryPackage(pkg);// No static shared libs on external storageif (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 childrenif (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 APKif (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 packageif ((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 packageif (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 permissionsPackageParser.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 updatedif (((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 packagesif (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 permif (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 permissionsif (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 oversourcePackageSetting.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 sdcardthrow 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 appthrow 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 rollscanFlags |= 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 stagescanFlags |= 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 validfinal 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 matchingif (!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 matchesif (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 restrictionpkg.restrictUpdateHash = oldPackage.restrictUpdateHash;}// Check for shared user id changesString 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 stateallUsers = sUserManager.getUserIds();installedUsers = ps.queryInstalledUsers(allUsers, true);// don't allow an upgrade from full to ephemeralif (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 instantSlog.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 instantSlog.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 removedres.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 neededfinal 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 replacereplace = 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 installps = null;childPackages = null;disabledPs = null;replace = false;existingPackage = null;// Remember this for later, in case we need to rollback this installString pkgName1 = pkg.packageName;if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);// TODO(patb): MOVE TO RECONCILEsynchronized (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 installshouldCloseFreezerBeforeReturn = 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 collectionfor (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 需要完成一些创建应用数据的任务

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • fatal: The current branch master has no upstream branch.
  • 【最小生成树】(三) Prim 算法
  • 某通用系统0day审计过程
  • Leetcode - 周赛409
  • glTF的基本结构
  • 【OpenHarmony】openharmony移植到RK3568------搭建开发环境
  • Spring——Second
  • AI赋能周界安防:智能视频分析技术构建无懈可击的安全防线
  • c++版opencv长文指南
  • Java进阶篇之深入理解多态的概念与应用
  • PHP项目任务系统小程序源码
  • 【网络基础一】几乎不讲任何网络协议细节,搭建网络基本结构
  • 【vue】在页面右下角添加悬浮按钮组件
  • 循环神经网络六-Pytorch中的序列化器
  • DreamFusion 论文学习
  • php的引用
  • 2017届校招提前批面试回顾
  • Angular 响应式表单 基础例子
  • Angularjs之国际化
  • avalon2.2的VM生成过程
  • Docker下部署自己的LNMP工作环境
  • Hexo+码云+git快速搭建免费的静态Blog
  • idea + plantuml 画流程图
  • JavaScript的使用你知道几种?(上)
  • JavaScript中的对象个人分享
  • Laravel Mix运行时关于es2015报错解决方案
  • Linux链接文件
  • SpiderData 2019年2月25日 DApp数据排行榜
  • vuex 笔记整理
  • windows下mongoDB的环境配置
  • 从setTimeout-setInterval看JS线程
  • 当SetTimeout遇到了字符串
  • 互联网大裁员:Java程序员失工作,焉知不能进ali?
  • 前端技术周刊 2019-02-11 Serverless
  • 通过调用文摘列表API获取文摘
  • ​软考-高级-系统架构设计师教程(清华第2版)【第15章 面向服务架构设计理论与实践(P527~554)-思维导图】​
  • ​探讨元宇宙和VR虚拟现实之间的区别​
  • # Swust 12th acm 邀请赛# [ K ] 三角形判定 [题解]
  • ### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTr
  • $L^p$ 调和函数恒为零
  • (2022 CVPR) Unbiased Teacher v2
  • (ctrl.obj) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MDd_DynamicDebug”不匹配值“
  • (C语言)fread与fwrite详解
  • (Redis使用系列) SpirngBoot中关于Redis的值的各种方式的存储与取出 三
  • (ZT) 理解系统底层的概念是多么重要(by趋势科技邹飞)
  • (笔试题)合法字符串
  • (接上一篇)前端弄一个变量实现点击次数在前端页面实时更新
  • (论文阅读40-45)图像描述1
  • (三)Kafka离线安装 - ZooKeeper开机自启
  • (四)JPA - JQPL 实现增删改查
  • (转)ORM
  • (自用)learnOpenGL学习总结-高级OpenGL-抗锯齿
  • .Net 8.0 新的变化
  • .net core 6 redis操作类
  • .NET 事件模型教程(二)