-
第7步 开启真正的安装之路
在开启继上文中的分析之前,我来大体做个简单总结说明:
Android10的安装流程变化了不少,同样为了兼容之前的流程,导致代码里有很多不合理或者说重复判断的情况出现,甚至还有前后矛盾的地方。总体上Android 10 安装应用要考虑的因素比较多,有以下几个方面:
- 1.系统应用只允许安装到/data分区。
- 2.分区空间要足够。
- 3.覆盖安装要保持和原有安装在同一个分区。
- 4.是否允许第三方应用安装到/data分区。
- 5.是否强制允许安装应用到外置存储。
- 6.AndroidManifest.xml里面的installLocation 标签。auto, internalOnly,preferExternal
前面5点在上文的分析中基本上都有体现,也比较容易理解。这里我们着重说以下第6点,AndroidManifest。在Android10中,默认的installLocation是internalOnly, 也就是只允许应用安装到/data分区,但是需要考虑之前是否已经安装过这个应用,如果已经在其他分区安装过,则可能发生不兼容,auto 和 preferExternal都是参考值,目前Android已经不在允许将应用直接安装到主存储,只允许将应用安装到内置存储和内置扩展存储。这是基于安全考虑,另外其实目前的主存储也是从内置存储或者扩展的内置存储上使用fuse划分出来的一个目录,二者其实是共用存储空间的,所以安装到主存储上其实意义不大,所以preferExternal标签其实已经被架空。
说到代码架空,本文中分析的不少代码是为了兼容老流程为存在的,所以也有不少代码本来是被架空的,也就是很多逻辑其实是走不到的。
OK,我们继续!
上文我们说到在InstallInstalling的onResume()
方法中主要对各种文件执行整理认证,剔除不必要的文件和逻辑,执行到最后mHandler.obtainMessage(MSG_COMMIT).sendToTarget()
这个mHandler是PackgeInstallerSession的属性,封装了下面的mHandlerCallback
作为callback处理,可以接收MSG_COMMIT和MSG_ON_PACKAGE_INSTALLED事件:
private final Handler.Callback mHandlerCallback = new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case MSG_COMMIT:
handleCommit();//***1***
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;
}
};
···
mHandler = new Handler(looper, mHandlerCallback);
···
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 childSessions = getChildSessions();
try {
synchronized (mLock) {
commitNonStagedLocked(childSessions);//***2***
}
} 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 commitNonStagedLocked(List childSessions)
throws PackageManagerException {
final PackageManagerService.ActiveInstallSession committingSession =
makeSessionActiveLocked();//***3***
if (committingSession == null) {
return;
}
if (isMultiPackage()) {
List 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();//***4***
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);//***5***
} else {
mPm.installStage(committingSession);//***6***
}
}
/**
* Stages this session for install and returns a
* {@link PackageManagerService.ActiveInstallSession} representing this new staged state or null
* in case permissions need to be requested before install can proceed.
*/
@GuardedBy("mLock")
private PackageManagerService.ActiveInstallSession makeSessionActiveLocked()
throws PackageManagerException {
if (mRelinquished) {
throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
"Session relinquished");
}
if (mDestroyed) {
throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed");
}
if (!mSealed) {
throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session not sealed");
}
//这里的IPackageInstallObserver2在下午有初始化,是传递给PackageManagerService用的。
//这个localObserver主要用PackageManagerService的PackageHandler接收处理POST_INSTALL事件时所用
//注意和上文Android APK安装流程(2)的mRemoteObserver的区别
final IPackageInstallObserver2 localObserver;
if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) {
localObserver = null;
} else {
if (!params.isMultiPackage) {
Preconditions.checkNotNull(mPackageName);
Preconditions.checkNotNull(mSigningDetails);
Preconditions.checkNotNull(mResolvedBaseFile);
if (needToAskForPermissionsLocked()) {//***7***
// User needs to confirm installation;
// give installer an intent they can use to involve
// user.
final Intent intent = new Intent(PackageInstaller.ACTION_CONFIRM_INSTALL);
intent.setPackage(mPm.getPackageInstallerPackageName());
intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
try {
mRemoteObserver.onUserActionRequired(intent);
} catch (RemoteException ignored) {
}
// Commit was keeping session marked as active until now; release
// that extra refcount so session appears idle.
closeInternal(false);
return null;
}
// Inherit any packages and native libraries from existing install that
// haven't been overridden.
if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
try {
final List fromFiles = mResolvedInheritedFiles;
final File toDir = resolveStageDirLocked();//***8***
if (LOGD) Slog.d(TAG, "Inherited files: " + mResolvedInheritedFiles);
if (!mResolvedInheritedFiles.isEmpty() && mInheritedFilesBase == null) {
throw new IllegalStateException("mInheritedFilesBase == null");
}
if (isLinkPossible(fromFiles, toDir)) {
if (!mResolvedInstructionSets.isEmpty()) {
final File oatDir = new File(toDir, "oat");
createOatDirs(mResolvedInstructionSets, oatDir);//***9***
}
// pre-create lib dirs for linking if necessary
if (!mResolvedNativeLibPaths.isEmpty()) {
for (String libPath : mResolvedNativeLibPaths) {
// "/lib/arm64" -> ["lib", "arm64"]
final int splitIndex = libPath.lastIndexOf('/');
if (splitIndex < 0 || splitIndex >= libPath.length() - 1) {
Slog.e(TAG,
"Skipping native library creation for linking due"
+ " to invalid path: " + libPath);
continue;
}
final String libDirPath = libPath.substring(1, splitIndex);
final File libDir = new File(toDir, libDirPath);
if (!libDir.exists()) {
NativeLibraryHelper.createNativeLibrarySubdir(libDir);//***10***
}
final String archDirPath = libPath.substring(splitIndex + 1);
NativeLibraryHelper.createNativeLibrarySubdir(
new File(libDir, archDirPath));//***11***
}
}
linkFiles(fromFiles, toDir, mInheritedFilesBase);
} else {
// TODO: this should delegate to DCS so the system process
// avoids holding open FDs into containers.
copyFiles(fromFiles, toDir);//***12***
}
} catch (IOException e) {
throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
"Failed to inherit existing install", e);
}
}
// TODO: surface more granular state from dexopt
mInternalProgress = 0.5f;
computeProgressLocked(true);//***13***
// Unpack native libraries
extractNativeLibraries(mResolvedStageDir, params.abiOverride,
mayInheritNativeLibs());//***14***
}
// We've reached point of no return; call into PMS to install the stage.
// Regardless of success or failure we always destroy session.
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) {
destroyInternal();
dispatchSessionFinished(returnCode, msg, extras);
}
};
}
final UserHandle user;
if ((params.installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {
user = UserHandle.ALL;
} else {
user = new UserHandle(userId);
}
mRelinquished = true;
return new PackageManagerService.ActiveInstallSession(mPackageName, stageDir,
localObserver, params, mInstallerPackageName, mInstallerUid, user,
mSigningDetails);
}
makeSessionActiveLocked()
方法里主要干了以下4个事儿:
- 1.如果是SessionParams.MODE_INHERIT_EXISTING安装模式,那么说明是进行安装覆盖,则会遍历该目录下所有的文件。通过isLinkPossible来检查安装原有的文件和当前的原有的文件,mResolvedInheritedFiles中的文件是否可以进行覆盖,如果文件信息一致说明可以覆盖,不能则直接拷贝到
/data/app/vmdlsessionId.tmp/
目录下。 - 2.mInternalProgress 设置为0.5,并且更新进度条回调给正在监听的Activity
- 3.执行
extractNativeLibraries()
方法,创建/data/app/vmdlsessionId.tmp/lib,copyNativeBinariesWithOverride并在这个文件下创建该系统支持的一系列的如64位,32位的arm-v7的so库保存目录 - 4.把localObserver这个本地Binder作为参数调用PMS的installStage方法,此时安装步骤将会转移到PMS中。之后等到PMS到达了某个阶段就会回调到onPackageInstalled,从而得知PMS那边安装完成了。
makeSessionActiveLocked()
执行完毕后可以获取到committingSession
变量,最后通过mPm.installStage(committingSession);
然后进入到PackageManagerService的installStage()
方法:
#PackageManagerService
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);//***15***
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);//发送INIT_COPY事件
}
mHandler是PackageManagerService的内部类PackageHandler:
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();//***16***
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
break;
}
...
HandlerParams的startCopy()
方法:
final void startCopy() {
if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
handleStartCopy();//***17***
handleReturnCode();//***18***
}
abstract void handleStartCopy();
abstract void handleReturnCode();
代码走到这里我们发现2个abstract方法,所以我们需要研究HandlerParams这个类。HandlerParams是个抽象类,其有2个实现类InstallParams和MultiPackageInstallParams,MutilPackageInstallParams用于负责批量安装, InstallParams则负责单一安装, MutilPackageInstallParams的成员变量mChildParams指向多个InstallParams, 说明批量安装其实就是调用多个单一安装的实现的。从上文传递的属性我们可以看到执行的是单一安装也就是InstallParams,所以执行的是InstallParams的handleStartCopy()
和handleReturnCode()
我们来看看InstallParams的handleStartCopy()
方法:
/*
* Invoke remote method to get package information and install
* location values. Override install location based on default
* policy if needed and then create install arguments based
* on the install location.
*/
public void handleStartCopy() {
int ret = PackageManager.INSTALL_SUCCEEDED;
// If we're already staged, we've firmly committed to an install location
//1.表示前边已经确定好了安装目录(\${stageDir}/PackageInstaller),确定文件是否存在,设置INSTALL_INTERNAL标志(double check)。
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;
// 2 简单的解析下安装包的AndroidManifest.xml文件,这里面会调用PackageHelper.resolveInstallLocation()函数确定推荐的安装位置。
pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
origin.resolvedPath, installFlags, packageAbiOverride);//***19***
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.
*/
// 3. 空间不足使用mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0);释放一些空间,
//注意3这种情况并没有使用PackageInstallerSession将安装文件拷贝到临时目录,如果已经拷贝,则并不需要关心空间问题
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);//***20***
if (sizeBytes >= 0) {
try {
mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0);//***21***
pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
origin.resolvedPath, installFlags, packageAbiOverride);//***22***
} 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.
*/
// 3.1 freeCache把安装包删了,设置PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE表示是由于空间问题安装失败的。
if (pkgLite.recommendedInstallLocation
== PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
pkgLite.recommendedInstallLocation
= PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
}
}
if (ret == PackageManager.INSTALL_SUCCEEDED) {
// 4.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.
// 4.2 前面都处理成功了,看下是否还需要更换安装位置
loc = installLocationPolicy(pkgLite);//***23***
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);//***24***
mVerificationCompleted = true;
mEnableRollbackCompleted = true;
mArgs = args;
if (ret == PackageManager.INSTALL_SUCCEEDED) {
// TODO: http://b/22976637
// Apps installed for "all" users use the device owner to verify the app
UserHandle verifierUser = getUser();
if (verifierUser == UserHandle.ALL) {
verifierUser = UserHandle.SYSTEM;
}
/*
* Determine if we have any installed package verifiers. If we
* do, then we'll defer to them to verify the packages.
*/
final int requiredUid = mRequiredVerifierPackage == null ? -1
: getPackageUid(mRequiredVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING,
verifierUser.getIdentifier());//***25***
final int installerUid =
verificationInfo == null ? -1 : verificationInfo.installerUid;
if (!origin.existing && requiredUid != -1
&& isVerificationEnabled(
verifierUser.getIdentifier(), installFlags, installerUid)) {//***26***
final Intent verification = new Intent(
Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
verification.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
verification.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)),
PACKAGE_MIME_TYPE);
verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
// Query all live verifiers based on current user state
final List receivers = queryIntentReceiversInternal(verification,
PACKAGE_MIME_TYPE, 0, verifierUser.getIdentifier(),
false /*allowDynamicSplits*/);
if (DEBUG_VERIFY) {
Slog.d(TAG, "Found " + receivers.size() + " verifiers for intent "
+ verification.toString() + " with " + pkgLite.verifiers.length
+ " optional verifiers");
}
final int verificationId = mPendingVerificationToken++;
verification.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId);
verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_PACKAGE,
installerPackageName);
verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALL_FLAGS,
installFlags);
verification.putExtra(PackageManager.EXTRA_VERIFICATION_PACKAGE_NAME,
pkgLite.packageName);
verification.putExtra(PackageManager.EXTRA_VERIFICATION_VERSION_CODE,
pkgLite.versionCode);
verification.putExtra(PackageManager.EXTRA_VERIFICATION_LONG_VERSION_CODE,
pkgLite.getLongVersionCode());
if (verificationInfo != null) {
if (verificationInfo.originatingUri != null) {
verification.putExtra(Intent.EXTRA_ORIGINATING_URI,
verificationInfo.originatingUri);
}
if (verificationInfo.referrer != null) {
verification.putExtra(Intent.EXTRA_REFERRER,
verificationInfo.referrer);
}
if (verificationInfo.originatingUid >= 0) {
verification.putExtra(Intent.EXTRA_ORIGINATING_UID,
verificationInfo.originatingUid);
}
if (verificationInfo.installerUid >= 0) {
verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_UID,
verificationInfo.installerUid);
}
}
final PackageVerificationState verificationState = new PackageVerificationState(
requiredUid, this);
mPendingVerification.append(verificationId, verificationState);
final List sufficientVerifiers = matchVerifiers(pkgLite,
receivers, verificationState);//***27***
DeviceIdleController.LocalService idleController = getDeviceIdleController();
final long idleDuration = getVerificationTimeout();
/*
* If any sufficient verifiers were listed in the package
* manifest, attempt to ask them.
*/
if (sufficientVerifiers != null) {
final int N = sufficientVerifiers.size();
if (N == 0) {
Slog.i(TAG, "Additional verifiers required, but none installed.");
ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
} else {
for (int i = 0; i < N; i++) {
final ComponentName verifierComponent = sufficientVerifiers.get(i);
idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
verifierComponent.getPackageName(), idleDuration,
verifierUser.getIdentifier(), false, "package verifier");
final Intent sufficientIntent = new Intent(verification);
sufficientIntent.setComponent(verifierComponent);
mContext.sendBroadcastAsUser(sufficientIntent, verifierUser);//***28***
}
}
}
final ComponentName requiredVerifierComponent = matchComponentForVerifier(
mRequiredVerifierPackage, receivers);
if (ret == PackageManager.INSTALL_SUCCEEDED
&& mRequiredVerifierPackage != null) {
Trace.asyncTraceBegin(
TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
/*
* Send the intent to the required verification agent,
* but only start the verification timeout after the
* target BroadcastReceivers have run.
*/
verification.setComponent(requiredVerifierComponent);
idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
mRequiredVerifierPackage, idleDuration,
verifierUser.getIdentifier(), false, "package verifier");
//***29***
mContext.sendOrderedBroadcastAsUser(verification, verifierUser,
android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final Message msg = mHandler
.obtainMessage(CHECK_PENDING_VERIFICATION);
msg.arg1 = verificationId;
mHandler.sendMessageDelayed(msg, getVerificationTimeout());
}
}, null, 0, null, null);
/*
* We don't want the copy to proceed until verification
* succeeds.
*/
mVerificationCompleted = false;
}
}
if ((installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
// TODO(ruhler) b/112431924: Don't do this in case of 'move'?
final int enableRollbackToken = mPendingEnableRollbackToken++;
Trace.asyncTraceBegin(
TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken);
mPendingEnableRollback.append(enableRollbackToken, this);
final int[] installedUsers;
synchronized (mPackages) {
PackageSetting ps = mSettings.getPackageLPr(pkgLite.packageName);
if (ps != null) {
installedUsers = ps.queryInstalledUsers(sUserManager.getUserIds(),
true);
} else {
installedUsers = new int[0];
}
}
Intent enableRollbackIntent = new Intent(Intent.ACTION_PACKAGE_ENABLE_ROLLBACK);
enableRollbackIntent.putExtra(
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN,
enableRollbackToken);
enableRollbackIntent.putExtra(
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALL_FLAGS,
installFlags);
enableRollbackIntent.putExtra(
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALLED_USERS,
installedUsers);
enableRollbackIntent.putExtra(
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_USER,
getRollbackUser().getIdentifier());
enableRollbackIntent.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)),
PACKAGE_MIME_TYPE);
enableRollbackIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
// Allow the broadcast to be sent before boot complete.
// This is needed when committing the apk part of a staged
// session in early boot. The rollback manager registers
// its receiver early enough during the boot process that
// it will not miss the broadcast.
enableRollbackIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
//***30***
mContext.sendOrderedBroadcastAsUser(enableRollbackIntent, UserHandle.SYSTEM,
android.Manifest.permission.PACKAGE_ROLLBACK_AGENT,
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// the duration to wait for rollback to be enabled, in millis
long rollbackTimeout = DeviceConfig.getLong(
DeviceConfig.NAMESPACE_ROLLBACK,
PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS,
DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS);
if (rollbackTimeout < 0) {
rollbackTimeout = DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS;
}
final Message msg = mHandler.obtainMessage(
ENABLE_ROLLBACK_TIMEOUT);
msg.arg1 = enableRollbackToken;
mHandler.sendMessageDelayed(msg, rollbackTimeout);
}
}, null, 0, null, null);
mEnableRollbackCompleted = false;
}
}
mRet = ret;
}
- 1.调用
PackageManagerServiceUtils.getMinimalPackageInfo()
扫描安装apk信息到Android系统中,并对存储空间是否足够进行判断,如果不够则进行内存释放。其实这个方法里执行的基本上都是无用代码,因为在之前我们因为分析到通过Session已经完成计算存储空间,释放内存等的操作。
/**
* Parse given package and return minimal details.
*/
public static PackageInfoLite getMinimalPackageInfo(Context context, String packagePath,
int flags, String abiOverride) {
final PackageInfoLite ret = new PackageInfoLite();
if (packagePath == null) {
Slog.i(TAG, "Invalid package file " + packagePath);
ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK;
return ret;
}
final File packageFile = new File(packagePath);
final PackageParser.PackageLite pkg;
final long sizeBytes;
try {
//对apk包进行解析,就是解析包中的AndroidManifest最外层的数据.
//拿到版本号,包名,包的路径等等不包含四大组件的基础信息。
//和parseMonolithicPackageLite作用十分相似,核心还是遍历这个目录里面
//所有的apk文件,以splitName为key,ApkLite为value保存起来,
//并且找出null为key对应的baseApk的value
pkg = PackageParser.parsePackageLite(packageFile, 0);//***31***
// 对安装后的包进行大小统计,计算结果是:
// 安装后大小 = 每一个包安装路径下文件的大小(/data/app/vmdlsessionId.tmp/base.apk)+ .dm后缀的文件大小 + so库大小
sizeBytes = PackageHelper.calculateInstalledSize(pkg, abiOverride);//***32***
} catch (PackageParserException | IOException e) {
Slog.w(TAG, "Failed to parse package at " + packagePath + ": " + e);
if (!packageFile.exists()) {
ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_URI;
} else {
ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK;
}
return ret;
}
//计算出返回的结果
final int recommendedInstallLocation = PackageHelper.resolveInstallLocation(context,
pkg.packageName, pkg.installLocation, sizeBytes, flags);//***33***
ret.packageName = pkg.packageName;
ret.splitNames = pkg.splitNames;
ret.versionCode = pkg.versionCode;
ret.versionCodeMajor = pkg.versionCodeMajor;
ret.baseRevisionCode = pkg.baseRevisionCode;
ret.splitRevisionCodes = pkg.splitRevisionCodes;
ret.installLocation = pkg.installLocation;
ret.verifiers = pkg.verifiers;
ret.recommendedInstallLocation = recommendedInstallLocation;
ret.multiArch = pkg.multiArch;
return ret;
}
- 2.通过
createInstallArgs()
构建InstallArgs对象(这里是FileInstallArgs),如果getMinimalPackageInfo()
的安装成功了,则会进行判断该包是否已经安装过且isVerificationEnabled()
是否允许进行包校验器进行校验。
private InstallArgs createInstallArgs(InstallParams params) {
if (params.move != null) {
return new MoveInstallArgs(params);//***34***
} else {
return new FileInstallArgs(params);//***35***
}
}
- 3.如果可以进行包校验,则通过data为
"application/vnd.android.package-archive"
调用queryIntentReceiversInternal()
方法查找有没有注册在Android系统中的包校验广播接受者;通过matchVerifiers()
方法筛选出当前合适的包校验器;最后依次发送广播,让包校验接受者根据包名,versionCode,packageName,安装来源等信息进行校验. - 4.调用
mContext.sendOrderedBroadcastAsUser()
发送广播,验证完毕后,调用final Message msg = mHandler.obtainMessage(CHECK_PENDING_VERIFICATION);
给mHandler发消息:
···
case CHECK_PENDING_VERIFICATION: {
final int verificationId = msg.arg1;
final PackageVerificationState state = mPendingVerification.get(verificationId);
if ((state != null) && !state.timeoutExtended()) {
final InstallParams params = state.getInstallParams();
final InstallArgs args = params.mArgs;
final Uri originUri = Uri.fromFile(args.origin.resolvedFile);
Slog.i(TAG, "Verification timed out for " + originUri);
mPendingVerification.remove(verificationId);
final UserHandle user = args.getUser();
if (getDefaultVerificationResponse(user)
== PackageManager.VERIFICATION_ALLOW) {
Slog.i(TAG, "Continuing with installation of " + originUri);
state.setVerifierResponse(Binder.getCallingUid(),
PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT);
broadcastPackageVerified(verificationId, originUri,
PackageManager.VERIFICATION_ALLOW, user);
} else {
broadcastPackageVerified(verificationId, originUri,
PackageManager.VERIFICATION_REJECT, user);
params.setReturnCode(
PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE);
}
Trace.asyncTraceEnd(
TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
params.handleVerificationFinished();//***36***
}
break;
}
···
params.handleVerificationFinished()
方法:
void handleVerificationFinished() {
mVerificationCompleted = true;//在handleReturnCode()里用到
handleReturnCode();
}
- 5.同4相似,调用
mContext.sendOrderedBroadcastAsUser()
发送广播,对Rollback(这个Rollback是什么?)进行验证。然后调用final Message msg = mHandler.obtainMessage(ENABLE_ROLLBACK_TIMEOUT);
给mHandler发消息:
···
case ENABLE_ROLLBACK_TIMEOUT: {
final int enableRollbackToken = msg.arg1;
final InstallParams params = mPendingEnableRollback.get(enableRollbackToken);
if (params != null) {
final InstallArgs args = params.mArgs;
final Uri originUri = Uri.fromFile(args.origin.resolvedFile);
Slog.w(TAG, "Enable rollback timed out for " + originUri);
mPendingEnableRollback.remove(enableRollbackToken);
Slog.w(TAG, "Continuing with installation of " + originUri);
Trace.asyncTraceEnd(
TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken);
params.handleRollbackEnabled();//***37***
Intent rollbackTimeoutIntent = new Intent(
Intent.ACTION_CANCEL_ENABLE_ROLLBACK);
rollbackTimeoutIntent.putExtra(
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN,
enableRollbackToken);
rollbackTimeoutIntent.addFlags(
Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
mContext.sendBroadcastAsUser(rollbackTimeoutIntent, UserHandle.SYSTEM,
android.Manifest.permission.PACKAGE_ROLLBACK_AGENT);
}
break;
}
···
params.handleRollbackEnabled();
方法:
void handleRollbackEnabled() {
// TODO(ruhler) b/112431924: Consider halting the install if we
// couldn't enable rollback.
mEnableRollbackCompleted = true;
handleReturnCode();
}
再看handleReturnCode();
方法:
@Override
void handleReturnCode() {
//由于上面的36和37都执行了,所以这个true
if (mVerificationCompleted && mEnableRollbackCompleted) {
if ((installFlags & PackageManager.INSTALL_DRY_RUN) != 0) {
String packageName = "";
try {
PackageLite packageInfo =
new PackageParser().parsePackageLite(origin.file, 0);//***38***
packageName = packageInfo.packageName;
} catch (PackageParserException e) {
Slog.e(TAG, "Can't parse package at " + origin.file.getAbsolutePath(), e);
}
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) {
//***39***
mRet = mArgs.copyApk();
}
//***40***复制完成之后进入下一阶段
processPendingInstall(mArgs, mRet);
}
}
看FileInstallArgs类的copyApk()
方法:
int copyApk() {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk");
try {
return doCopyApk();//***41***
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
private int doCopyApk() {
// 前边计算了一大通,最终还是以origin.staged为准
if (origin.staged) {
//如果已经copy过了,直接返回INSTALL_SUCCEEDED,在Android10里其实前面是已经copy过了
if (DEBUG_INSTALL) Slog.d(TAG, origin.file + " already staged; skipping copy");
codeFile = origin.file;
resourceFile = origin.file;
return PackageManager.INSTALL_SUCCEEDED;
}
try {
// 2 instant app 和external 计算安装位置并拷贝
final boolean isEphemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
final File tempDir =
mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral);//***42***
codeFile = tempDir;
resourceFile = tempDir;
} catch (IOException e) {
Slog.w(TAG, "Failed to create copy file: " + e);
return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
}
int ret = PackageManagerServiceUtils.copyPackage(
origin.file.getAbsolutePath(), codeFile);//***43***
if (ret != PackageManager.INSTALL_SUCCEEDED) {
Slog.e(TAG, "Failed to copy package");
return ret;
}
//3 拷贝lib目录
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);//***44***
} catch (IOException e) {
Slog.e(TAG, "Copying native libraries failed", e);
ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
} finally {
IoUtils.closeQuietly(handle);//***45***
}
return ret;
}
由于之前PackageInstallerSession已经完成了copy动作(即origin.staged=true),所以这个方法会直接返回。当然,也许如果origin.staged=false:
- 调用
mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral)
创建拷贝的文件位置,
可以看到@Deprecated public File allocateStageDirLegacy(String volumeUuid, boolean isEphemeral) throws IOException { synchronized (mSessions) { try { final int sessionId = allocateSessionIdLocked(); mLegacySessions.put(sessionId, true); final File sessionStageDir = buildTmpSessionDir(sessionId, volumeUuid);//***46*** prepareStageDir(sessionStageDir);//***47*** return sessionStageDir; } catch (IllegalStateException e) { throw new IOException(e); } } } private File buildTmpSessionDir(int sessionId, String volumeUuid) { final File sessionStagingDir = getTmpSessionDir(volumeUuid);//***48*** return new File(sessionStagingDir, "vmdl" + sessionId + ".tmp"); }
buildTmpSessionDir()
方法,之前的PackageInstallerSession进行copy过程也调用PackageInstallerService的createSession()
然后调用到buildTmpSessionDir()
。
- 调用
PackageManagerServiceUtils.copyPackage(origin.file.getAbsolutePath(), codeFile)
执行copy工作,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); // 基础apk拷贝 copyFile(pkg.baseCodePath, targetDir, "base.apk");//***49*** // split 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); // 这里和PackagerInstallerSession的doWriteInternal()方法相似,0644是本用户能读写,其他和同一个用户组只能读 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); } }
- 调用
NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,abiOverride);
对native libraries进行Unpack处理:public static int copyNativeBinariesWithOverride(Handle handle, File libraryRoot, String abiOverride) { try { if (handle.multiArch) { // Warn if we've set an abiOverride for multi-lib packages.. // By definition, we need to copy both 32 and 64 bit libraries for // such packages. if (abiOverride != null && !CLEAR_ABI_OVERRIDE.equals(abiOverride)) { Slog.w(TAG, "Ignoring abiOverride for multi arch application."); } int copyRet = PackageManager.NO_NATIVE_LIBRARIES; if (Build.SUPPORTED_32_BIT_ABIS.length > 0) { copyRet = copyNativeBinariesForSupportedAbi(handle, libraryRoot, Build.SUPPORTED_32_BIT_ABIS, true /* use isa specific subdirs */); if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES && copyRet != PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) { Slog.w(TAG, "Failure copying 32 bit native libraries; copyRet=" +copyRet); return copyRet; } } if (Build.SUPPORTED_64_BIT_ABIS.length > 0) { //***50*** copyRet = copyNativeBinariesForSupportedAbi(handle, libraryRoot, Build.SUPPORTED_64_BIT_ABIS, true /* use isa specific subdirs */); if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES && copyRet != PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) { Slog.w(TAG, "Failure copying 64 bit native libraries; copyRet=" +copyRet); return copyRet; } } } else { String cpuAbiOverride = null; if (CLEAR_ABI_OVERRIDE.equals(abiOverride)) { cpuAbiOverride = null; } else if (abiOverride != null) { cpuAbiOverride = abiOverride; } String[] abiList = (cpuAbiOverride != null) ? new String[] { cpuAbiOverride } : Build.SUPPORTED_ABIS; if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && cpuAbiOverride == null && hasRenderscriptBitcode(handle)) { abiList = Build.SUPPORTED_32_BIT_ABIS; } int copyRet = copyNativeBinariesForSupportedAbi(handle, libraryRoot, abiList, true /* use isa specific subdirs */); if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) { Slog.w(TAG, "Failure copying native libraries [errorCode=" + copyRet + "]"); return copyRet; } } return PackageManager.INSTALL_SUCCEEDED; } catch (IOException e) { Slog.e(TAG, "Copying native libraries failed", e); return PackageManager.INSTALL_FAILED_INTERNAL_ERROR; } }
PackageInstallerSession的extractNativeLibraries(File packageDir, String abiOverride, boolean inherit)
方法也调用NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libDir, abiOverride);
对native libraries进行copy处理。
下一阶段是APK的加载流程