Android 包管理机制---PackageInstaller
本文基于API 30即Android11源码解读
前些日子做了一个电视机的应用市场APP,搞了一下Android的应用管理机制。撸篇文章记录一下。
一、安装应用 PackageInstaller初始化
/**
* 安装Apk
* 非静默安装
*/
private fun installApk(context: Context, path: String){
val intent =Intent(Intent.ACTION_VIEW)
val file=File(path)
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.N){
//7.0版本及以上
val apkUri=FileProvider.getUriForFile(context,"包名.provider",file)
intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
intent.setDataAndType(apkUri,"application/vnd.android.package-archive")
}else{
//7.0版本以下
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
val uri=Uri.fromFile(file)
intent.setDataAndType(uri, "application/vnd.android.package-archive");
}
context.startActivity(intent)
}
由于StrictMode API 政策,我们在7.0及以上不能再使用file:// Uri形式进行应用安装。但无论7.0以上还是一下,我们都调用了
val intent =Intent(Intent.ACTION_VIEW)
context.startActivity(intent)
Intent.ACTION_VIEW在7.0隐式匹配的是Activity为PackageInstallerActivity,
8.0及以上隐式匹配的是Activity为InstallStart,从调用startActivity()方法我们可以认为应用安装的入口是拉起一个Activity界面。我们这里查看的是Android11.0的源码,那么便进入InstallStart的onCreate()方法看一看
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mIPackageManager = AppGlobals.getPackageManager();
mIPermissionManager = AppGlobals.getPermissionManager();
mUserManager = getSystemService(UserManager.class);
......
final boolean isSessionInstall =
PackageInstaller.ACTION_CONFIRM_INSTALL.equals(intent.getAction());
......
......
if (isSessionInstall) {
nextActivity.setClass(this, PackageInstallerActivity.class);
} else {
Uri packageUri = intent.getData();
if (packageUri != null && packageUri.getScheme().equals(
ContentResolver.SCHEME_CONTENT)) {
// [IMPORTANT] This path is deprecated, but should still work. Only necessary
// features should be added.
// Copy file to prevent it from being changed underneath this process
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();
}
这里首先会判断intent传进来的action是否为CONFIRM_INSTALL,根据我们方法参数传入情况显然不是。然后对packageUri 的Scheme进行判断。如果是content就跳转到InstallStaging,如果是package就跳转到PackageInstallerActivity,否则就置空。在Android7.0及以上安装应用,我们都会使用FileProvider来处理URI ,FileProvider会隐藏文件真实路径,将路径转换成content://Uri路径,这样就满足packageUri Scheme协议匹配content的条件,后续跳转进入InstallStaging界面。
在InstallStagingon的核心逻辑它的onResume()方法执行
@Override
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;
}
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) {
if (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));
if (installIntent.getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
installIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
}
installIntent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
startActivity(installIntent);
InstallStaging.this.finish();
} else {
showError();
}
}
}
onResume()方法其实就是执行了一个StagingAsyncTask任务,在StagingAsyncTask的doInBackground(Uri... params)方法中会将packageUri协议写到mStagedFile中,然后再onPostExecute(Boolean success)方法中执行对DeleteStagedFileOnResult的跳转,并将mStagedFile传入,在DeleteStagedFileOnResult中执行了对PackageInstallerActivity的跳转,执行一圈,最终还是回到了PackageInstallerActivity类
@Override
protected void onCreate(Bundle icicle) {
getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
super.onCreate(null);
......
......
boolean wasSetUp = processPackageUri(packageUri);
if (!wasSetUp) {
return;
}
// load dummy layout with OK button disabled until we override this layout in
// startInstallConfirm
bindUi();
checkIfAllowedAndInitiateInstall();
}
在PackageInstallerActivity的onCreate(Bundle icicle)方法中会调用processPackageUri()方法对packageUri进行预处理, bindUi()方法进行应用安装界面初始化 ,checkIfAllowedAndInitiateInstall()方法用来判断是否是未知来源的应用,如果开启允许安装未知来源选项则直接初始化安装
private void checkIfAllowedAndInitiateInstall() {
// Check for install apps user restriction first.
final int installAppsRestrictionSource = mUserManager.getUserRestrictionSource(
UserManager.DISALLOW_INSTALL_APPS, Process.myUserHandle());
if ((installAppsRestrictionSource & UserManager.RESTRICTION_SOURCE_SYSTEM) != 0) {
showDialogInner(DLG_INSTALL_APPS_RESTRICTED_FOR_USER);
return;
} else if (installAppsRestrictionSource != UserManager.RESTRICTION_NOT_SET) {
startActivity(new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS));
finish();
return;
}
//如果允许安装,就进入安装流程
if (mAllowUnknownSources || !isInstallRequestFromUnknownSource(getIntent())) {
//调用安装方法
initiateInstall();
} else {
// Check for unknown sources restrictions.
final int unknownSourcesRestrictionSource = mUserManager.getUserRestrictionSource(
UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, Process.myUserHandle());
final int unknownSourcesGlobalRestrictionSource = mUserManager.getUserRestrictionSource(
UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY, Process.myUserHandle());
final int systemRestriction = UserManager.RESTRICTION_SOURCE_SYSTEM
& (unknownSourcesRestrictionSource | unknownSourcesGlobalRestrictionSource);
if (systemRestriction != 0) {
showDialogInner(DLG_UNKNOWN_SOURCES_RESTRICTED_FOR_USER);
} else if (unknownSourcesRestrictionSource != UserManager.RESTRICTION_NOT_SET) {
startAdminSupportDetailsActivity(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
} else if (unknownSourcesGlobalRestrictionSource != UserManager.RESTRICTION_NOT_SET) {
startAdminSupportDetailsActivity(
UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY);
} else {
handleUnknownSources();
}
}
}
private void initiateInstall() {
String pkgName = mPkgInfo.packageName;
// Check if there is already a package on the device with this name
// but it has been renamed to something else.
String[] oldName = mPm.canonicalToCurrentPackageNames(new String[] { pkgName });
if (oldName != null && oldName.length > 0 && oldName[0] != null) {
pkgName = oldName[0];
mPkgInfo.packageName = pkgName;
mPkgInfo.applicationInfo.packageName = pkgName;
}
// Check if package is already installed. display confirmation dialog if replacing pkg
try {
// This is a little convoluted because we want to get all uninstalled
// apps, but this may include apps with just data, and if it is just
// data we still want to count it as "installed".
mAppInfo = mPm.getApplicationInfo(pkgName,
PackageManager.MATCH_UNINSTALLED_PACKAGES);
if ((mAppInfo.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
mAppInfo = null;
}
} catch (NameNotFoundException e) {
mAppInfo = null;
}
//设置安装确认界面可见
startInstallConfirm();
}
private void startInstallConfirm() {
View viewToEnable;
if (mAppInfo != null) {
viewToEnable = (mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
? requireViewById(R.id.install_confirm_question_update_system)
: requireViewById(R.id.install_confirm_question_update);
} else {
// This is a new application with no permissions.
viewToEnable = requireViewById(R.id.install_confirm_question);
}
viewToEnable.setVisibility(View.VISIBLE);
mEnableOk = true;
mOk.setEnabled(true);
mOk.setFilterTouchesWhenObscured(true);
}
在initiateInstall()方法中,mPm.getApplicationInfo(pkgName,
PackageManager.MATCH_UNINSTALLED_PACKAGES)会通过包名拿到应用信息。在startInstallConfirm()方法中会通过 viewToEnable.setVisibility(View.VISIBLE)使确认界面对用户可见,执行到这个阶段PackageInstaller的初始化工作便完成了
二、APK的验证拷贝
在第一阶段对PackageInstaller 完成了初始化工作并拉起安装确认界面,那么第二阶段便从安装确认界面的确认按钮点击事件开始
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);
......
......
}
mSessionId 是在PackageInstallerActivity的onCreate()方法中进行赋值的,我们直接去看 startInstall()方法
private void startInstall() {
// Start subactivity to actually install the application
Intent newIntent = new Intent();
newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
mPkgInfo.applicationInfo);
newIntent.setData(mPackageURI);
newIntent.setClass(this, InstallInstalling.class);
String installerPackageName = getIntent().getStringExtra(
Intent.EXTRA_INSTALLER_PACKAGE_NAME);
if (mOriginatingURI != null) {
newIntent.putExtra(Intent.EXTRA_ORIGINATING_URI, mOriginatingURI);
}
if (mReferrerURI != null) {
newIntent.putExtra(Intent.EXTRA_REFERRER, mReferrerURI);
}
if (mOriginatingUid != PackageInstaller.SessionParams.UID_UNKNOWN) {
newIntent.putExtra(Intent.EXTRA_ORIGINATING_UID, mOriginatingUid);
}
if (installerPackageName != null) {
newIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME,
installerPackageName);
}
if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
}
newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
if(localLOGV) Log.i(TAG, "downloaded app uri="+mPackageURI);
startActivity(newIntent);
finish();
}
startInstall() 主要作用就是跳转到InstallInstalling类并关闭当前安装确认界面。
在InstallInstalling的onCreate()方法会通过PackageParser.parsePackageLite(file, 0)对apk文件进行轻量解析,并调用getPackageManager().getPackageInstaller().createSession(params)。实际是调用PackageInstaller的createSession()方法
public int createSession(@NonNull SessionParams params) throws IOException {
try {
return mInstaller.createSession(params, mInstallerPackageName, mUserId);
} catch (RuntimeException e) {
ExceptionUtils.maybeUnwrapIOException(e);
throw e;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
mInstaller是一个IPackageInstaller对象,IPackageInstaller是一个aidl接口类,它的实现类PackageInstallerService,所以mInstaller.createSession()最终调用到的是PackageInstallerService的createSession()方法并返回了mSessionId。 由此二者实现了进程间的通信
在看一下InstallInstalling的onResume()方法
protected void onResume() {
super.onResume();
// This is the first onResume in a single life of the activity
if (mInstallingTask == null) {
PackageInstaller installer = getPackageManager().getPackageInstaller();
//用mSessionId通过PackageInstaller 的getSessionInfo()拿到sessionInfo 信息
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);
}
}
}
在onResume()方法中,通过mSessionId拿到了SessionInfo信息然后执行力InstallingAsyncTask任务,InstallingAsyncTask的doInBackground方法中会根据安装包包(APK)的Uri,将APK的信息通过IO流的形式写入到PackageInstaller.Session中。InstallingAsyncTask的onPostExecute方法如下所示
@Override
protected void onPostExecute(PackageInstaller.Session session) {
if (session != null) {
Intent broadcastIntent = new Intent(BROADCAST_ACTION);
broadcastIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
broadcastIntent.setPackage(getPackageName());
broadcastIntent.putExtra(EventResultPersister.EXTRA_ID, mInstallId);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
InstallInstalling.this,
mInstallId,
broadcastIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
//通过 PackageInstaller.Session 的commit方法将IntentSender提交
session.commit(pendingIntent.getIntentSender());
mCancelButton.setEnabled(false);
setFinishOnTouchOutside(false);
} else {
getPackageManager().getPackageInstaller().abandonSession(mSessionId);
if (!isCancelled()) {
launchFailure(PackageManager.INSTALL_FAILED_INVALID_APK, null);
}
}
}
onPostExecute() 中创建了一个PendingIntent,并将该PendingIntent的IntentSender通过PackageInstaller.Session的commit方法发送出去。
public void commit(@NonNull IntentSender statusReceiver) {
try {
mSession.commit(statusReceiver, false);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
mSession为IPackageInstallerSession实例化对象,是一个aidl对象,它的实现类为PackageInstallerSession,这表明要通过IPackageInstallerSession来实现进程间的通信,然后调用到PackageInstallerSession的commit()方法
/frameworks/base/services/core/java/com/android/server/pm/PackageInstallerSession.java
@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.");
}
if (!markAsSealed(statusReceiver, forTransfer)) {
return;
}
if (isMultiPackage()) {
final SparseIntArray remainingSessions = mChildSessionIds.clone();
final IntentSender childIntentSender =
new ChildStatusIntentReceiver(remainingSessions, statusReceiver)
.getIntentSender();
boolean sealFailed = false;
for (int i = mChildSessionIds.size() - 1; i >= 0; --i) {
final int childSessionId = mChildSessionIds.keyAt(i);
// seal all children, regardless if any of them fail; we'll throw/return
// as appropriate once all children have been processed
if (!mSessionProvider.getSession(childSessionId)
.markAsSealed(childIntentSender, forTransfer)) {
sealFailed = true;
}
}
if (sealFailed) {
return;
}
}
dispatchStreamValidateAndCommit();
}
private void dispatchStreamValidateAndCommit() {
//向Handler发送消息
mHandler.obtainMessage(MSG_STREAM_VALIDATE_AND_COMMIT).sendToTarget();
}
//处理对应消息
private final Handler.Callback mHandlerCallback = new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case MSG_STREAM_VALIDATE_AND_COMMIT:
handleStreamValidateAndCommit();
break;
case MSG_INSTALL:
handleInstall();
break;
......
......
}
return true;
}
};
private void handleStreamValidateAndCommit() {
PackageManagerException unrecoverableFailure = null;
// This will track whether the session and any children were validated and are ready to
// progress to the next phase of install
boolean allSessionsReady = false;
......
......
mHandler.obtainMessage(MSG_INSTALL).sendToTarget();
}
private void handleInstall() {
......
......
try {
//保证线程同步
synchronized (mLock) {
installNonStagedLocked(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);
}
}
@GuardedBy("mLock")
private void installNonStagedLocked(List<PackageInstallerSession> childSessions)
throws PackageManagerException {
final PackageManagerService.ActiveInstallSession installingSession =
makeSessionActiveLocked();
if (installingSession == null) {
return;
}
if (isMultiPackage()) {
......
......
//mPm是PackageManagerService的实例对象
mPm.installStage(installingChildSessions);
} else {
mPm.installStage(installingSession);
}
}
在PackageInstallerSession##commit()方法中会调用到dispatchStreamValidateAndCommit(),该方法作用就是向mHandler以Callback形式发送一条msg.what为MSG_STREAM_VALIDATE_AND_COMMIT的消息,在mHandler的handleMessage()中会调用handleStreamValidateAndCommit()对该消息进行处理在handleStreamValidateAndCommit()中又会向向mHandler以Callback形式发送一条msg.what为MSG_INSTALL的消息,以 handleInstall()对该消息进行处理,在handleInstall()中通过synchronized 保证了对installNonStagedLocked()方法调用的线程同步,installNonStagedLocked()方法中会调用 mPm.installStage(),mPm是PackageManagerService实例化对象。这样代码逻辑便进入PackageManagerService##installStage()
void installStage(ActiveInstallSession activeInstallSession) {
if (DEBUG_INSTANT) {
if ((activeInstallSession.getSessionParams().installFlags
& PackageManager.INSTALL_INSTANT_APP) != 0) {
Slog.d(TAG, "Ephemeral install of " + activeInstallSession.getPackageName());
}
}
final Message msg = mHandler.obtainMessage(INIT_COPY);
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));
mHandler.sendMessage(msg);
}
void installStage(List<ActiveInstallSession> children)
throws PackageManagerException {
final Message msg = mHandler.obtainMessage(INIT_COPY);
final MultiPackageInstallParams params =
new MultiPackageInstallParams(UserHandle.ALL, children);
params.setTraceMethod("installStageMultiPackage")
.setTraceCookie(System.identityHashCode(params));
msg.obj = params;
Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStageMultiPackage",
System.identityHashCode(msg.obj));
Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
System.identityHashCode(msg.obj));
mHandler.sendMessage(msg);
}
PackageManagerService##installStage()有两个不同参数的重载方法,这个方法没什么重点,只是创建并向Handler发送一条msg.what为INIT_COPY的消息
class PackageHandler extends Handler {
PackageHandler(Looper looper) {
super(looper);
}
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");
params.startCopy();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
break;
}
}
}
}
在PackageHandler 对该消息的处理逻辑是调用HandlerParams ##startCopy()
final void startCopy() {
if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
handleStartCopy();
handleReturnCode();
}
abstract void handleStartCopy();
abstract void handleReturnCode();
HandlerParams是一个抽象类它的实现类有PackageManagerService##MultiPackageInstallParams及
PackageManagerService##InstallParams。在PackageHandler ##doHandleMessage()方法对msg的处理逻辑中可以发现,INIT_COPY消息体中包含HandlerParams 对象,往前查看发现传入对象为根据调用方法不一样而分为MultiPackageInstallParams与InstallParams两种。先看一下MultiPackageInstallParams##handleStartCopy()实现
@Override
void handleStartCopy() {
for (InstallParams params : mChildParams) {
//还是调用到了InstallParams 的handleStartCopy()
params.handleStartCopy();
if (params.mRet != INSTALL_SUCCEEDED) {
mRet = params.mRet;
}
}
}
发现其实就是对InstallParams集合进行了遍历然后调用handleStartCopy()方法。所以,殊途同归handleStartCopy()的实现最终还是要看InstallParams##handleStartCopy()
public void handleStartCopy() {
int ret = PackageManager.INSTALL_SUCCEEDED;
// If we're already staged, we've firmly committed to an install location
//检查文件是否已生成 是则对installFlags进行赋值
if (origin.staged) {
if (origin.file != null) {
installFlags |= PackageManager.INSTALL_INTERNAL;
} else {
throw new IllegalStateException("Invalid stage location");
}
}
final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;
final boolean ephemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
PackageInfoLite pkgLite = null;
pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
origin.resolvedPath, installFlags, packageAbiOverride);
if (DEBUG_INSTANT && ephemeral) {
Slog.v(TAG, "pkgLite for install: " + pkgLite);
}
/*
* If we have too little free space, try to free cache
* before giving up.
*/
//判断安装空间是否充足,若不充足则尝试释放部分空间
if (!origin.staged && pkgLite.recommendedInstallLocation
== PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
// TODO: focus freeing disk space on the target device
final StorageManager storage = StorageManager.from(mContext);
final long lowThreshold = storage.getStorageLowBytes(
Environment.getDataDirectory());
final long sizeBytes = PackageManagerServiceUtils.calculateInstalledSize(
origin.resolvedPath, packageAbiOverride);
if (sizeBytes >= 0) {
try {
mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0);
pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
origin.resolvedPath, installFlags, packageAbiOverride);
} catch (InstallerException e) {
Slog.w(TAG, "Failed to free cache", e);
}
}
/*
* The cache free must have deleted the file we downloaded to install.
*
* TODO: fix the "freeCache" call to not delete the file we care about.
*/
if (pkgLite.recommendedInstallLocation
== PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
pkgLite.recommendedInstallLocation
= PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
}
}
if (ret == PackageManager.INSTALL_SUCCEEDED) {//1
int loc = pkgLite.recommendedInstallLocation;
if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION) {
ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
} else if (loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS) {
ret = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
} else if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
} else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) {
ret = PackageManager.INSTALL_FAILED_INVALID_APK;
} else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
ret = PackageManager.INSTALL_FAILED_INVALID_URI;
} else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) {
ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
} else {
// Override with defaults if needed.
//对包信息进行覆盖
loc = installLocationPolicy(pkgLite);
if (loc == PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE) {
ret = PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
} else if (loc == PackageHelper.RECOMMEND_FAILED_WRONG_INSTALLED_VERSION) {
ret = PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION;
} else if (!onInt) {
// Override install location with flags
if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
// Set the flag to install on external media.
installFlags &= ~PackageManager.INSTALL_INTERNAL;
} else if (loc == PackageHelper.RECOMMEND_INSTALL_EPHEMERAL) {
if (DEBUG_INSTANT) {
Slog.v(TAG, "...setting INSTALL_EPHEMERAL install flag");
}
installFlags |= PackageManager.INSTALL_INSTANT_APP;
installFlags &= ~PackageManager.INSTALL_INTERNAL;
} else {
// Make sure the flag for installing on external
// media is unset
installFlags |= PackageManager.INSTALL_INTERNAL;
}
}
}
}
final InstallArgs args = createInstallArgs(this);
mVerificationCompleted = true;
mIntegrityVerificationCompleted = true;
mEnableRollbackCompleted = true;
mArgs = args;
if (ret == PackageManager.INSTALL_SUCCEEDED) {
final int verificationId = mPendingVerificationToken++;
// Perform package verification (unless we are simply moving the package).
//验证包信息
if (!origin.existing) {
PackageVerificationState verificationState =
new PackageVerificationState(this);
mPendingVerification.append(verificationId, verificationState);
sendIntegrityVerificationRequest(verificationId, pkgLite, verificationState);
ret = sendPackageVerificationRequest(
verificationId, pkgLite, verificationState);
// If both verifications are skipped, we should remove the state.
if (verificationState.areAllVerificationsComplete()) {
mPendingVerification.remove(verificationId);
}
}
......
......
}
mRet = ret;
}
在InstallParams##handleStartCopy()主要功能就是四点:
1.验证文件是否已生成,若生成则对installFlags进行赋值处理
2.验证空间是否充足 不充足则尝试释放无用空间
3.对包信息进行覆盖处理 同时返回一个int值 loc
4.验证包信息
同样handleReturnCode()最终实现也是在InstallParams类中
@Override
void handleReturnCode() {
if (mVerificationCompleted
&& mIntegrityVerificationCompleted && mEnableRollbackCompleted) {
if ((installFlags & PackageManager.INSTALL_DRY_RUN) != 0) {
String packageName = "";
ParseResult<PackageLite> result = ApkLiteParseUtils.parsePackageLite(
new ParseTypeImpl(
(changeId, packageName1, targetSdkVersion) -> {
ApplicationInfo appInfo = new ApplicationInfo();
appInfo.packageName = packageName1;
appInfo.targetSdkVersion = targetSdkVersion;
return mPackageParserCallback.isChangeEnabled(changeId,
appInfo);
}).reset(),
origin.file, 0);
if (result.isError()) {
Slog.e(TAG, "Can't parse package at " + origin.file.getAbsolutePath(),
result.getException());
} else {
packageName = result.getResult().packageName;
}
try {
observer.onPackageInstalled(packageName, mRet, "Dry run", new Bundle());
} catch (RemoteException e) {
Slog.i(TAG, "Observer no longer exists.");
}
return;
}
if (mRet == PackageManager.INSTALL_SUCCEEDED) {
mRet = mArgs.copyApk();
}
processPendingInstall(mArgs, mRet);
}
}
InstallParams##handleReturnCode()中调用InstallArgs的copyApk()进行APK的拷贝工作。InstallArgs是一个抽象类,FileInstallArgs及MoveInstallArgs继承并实现了它。InstallArgs的实例对象会在InstallParams##handleStartCopy()中调用createInstallArgs()进行创建,最终创建出来的是一个FileInstallArgs类型对象。所以代码逻辑又执行到了FileInstallArgs##copyApk()
int copyApk() {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk");
try {
return doCopyApk();
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
private int doCopyApk() {
.....
......
int ret = PackageManagerServiceUtils.copyPackage(
origin.file.getAbsolutePath(), codeFile);
if (ret != PackageManager.INSTALL_SUCCEEDED) {
Slog.e(TAG, "Failed to copy package");
return ret;
}
final boolean isIncremental = isIncrementalPath(codeFile.getAbsolutePath());
final File libraryRoot = new File(codeFile, LIB_DIR_NAME);
NativeLibraryHelper.Handle handle = null;
try {
handle = NativeLibraryHelper.Handle.create(codeFile);
ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
abiOverride, isIncremental);
} catch (IOException e) {
Slog.e(TAG, "Copying native libraries failed", e);
ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
} finally {
IoUtils.closeQuietly(handle);
}
return ret;
}
public static int copyPackage(String packagePath, File targetDir) {
if (packagePath == null) {
return PackageManager.INSTALL_FAILED_INVALID_URI;
}
try {
final File packageFile = new File(packagePath);
final PackageParser.PackageLite pkg = PackageParser.parsePackageLite(packageFile, 0);
copyFile(pkg.baseCodePath, targetDir, "base.apk");
if (!ArrayUtils.isEmpty(pkg.splitNames)) {
for (int i = 0; i < pkg.splitNames.length; i++) {
copyFile(pkg.splitCodePaths[i], targetDir,
"split_" + pkg.splitNames[i] + ".apk");
}
}
return PackageManager.INSTALL_SUCCEEDED;
} catch (PackageParserException | IOException | ErrnoException e) {
Slog.w(TAG, "Failed to copy package at " + packagePath + ": " + e);
return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
}
}
private static void copyFile(String sourcePath, File targetDir, String targetName)
throws ErrnoException, IOException {
if (!FileUtils.isValidExtFilename(targetName)) {
throw new IllegalArgumentException("Invalid filename: " + targetName);
}
Slog.d(TAG, "Copying " + sourcePath + " to " + targetName);
final File targetFile = new File(targetDir, targetName);
final FileDescriptor targetFd = Os.open(targetFile.getAbsolutePath(),
O_RDWR | O_CREAT, 0644);
Os.chmod(targetFile.getAbsolutePath(), 0644);
FileInputStream source = null;
try {
source = new FileInputStream(sourcePath);
FileUtils.copy(source.getFD(), targetFd);
} finally {
IoUtils.closeQuietly(source);
}
}
在copyApk()调用 doCopyApk(),在 doCopyApk()再调用到PackageManagerServiceUtils##copyPackage(),逻辑进入到PackageManagerServiceUtils##copyPackage()会调用PackageManagerServiceUtils##copyFile()方法,而copyFile()方法就是将文件通过IO流将apk拷贝到相关目录下
至此,APK验证拷贝流程完结
三、安装APK
在APK拷贝完成后即InstallParams##handleReturnCode()中mArgs.copyApk()流程执行完毕后,会在调用processPendingInstall()开始安装
private void processPendingInstall(final InstallArgs args, final int currentStatus) {
if (args.mMultiPackageInstallParams != null) {
args.mMultiPackageInstallParams.tryProcessInstallRequest(args, currentStatus);
} else {
PackageInstalledInfo res = createPackageInstalledInfo(currentStatus);
processInstallRequestsAsync(
res.returnCode == PackageManager.INSTALL_SUCCEEDED,
Collections.singletonList(new InstallRequest(args, res)));
}
}
// Queue up an async operation since the package installation may take a little while.
private void processInstallRequestsAsync(boolean success,
List<InstallRequest> installRequests) {
mHandler.post(() -> {
if (success) {
for (InstallRequest request : installRequests) {
//安装前处理
request.args.doPreInstall(request.installResult.returnCode);
}
synchronized (mInstallLock) {
installPackagesTracedLI(installRequests);
}
for (InstallRequest request : installRequests) {
//安装后收尾
request.args.doPostInstall(
request.installResult.returnCode, request.installResult.uid);
}
}
for (InstallRequest request : installRequests) {
restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult,
new PostInstallData(request.args, request.installResult, null));
}
});
}
@GuardedBy({"mInstallLock", "mLock"})
private void installPackagesTracedLI(List<InstallRequest> requests) {
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages");
installPackagesLI(requests);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
@GuardedBy("mInstallLock")
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) {
// 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);
}
......
try {
//扫描分析准备阶段拿到的包信息
final ScanResult result = scanPackageTracedLI(
prepareResult.packageToScan, prepareResult.parseFlags,
prepareResult.scanFlags, System.currentTimeMillis(),
request.args.user, request.args.abiOverride);
......
} catch (PackageManagerException e) {
request.installResult.setError("Scanning Failed.", e);
return;
}
}
//创建一个ReconcileRequest对象保存包扫描结果和相关请求详细信息,用于协调可能向系统添加的一个或多个包。
ReconcileRequest reconcileRequest = new ReconcileRequest(preparedScans, installArgs,
installResults,
prepareResults,
mSharedLibraries,
Collections.unmodifiableMap(mPackages), versionInfos,
lastStaticSharedLibSettings);
CommitRequest commitRequest = null;
synchronized (mLock) {
Map<String, ReconciledPackage> reconciledPackages;
......
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "commitPackages");
commitRequest = new CommitRequest(reconciledPackages,
mUserManager.getUserIds());
//提交扫描到的包信息并且在其中删除旧状态,写入新状态
commitPackagesLocked(commitRequest);
success = true;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
//完成APK的安装
executePostCommitSteps(commitRequest);
} finally {
......
}
}
processPendingInstall()会调用processInstallRequestsAsync()方法,在processInstallRequestsAsync()方法中再调用installPackagesTracedLI()方法执行安装流程,同时会对该方法以synchronized修饰保证线程同步。
在installPackagesTracedLI()中会对应用信息进行处理然后调用executePostCommitSteps ()执行安装。
executePostCommitSteps ()方法中会为新的代码路径准备应用程序配置文件,并在此检查是否需要dex优化。
如果是安装新包,会为新的代码路径准备应用程序配置文件;如果是替换已安装应用,其主要过程为更新设置,清除原有应用数据数据,重新生成相关的app数据目录等步骤,同时要区分系统应用替换和非系统应用替换。而安装新包,则直接更新设置,生成APP数据即可。这部分代码以及总结会后续补全发出