apk的安装有多种方式(系统、adb、应用商店、第三方)。这里我们取用路径最长的一种安装方式(第三方安装)进行分析,先上一个整个流程的时序图。
注意:本文是关于整个安装流程的详细调用链,文章较长涉及代码较多,适合源码探索,androidstudio导入系统源码
,需要可自取
第三方安装调用
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(uri, "application/vnd.android.package-archive");
context.startActivity(intent);
这里就不用去区分7.0之前和之后,uri都代表了文件地址
安装器AndroidManifest
路径:frameworks/base/packages/PackageInstaller/AndroidManifest.xml
这里将安装过程要用到的所有组件都列出来
<application >
//意图接收页面
<activity android:name=".InstallStart"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
android:exported="true"
android:excludeFromRecents="true">
<intent-filter android:priority="1">
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.INSTALL_PACKAGE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="content" />
<data android:mimeType="application/vnd.android.package-archive" />
</intent-filter>
<intent-filter android:priority="1">
<action android:name="android.intent.action.INSTALL_PACKAGE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="package" />
<data android:scheme="content" />
</intent-filter>
<intent-filter android:priority="1">
<action android:name="android.content.pm.action.CONFIRM_INSTALL" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
//中转页面,目的是将不同形式的文件路径,转为系统temp目录下等待安装
<activity android:name=".InstallStaging"
android:exported="false" />
//中转页面,安装成功后删除上面temp目录下的安装包
<activity android:name=".DeleteStagedFileOnResult"
android:theme="@style/Theme.AlertDialogActivity.NoActionBar"
android:exported="false" />
//包信息展示页面,有icon、应用名称、安装/取消按钮的那个页面
<activity android:name=".PackageInstallerActivity"
android:exported="false" />
//安装进程中页面
<activity android:name=".InstallInstalling"
android:theme="@style/Theme.AlertDialogActivity.NoAnimation"
android:exported="false" />
//安装session结果接受广播
<receiver android:name=".InstallEventReceiver"
android:permission="android.permission.INSTALL_PACKAGES"
android:exported="false">
<intent-filter android:priority="1">
<action android:name="com.android.packageinstaller.ACTION_INSTALL_COMMIT" />
</intent-filter>
</receiver>
//安装成功状态展示页面
<activity android:name=".InstallSuccess"
android:theme="@style/Theme.AlertDialogActivity.NoAnimation"
android:exported="false" />
//安装失败状态展示页面
<activity android:name=".InstallFailed"
android:theme="@style/Theme.AlertDialogActivity.NoAnimation"
android:exported="false" />
...
</application>
InstallStart
路径:frameworks\base\packages\PackageInstaller\src\com\android\packageinstaller\InstallStart.java
根据意图跳转至InstallStart
中
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
//是否是session安装
final boolean isSessionInstall =
PackageInstaller.ACTION_CONFIRM_INSTALL.equals(intent.getAction());
....
Intent nextActivity = new Intent(intent);
nextActivity.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
| Intent.FLAG_GRANT_READ_URI_PERMISSION);
// The the installation source as the nextActivity thinks this activity is the source, hence
// set the originating UID and sourceInfo explicitly
nextActivity.putExtra(PackageInstallerActivity.EXTRA_CALLING_PACKAGE, callingPackage);
nextActivity.putExtra(PackageInstallerActivity.EXTRA_CALLING_ATTRIBUTION_TAG,
callingAttributionTag);
nextActivity.putExtra(PackageInstallerActivity.EXTRA_ORIGINAL_SOURCE_INFO, sourceInfo);
nextActivity.putExtra(Intent.EXTRA_ORIGINATING_UID, originatingUid);
//根据前面获取到的状态,跳转不同的页面
if (isSessionInstall) {
nextActivity.setClass(this, PackageInstallerActivity.class);
} else {
Uri packageUri = intent.getData();
if (packageUri != null && packageUri.getScheme().equals(
ContentResolver.SCHEME_CONTENT)) {
// 更注册的意图,可知第三方安装满足这个条件
nextActivity.setClass(this, InstallStaging.class);
} else if (packageUri != null && packageUri.getScheme().equals(
PackageInstallerActivity.SCHEME_PACKAGE)) {
nextActivity.setClass(this, PackageInstallerActivity.class);
} else {
Intent result = new Intent();
result.putExtra(Intent.EXTRA_INSTALL_RESULT,
PackageManager.INSTALL_FAILED_INVALID_URI);
setResult(RESULT_FIRST_USER, result);
nextActivity = null;
}
}
if (nextActivity != null) {
startActivity(nextActivity);
}
finish();
}
InstallStaging
路径:frameworks\base\packages\PackageInstaller\src\com\android\packageinstaller\InstallStaging.java
中转页面,将意图中提供的uri文件,拷贝至目录(/data/user/0/com.android.packageinstaller/no_backup/packagexxx.apk)下
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//设置取消按钮
mAlert.setIcon(R.drawable.ic_file_download);
mAlert.setTitle(getString(R.string.app_name_unknown));
mAlert.setView(R.layout.install_content_view);
mAlert.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.cancel),
(ignored, ignored2) -> {
if (mStagingTask != null) {
mStagingTask.cancel(true);
}
setResult(RESULT_CANCELED);
finish();
}, null);
setupAlert();
requireViewById(R.id.staging).setVisibility(View.VISIBLE);
if (savedInstanceState != null) {
mStagedFile = new File(savedInstanceState.getString(STAGED_FILE));
if (!mStagedFile.exists()) {
mStagedFile = null;
}
}
}
//文件存在,异步拷贝
protected void onResume() {
super.onResume();
// This is the first onResume in a single life of the activity
if (mStagingTask == null) {
// File does not exist, or became invalid
if (mStagedFile == null) {
// Create file delayed to be able to show error
try {
mStagedFile = TemporaryFileManager.getStagedFile(this);
} catch (IOException e) {
showError();
return;
}
}
mStagingTask = new StagingAsyncTask();
mStagingTask.execute(getIntent().getData());
}
}
private final class StagingAsyncTask extends AsyncTask<Uri, Void, Boolean> {
@Override
protected Boolean doInBackground(Uri... params) {
if (params == null || params.length <= 0) {
return false;
}
//apk包拷贝至/data/user/0/com.android.packageinstaller/no_backup/packagexxx.apk
Uri packageUri = params[0];
try (InputStream in = getContentResolver().openInputStream(packageUri)) {
// Despite the comments in ContentResolver#openInputStream the returned stream can
// be null.
if (in == null) {
return false;
}
try (OutputStream out = new FileOutputStream(mStagedFile)) {
byte[] buffer = new byte[1024 * 1024];
int bytesRead;
while ((bytesRead = in.read(buffer)) >= 0) {
// Be nice and respond to a cancellation
if (isCancelled()) {
return false;
}
out.write(buffer, 0, bytesRead);
}
}
} catch (IOException | SecurityException | IllegalStateException e) {
Log.w(LOG_TAG, "Error staging apk from content URI", e);
return false;
}
return true;
}
@Override
protected void onPostExecute(Boolean success) {
// Now start the installation again from a file
Intent installIntent = new Intent(getIntent());
installIntent.setClass(InstallStaging.this, DeleteStagedFileOnResult.class);
installIntent.setData(Uri.fromFile(mStagedFile));
...
//拷贝完成,跳转至删除中转Activity
startActivity(installIntent);
InstallStaging.this.finish();
}
}
DeleteStagedFileOnResult
路径:frameworks\base\packages\PackageInstaller\src\com\android\packageinstaller\DeleteStagedFileOnResult.java
删除中转页面,安装成功后删除上面拷贝的安装包
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
Intent installIntent = new Intent(getIntent());
installIntent.setClass(this, PackageInstallerActivity.class);
installIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
//跳转至应用安装详情页面
startActivityForResult(installIntent, 0);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
setResult(resultCode, data);
finish();
}
//安装流程结束,同时也删除中转的包
@Override
protected void onDestroy() {
super.onDestroy();
//删除安装包
if (isFinishing()) {
File sourceFile = new File(getIntent().getData().getPath());
new Thread(sourceFile::delete).start();
}
}
PackageInstallerActivity
路径:frameworks\base\packages\PackageInstaller\src\com\android\packageinstaller\PackageInstallerActivity.java
安装确认界面,也是应用宝信息展示页面,也是厂商广告展示页面☺
protected void onCreate(Bundle icicle) {
...
//解析url,获取应用信息
boolean wasSetUp = processPackageUri(packageUri);
...
}
protected void onResume() {
super.onResume();
if (mLocalLOGV) Log.i(TAG, "onResume(): mAppSnippet=" + mAppSnippet);
if (mAppSnippet != null) {
//用获取的应用信息,填充页面(icon,名称,版本,权限等)
bindUi();
//检查发起程序是否有第三方应用安装权限
checkIfAllowedAndInitiateInstall();
}
if (mOk != null) {
//还不允许点击安装按钮
mOk.setEnabled(mEnableOk);
}
}
private void bindUi() {
...
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);
...
mOk = mAlert.getButton(DialogInterface.BUTTON_POSITIVE);
mOk.setEnabled(false);
...
}
private void startInstall() {
Intent newIntent = new Intent();
newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
mPkgInfo.applicationInfo);
newIntent.setData(mPackageURI);
newIntent.setClass(this, InstallInstalling.class);
...
//点击安装按钮后,跳转至正在安装页面
startActivity(newIntent);
finish();
}
checkIfAllowedAndInitiateInstall:方法会去检查发起安装的应用,是否有第三方安装权限,没有就弹出请求弹窗,然后跳转至设置界面。根据授权结果,在onActivityResult更改安装按钮状态
InstallInstalling
路径:frameworks\base\packages\PackageInstaller\src\com\android\packageinstaller\InstallInstalling.java
安装中页面,在onCreate中初始化loading动画和取消按钮
protected void onCreate(@Nullable Bundle savedInstanceState) {
...
//在安装结束的广播中添加监听,launchFinishBasedOnResult中根据状态码跳转成功/失败页面
mInstallId = InstallEventReceiver.addObserver(this, EventResultPersister.GENERATE_NEW_ID,
this::launchFinishBasedOnResult);
...
//创建Session
mSessionId = getPackageManager().getPackageInstaller().createSession(params);
...
}
protected void onResume() {
super.onResume();
if (mInstallingTask == null) {
PackageInstaller installer = getPackageManager().getPackageInstaller();
//取出Seesion
PackageInstaller.SessionInfo sessionInfo = installer.getSessionInfo(mSessionId);
//判断Session活跃状态
if (sessionInfo != null && !sessionInfo.isActive()) {
//未开始安装,进行下一步安装
mInstallingTask = new InstallingAsyncTask();
mInstallingTask.execute();
} else {
//正在安装,等待安装完成
mCancelButton.setEnabled(false);
setFinishOnTouchOutside(false);
}
}
}
private final class InstallingAsyncTask extends AsyncTask<Void, Void,
PackageInstaller.Session> {
volatile boolean isDone;
@Override
protected PackageInstaller.Session doInBackground(Void... params) {
PackageInstaller.Session session;
try {
//打开Session
session = getPackageManager().getPackageInstaller().openSession(mSessionId);
} catch (IOException e) {
synchronized (this) {
isDone = true;
notifyAll();
}
return null;
}
//设置写入进度
session.setStagingProgress(0);
try {
File file = new File(mPackageURI.getPath());
try (InputStream in = new FileInputStream(file)) {
long sizeBytes = file.length();
//设置文件大小,优化写入磁盘操作
try (OutputStream out = session
.openWrite("PackageInstaller", 0, sizeBytes)) {
byte[] buffer = new byte[1024 * 1024];
while (true) {
int numRead = in.read(buffer);
if (numRead == -1) {
//更新到磁盘
session.fsync(out);
break;
}
if (isCancelled()) {
session.close();
break;
}
//写入数据
out.write(buffer, 0, numRead);
if (sizeBytes > 0) {
float fraction = ((float) numRead / (float) sizeBytes);
//设置进度
session.addProgress(fraction);
}
}
}
}
return session;
} catch (IOException | SecurityException e) {
Log.e(LOG_TAG, "Could not write package", e);
session.close();
return null;
} finally {
synchronized (this) {
isDone = true;
notifyAll();
}
}
}
@Override
protected void onPostExecute(PackageInstaller.Session session) {
if (session != null) {
//BROADCAST_ACTION的值为:com.android.packageinstaller.ACTION_INSTALL_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 | PendingIntent.FLAG_MUTABLE);
//Session提交IntentSender,用于完成后发送完成的广播
session.commit(pendingIntent.getIntentSender());
//取消按钮设置为不可点击
mCancelButton.setEnabled(false);
setFinishOnTouchOutside(false);
} else {
getPackageManager().getPackageInstaller().abandonSession(mSessionId);
if (!isCancelled()) {
launchFailure(PackageInstaller.STATUS_FAILURE,
PackageManager.INSTALL_FAILED_INVALID_APK, null);
}
}
}
}
- 给安装结束的广播中添加监听
- 创建
Session
- 通过
Session
将安装包写入磁盘 -
Session
提交具有发送安装结束功能的IntentSender
PackageInstallerSession
路径:frameworks\base\services\core\java\com\android\server\pm\PackageInstallerSession.java
PackageInstaller.Session.commit
方法最终远程调用到了PackageInstallerSession.commit
方法
@Override
public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
if (hasParentSessionId()) {
throw new IllegalStateException(
"Session " + sessionId + " is a child of multi-package session "
+ getParentSessionId() + " and may not be committed directly.");
}
//标识请求,同时记录statusReceiver,用于发送安装结果
if (!markAsSealed(statusReceiver, forTransfer)) {
return;
}
if (isMultiPackage()) {
//多包安装
}
dispatchSessionSealed();
}
private void dispatchSessionSealed() {
mHandler.obtainMessage(MSG_ON_SESSION_SEALED).sendToTarget();
}
private final Handler.Callback mHandlerCallback = new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case MSG_ON_SESSION_SEALED:
handleSessionSealed();
break;
case MSG_STREAM_VALIDATE_AND_COMMIT:
handleStreamValidateAndCommit();
break;
case MSG_INSTALL:
handleInstall();
break;
}
}
private void handleSessionSealed() {
...
dispatchStreamValidateAndCommit();
}
private void dispatchStreamValidateAndCommit() {
mHandler.obtainMessage(MSG_STREAM_VALIDATE_AND_COMMIT).sendToTarget();
}
private void handleStreamValidateAndCommit() {
...
mHandler.obtainMessage(MSG_INSTALL).sendToTarget();
}
private void handleInstall() {
//apex安装这种大多数用于系统安装
if (isApexSession()) {
...
}
//分阶段安装,一般需要重启后会进行后面的安装步骤
if (params.isStaged) {
}
verify();
}
private void verify() {
verifyNonStaged();
}
private void verifyNonStaged()
throws PackageManagerException {
//创建验证参数
final PackageManagerService.VerificationParams verifyingSession =
prepareForVerification();
...
mPm.verifyStage(verifyingSession);
}
private PackageManagerService.VerificationParams prepareForVerification()
throws PackageManagerException {
....
synchronized (mLock) {
return makeVerificationParamsLocked();
}
}
private PackageManagerService.VerificationParams makeVerificationParamsLocked() {
final IPackageInstallObserver2 localObserver;
if (!hasParentSessionId()) {
//添加验证回调
localObserver = new IPackageInstallObserver2.Stub() {
@Override
public void onUserActionRequired(Intent intent) {
throw new IllegalStateException();
}
@Override
public void onPackageInstalled(String basePackageName, int returnCode, String msg,
Bundle extras) {
if (returnCode == INSTALL_SUCCEEDED) {
onVerificationComplete();
} else {
onSessionVerificationFailure(returnCode, msg);
}
}
};
...
return mPm.new VerificationParams(user, stageDir, localObserver, copiedParams,
mInstallSource, mInstallerUid, mSigningDetails, sessionId, mPackageLite);
}
- 记录提交过来的
IntentSender
用于后面发送广播 - 创建验证回调,并在创建验证参数是传入
PackageManagerService
路径:frameworks\base\services\core\java\com\android\server\pm\PackageManagerService.java
调用了pms的verifyStage方法
void verifyStage(VerificationParams params) {
mHandler.post(()-> {
params.startCopy();
});
}
VerificationParams
路径:frameworks\base\services\core\java\com\android\server\pm\PackageManagerService$VerificationParams.java
调用的是VerificationParams
对象的startCopy()
方法,VerificationParams
对象继承了HandlerParams
,并未重写startCopy()
方法
final void startCopy() {
handleStartCopy();
handleReturnCode();
}
public void handleStartCopy() {
//获取包信息
PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
mPackageLite, origin.resolvedPath, installFlags, packageAbiOverride);
//验证versioncode是否合法(降级等)
mRet = verifyReplacingVersionCode(pkgLite, requiredInstalledVersionCode, installFlags);
if (mRet != INSTALL_SUCCEEDED) {
return;
}
...
}
void handleReturnCode() {
if (mWaitForVerificationToComplete || mWaitForIntegrityVerificationToComplete
|| mWaitForEnableRollbackToComplete) {
return;
}
sendVerificationCompleteNotification();
}
private void sendVerificationCompleteNotification() {
//调用前面设置的回调
observer.onPackageInstalled(null, mRet, "Package Verification Result",
new Bundle());
}
PackageInstallerSession
验证回调中调用onVerificationComplete()
方法
private void onVerificationComplete() {
...
install();
}
private void install() {
installNonStaged();
}
private void installNonStaged()
throws PackageManagerException {
//创建安装参数
final PackageManagerService.InstallParams installingSession = makeInstallParams();
...
//开始安装
mPm.installStage(installingSession);
}
private PackageManagerService.InstallParams makeInstallParams()
throws PackageManagerException {
//创建安装监听
final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() {
@Override
public void onUserActionRequired(Intent intent) {
throw new IllegalStateException();
}
@Override
public void onPackageInstalled(String basePackageName, int returnCode, String msg,
Bundle extras) {
if (isStaged()) {
sendUpdateToRemoteStatusReceiver(returnCode, msg, extras);
} else {
//不是分段安装,安装成功后会回调这里
destroyInternal();
dispatchSessionFinished(returnCode, msg, extras);
}
}
};
.....
synchronized (mLock) {
return mPm.new InstallParams(stageDir, localObserver, params, mInstallSource, user,
mSigningDetails, mInstallerUid, mPackageLite);
}
}
调用makeInstallParams
方法创建安装参数,并添加IPackageInstallObserver2
监听
当安装成功后会调用onPackageInstalled
方法,returnCode
为安装状态码。后面会分析dispatchSessionFinished
方法。
PackageManagerService
void installStage(InstallParams params) {
final Message msg = mHandler.obtainMessage(INIT_COPY);
...
mHandler.sendMessage(msg);
}
class PackageHandler extends Handler {
...
public void handleMessage(Message msg) {
try {
doHandleMessage(msg);
} finally {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
}
}
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");
执行InstallParams.startCopy()方法
params.startCopy();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
break;
}
case POST_INSTALL: {
...
//安装成功后发送消息
handlePackagePostInstall(parentRes, killApp, virtualPreload,
didRestore, args.installSource.installerPackageName, args.observer,
args.mDataLoaderType);
...
} break;
}
}
InstallParams
路径:frameworks\base\services\core\java\com\android\server\pm\PackageManagerService$InstallParams.java
InstallParams
类真正执行了将apk安装到系统的操作
final void startCopy() {
handleStartCopy();
handleReturnCode();
}
public void handleStartCopy() {
if ((installFlags & PackageManager.INSTALL_APEX) != 0) {
mRet = INSTALL_SUCCEEDED;
return;
}
PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
mPackageLite, origin.resolvedPath, installFlags, packageAbiOverride);
...
boolean isStaged = (installFlags & INSTALL_STAGED) != 0;
//这里是分段安装的再次验证,第三方安装流程不会走这里
if (isStaged) {
mRet = verifyReplacingVersionCode(
pkgLite, requiredInstalledVersionCode, installFlags);
if (mRet != INSTALL_SUCCEEDED) {
return;
}
}
//获取覆盖安装的位置
mRet = overrideInstallLocation(pkgLite);
}
void handleReturnCode() {
processPendingInstall();
}
private void processPendingInstall() {
InstallArgs args = createInstallArgs(this);
if (mRet == PackageManager.INSTALL_SUCCEEDED) {
//拷贝安装包和动态链接库
mRet = args.copyApk();
}
if (mRet == PackageManager.INSTALL_SUCCEEDED) {
//释放资源占用的空间
F2fsUtils.releaseCompressedBlocks(
mContext.getContentResolver(), new File(args.getCodePath()));
}
if (mParentInstallParams != null) {
mParentInstallParams.tryProcessInstallRequest(args, mRet);
} else {
PackageInstalledInfo res = createPackageInstalledInfo(mRet);
//异步执行解析、系统配置写入等操作
processInstallRequestsAsync(
res.returnCode == PackageManager.INSTALL_SUCCEEDED,
Collections.singletonList(new InstallRequest(args, res)));
}
}
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) {
//清理安装过程造成的无用文件,和doPreInstall作用是一样的
request.args.doPostInstall(
request.installResult.returnCode, request.installResult.uid);
}
}
for (InstallRequest request : apkInstallRequests) {
//发送广播,通知系统更换或者添加icon、通知安装应用、通知监听安装事件的其他广播等
//如果安装失败进行回滚
restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult,
new PostInstallData(request.args, request.installResult, null));
}
});
private void installPackagesTracedLI(List<InstallRequest> requests) {
installPackagesLI(requests);
}
private void installPackagesLI(List<InstallRequest> requests) {
final Map<String, ScanResult> preparedScans = new ArrayMap<>(requests.size());
final Map<String, InstallArgs> installArgs = new ArrayMap<>(requests.size());
final Map<String, PackageInstalledInfo> installResults = new ArrayMap<>(requests.size());
final Map<String, PrepareResult> prepareResults = new ArrayMap<>(requests.size());
final Map<String, VersionInfo> versionInfos = new ArrayMap<>(requests.size());
final Map<String, PackageSetting> lastStaticSharedLibSettings =
new ArrayMap<>(requests.size());
final Map<String, Boolean> createdAppId = new ArrayMap<>(requests.size());
boolean success = false;
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackagesLI");
for (InstallRequest request : requests) {
...
//1.准备:分析当前安装状态,解析包并初始验证
prepareResult =
preparePackageLI(request.args, request.installResult);
...
//2.扫描:根据准备阶段解析的包信息上下文 进一步解析
final ScanResult result = scanPackageTracedLI(
prepareResult.packageToScan, prepareResult.parseFlags,
prepareResult.scanFlags, System.currentTimeMillis(),
request.args.user, request.args.abiOverride);
//注册appId
createdAppId.put(packageName, optimisticallyRegisterAppId(result));
//保存version信息
versionInfos.put(result.pkgSetting.pkg.getPackageName(),
getSettingsVersionForPackage(result.pkgSetting.pkg));
..
//3.核对:验证扫描后的包信息和系统状态,确保安装成功
reconciledPackages = reconcilePackagesLocked(
reconcileRequest, mSettings.getKeySetManagerService(), mInjector);
...
//4.提交:提交扫描的包、更新系统状态。这是唯一可以修改系统状态的地方,并且要对所有可预测的错误进行检测。
commitRequest = new CommitRequest(reconciledPackages,
mUserManager.getUserIds());
commitPackagesLocked(commitRequest);
//安装后续,准备App数据、编译布局资源、执行dexopt
executePostCommitSteps(commitRequest);
}
}
private void executePostCommitSteps(CommitRequest commitRequest) {
final ArraySet<IncrementalStorage> incrementalStorages = new ArraySet<>();
for (ReconciledPackage reconciledPkg : commitRequest.reconciledPackages.values()) {
...
//准备app目录(/data/user/用户ID/包名/code_cache)
prepareAppDataAfterInstallLIF(pkg);
...
//准备应用配置文件
mArtManagerService.prepareAppProfiles(
pkg,
resolveUserIds(reconciledPkg.installArgs.user.getIdentifier()),
/* updateReferenceProfileContent= */ true);
...
//dexopt操作
mPackageDexOptimizer.performDexOpt(pkg, realPkgSetting,
null /* instructionSets */,
getOrCreateCompilerPackageStats(pkg),
mDexManager.getPackageUseInfoOrDefault(packageName),
dexoptOptions);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
...
}
}
将包拷贝到data/app目录下后执行了4个关键的操作:
-
准备:分析当前安装状态,解析包并初始验证
- 对apk的
AndroidManifest.xml
文件做了全面的解析,比如apk中的所有 -
activity
、service
、permission
等信息,并将解析结果保存在了PackageParser.Package
类里 - 通过
Dm-verity
校验dex文件的有效性 - 解析apk签名信息
- 解析android资源索引表
resources.arsc
文件。
- 对apk的
- 扫描:根据准备阶段解析的包信息上下文 进一步解析
- 核对:验证扫描后的包信息和系统状态,确保安装成功
- 提交:提交扫描的包、更新系统状态。这是唯一可以修改系统状态的地方,并且要对所有可预测的错误进行检测。
安装完成后,会进行后续的步骤:
- 准备App data目录,如果已经存在则对目录进行校验
- 准备应用配置文件
- 对dex进行
dexopt
操作
下图附一张不同版本dexopt区别
返回到上面的processInstallRequestsAsync()
方法中,进行安装完成后的后续处理restoreAndPostInstall
方法
PackageManagerService
private void restoreAndPostInstall(
int userId, PackageInstalledInfo res, @Nullable PostInstallData data) {
if (DEBUG_INSTALL) {
Log.v(TAG, "restoreAndPostInstall userId=" + userId + " package=" + res.pkg);
}
//是否更新标识
final boolean update = res.removedInfo != null
&& res.removedInfo.removedPackage != null;
//是否回滚
boolean doRestore = !update && res.pkg != null;
...
//安装成功,并且需要回滚
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {
if (res.freezer != null) {
res.freezer.close();
}
doRestore = performBackupManagerRestore(userId, token, res);
}
//更新应用,做数据回滚
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && !doRestore && update) {
doRestore = performRollbackManagerRestore(userId, token, res, data);
}
//不回滚发送消息进行后面的操作
if (!doRestore) {
// No restore possible, or the Backup Manager was mysteriously not
// available -- just fire the post-install work request directly.
if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token);
Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "postInstall", token);
//这个消息最终会调用handlePackagePostInstall方法
Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
mHandler.sendMessage(msg);
}
}
private void handlePackagePostInstall(PackageInstalledInfo res, boolean killApp,
boolean virtualPreload, boolean launchedForRestore, String installerPackage,
IPackageInstallObserver2 installObserver, int dataLoaderType) {
...
//发送消息更新桌面icon
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, 0 /*flags*/,
null /*targetPackage*/, null /*finishedReceiver*/,
updateUserIds, instantUserIds, newBroadcastAllowList, null);
//通知上面InstallParams对象中注册的监听对象
notifyInstallObserver(res, installObserver);
}
PackageInstallerSession
private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) {
sendUpdateToRemoteStatusReceiver(returnCode, msg, extras);
...
}
private void sendUpdateToRemoteStatusReceiver(int returnCode, String msg, Bundle extras) {
...
//最终调用了sendOnPackageInstalled方法
mHandler.obtainMessage(MSG_ON_PACKAGE_INSTALLED, args).sendToTarget();
}
private static void sendOnPackageInstalled(Context context, IntentSender target, int sessionId,
boolean showNotification, int userId, String basePackageName, int returnCode,
String msg, Bundle extras) {
...
//target对象为commit提交的IntentSender对象。
target.sendIntent(context, 0, fillIn, null, null);
}
使用IntentSender
对象发送action(com.android.packageinstaller.ACTION_INSTALL_COMMIT)
广播,根据上面AndroidManifest.xml中注册的BroadcastReceiver
,最终InstallEventReceiver
会收到广播
PackageInstallerSession
路径:frameworks\base\packages\PackageInstaller\src\com\android\packageinstaller\InstallEventReceiver.java
public class InstallEventReceiver extends BroadcastReceiver {
...
@Override
public void onReceive(Context context, Intent intent) {
getReceiver(context).onEventReceived(context, intent);
}
...
}
InstallEventReceiver
的onReceive
中执行了EventResultPersister.onEventReceivedf
方法,最终回调InstallInstalling.launchFinishBasedOnResult
方法,launchFinishBasedOnResult方法
又根据安装状态码展示成功或者失败页面。