PackageManagerService
一、PackageManagerService.installStage
接下来,进入 PackageManagerService 阶段。从PackageInstallerSession.java的commitLocked调用
这里的 IPackageInstallObserver2 observer 是前面创建的本次 localObserver:
位置:./frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
java
void installStage(String packageName, File stagedDir,
IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,
String installerPackageName, int installerUid, UserHandle user,
PackageParser.SigningDetails signingDetails) {
if (DEBUG_INSTANT) {
if ((sessionParams.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
Slog.d(TAG, "Ephemeral install of " + packageName);
}
}
//【1.1】创建一个 VerificationInfo 对象,用于校验
final VerificationInfo verificationInfo = new VerificationInfo(
sessionParams.originatingUri, sessionParams.referrerUri,
sessionParams.originatingUid, installerUid);
//【1.2】创建了一个 OriginInfo 对象
final OriginInfo origin = OriginInfo.fromStagedFile(stagedDir);
//【1】创建了一个 INIT_COPY 消息
final Message msg = mHandler.obtainMessage(INIT_COPY);
final int installReason = fixUpInstallReason(installerPackageName, installerUid,
sessionParams.installReason);
//【1.3】创建一个 InstallParams 安装参数对象
final InstallParams params = new InstallParams(origin, null, observer,
sessionParams.installFlags, installerPackageName, sessionParams.volumeUuid,
verificationInfo, user, sessionParams.abiOverride,
sessionParams.grantedRuntimePermissions, signingDetails, installReason);
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));
//【2】发送 INIT_COPY 消息
mHandler.sendMessage(msg);
}
这里的 mHandler 是在 PackageManagerService 的构造器中创建的:
java
synchronized (mPackages) {
mHandlerThread = new ServiceThread(TAG,
Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
mHandlerThread.start();
mHandler = new PackageHandler(mHandlerThread.getLooper());
//...
}
是一个 PackageHandler 实例,其绑定了一个子线程 ServiceThread
1.1 new VerificationInfo
VerificationInfo 类定义在 PackageManagerService 中,用于信息校验:
java
static class VerificationInfo {
/** A constant used to indicate that a uid value is not present. */
public static final int NO_UID = -1;
/** URI referencing where the package was downloaded from. */
final Uri originatingUri;
/** HTTP referrer URI associated with the originatingURI. */
final Uri referrer;
/** UID of the application that the install request originated from. */
final int originatingUid;
/** UID of application requesting the install */
final int installerUid; // 安装者应用的 uid
VerificationInfo(Uri originatingUri, Uri referrer, int originatingUid, int installerUid) {
this.originatingUri = originatingUri;
this.referrer = referrer;
this.originatingUid = originatingUid;
this.installerUid = installerUid;
}
}
1.2 new OriginInfo
这里创建了一个 OriginInfo 实例,封装安装目录相关信息
java
static class OriginInfo {
/**
* Location where install is coming from, before it has been
* copied/renamed into place. This could be a single monolithic APK
* file, or a cluster directory. This location may be untrusted.
*/
final File file; // 安装到内置存储,不为 null
/**
* Flag indicating that {@link #file} or {@link #cid} has already been
* staged, meaning downstream users don't need to defensively copy the
* contents.
*/
final boolean staged;
/**
* Flag indicating that {@link #file} or {@link #cid} is an already
* installed app that is being moved.
*/
final boolean existing;
final String resolvedPath;
final File resolvedFile;
static OriginInfo fromNothing() {
return new OriginInfo(null, false, false);
}
static OriginInfo fromUntrustedFile(File file) {
return new OriginInfo(file, false, false);
}
static OriginInfo fromExistingFile(File file) {
return new OriginInfo(file, false, true);
}
static OriginInfo fromStagedFile(File file) { //【1】安装到内置存储会调用
return new OriginInfo(file, true, false);
}
private OriginInfo(File file, boolean staged, boolean existing) {
this.file = file; // 内置时为:/data/app/vmdl[sessionId].tmp
this.staged = staged; // 安装到内置存储时为 true
this.existing = existing; // 安装到内置存储时为 false
if (file != null) {
resolvedPath = file.getAbsolutePath();
resolvedFile = file;
} else {
resolvedPath = null;
resolvedFile = null;
}
}
}
这里我们先关注安装到内置存储中的逻辑
1.3 new PMS.InstallParams
InstallParams 类定义在 PackageManagerService 中,封装了安装参数:
java
class InstallParams extends HandlerParams {
final OriginInfo origin;
final MoveInfo move; // move package 才会传入,安装时为 null
final IPackageInstallObserver2 observer; // 本地传观察者
int installFlags;
final String installerPackageName;
final String volumeUuid;
private InstallArgs mArgs;
private int mRet;
final String packageAbiOverride;
final String[] grantedRuntimePermissions; // 安装时授予的运行时权限列表
final VerificationInfo verificationInfo;
final PackageParser.SigningDetails signingDetails;
final int installReason;
InstallParams(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer,
int installFlags, String installerPackageName, String volumeUuid,
VerificationInfo verificationInfo, UserHandle user, String packageAbiOverride,
String[] grantedPermissions, PackageParser.SigningDetails signingDetails, int installReason) {
super(user);
this.origin = origin;
this.move = move;
this.observer = observer;
this.installFlags = installFlags;
this.installerPackageName = installerPackageName;
this.volumeUuid = volumeUuid;
this.verificationInfo = verificationInfo;
this.packageAbiOverride = packageAbiOverride;
this.grantedRuntimePermissions = grantedPermissions;
this.signingDetails = signingDetails;
this.installReason = installReason;
}
//...
}
InstallParams 继承了 HandlerParams
这里涉及到一个 MoveInfo move,在 movePackageInternal 也就是移动 package 时才会调用,这里是安装,我们先不关注
二、PackageHandler.doHandleMessage[INIT_COPY]
位置:./frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
installStage最后发送了INIT_COPY消息,它会在子线程的PackageHandler 中处理 INIT_COPY 消息:
java
case INIT_COPY: {
//【1】取出 InstallParams
HandlerParams params = (HandlerParams) msg.obj;
// mPendingInstalls 中会保存所有正在等待的安装
int idx = mPendingInstalls.size();
if (DEBUG_INSTALL) Slog.i(TAG, "init_copy idx=" + idx + ": " + params);
// If a bind was already initiated we dont really
// need to do anything. The pending install
// will be processed later on.
//【2】mBound 用来判断是否已经绑定到了 DefaultContainerService,该服务用于安装
if (!mBound) {
Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
System.identityHashCode(mHandler));
// If this is the only one pending we might
// have to bind to the service again.
//【2.1】尝试去 bind 服务,bind 成功后,mBound 置为 true
if (!connectToService()) {
Slog.e(TAG, "Failed to bind to media container service");
//【2.2】如果不能 bind 成功,那就触发 HandlerParams 的 serviceError 方法
params.serviceError();
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
System.identityHashCode(mHandler));
if (params.traceMethod != null) {
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, params.traceMethod,
params.traceCookie);
}
return;
} else {
// Once we bind to the service, the first
// pending request will be processed.
//【3】将本次的安装参数添加到等待集合中
mPendingInstalls.add(idx, params);
}
} else {
//【4】如果之前已经 bind 了,那就直接将安装参数添加到等待集合中
mPendingInstalls.add(idx, params);
// Already bound to the service. Just make
// sure we trigger off processing the first request.
//【3】如果是第一次添加,发送 MCS_BOUND 消息
if (idx == 0) {
mHandler.sendEmptyMessage(MCS_BOUND);
}
}
break;
}
这里逻辑很清晰了,我们继续看
2.1 PackageHandler.connectToService
java
private boolean connectToService() {
if (DEBUG_INSTALL) Log.i(TAG, "Trying to bind to DefaultContainerService");
Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
//【1】开始 bind 服务,传入了 mDefContainerConn 对象
if (mContext.bindServiceAsUser(service, mDefContainerConn,
Context.BIND_AUTO_CREATE, UserHandle.SYSTEM)) {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
mBound = true;
return true;
}
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
return false;
}
这里 bind 的服务是 DefaultContainerService
java
public static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
DEFAULT_CONTAINER_PACKAGE,
"com.android.defcontainer.DefaultContainerService");
PackageManagerService 内部持有一个 DefaultContainerConnection 实例
java
final private DefaultContainerConnection mDefContainerConn =
new DefaultContainerConnection();
class DefaultContainerConnection implements ServiceConnection {
public void onServiceConnected(ComponentName name, IBinder service) {
if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceConnected");
//【1】获得 DefaultContainerConnection 代理对象
final IMediaContainerService imcs = IMediaContainerService.Stub
.asInterface(Binder.allowBlocking(service));
//【5.3】发送 MCS_BOUND 消息
mHandler.sendMessage(mHandler.obtainMessage(MCS_BOUND, imcs));
}
public void onServiceDisconnected(ComponentName name) {
if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceDisconnected");
}
}
最后会发送 MCS_BOUND 消息给 PackageHandler 对象
2.2 InstallParams.serviceError
serviceError 方法是从 HandlerParams 中继承到的
java
final void serviceError() {
if (DEBUG_INSTALL) Slog.i(TAG, "serviceError");
//【4.2】安装异常,保存结果
handleServiceError();
handleReturnCode();
}
三、PackageHandler.doHandleMessage[MCS_BOUND] - 绑定服务
继续来看下 PackageHandler 对 MCS_BOUND 的处理
java
case MCS_BOUND: {
if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");
//【1】这里的 msg.obj 是前面 bind 获得的代理对象,将其保存到 mContainerService 中
if (msg.obj != null) {
mContainerService = (IMediaContainerService) msg.obj;
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
System.identityHashCode(mHandler));
}
//【2】异常处理,如果 mContainerService 为 null,且 mBound 为 ture,那么这种情况是异常
if (mContainerService == null) {
if (!mBound) {
// Something seriously wrong since we are not bound and we are not
// waiting for connection. Bail out.
Slog.e(TAG, "Cannot bind to media container service");
//【2.1】遍历所有的 HandlerParams 安装参数,回调 serviceError
for (HandlerParams params : mPendingInstalls) {
// Indicate service bind error
params.serviceError();
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
System.identityHashCode(params));
if (params.traceMethod != null) {
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER,
params.traceMethod, params.traceCookie);
}
}
//【2.2】清空 mPendingInstalls 集合
mPendingInstalls.clear();
} else {
Slog.w(TAG, "Waiting to connect to media container service");
}
} else if (mPendingInstalls.size() > 0) {
//【3】正常情况下,bind 是有效的,那么会进入这里
HandlerParams params = mPendingInstalls.get(0);
if (params != null) {
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
System.identityHashCode(params));
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
//【5.4】调用了 HandlerParams 的 startCopy 方法
if (params.startCopy()) {
// We are done... look for more work or to
// go idle.
if (DEBUG_SD_INSTALL) Log.i(TAG,
"Checking for more work or unbind...");
// Delete pending install
//【3.1】本次安装完成,删除本次处理的安装参数
if (mPendingInstalls.size() > 0) {
mPendingInstalls.remove(0);
}
if (mPendingInstalls.size() == 0) {
//【3.2】如果所有的安装参数都处理玩了,unbind 服务
// 这里的 unbind 延迟了 10s
if (mBound) {
if (DEBUG_SD_INSTALL) Log.i(TAG,
"Posting delayed MCS_UNBIND");
removeMessages(MCS_UNBIND);
Message ubmsg = obtainMessage(MCS_UNBIND);
// Unbind after a little delay, to avoid
// continual thrashing.
sendMessageDelayed(ubmsg, 10000);
}
} else {
// There are more pending requests in queue.
// Just post MCS_BOUND message to trigger processing
// of next pending install.
//【3.3】在安装队列中有其他的安装项,我们发送 MCS_BOUND 消息继续处理
if (DEBUG_SD_INSTALL) Log.i(TAG,
"Posting MCS_BOUND for next work");
mHandler.sendEmptyMessage(MCS_BOUND);
}
}
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
} else {
// Should never happen ideally.
Slog.w(TAG, "Empty queue");
}
break;
}
四、InstallParams.startCopy
InstallParams 继承了 HandlerParams
java
final boolean startCopy() {
boolean res;
try {
if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
//【1】如果重试次数大于 4 ,那么就放弃本次安装
if (++mRetries > MAX_RETRIES) {
Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
//【4.1】发送 MCS_GIVE_UP 消息
mHandler.sendEmptyMessage(MCS_GIVE_UP);
//【4.2】处理失败结果
handleServiceError();
return false;
} else {
//【5】继续安装
handleStartCopy();
res = true;
}
} catch (RemoteException e) {
if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");
//【4.3】发送 MCS_RECONNECT 消息
mHandler.sendEmptyMessage(MCS_RECONNECT);
res = false;
}
//【4.4】处理返回码
handleReturnCode();
return res;
}
这里定义了安装尝试次数:
java
private static final int MAX_RETRIES = 4;
4.1 PackageHandler.doHandleMessage[MCS_GIVE_UP] - 放弃安装
重试次数大于 4 ,那么就放弃本次安装
java
case MCS_GIVE_UP: {
if (DEBUG_INSTALL) Slog.i(TAG, "mcs_giveup too many retries");
//【1】移除这个安装参数
HandlerParams params = mPendingInstalls.remove(0);
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
System.identityHashCode(params));
break;
}
4.2 InstallParams.handleServiceError
处理本次安装失败的结果:
java
@Override
void handleServiceError() {
//【2.3】创建安装参数 InstallArgs
mArgs = createInstallArgs(this);
mRet = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
}
这里的 createInstallArgs 方法我们后面再分析
4.3 PackageHandler.doHandleMessage[MCS_RECONNECT] - 重连服务
MCS_RECONNECT 消息会尝试重连服务
java
case MCS_RECONNECT: {
if (DEBUG_INSTALL) Slog.i(TAG, "mcs_reconnect");
if (mPendingInstalls.size() > 0) {
//【1】如果 mBound 为 true,先尝试断开连接
if (mBound) {
disconnectService();
}
//【2】开始重新连接服务
if (!connectToService()) {
Slog.e(TAG, "Failed to bind to media container service");
for (HandlerParams params : mPendingInstalls) {
// Indicate service bind error
//【2.2】返回安装异常
params.serviceError();
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
System.identityHashCode(params));
}
//【3】清空 mPendingInstalls 集合
mPendingInstalls.clear();
}
}
break;
}
4.4 InstallParams.handleReturnCode
当 mArgs 为 null 的时候,此时该 package 正在被校验,所以需要等到校验成功后才能安装,所以不会进入这里
java
@Override
void handleReturnCode() {
// If mArgs is null, then MCS couldn't be reached. When it
// reconnects, it will try again to install. At that point, this
// will succeed.
//【1】如果 mArgs 这里为 null,可能是不需要校验
if (mArgs != null) {
processPendingInstall(mArgs, mRet); //【7】继续安装
}
}
五、InstallParams.handleStartCopy
在startCopy里,如果正常就继续copy,调用handleStartCopy()
java
public void handleStartCopy() throws RemoteException {
//【1】保存安装结果,默认为成功
int ret = PackageManager.INSTALL_SUCCEEDED;
// If we're already staged, we've firmly committed to an install location
//【2】我们知道 origin 中存储了安装目录相关的信息
if (origin.staged) {
if (origin.file != null) {
//【2.1】安装到内置存储中
installFlags |= PackageManager.INSTALL_INTERNAL;
installFlags &= ~PackageManager.INSTALL_EXTERNAL;
} else {
throw new IllegalStateException("Invalid stage location");
}
}
//【3】判断安装位置
final boolean onSd = (installFlags & PackageManager.INSTALL_EXTERNAL) != 0;
final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;
final boolean ephemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
PackageInfoLite pkgLite = null;
//【4】判断安装位置是否满足条件
if (onInt && onSd) {
// Check if both bits are set. //【4.1】不能同时设置安装在 sd 和内置中
Slog.w(TAG, "Conflicting flags specified for installing on both internal and external");
ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
} else if (onSd && ephemeral) {
Slog.w(TAG, "Conflicting flags specified for installing ephemeral on external");
//【4.2】不能设置短暂安装在 sd 中
ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
} else {
//【5.1】利用 ContainerService 获取 PackageInfoLite,同时判断空间是否合适
pkgLite = mContainerService.getMinimalPackageInfo(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.
*/ //【4.3】空间不足,尝试释放空间
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 = mContainerService.calculateInstalledSize(
origin.resolvedPath, packageAbiOverride);
try {
//【4.4】通过 installd 释放存储
mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0);
//【5.1】再次利用 ContainerService 获取 PackageInfoLite,同时判断空间是否合适
pkgLite = mContainerService.getMinimalPackageInfo(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.
*/ //【4.5】依然无法安装,设置结果为 RECOMMEND_FAILED_INSUFFICIENT_STORAGE
if (pkgLite.recommendedInstallLocation
== PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
pkgLite.recommendedInstallLocation
= PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
}
}
}
//【5】处理前面的空间判断后的结果
if (ret == PackageManager.INSTALL_SUCCEEDED) {
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.
//【5.2】调用 installLocationPolicy 方法,针对于降级安装和替换安装做处理
loc = installLocationPolicy(pkgLite);
if (loc == PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE) {
ret = PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE; // 处理无法降级的结果
} else if (!onSd && !onInt) {
// Override install location with flags
// 如果 flags 没有指定内置还是外置,那么由 installLocationPolicy 的返回值指定
if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
// Set the flag to install on external media.
installFlags |= PackageManager.INSTALL_EXTERNAL; // 外置
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_EXTERNAL
|PackageManager.INSTALL_INTERNAL);
} else {
// Make sure the flag for installing on external
// media is unset
installFlags |= PackageManager.INSTALL_INTERNAL; // 内置并且是短暂安装
installFlags &= ~PackageManager.INSTALL_EXTERNAL;
}
}
}
}
//【5.3】创建一个 InstallArgs 对象,和 InstallParams 相互引用
final InstallArgs args = createInstallArgs(this);
mArgs = args;
if (ret == PackageManager.INSTALL_SUCCEEDED) {
// TODO: http://b/22976637
// Apps installed for "all" users use the device owner to verify the app
//【6】如果该应用是安装给 all users 的,那么需要校验应用
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.
*/
//【7】尝试找到系统中安装的 pacakge 校验器,如果可以找到,那就要做校验啦
//【7.1】获得校验器的 uid
final int requiredUid = mRequiredVerifierPackage == null ? -1
: getPackageUid(mRequiredVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING,
verifierUser.getIdentifier());
//【7.1】如果是安装到内置存储(existing 为 true),并且系统中有校验器,并且系统打开了校验功能,那么就尝试校验
//【5.4】通过 isVerificationEnabled 判断是否打开校验功能
final int installerUid =
verificationInfo == null ? -1 : verificationInfo.installerUid;
if (!origin.existing && requiredUid != -1
&& isVerificationEnabled(
verifierUser.getIdentifier(), installFlags, installerUid)) {
//【7.1.1】准备发送校验广播
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); // 设置 DataAndType 属性,包含了 apk 路径对应的 uri
verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // 增加了临时的权限授予
// Query all live verifiers based on current user state
//【7.1.2】查询校验器
final List<ResolveInfo> 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");
}
// 计算本次校验的唯一标识 token
final int verificationId = mPendingVerificationToken++;
verification.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId);
// 安装器(packageInstaller)
verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_PACKAGE,
installerPackageName);
// 本次安装的 installFlags
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());
// 如果指定了校验信息,将其写入 intent
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);
}
}
//【5.5.5】创建一个 PackageVerificationState 对象,用于保存应用校验状态,同时将创建的
// installArgs 作为参数传入,并加入 mPendingVerification 集合中
final PackageVerificationState verificationState = new PackageVerificationState(
requiredUid, args);
mPendingVerification.append(verificationId, verificationState);
//【7.1.3】如果应用指定了校验者,那么我们要尝试先用指定的校验器校验
final List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite,
receivers, verificationState);
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);
// 使用前面创建的 verification 意图,再创建一个 intent!
// 指定组件为应用指定的校验器,并发送广播
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);
}
}
}
//【7.1.4】找到和 mRequiredVerifierPackage(系统指定的默认校验器)匹配的接收者
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.
*/
//【7.1.5】指定目标应用为 mRequiredVerifierPackage 的内部组件
// 发送 verification 意图
verification.setComponent(requiredVerifierComponent);
idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
mRequiredVerifierPackage, idleDuration,
verifierUser.getIdentifier(), false, "package verifier");
mContext.sendOrderedBroadcastAsUser(verification, verifierUser,
android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
//【7.1.6】当 mRequiredVerifierPackage 接收到广播后,会回调
// 该 BroadcastReceiver 的 onReceive 方法!
//【5.6】此时校验完成,这里会发送 CHECK_PENDING_VERIFICATION 给 PackageHandler
// 携带校验标识符
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, so null out this field.
*/
mArgs = null;
}
} else {
/*
* No package verification is enabled, so immediately start
* the remote call to initiate copy using temporary file.
*/
//【5.7】没有合适的校验器,那么会调用 InstallArgs 的 copyApk 方法
ret = args.copyApk(mContainerService, true);
}
}
mRet = ret;
}
5.1 DefaultContainerService.getMinimalPackageInfo
getMinimalPackageInfo 方法会解析 apk,返回 apk 的解析信息,同时判断空间状态
位置:"./frameworks/base/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java"
java
public PackageInfoLite getMinimalPackageInfo(String packagePath, int flags,
String abiOverride) {
final Context context = DefaultContainerService.this;
//【5.1.1】创建了一个 PackageInfoLite 实例
PackageInfoLite ret = new PackageInfoLite();
if (packagePath == null) {
Slog.i(TAG, "Invalid package file " + packagePath);
ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK; // 该 apk 无效
return ret;
}
final File packageFile = new File(packagePath);
final PackageParser.PackageLite pkg;
final long sizeBytes;
try {
//【2】解析 apk,获得其 PackageLite 对象,并计算安装所需空间
pkg = PackageParser.parsePackageLite(packageFile, 0);
sizeBytes = PackageHelper.calculateInstalledSize(pkg, abiOverride);
} catch (PackageParserException | IOException e) {
Slog.w(TAG, "Failed to parse package at " + packagePath + ": " + e);
if (!packageFile.exists()) {
ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_URI; // 该 apk 无效
} else {
ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK; // 该 apk 无效
}
return ret;
}
final int recommendedInstallLocation;
final long token = Binder.clearCallingIdentity();
try {
//【5.1.2】解析安装位置状态信息
recommendedInstallLocation = PackageHelper.resolveInstallLocation(context,
pkg.packageName, pkg.installLocation, sizeBytes, flags);
} finally {
Binder.restoreCallingIdentity(token);
}
//【3】将解析到的参数保存到 PackageInfoLite 中
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;
//【4】返回该 PackageInfoLite 实例
return ret;
}
5.1.1 new PackageInfoLite
PackageInfoLite 用来保存解析到的 apk 的一些信息
位置:./frameworks/base/core/java/android/content/pm/PackageInfoLite.java
java
public class PackageInfoLite implements Parcelable {
/**
* The name of this package. From the <manifest> tag's "name"
* attribute.
*/
public String packageName; // 应用包名
/** Names of any split APKs, ordered by parsed splitName */
public String[] splitNames; // split apk 的名字
/**
* The android:versionCode of the package.
* @deprecated Use {@link #getLongVersionCode()} instead, which includes both
* this and the additional
* {@link android.R.styleable#AndroidManifest_versionCode versionCodeMajor} attribute.
*/
@Deprecated
public int versionCode; // 版本号
/**
* @hide
* The android:versionCodeMajor of the package.
*/
public int versionCodeMajor;
/**
* Return {@link #versionCode} and {@link #versionCodeMajor} combined together as a
* single long value. The {@link #versionCodeMajor} is placed in the upper 32 bits.
*/
public long getLongVersionCode() {
return PackageInfo.composeLongVersionCode(versionCodeMajor, versionCode);
}
/** Revision code of base APK */
public int baseRevisionCode;
/** Revision codes of any split APKs, ordered by parsed splitName */
public int[] splitRevisionCodes;
/**
* The android:multiArch flag from the package manifest. If set,
* we will extract all native libraries for the given app, not just those
* from the preferred ABI.
*/
public boolean multiArch;
/**
* Specifies the recommended install location. Can be one of
* {@link PackageHelper#RECOMMEND_INSTALL_INTERNAL} to install on internal storage,
* {@link PackageHelper#RECOMMEND_INSTALL_EXTERNAL} to install on external media,
* {@link PackageHelper#RECOMMEND_FAILED_INSUFFICIENT_STORAGE} for storage errors,
* or {@link PackageHelper#RECOMMEND_FAILED_INVALID_APK} for parse errors.
*/
public int recommendedInstallLocation;
public int installLocation;
public VerifierInfo[] verifiers;
public PackageInfoLite() {
}
//...
}
这里的 recommendedInstallLocation 可以取下面四个值:
PackageHelper.RECOMMEND_INSTALL_INTERNAL // 内置
PackageHelper.RECOMMEND_INSTALL_EXTERNAL // 外置
PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE // 存储异常
PackageHelper.RECOMMEND_FAILED_INVALID_APK // apk解析异常
5.1.2 PackageHelper.resolveInstallLocation
resolveInstallLocation 方法用于计算一个合适的安装位置给 apk
java
@Deprecated
public static int resolveInstallLocation(Context context, String packageName,
int installLocation, long sizeBytes, int installFlags) {
final SessionParams params = new SessionParams(SessionParams.MODE_INVALID);
params.appPackageName = packageName;
params.installLocation = installLocation;
params.sizeBytes = sizeBytes;
params.installFlags = installFlags;
try {
return resolveInstallLocation(context, params);
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
/**
* Given a requested {@link PackageInfo#installLocation} and calculated
* install size, pick the actual location to install the app.
*/
public static int resolveInstallLocation(Context context, SessionParams params)
throws IOException {
//【1】如果该应用已经安装了,那么我们获得上一次安装后的信息
ApplicationInfo existingInfo = null;
try {
existingInfo = context.getPackageManager().getApplicationInfo(params.appPackageName,
PackageManager.MATCH_ANY_USER);
} catch (NameNotFoundException ignored) {
}
final int prefer;
final boolean checkBoth;
boolean ephemeral = false;
//【2】根据安装参数 installFlags,来选择合适的安装位置,按照优先级依次解析
if ((params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
//【2.1】如果指定了 PackageManager.INSTALL_EPHEMERAL,优先内置
prefer = RECOMMEND_INSTALL_INTERNAL;
ephemeral = true; // 表示短暂安装
checkBoth = false;
} else if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
//【2.2】如果指定了 PackageManager.INSTALL_INTERNAL,优先内置
prefer = RECOMMEND_INSTALL_INTERNAL;
checkBoth = false;
} else if ((params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
//【2.3】如果指定了 PackageManager.INSTALL_EXTERNAL,优先外置
prefer = RECOMMEND_INSTALL_EXTERNAL;
checkBoth = false;
} else if (params.installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) {
//【2.4】如果指定了 PackageManager.INSTALL_LOCATION_INTERNAL_ONLY,优先内置
prefer = RECOMMEND_INSTALL_INTERNAL;
checkBoth = false;
} else if (params.installLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL) {
//【2.5】如果指定了 PackageManager.INSTALL_LOCATION_PREFER_EXTERNAL,优先外置
prefer = RECOMMEND_INSTALL_EXTERNAL;
checkBoth = true;
} else if (params.installLocation == PackageInfo.INSTALL_LOCATION_AUTO) {
// When app is already installed, prefer same medium
//【2.6】如果指定了 PackageManager.INSTALL_LOCATION_AUTO,那么我们自动调整
if (existingInfo != null) {
// TODO: distinguish if this is external ASEC
//【2.6.1】如果之前已经安装过该应用,那么就和之前安装的位置保持一致
if ((existingInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
prefer = RECOMMEND_INSTALL_EXTERNAL;
} else {
prefer = RECOMMEND_INSTALL_INTERNAL;
}
} else {
//【2.6.2】否则,自动安装到内置
prefer = RECOMMEND_INSTALL_INTERNAL;
}
checkBoth = true;
} else {
//【2.7】其他情况,默认是内置
prefer = RECOMMEND_INSTALL_INTERNAL;
checkBoth = false;
}
//【3】再次校验内置和外置是否合适
boolean fitsOnInternal = false;
if (checkBoth || prefer == RECOMMEND_INSTALL_INTERNAL) {
fitsOnInternal = fitsOnInternal(context, params);
}
boolean fitsOnExternal = false;
if (checkBoth || prefer == RECOMMEND_INSTALL_EXTERNAL) {
fitsOnExternal = fitsOnExternal(context, params);
}
//【4】最后,返回合适的安装位置
if (prefer == RECOMMEND_INSTALL_INTERNAL) {
// The ephemeral case will either fit and return EPHEMERAL, or will not fit
// and will fall through to return INSUFFICIENT_STORAGE
//【4.1】如果优先安装到内置,且内置存储是合适的,根据是否是 ephemeral 返回不同的值
if (fitsOnInternal) {
return (ephemeral)
? PackageHelper.RECOMMEND_INSTALL_EPHEMERAL
: PackageHelper.RECOMMEND_INSTALL_INTERNAL;
}
} else if (prefer == RECOMMEND_INSTALL_EXTERNAL) {
//【4.2】如果优先安装到外置,且外置存储是合适的,返回结果
if (fitsOnExternal) {
return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
}
}
//【4.3】其他情况
if (checkBoth) {
if (fitsOnInternal) {
return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
} else if (fitsOnExternal) {
return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
}
}
//【5】异常情况,返回 PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE
return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
}
5.2 PackageManagerS.installLocationPolicy
PackageInfoLite pkgLite 保存了本次要安装的应用的信息
installLocationPolicy 方法会对降级安装和替换安装做一个校验和判断
java
private int installLocationPolicy(PackageInfoLite pkgLite) {
String packageName = pkgLite.packageName;
int installLocation = pkgLite.installLocation;
boolean onSd = (installFlags & PackageManager.INSTALL_EXTERNAL) != 0;
// reader
synchronized (mPackages) {
// Currently installed package which the new package is attempting to replace or
// null if no such package is installed. //【1】如果该应用已经安装过的话,那就获得上次安装后的解析信息
PackageParser.Package installedPkg = mPackages.get(packageName);
// Package which currently owns the data which the new package will own if installed.
// If an app is unstalled while keeping data (e.g., adb uninstall -k), installedPkg
// will be null whereas dataOwnerPkg will contain information about the package
// which was uninstalled while keeping its data.
// 下面这段代码主要是处理卸载但是保留了数据的情况,比如 adb uninstall -k
PackageParser.Package dataOwnerPkg = installedPkg;
if (dataOwnerPkg == null) {
PackageSetting ps = mSettings.mPackages.get(packageName);
if (ps != null) {
dataOwnerPkg = ps.pkg;
}
}
//【2】如果 dataOwnerPkg 不为 nulkl,说明之前已经安装了
if (dataOwnerPkg != null) {
// If installed, the package will get access to data left on the device by its
// predecessor. As a security measure, this is permited only if this is not a
// version downgrade or if the predecessor package is marked as debuggable and
// a downgrade is explicitly requested.
//
// On debuggable platform builds, downgrades are permitted even for
// non-debuggable packages to make testing easier. Debuggable platform builds do
// not offer security guarantees and thus it's OK to disable some security
// mechanisms to make debugging/testing easier on those builds. However, even on
// debuggable builds downgrades of packages are permitted only if requested via
// installFlags. This is because we aim to keep the behavior of debuggable
// platform builds as close as possible to the behavior of non-debuggable
// platform builds.
//【2.1】如果安装标志位设置了 INSTALL_ALLOW_DOWNGRADE,表示允许降级安装
final boolean downgradeRequested =
(installFlags & PackageManager.INSTALL_ALLOW_DOWNGRADE) != 0;
//【2.2】判断应用是否允许 debug
final boolean packageDebuggable =
(dataOwnerPkg.applicationInfo.flags
& ApplicationInfo.FLAG_DEBUGGABLE) != 0;
//【2.3】如果要能够降级安装,必须满足 2 个条件:1、安装标志位设置了 allow downgrade
// 2、系统允许 debug 或者该应用可以 debug
final boolean downgradePermitted =
(downgradeRequested) && ((Build.IS_DEBUGGABLE) || (packageDebuggable));
if (!downgradePermitted) {
try {
//【5.2.1】如果,安装不允许降级,那就需要做检查
checkDowngrade(dataOwnerPkg, pkgLite);
} catch (PackageManagerException e) {
Slog.w(TAG, "Downgrade detected: " + e.getMessage());
return PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE;
}
}
}
//【3】接着处理覆盖安装的情况,即相同包名的应用已经存在
if (installedPkg != null) {
//【3.1】覆盖安装的情况,必须携带 PackageManager.INSTALL_REPLACE_EXISTING 安装标志位
if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
// Check for updated system application.
if ((installedPkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
//【3.1.1】对于系统应用,不能覆盖安装到 sd 卡上
if (onSd) {
Slog.w(TAG, "Cannot install update to system app on sdcard");
return PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION;
}
return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
} else {
//【3.1.2】对于非系统应用,如果是安装到 sdcard,直接返回对应值
if (onSd) {
// Install flag overrides everything.
return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
}
// If current upgrade specifies particular preference
//【3.1.2】对于非系统应用,如果只安装到内置,直接返回对应值
if (installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) {
// Application explicitly specified internal.
return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
} else if (installLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL) {
// App explictly prefers external. Let policy decide
//【3.1.3】对于非系统应用,如果优先安装到外置,那么安装位置由
// pkgLite.recommendedInstallLocation 决定
} else {
// Prefer previous location //【3.1.4】对于非系统应用,其他情况进入这里
if (isExternal(installedPkg)) {
return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
}
return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
}
}
} else {
// Invalid install. Return error code //【3.2】异常情况
return PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS;
}
}
}
// All the special cases have been taken care of.
// Return result based on recommended install location.
//【4】如果上面的条件都不满足,并且指定了在 sdcard,那么就返回 RECOMMEND_INSTALL_EXTERNAL
if (onSd) {
return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
}
//【5】其他情况,均由 pkgLite.recommendedInstallLocation 决定
return pkgLite.recommendedInstallLocation;
}
5.3 PackageManagerS.createInstallArgs
其实就是针对不同的安装方式,创建不同的 InstallArgs
java
private InstallArgs createInstallArgs(InstallParams params) {
if (params.move != null) {
//【1】如果是 move package,那么会创建 MoveInstallArgs 实例
return new MoveInstallArgs(params);
} else {
//【5.3.1】对于一般安装,创建 FileInstallArgs 实例
return new FileInstallArgs(params);
}
}
这里我们先关注一般情况,即创建 FileInstallArgs 实例的情况
5.3.1 new FileInstallArgs - 要安装的 apk
java
class FileInstallArgs extends InstallArgs {
private File codeFile;
private File resourceFile;
// Example topology:
// /data/app/com.example/base.apk
// /data/app/com.example/split_foo.apk
// /data/app/com.example/lib/arm/libfoo.so
// /data/app/com.example/lib/arm64/libfoo.so
// /data/app/com.example/dalvik/arm/base.apk@classes.dex
/** New install */ //【1】安装一个新的 apk
FileInstallArgs(InstallParams params) {
super(params.origin, params.move, params.observer, params.installFlags,
params.installerPackageName, params.volumeUuid,
params.getUser(), null /*instructionSets*/, params.packageAbiOverride,
params.grantedRuntimePermissions,
params.traceMethod, params.traceCookie, params.signingDetails,
params.installReason);
//【1.1】这里校验了下是否是 Forward Locked 的
if (isFwdLocked()) {
throw new IllegalArgumentException("Forward locking only supported in ASEC");
}
}
/** Existing install */ //【2】用于描述已存在的一个安装
FileInstallArgs(String codePath, String resourcePath, String[] instructionSets) {
super(OriginInfo.fromNothing(), null, null, 0, null, null, null, instructionSets,
null, null, null, 0, PackageParser.SigningDetails.UNKNOWN,
PackageManager.INSTALL_REASON_UNKNOWN);
this.codeFile = (codePath != null) ? new File(codePath) : null;
this.resourceFile = (resourcePath != null) ? new File(resourcePath) : null;
}
//...
}
我们看到 FileInstallArgs 有两个构造器
- 一参数构造器用于创建安装过程中的 InstallArgs
- 三参数构造器,用于描述一个已存在的安装,主要用于清除旧的安装,或者作为移动应用的时候的源数据,我们在 pms 开机初始化的过程中就已经看到过了
当然,这里我们重点关注安装过程
5.4 PackageManagerService.isVerificationEnabled
isVerificationEnabled 用于校验系统是否打开了校验功能
java
private boolean isVerificationEnabled(int userId, int installFlags, int installerUid) {
if (!DEFAULT_VERIFY_ENABLE) { //【1】如果默认没有打开校验,false
return false;
}
//【3】判断该用户下是否允许校验应用
boolean ensureVerifyAppsEnabled = isUserRestricted(userId, UserManager.ENSURE_VERIFY_APPS);
// Check if installing from ADB //【4】如果安装指定了 INSTALL_FROM_ADB,进入这里
if ((installFlags & PackageManager.INSTALL_FROM_ADB) != 0) {
// Do not run verification in a test harness environment //【4.1】test harness environment 不校验
if (ActivityManager.isRunningInTestHarness()) {
return false;
}
//【4.2】如果同时该用户下能校验应用,返回 true
if (ensureVerifyAppsEnabled) {
return true;
}
// Check if the developer does not want package verification for ADB installs
//【4.3】对于 adb install,如果系统属性 PACKAGE_VERIFIER_INCLUDE_ADB 为 0 ,那就不用校验
if (android.provider.Settings.Global.getInt(mContext.getContentResolver(),
android.provider.Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, 1) == 0) {
return false;
}
} else { //【2】如果不是INSTALL_FROM_ADB方式的安装,不校验,false
// only when not installed from ADB, skip verification for instant apps when
// the installer and verifier are the same.
if ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
if (mInstantAppInstallerActivity != null
&& mInstantAppInstallerActivity.packageName.equals(
mRequiredVerifierPackage)) {
try {
mContext.getSystemService(AppOpsManager.class)
.checkPackage(installerUid, mRequiredVerifierPackage);
if (DEBUG_VERIFY) {
Slog.i(TAG, "disable verification for instant app");
}
return false;
} catch (SecurityException ignore) { }
}
}
}
//【5】如果该用户下能校验应用,返回 true
if (ensureVerifyAppsEnabled) {
return true;
}
//【6】判断系统属性 PACKAGE_VERIFIER_ENABLE 如果为 0,那就不用校验
return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
android.provider.Settings.Global.PACKAGE_VERIFIER_ENABLE, 1) == 1;
}
5.5 new PackageVerificationState
PackageVerificationState 用于保存被安装的应用的校验状态信息:
java
class PackageVerificationState {
private final InstallArgs mArgs; // InstallArgs 实例
private final SparseBooleanArray mSufficientVerifierUids;
private final int mRequiredVerifierUid; // 校验者的 uid
private boolean mSufficientVerificationComplete;
private boolean mSufficientVerificationPassed;
private boolean mRequiredVerificationComplete;
private boolean mRequiredVerificationPassed;
private boolean mExtendedTimeout;
/**
* Create a new package verification state where {@code requiredVerifierUid}
* is the user ID for the package that must reply affirmative before things
* can continue.
*
* @param requiredVerifierUid user ID of required package verifier
* @param args
*/
public PackageVerificationState(int requiredVerifierUid, InstallArgs args) {
mRequiredVerifierUid = requiredVerifierUid;
mArgs = args;
mSufficientVerifierUids = new SparseBooleanArray();
mExtendedTimeout = false; // 表示是否超时
}
}
六、PackageHandler.doHandleMessage[CHECK_PENDING_VERIFICATION] - 校验完成
java
case CHECK_PENDING_VERIFICATION: {
//【1】获得校验唯一标识
final int verificationId = msg.arg1;
//【2】获得本次校验的 PackageVerificationState 实例
final PackageVerificationState state = mPendingVerification.get(verificationId);
if ((state != null) && !state.timeoutExtended()) {
//【3】获得 InstallArgs 实例
final InstallArgs args = state.getInstallArgs();
final Uri originUri = Uri.fromFile(args.origin.resolvedFile);
Slog.i(TAG, "Verification timed out for " + originUri);
//【4】从 mPendingVerification 中移除校验状态对象
mPendingVerification.remove(verificationId);
int ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
final UserHandle user = args.getUser();
//【5】处理校验结果
if (getDefaultVerificationResponse(user)
== PackageManager.VERIFICATION_ALLOW) {
//【5.1】校验成功
Slog.i(TAG, "Continuing with installation of " + originUri);
state.setVerifierResponse(Binder.getCallingUid(),
PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT);
//【5.6.1】发送 Intent.ACTION_PACKAGE_VERIFIED 广播
broadcastPackageVerified(verificationId, originUri,
PackageManager.VERIFICATION_ALLOW, user);
try {
//【5.6.2】校验成功后,调用 installArgs.copyApk 继续处理
ret = args.copyApk(mContainerService, true);
} catch (RemoteException e) {
Slog.e(TAG, "Could not contact the ContainerService");
}
} else {
//【5.6.1】校验失败,发送 Intent.ACTION_PACKAGE_VERIFIED 广播
broadcastPackageVerified(verificationId, originUri,
PackageManager.VERIFICATION_REJECT, user);
}
Trace.asyncTraceEnd(
TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
//【5.7】继续安装
processPendingInstall(args, ret);
// 安装过程结束,发送 MCS_UNBIND 消息
mHandler.sendEmptyMessage(MCS_UNBIND);
}
Slog.d(TAG, "Tuo CHECK_PENDING_VERIFICATION end");
break;
}
这里我们通过 getDefaultVerificationResponse 方法返回校验结果:
java
/**
* Get the default verification agent response code.
*
* @return default verification response code
*/
private int getDefaultVerificationResponse(UserHandle user) {
if (sUserManager.hasUserRestriction(UserManager.ENSURE_VERIFY_APPS, user.getIdentifier())) {
return PackageManager.VERIFICATION_REJECT;
}
return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
android.provider.Settings.Global.PACKAGE_VERIFIER_DEFAULT_RESPONSE,
DEFAULT_VERIFICATION_RESPONSE);
}
默认返回的是 PackageManager.VERIFICATION_ALLOW,比如在校验超时的情况下
6.1 PackageManagerS.broadcastPackageVerified
java
private void broadcastPackageVerified(int verificationId, Uri packageUri,
int verificationCode, UserHandle user) {
final Intent intent = new Intent(Intent.ACTION_PACKAGE_VERIFIED);
intent.setDataAndType(packageUri, PACKAGE_MIME_TYPE);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId);
intent.putExtra(PackageManager.EXTRA_VERIFICATION_RESULT, verificationCode);
mContext.sendBroadcastAsUser(intent, user,
android.Manifest.permission.PACKAGE_VERIFICATION_AGENT);
}
6.2 FileInstallArgs.(do)copyApk
java
int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk");
try {
return doCopyApk(imcs, temp);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
copyApk 调用了 doCopyApk 方法:
java
private int doCopyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
//【1】如果 origin.staged 为 true,那么说明应用已经 copy 到目标目录了,
// 那就直接返回 PackageManager.INSTALL_SUCCEEDED
if (origin.staged) {
if (DEBUG_INSTALL) Slog.d(TAG, origin.file + " already staged; skipping copy");
//【1.1】设置 FileInstallArgs 的 codeFile 属性
codeFile = origin.file;
resourceFile = origin.file;
return PackageManager.INSTALL_SUCCEEDED;
}
//【2】如果 origin.staged 为 false,说明应用没有拷贝到目标目录
try {
final boolean isEphemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
//【5.6.2.1】获得要拷贝的目标目录
final File tempDir =
mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral);
codeFile = tempDir;
resourceFile = tempDir;
} catch (IOException e) {
Slog.w(TAG, "Failed to create copy file: " + e);
return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
}
//【3】回调接口
final IParcelFileDescriptorFactory target = new IParcelFileDescriptorFactory.Stub() {
@Override
public ParcelFileDescriptor open(String name, int mode) throws RemoteException {
if (!FileUtils.isValidExtFilename(name)) {
throw new IllegalArgumentException("Invalid filename: " + name);
}
try {
//【3.1】访问 codeFile 目录下的 name 文件,设置权限,并返回其文件描述符
final File file = new File(codeFile, name);
final FileDescriptor fd = Os.open(file.getAbsolutePath(),
O_RDWR | O_CREAT, 0644);
Os.chmod(file.getAbsolutePath(), 0644);
return new ParcelFileDescriptor(fd);
} catch (ErrnoException e) {
throw new RemoteException("Failed to open: " + e.getMessage());
}
}
};
int ret = PackageManager.INSTALL_SUCCEEDED;
//【6.2.2】将应用程序拷贝到目标目录
ret = imcs.copyPackage(origin.file.getAbsolutePath(), target);
if (ret != PackageManager.INSTALL_SUCCEEDED) {
Slog.e(TAG, "Failed to copy package");
return ret;
}
//【4】解压本地 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);
} catch (IOException e) {
Slog.e(TAG, "Copying native libraries failed", e);
ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
} finally {
IoUtils.closeQuietly(handle);
}
return ret;
}
根据前面创建 OriginInfo 时知道:
java
if (stagedDir != null) {
origin = OriginInfo.fromStagedFile(stagedDir);
} else {
origin = OriginInfo.fromStagedContainer(stagedCid);
}
通过 adb 安装时,安装到内置存储,会调用 OriginInfo.fromStagedFile 方法,此时 OriginInfo.staged 为 true,安装到外置存储时, OriginInfo.staged 也会为 true
这是因为在进行 adb install 过程中时,我们通过 Session,已经拷贝到目标目录了:/data/app/vml[sessionId].tmp/,所以这里 doCopyApk 无需在继续进行下去
对于其他的安装方式,OriginInfo.staged 为 false 的,那么会进入 doCopyApk 的下一步
6.2.1 PackageInstallerService.allocateStageDirLegacy
java
@Deprecated
public File allocateStageDirLegacy(String volumeUuid, boolean isEphemeral) throws IOException {
synchronized (mSessions) {
try {
//【3.1.2】分配一个 sessionId,保存到 mLegacySessions 中
final int sessionId = allocateSessionIdLocked();
mLegacySessions.put(sessionId, true);
//【3.1.2】创建目标目录
final File stageDir = buildStageDir(volumeUuid, sessionId, isEphemeral);
//【2】创建目录,设置权限
prepareStageDir(stageDir);
return stageDir;
} catch (IllegalStateException e) {
throw new IOException(e);
}
}
}
6.2.2 DefaultContainerService.copyPackage(Inner)
java
public int copyPackage(String packagePath, IParcelFileDescriptorFactory target) {
if (packagePath == null || target == null) {
return PackageManager.INSTALL_FAILED_INVALID_URI;
}
PackageLite pkg = null;
try {
final File packageFile = new File(packagePath);
//【1】解析应用
pkg = PackageParser.parsePackageLite(packageFile, 0);
//【2】继续处理 copyPackageInner
return copyPackageInner(pkg, target);
} catch (PackageParserException | IOException | RemoteException e) {
Slog.w(TAG, "Failed to copy package at " + packagePath + ": " + e);
return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
}
}
private int copyPackageInner(PackageLite pkg, IParcelFileDescriptorFactory target)
throws IOException, RemoteException {
//【1】对 base apk 和 split apk 分别执行 copy
copyFile(pkg.baseCodePath, target, "base.apk");
if (!ArrayUtils.isEmpty(pkg.splitNames)) {
for (int i = 0; i < pkg.splitNames.length; i++) {
copyFile(pkg.splitCodePaths[i], target, "split_" + pkg.splitNames[i] + ".apk");
}
}
return PackageManager.INSTALL_SUCCEEDED;
}
//最终,调用了 copyFile 执行 copy
private void copyFile(String sourcePath, IParcelFileDescriptorFactory target, String targetName)
throws IOException, RemoteException {
Slog.d(TAG, "Copying " + sourcePath + " to " + targetName);
InputStream in = null;
OutputStream out = null;
try {
in = new FileInputStream(sourcePath);
out = new ParcelFileDescriptor.AutoCloseOutputStream(
target.open(targetName, ParcelFileDescriptor.MODE_READ_WRITE));
FileUtils.copy(in, out);
} finally {
IoUtils.closeQuietly(out);
IoUtils.closeQuietly(in);
}
}
七、PackageManagerS.processPendingInstall
processPendingInstall 用于继续安装:
java
private void processPendingInstall(final InstallArgs args, final int currentStatus) {
// Queue up an async operation since the package installation may take a little while.
mHandler.post(new Runnable() {
public void run() {
mHandler.removeCallbacks(this);
// Result object to be returned
//【5.7.1】创建 PackageInstalledInfo 实例,封装安装结果
PackageInstalledInfo res = new PackageInstalledInfo();
res.setReturnCode(currentStatus); // 保存当前的返回码
res.uid = -1;
res.pkg = null;
res.removedInfo = null;
//【1】如果返回码为 PackageManager.INSTALL_SUCCEEDED
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
//【×5.7.2】安装前处理
args.doPreInstall(res.returnCode);
synchronized (mInstallLock) {
//【×5.7.3】执行安装
installPackageTracedLI(args, res);
}
//【×5.7.4】安装后处理
args.doPostInstall(res.returnCode, res.uid);
}
// A restore should be performed at this point if (a) the install
// succeeded, (b) the operation is not an update, and (c) the new
// package has not opted out of backup participation.
//【2】判断是否执行备份,要备份必须满足 3 个条件
// 1、安装正常;2、本次安装并不是更新操作!3、应用允许备份
final boolean update = res.removedInfo != null
&& res.removedInfo.removedPackage != null;
final int flags = (res.pkg == null) ? 0 : res.pkg.applicationInfo.flags;
boolean doRestore = !update
&& ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0);
// Set up the post-install work request bookkeeping. This will be used
// and cleaned up by the post-install event handling regardless of whether
// there's a restore pass performed. Token values are >= 1.
//【3】计算本次安装的 token
int token;
if (mNextInstallToken < 0) mNextInstallToken = 1;
token = mNextInstallToken++;
//【*5.7.5】创建一个 PostInstallData 对象,并将其加入 mRunningInstalls 中
PostInstallData data = new PostInstallData(args, res);
mRunningInstalls.put(token, data);
if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token);
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {
// Pass responsibility to the Backup Manager. It will perform a
// restore if appropriate, then pass responsibility back to the
// Package Manager to run the post-install observer callbacks
// and broadcasts.
//【4】如果安装成功,并且需要备份,那就获得 BackupManager 执行备份
IBackupManager bm = IBackupManager.Stub.asInterface(
ServiceManager.getService(Context.BACKUP_SERVICE));
if (bm != null) {
if (DEBUG_INSTALL) Log.v(TAG, "token " + token
+ " to BM for possible restore");
Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
try {
// TODO: http://b/22388012
if (bm.isBackupServiceActive(UserHandle.USER_SYSTEM)) {
bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token);
} else {
doRestore = false;
}
} catch (RemoteException e) {
// can't happen; the backup manager is local
} catch (Exception e) {
Slog.e(TAG, "Exception trying to enqueue restore", e);
doRestore = false;
}
} else {
Slog.e(TAG, "Backup Manager not found!");
doRestore = false;
}
}
//【5】如果备份失败或者不需要备份,那就进入这个阶段
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);
Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
mHandler.sendMessage(msg);
}
}
});
}
7.1 new PackageInstalledInfo
PackageInstalledInfo 用于保存该应用的安装结果信息
java
static class PackageInstalledInfo {
String name;
int uid;
// The set of users that originally had this package installed.
int[] origUsers; // 该 pacakge 之前安装后所属的 user
// The set of users that now have this package installed.
int[] newUsers; // 该 pacakge 现在安装后所属的 user
PackageParser.Package pkg;
int returnCode; // 返回码
String returnMsg;
String installerPackageName;
PackageRemovedInfo removedInfo; //【7.1.1】用于封装要移除的 apk 的信息
ArrayMap<String, PackageInstalledInfo> addedChildPackages; // split apk 的安装结果信息
//...
// In some error cases we want to convey more info back to the observer
String origPackage;
String origPermission;
}
7.1.1 new PackageRemovedInfo
封装要移除的 apk 的信息:
java
static class PackageRemovedInfo {
final PackageSender packageSender;
String removedPackage;
String installerPackageName;
int uid = -1;
int removedAppId = -1;
int[] origUsers;
int[] removedUsers = null;
int[] broadcastUsers = null;
int[] instantUserIds = null;
SparseArray<Integer> installReasons;
boolean isRemovedPackageSystemUpdate = false;
boolean isUpdate;
boolean dataRemoved;
boolean removedForAllUsers;
boolean isStaticSharedLib;
// Clean up resources deleted packages. //【1】InstallArgs 用于清除 apk 的相关数据,后面会看到
InstallArgs args = null;
ArrayMap<String, PackageRemovedInfo> removedChildPackages;
ArrayMap<String, PackageInstalledInfo> appearedChildPackages;
//...
}
7.2 FileInstallArgs.doPreInstall
安装前执行清理操作,正常情况不会触发
java
int doPreInstall(int status) {
//【1】如果安装前的状态不是 PackageManager.INSTALL_SUCCEEDED
if (status != PackageManager.INSTALL_SUCCEEDED) {
//【5.7.2.1】执行清理操作
cleanUp();
}
return status;
}
7.2.1 FileInstallArgs.cleanUp(ResourcesLI)
清理操作
java
private boolean cleanUp() {
if (codeFile == null || !codeFile.exists()) {
return false;
}
//【1】删除目标目录下的所有文件
removeCodePathLI(codeFile);
if (resourceFile != null && !FileUtils.contains(codeFile, resourceFile)) {
resourceFile.delete();
}
return true;
}
//可以看到,最后调用了 removeCodePathLI 方法
void removeCodePathLI(File codePath) {
if (codePath.isDirectory()) {
try {
mInstaller.rmPackageDir(codePath.getAbsolutePath());
} catch (InstallerException e) {
Slog.w(TAG, "Failed to remove code path", e);
}
} else {
codePath.delete();
}
}
7.3 PackageManagerS.installPackageTracedLI - 核心安装入口
java
private void installPackageTracedLI(InstallArgs args, PackageInstalledInfo res) {
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackage");
//【1】调用了 installPackageLI 方法
installPackageLI(args, res);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
//这里调用了 installPackageLI 方法:
private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
//【1】获得安装时传入的参数和标志位
final int installFlags = args.installFlags;
final String installerPackageName = args.installerPackageName;
final String volumeUuid = args.volumeUuid;
final File tmpPackageFile = new File(args.getCodePath());
final boolean forwardLocked = ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);
final boolean onExternal = (((installFlags & PackageManager.INSTALL_EXTERNAL) != 0)
|| (args.volumeUuid != null));
final boolean instantApp = ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0);
final boolean fullApp = ((installFlags & PackageManager.INSTALL_FULL_APP) != 0);
final boolean forceSdk = ((installFlags & PackageManager.INSTALL_FORCE_SDK) != 0);
final boolean virtualPreload =
((installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
boolean replace = false;
//【2】重新设置扫描参数
@ScanFlags int scanFlags = SCAN_NEW_INSTALL | SCAN_UPDATE_SIGNATURE;
if (args.move != null) {
// moving a complete application; perform an initial scan on the new install location
//【2.1】如果 args.move 不为 null,表示正在移动一个 app,我们会对其进行一个初始化的扫描
// 增加 SCAN_INITIAL 位
scanFlags |= SCAN_INITIAL;
}
if ((installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) {
//【2.2】如果安装参数指定了 INSTALL_DONT_KILL_APP,那么增加 SCAN_DONT_KILL_APP 位
scanFlags |= SCAN_DONT_KILL_APP;
}
if (instantApp) {
scanFlags |= SCAN_AS_INSTANT_APP;
}
if (fullApp) {
scanFlags |= SCAN_AS_FULL_APP;
}
if (virtualPreload) {
scanFlags |= SCAN_AS_VIRTUAL_PRELOAD;
}
// Result object to be returned //【3】更新结果码
res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
res.installerPackageName = installerPackageName;
if (DEBUG_INSTALL) Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile);
// Sanity check //【4】检查 instantApp 是否和 forwardLocked/onExternal 共存,共存则报错
if (instantApp && (forwardLocked || onExternal)) {
Slog.i(TAG, "Incompatible ephemeral install; fwdLocked=" + forwardLocked
+ " external=" + onExternal);
res.setReturnCode(PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
return;
}
// Retrieve PackageSettings and parse package //【5】设置解析参数 parseFlags
@ParseFlags final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
| PackageParser.PARSE_ENFORCE_CODE
| (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0)
| (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0)
| (forceSdk ? PackageParser.PARSE_FORCE_SDK : 0);
PackageParser pp = new PackageParser(); //【6】创建解析对象
pp.setSeparateProcesses(mSeparateProcesses);
pp.setDisplayMetrics(mMetrics);
pp.setCallback(mPackageParserCallback);
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
final PackageParser.Package pkg;
try {
//【*7.3.1】解析 apk,获得其对应的 Package 对象
pkg = pp.parsePackage(tmpPackageFile, parseFlags);
DexMetadataHelper.validatePackageDexMetadata(pkg);
} catch (PackageParserException e) {
res.setError("Failed parse during installPackageLI", e);
return;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
// Instant apps have several additional install-time checks.
if (instantApp) {
if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.O) {
Slog.w(TAG,
"Instant app package " + pkg.packageName + " does not target at least O");
res.setError(INSTALL_FAILED_INSTANT_APP_INVALID,
"Instant app package must target at least O");
return;
}
if (pkg.applicationInfo.targetSandboxVersion != 2) {
Slog.w(TAG, "Instant app package " + pkg.packageName
+ " does not target targetSandboxVersion 2");
res.setError(INSTALL_FAILED_INSTANT_APP_INVALID,
"Instant app package must use targetSandboxVersion 2");
return;
}
if (pkg.mSharedUserId != null) {
Slog.w(TAG, "Instant app package " + pkg.packageName
+ " may not declare sharedUserId.");
res.setError(INSTALL_FAILED_INSTANT_APP_INVALID,
"Instant app package may not declare a sharedUserId");
return;
}
}
if (pkg.applicationInfo.isStaticSharedLibrary()) {
// Static shared libraries have synthetic package names
renameStaticSharedLibraryPackage(pkg);
// No static shared libs on external storage
if (onExternal) {
Slog.i(TAG, "Static shared libs can only be installed on internal storage.");
res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
"Packages declaring static-shared libs cannot be updated");
return;
}
}
// If we are installing a clustered package add results for the children
//【7】如果该应用有子包的话,那么对于每个子包,也会创建安装结果对象
if (pkg.childPackages != null) {
synchronized (mPackages) {
final int childCount = pkg.childPackages.size();
for (int i = 0; i < childCount; i++) {
PackageParser.Package childPkg = pkg.childPackages.get(i);
//【*5.7.1】针对子包,创建 PackageInstalledInfo 对象!
// 设置返回码,子包包名
PackageInstalledInfo childRes = new PackageInstalledInfo();
childRes.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
childRes.pkg = childPkg;
childRes.name = childPkg.packageName;
//【7.1】获得子包的源 user
PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
if (childPs != null) {
childRes.origUsers = childPs.queryInstalledUsers(
sUserManager.getUserIds(), true);
}
//【7.2】如果子包之前被扫描到了(安装过),创建 PackageRemovedInfo 对象
if ((mPackages.containsKey(childPkg.packageName))) {
childRes.removedInfo = new PackageRemovedInfo(this);
childRes.removedInfo.removedPackage = childPkg.packageName;
childRes.removedInfo.installerPackageName = childPs.installerPackageName;
}
if (res.addedChildPackages == null) {
res.addedChildPackages = new ArrayMap<>();
}
//【7.3】将子包的安装结果对象保存到 base apk 的信息中
res.addedChildPackages.put(childPkg.packageName, childRes);
}
}
}
// If package doesn't declare API override, mark that we have an install
// time CPU ABI override. // 如果应用没有指定 abi,我们通过安装参数指定
if (TextUtils.isEmpty(pkg.cpuAbiOverride)) {
pkg.cpuAbiOverride = args.abiOverride;
}
// 如果应用指定了 ApplicationInfo.FLAG_TEST_ONLY,那么安装参数也需要指定这个参数
String pkgName = res.name = pkg.packageName;
if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) {
if ((installFlags & PackageManager.INSTALL_ALLOW_TEST) == 0) {
res.setError(INSTALL_FAILED_TEST_ONLY, "installPackageLI");
return;
}
}
try {
//【8】收集证书信息
// either use what we've been given or parse directly from the APK
if (args.signingDetails != PackageParser.SigningDetails.UNKNOWN) {
pkg.setSigningDetails(args.signingDetails);
} else {
PackageParser.collectCertificates(pkg, false /* skipVerify */);
}
} catch (PackageParserException e) {
res.setError("Failed collect during installPackageLI", e);
return;
}
if (instantApp && pkg.mSigningDetails.signatureSchemeVersion
< SignatureSchemeVersion.SIGNING_BLOCK_V2) {
Slog.w(TAG, "Instant app package " + pkg.packageName
+ " is not signed with at least APK Signature Scheme v2");
res.setError(INSTALL_FAILED_INSTANT_APP_INVALID,
"Instant app package must be signed with APK Signature Scheme v2 or greater");
return;
}
// Get rid of all references to package scan path via parser.
pp = null;
String oldCodePath = null;
boolean systemApp = false;
synchronized (mPackages) {
// Check if installing already existing package
//【9】如果安装参数指定了 INSTALL_REPLACE_EXISTING,那么我们要尝试判断是否存在已安装的应用!
// 如果存在,那就要 replace
if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
String oldName = mSettings.getRenamedPackageLPr(pkgName); // 判断该应用是否重命名过
if (pkg.mOriginalPackages != null
&& pkg.mOriginalPackages.contains(oldName)
&& mPackages.containsKey(oldName)) {
// This package is derived from an original package,
// and this device has been updating from that original
// name. We must continue using the original name, so
// rename the new package here.
//【9.1】如果有源包(系统应用才会有),要命名为源包,replace 为 true
pkg.setPackageName(oldName);
pkgName = pkg.packageName;
replace = true;
if (DEBUG_INSTALL) Slog.d(TAG, "Replacing existing renamed package: oldName="
+ oldName + " pkgName=" + pkgName);
} else if (mPackages.containsKey(pkgName)) {
// This package, under its official name, already exists
// on the device; we should replace it.
//【9.2】如果没有源包(系统应用才会有),但是已经有相同包名的应用存在,replace 为 true
replace = true;
if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing pacakge: " + pkgName);
}
// Child packages are installed through the parent package
//【9.2】对于子包,只能通过父包更新,这里不处理子包的 replace
if (pkg.parentPackage != null) {
res.setError(PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
"Package " + pkg.packageName + " is child of package "
+ pkg.parentPackage.parentPackage + ". Child packages "
+ "can be updated only through the parent package.");
return;
}
//【9.3】如果需要替换已存在的 apk,那么需要做 sdk 的校验!
// 如果旧应用支持运行时,不允许新的应用不支持运行时
if (replace) {
// Prevent apps opting out from runtime permissions
PackageParser.Package oldPackage = mPackages.get(pkgName);
final int oldTargetSdk = oldPackage.applicationInfo.targetSdkVersion;
final int newTargetSdk = pkg.applicationInfo.targetSdkVersion;
if (oldTargetSdk > Build.VERSION_CODES.LOLLIPOP_MR1
&& newTargetSdk <= Build.VERSION_CODES.LOLLIPOP_MR1) {
res.setError(PackageManager.INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE,
"Package " + pkg.packageName + " new target SDK " + newTargetSdk
+ " doesn't support runtime permissions but the old"
+ " target SDK " + oldTargetSdk + " does.");
return;
}
// Prevent persistent apps from being updated //【9.4】如果旧包也是子包,也不安装
if ((oldPackage.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0) {
res.setError(PackageManager.INSTALL_FAILED_INVALID_APK,
"Package " + oldPackage.packageName + " is a persistent app. "
+ "Persistent apps are not updateable.");
return;
}
// Prevent installing of child packages
//【9.4】如果旧包也是子包,也不安装
if (oldPackage.parentPackage != null) {
res.setError(PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
"Package " + pkg.packageName + " is child of package "
+ oldPackage.parentPackage + ". Child packages "
+ "can be updated only through the parent package.");
return;
}
}
}
//【10】获得上一次的安装数据
PackageSetting ps = mSettings.mPackages.get(pkgName);
if (ps != null) {
if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps);
// Static shared libs have same package with different versions where
// we internally use a synthetic package name to allow multiple versions
// of the same package, therefore we need to compare signatures against
// the package setting for the latest library version.
PackageSetting signatureCheckPs = ps;
if (pkg.applicationInfo.isStaticSharedLibrary()) {
SharedLibraryEntry libraryEntry = getLatestSharedLibraVersionLPr(pkg);
if (libraryEntry != null) {
signatureCheckPs = mSettings.getPackageLPr(libraryEntry.apk);
}
}
// Quick sanity check that we're signed correctly if updating;
// we'll check this again later when scanning, but we want to
// bail early here before tripping over redefined permissions.
//【10.1】如果安装过旧版本,那就要校验签名!
//【×3.7.2】shouldCheckUpgradeKeySetLP 用于判断是否检查签名更新;
final KeySetManagerService ksms = mSettings.mKeySetManagerService;
if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) {
//【×3.7.3】checkUpgradeKeySetLP 用于检查签名更新;
if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, pkg)) {
res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
+ pkg.packageName + " upgrade keys do not match the "
+ "previously installed version");
return;
}
} else {
try {
final boolean compareCompat = isCompatSignatureUpdateNeeded(pkg);
final boolean compareRecover = isRecoverSignatureUpdateNeeded(pkg);
// We don't care about disabledPkgSetting on install for now.
//【×3.7.4】校验签名,如果签名不相等,那就禁止安装
final boolean compatMatch = verifySignatures(
signatureCheckPs, null, pkg.mSigningDetails, compareCompat,
compareRecover);
// The new KeySets will be re-added later in the scanning process.
if (compatMatch) {
synchronized (mPackages) {
ksms.removeAppKeySetDataLPw(pkg.packageName);
}
}
} catch (PackageManagerException e) {
res.setError(e.error, e.getMessage());
return;
}
}
//【10.2】获得旧的 apk 的路径,判断旧应用是否是系统应用
oldCodePath = mSettings.mPackages.get(pkgName).codePathString;
if (ps.pkg != null && ps.pkg.applicationInfo != null) {
systemApp = (ps.pkg.applicationInfo.flags &
ApplicationInfo.FLAG_SYSTEM) != 0;
}
res.origUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
}
//【11】检查权限是否被重新定义,如果重新定义,那就要校验权限
int N = pkg.permissions.size();
for (int i = N-1; i >= 0; i--) {
//【11.1】获得该应用定义的权限
final PackageParser.Permission perm = pkg.permissions.get(i);
//【11.2】尝试从系统中获得该权限已有的信息
final BasePermission bp =
(BasePermission) mPermissionManager.getPermissionTEMP(perm.info.name);
// Don't allow anyone but the system to define ephemeral permissions.
if ((perm.info.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0
&& !systemApp) {
Slog.w(TAG, "Non-System package " + pkg.packageName
+ " attempting to delcare ephemeral permission "
+ perm.info.name + "; Removing ephemeral.");
perm.info.protectionLevel &= ~PermissionInfo.PROTECTION_FLAG_INSTANT;
}
// Check whether the newly-scanned package wants to define an already-defined perm
if (bp != null) {
// If the defining package is signed with our cert, it's okay. This
// also includes the "updating the same package" case, of course.
// "updating same package" could also involve key-rotation.
//【11.3】如果该权限已经被定义过了,那就要校验下签名
final boolean sigsOk;
final String sourcePackageName = bp.getSourcePackageName();
final PackageSettingBase sourcePackageSetting = bp.getSourcePackageSetting();
final KeySetManagerService ksms = mSettings.mKeySetManagerService;
if (sourcePackageName.equals(pkg.packageName)
&& (ksms.shouldCheckUpgradeKeySetLocked(
sourcePackageSetting, scanFlags))) {
//【11.3.1】检查签名更新
sigsOk = ksms.checkUpgradeKeySetLocked(sourcePackageSetting, pkg);
} else { //【11.3.2】如果不检查签名更新,那就直接比较签名
// in the event of signing certificate rotation, we need to see if the
// package's certificate has rotated from the current one, or if it is an
// older certificate with which the current is ok with sharing permissions
if (sourcePackageSetting.signatures.mSigningDetails.checkCapability(
pkg.mSigningDetails,
PackageParser.SigningDetails.CertCapabilities.PERMISSION)) {
sigsOk = true;
} else if (pkg.mSigningDetails.checkCapability(
sourcePackageSetting.signatures.mSigningDetails,
PackageParser.SigningDetails.CertCapabilities.PERMISSION)) {
// the scanned package checks out, has signing certificate rotation
// history, and is newer; bring it over
sourcePackageSetting.signatures.mSigningDetails = pkg.mSigningDetails;
sigsOk = true;
} else {
sigsOk = false;
}
}
//【11.4】如果签名发生了变化
if (!sigsOk) {
// If the owning package is the system itself, we log but allow
// install to proceed; we fail the install on all other permission
// redefinitions.
if (!sourcePackageName.equals("android")) {
//【11.4.1】如果权限的定义者不是系统,那么不允许重新定义,同时不允许继续安装
res.setError(INSTALL_FAILED_DUPLICATE_PERMISSION, "Package "
+ pkg.packageName + " attempting to redeclare permission "
+ perm.info.name + " already owned by " + sourcePackageName);
res.origPermission = perm.info.name;
res.origPackage = sourcePackageName;
return;
} else {
Slog.w(TAG, "Package " + pkg.packageName
+ " attempting to redeclare system permission "
+ perm.info.name + "; ignoring new declaration");
pkg.permissions.remove(i);
}
} else if (!PLATFORM_PACKAGE_NAME.equals(pkg.packageName)) {
//【11.4.2】如果权限的定义不是系统,那么允许安装,但是会忽视掉新的定义
// Prevent apps to change protection level to dangerous from any other
// type as this would allow a privilege escalation where an app adds a
// normal/signature permission in other app's group and later redefines
// it as dangerous leading to the group auto-grant.
if ((perm.info.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
== PermissionInfo.PROTECTION_DANGEROUS) {
if (bp != null && !bp.isRuntime()) {
Slog.w(TAG, "Package " + pkg.packageName + " trying to change a "
+ "non-runtime permission " + perm.info.name
+ " to runtime; keeping old protection level");
perm.info.protectionLevel = bp.getProtectionLevel();
}
}
}
}
}
}
//【12】如果覆盖更新的是系统应用,要针对安装位置做判断!
// 新的 apk 不能是 onExternal / ephemeral
if (systemApp) {
if (onExternal) {
// Abort update; system app can't be replaced with app on sdcard
res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
"Cannot install updates to system apps on sdcard");
return;
} else if (instantApp) {
// Abort update; system app can't be replaced with an instant app
res.setError(INSTALL_FAILED_INSTANT_APP_INVALID,
"Cannot update a system app with an instant app");
return;
}
}
//【13】根据安装参数做不同的处理
if (args.move != null) {
// We did an in-place move, so dex is ready to roll
//【13.1】如果是 move package,进入这里
// 设置以下标签,无需做 odex,我们需要已有的移动过去即可
scanFlags |= SCAN_NO_DEX;
scanFlags |= SCAN_MOVE;
synchronized (mPackages) {
final PackageSetting ps = mSettings.mPackages.get(pkgName);
if (ps == null) {
res.setError(INSTALL_FAILED_INTERNAL_ERROR,
"Missing settings for moved package " + pkgName);
}
// We moved the entire application as-is, so bring over the
// previously derived ABI information. //【13.1.1】对于 abi,和移动前的保持一致
pkg.applicationInfo.primaryCpuAbi = ps.primaryCpuAbiString;
pkg.applicationInfo.secondaryCpuAbi = ps.secondaryCpuAbiString;
}
} else if (!forwardLocked && !pkg.applicationInfo.isExternalAsec()) {
// Enable SCAN_NO_DEX flag to skip dexopt at a later stage
//【13.2】如果不是 forward lock 模式安装且没有安装到外置存储上,进入这里
// 扫描参数设置 SCAN_NO_DEX,意味着后面不做 odex,因为这里会做
scanFlags |= SCAN_NO_DEX;
try {
String abiOverride = (TextUtils.isEmpty(pkg.cpuAbiOverride) ?
args.abiOverride : pkg.cpuAbiOverride);
final boolean extractNativeLibs = !pkg.isLibrary();
derivePackageAbi(pkg, abiOverride, extractNativeLibs);
} catch (PackageManagerException pme) {
Slog.e(TAG, "Error deriving application ABI", pme);
res.setError(INSTALL_FAILED_INTERNAL_ERROR, "Error deriving application ABI");
return;
}
// Shared libraries for the package need to be updated.
//【13.2.1】更新共享库文件
synchronized (mPackages) {
try {
updateSharedLibrariesLPr(pkg, null);
} catch (PackageManagerException e) {
Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
}
}
}
//【×5.7.3.5】重命名文件目录,此时文件目录由 /data/app/tmpl[SessionId].tmp 变为 /data/app/packageName-X
// 如果 X 存在,那么会 X + 1
if (!args.doRename(res.returnCode, pkg, oldCodePath)) {
res.setError(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
return;
}
if (PackageManagerServiceUtils.isApkVerityEnabled()) {
String apkPath = null;
synchronized (mPackages) {
// Note that if the attacker managed to skip verify setup, for example by tampering
// with the package settings, upon reboot we will do full apk verification when
// verity is not detected.
final PackageSetting ps = mSettings.mPackages.get(pkgName);
if (ps != null && ps.isPrivileged()) {
apkPath = pkg.baseCodePath;
}
}
if (apkPath != null) {
final VerityUtils.SetupResult result =
VerityUtils.generateApkVeritySetupData(apkPath);
if (result.isOk()) {
if (Build.IS_DEBUGGABLE) Slog.i(TAG, "Enabling apk verity to " + apkPath);
FileDescriptor fd = result.getUnownedFileDescriptor();
try {
final byte[] signedRootHash = VerityUtils.generateFsverityRootHash(apkPath);
mInstaller.installApkVerity(apkPath, fd, result.getContentSize());
mInstaller.assertFsverityRootHashMatches(apkPath, signedRootHash);
} catch (InstallerException | IOException | DigestException |
NoSuchAlgorithmException e) {
res.setError(INSTALL_FAILED_INTERNAL_ERROR,
"Failed to set up verity: " + e);
return;
} finally {
IoUtils.closeQuietly(fd);
}
} else if (result.isFailed()) {
res.setError(INSTALL_FAILED_INTERNAL_ERROR, "Failed to generate verity");
return;
} else {
// Do nothing if verity is skipped. Will fall back to full apk verification on
// reboot.
}
}
}
//【*7.3.6】开始 intentFilter 校验
if (!instantApp) {
startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg);
} else {
if (DEBUG_DOMAIN_VERIFICATION) {
Slog.d(TAG, "Not verifying instant app install for app links: " + pkgName);
}
}
//【*7.3.7】冻结应用
try (PackageFreezer freezer = freezePackageForInstall(pkgName, installFlags,
"installPackageLI")) {
if (replace) {
if (pkg.applicationInfo.isStaticSharedLibrary()) {
// Static libs have a synthetic package name containing the version
// and cannot be updated as an update would get a new package name,
// unless this is the exact same version code which is useful for
// development.
PackageParser.Package existingPkg = mPackages.get(pkg.packageName);
if (existingPkg != null &&
existingPkg.getLongVersionCode() != pkg.getLongVersionCode()) {
res.setError(INSTALL_FAILED_DUPLICATE_PACKAGE, "Packages declaring "
+ "static-shared libs cannot be updated");
return;
}
}
//【*6】如果是覆盖安装,进入这里
replacePackageLIF(pkg, parseFlags, scanFlags, args.user,
installerPackageName, res, args.installReason);
} else {
//【*7】如果是全新安装,进入这里
installNewPackageLIF(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
args.user, installerPackageName, volumeUuid, res, args.installReason);
}
}
// Prepare the application profiles for the new code paths.
// This needs to be done before invoking dexopt so that any install-time profile
// can be used for optimizations.
mArtManagerService.prepareAppProfiles(pkg, resolveUserIds(args.user.getIdentifier()));
// Check whether we need to dexopt the app.
//
// NOTE: it is IMPORTANT to call dexopt:
// - after doRename which will sync the package data from PackageParser.Package and its
// corresponding ApplicationInfo.
// - after installNewPackageLIF or replacePackageLIF which will update result with the
// uid of the application (pkg.applicationInfo.uid).
// This update happens in place!
//
// We only need to dexopt if the package meets ALL of the following conditions:
// 1) it is not forward locked.
// 2) it is not on on an external ASEC container.
// 3) it is not an instant app or if it is then dexopt is enabled via gservices.
// 4) it is not debuggable.
//
// Note that we do not dexopt instant apps by default. dexopt can take some time to
// complete, so we skip this step during installation. Instead, we'll take extra time
// the first time the instant app starts. It's preferred to do it this way to provide
// continuous progress to the useur instead of mysteriously blocking somewhere in the
// middle of running an instant app. The default behaviour can be overridden
// via gservices.
final boolean performDexopt = (res.returnCode == PackageManager.INSTALL_SUCCEEDED)
&& !forwardLocked
&& !pkg.applicationInfo.isExternalAsec()
&& (!instantApp || Global.getInt(mContext.getContentResolver(),
Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)
&& ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0);
//【13.2.2】执行 odex 优化
if (performDexopt) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
// Do not run PackageDexOptimizer through the local performDexOpt
// method because `pkg` may not be in `mPackages` yet.
//
// Also, don't fail application installs if the dexopt step fails.
DexoptOptions dexoptOptions = new DexoptOptions(pkg.packageName,
REASON_INSTALL,
DexoptOptions.DEXOPT_BOOT_COMPLETE |
DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE);
mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,
null /* instructionSets */,
getOrCreateCompilerPackageStats(pkg),
mDexManager.getPackageUseInfoOrDefault(pkg.packageName),
dexoptOptions);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
// Notify BackgroundDexOptService that the package has been changed.
// If this is an update of a package which used to fail to compile,
// BackgroundDexOptService will remove it from its blacklist.
// TODO: Layering violation
//【13.2.3】将该应用从 odex fail list 中删除
BackgroundDexOptService.notifyPackageChanged(pkg.packageName);
//【14】为本次安装的 apk 更新目标用户信息
synchronized (mPackages) {
final PackageSetting ps = mSettings.mPackages.get(pkgName);
if (ps != null) {
res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
ps.setUpdateAvailable(false /*updateAvailable*/);
}
final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
for (int i = 0; i < childCount; i++) {
PackageParser.Package childPkg = pkg.childPackages.get(i);
PackageInstalledInfo childRes = res.addedChildPackages.get(childPkg.packageName);
PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
if (childPs != null) {
childRes.newUsers = childPs.queryInstalledUsers(
sUserManager.getUserIds(), true);
}
}
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
updateSequenceNumberLP(ps, res.newUsers);
updateInstantAppInstallerLocked(pkgName);
}
}
}
7.3.1 PackageParser.parsePackage
PackageParser.parsePackage 其实我们在 PMS 启动扫描的过程中已经分析过了,这里我们重点关注其对 installFlags 的处理
java
public boolean shouldCheckUpgradeKeySetLocked(PackageSettingBase oldPs, int scanFlags) {
//【1】以下情况无需检查签名更新:
// 1、本次是全新安装;2、扫描设置了 SCAN_INITIAL(move pkg);3、本次是覆盖安装,但是应用是 sharedUser 的
// 4、应用不使用 upgradeKeySets
// Can't rotate keys during boot or if sharedUser.
if (oldPs == null || (scanFlags&SCAN_INITIAL) != 0 || oldPs.isSharedUser()
|| !oldPs.keySetData.isUsingUpgradeKeySets()) {
return false;
}
// app is using upgradeKeySets; make sure all are valid
//【2】如果应用是覆盖安装,且不是 move pkg,且不是共享 uid 的,且使用 upgradeKeySets,那么就要检查
// upgradeKeySets 有效性,只有有效的 upgradeKeySets 才能检查更新
long[] upgradeKeySets = oldPs.keySetData.getUpgradeKeySets();
for (int i = 0; i < upgradeKeySets.length; i++) {
//【2.1】判断 upgradeKeySets 是否有效
if (!isIdValidKeySetId(upgradeKeySets[i])) {
Slog.wtf(TAG, "Package "
+ (oldPs.name != null ? oldPs.name : "<null>")
+ " contains upgrade-key-set reference to unknown key-set: "
+ upgradeKeySets[i]
+ " reverting to signatures check.");
return false;
}
}
return true;
}
7.3.3 checkUpgradeKeySetLP
进行签名更新检查:
java
public boolean checkUpgradeKeySetLocked(PackageSettingBase oldPS,
PackageParser.Package newPkg) {
//【1】检查 key set 更新,更新有效的前提是新的 apk 持有的 keyset 至少包含旧应用的 keyset
// Upgrade keysets are being used. Determine if new package has a superset of the
// required keys.
long[] upgradeKeySets = oldPS.keySetData.getUpgradeKeySets();
for (int i = 0; i < upgradeKeySets.length; i++) {
Set<PublicKey> upgradeSet = getPublicKeysFromKeySetLPr(upgradeKeySets[i]);
if (upgradeSet != null && newPkg.mSigningDetails.publicKeys.containsAll(upgradeSet)) {
return true;
}
}
return false;
}
7.3.4 verifySignaturesLP
校验签名:
java
public static boolean verifySignatures(PackageSetting pkgSetting,
PackageSetting disabledPkgSetting, PackageParser.SigningDetails parsedSignatures,
boolean compareCompat, boolean compareRecover)
throws PackageManagerException {
final String packageName = pkgSetting.name;
boolean compatMatch = false;
if (pkgSetting.signatures.mSigningDetails.signatures != null) {
// Already existing package. Make sure signatures match
boolean match = parsedSignatures.checkCapability(
pkgSetting.signatures.mSigningDetails,
PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)
|| pkgSetting.signatures.mSigningDetails.checkCapability(
parsedSignatures,
PackageParser.SigningDetails.CertCapabilities.ROLLBACK);
if (!match && compareCompat) {
match = matchSignaturesCompat(packageName, pkgSetting.signatures,
parsedSignatures);
compatMatch = match;
}
if (!match && compareRecover) {
match = matchSignaturesRecover(
packageName,
pkgSetting.signatures.mSigningDetails,
parsedSignatures,
PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)
|| matchSignaturesRecover(
packageName,
parsedSignatures,
pkgSetting.signatures.mSigningDetails,
PackageParser.SigningDetails.CertCapabilities.ROLLBACK);
}
if (!match && isApkVerificationForced(disabledPkgSetting)) {
match = matchSignatureInSystem(pkgSetting, disabledPkgSetting);
}
if (!match) {
throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
"Package " + packageName +
" signatures do not match previously installed version; ignoring!");
}
}
// Check for shared user signatures
if (pkgSetting.sharedUser != null
&& pkgSetting.sharedUser.signatures.mSigningDetails
!= PackageParser.SigningDetails.UNKNOWN) {
// Already existing package. Make sure signatures match. In case of signing certificate
// rotation, the packages with newer certs need to be ok with being sharedUserId with
// the older ones. We check to see if either the new package is signed by an older cert
// with which the current sharedUser is ok, or if it is signed by a newer one, and is ok
// with being sharedUser with the existing signing cert.
boolean match =
parsedSignatures.checkCapability(
pkgSetting.sharedUser.signatures.mSigningDetails,
PackageParser.SigningDetails.CertCapabilities.SHARED_USER_ID)
|| pkgSetting.sharedUser.signatures.mSigningDetails.checkCapability(
parsedSignatures,
PackageParser.SigningDetails.CertCapabilities.SHARED_USER_ID);
if (!match && compareCompat) {
match = matchSignaturesCompat(
packageName, pkgSetting.sharedUser.signatures, parsedSignatures);
}
if (!match && compareRecover) {
match =
matchSignaturesRecover(packageName,
pkgSetting.sharedUser.signatures.mSigningDetails,
parsedSignatures,
PackageParser.SigningDetails.CertCapabilities.SHARED_USER_ID)
|| matchSignaturesRecover(packageName,
parsedSignatures,
pkgSetting.sharedUser.signatures.mSigningDetails,
PackageParser.SigningDetails.CertCapabilities.SHARED_USER_ID);
compatMatch |= match;
}
if (!match) {
throw new PackageManagerException(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
"Package " + packageName
+ " has no signatures that match those in shared user "
+ pkgSetting.sharedUser.name + "; ignoring!");
}
}
return compatMatch;
}
7.3.5 FileInstallArgs.doRename - 重命名临时目录
doRename 重命名文件,之前我们的临时目录为 /data/app/tmpl[SessionId].tmp,这里会将其重命名为 /data/app/packageName-X
java
boolean doRename(int status, PackageParser.Package pkg, String oldCodePath) {
if (status != PackageManager.INSTALL_SUCCEEDED) {
cleanUp();
return false;
}
//【1】获得改名前的临时目录 targetDir 就是 /data/app/tmpl[SessionId].tmp
final File targetDir = codeFile.getParentFile();
final File beforeCodeFile = codeFile;
//【7.3.5.1】获得改名后的目录:/data/app/packageName-X,策略取决为 getNextCodePath
final File afterCodeFile = getNextCodePath(targetDir, pkg.packageName);
if (DEBUG_INSTALL) Slog.d(TAG, "Renaming " + beforeCodeFile + " to " + afterCodeFile);
try {
Os.rename(beforeCodeFile.getAbsolutePath(), afterCodeFile.getAbsolutePath());
} catch (ErrnoException e) {
Slog.w(TAG, "Failed to rename", e);
return false;
}
//【2】恢复默认的安全上下文
if (!SELinux.restoreconRecursive(afterCodeFile)) {
Slog.w(TAG, "Failed to restorecon");
return false;
}
//【3】更新 FileInstallArgs 的目录为最终目录
// Reflect the rename internally
codeFile = afterCodeFile;
resourceFile = afterCodeFile;
// Reflect the rename in scanned details
try {
pkg.setCodePath(afterCodeFile.getCanonicalPath());
} catch (IOException e) {
Slog.e(TAG, "Failed to get path: " + afterCodeFile, e);
return false;
}
//【4】更新扫描到的应用的 Package 中的目录数据
// 以及 Application 中的数据
pkg.setBaseCodePath(FileUtils.rewriteAfterRename(beforeCodeFile,
afterCodeFile, pkg.baseCodePath));
pkg.setSplitCodePaths(FileUtils.rewriteAfterRename(beforeCodeFile,
afterCodeFile, pkg.splitCodePaths));
// Reflect the rename in app info
pkg.setApplicationVolumeUuid(pkg.volumeUuid);
pkg.setApplicationInfoCodePath(pkg.codePath);
pkg.setApplicationInfoBaseCodePath(pkg.baseCodePath);
pkg.setApplicationInfoSplitCodePaths(pkg.splitCodePaths);
pkg.setApplicationInfoResourcePath(pkg.codePath);
pkg.setApplicationInfoBaseResourcePath(pkg.baseCodePath);
pkg.setApplicationInfoSplitResourcePaths(pkg.splitCodePaths);
return true;
}
7.3.5.1 getNextCodePath
getNextCodePath 方法用于获得最终的目录
java
private File getNextCodePath(File targetDir, String packageName) {
File result;
SecureRandom random = new SecureRandom();
byte[] bytes = new byte[16];
do {
//【1】最终目录为 /data/app/packageName-X(X=1,2,3...)
// suffix 从 1 开始,如果 suffix 已存在,那就 +1
random.nextBytes(bytes);
String suffix = Base64.encodeToString(bytes, Base64.URL_SAFE | Base64.NO_WRAP);
result = new File(targetDir, packageName + "-" + suffix);
} while (result.exists());
return result;
}
7.3.7 freezePackageForInstall - 冻结应用
该方法用于冻结应用:
java
public PackageFreezer freezePackageForInstall(String packageName, int installFlags,
String killReason) {
return freezePackageForInstall(packageName, UserHandle.USER_ALL, installFlags, killReason);
}
public PackageFreezer freezePackageForInstall(String packageName, int userId, int installFlags,
String killReason) {
if ((installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) {
//【1】如果指定了卸载时不 kill app,就用默认的参数(卸载时才会进入)
return new PackageFreezer();
} else {
//【2】默认是需要 kill app 的,调用 freezePackage
return freezePackage(packageName, userId, killReason);
}
}
继续调用 freezePackage 方法:
java
public PackageFreezer freezePackage(String packageName, int userId, String killReason) {
//【×7.3.7.1】创建了一个 PackageFreezer 实例
return new PackageFreezer(packageName, userId, killReason);
}
7.3.7.1 new PackageFreezer
如果不杀进程,那就只创建一个 PackageFreezer 实例,并返回,不做任何事情
java
public PackageFreezer() {
mPackageName = null;
mChildren = null;
mWeFroze = false;
mCloseGuard.open("close");
}
//如果要 kill app,那么会创建 PackageFreezer(父包和子包),并且会杀掉进程
public PackageFreezer(String packageName, int userId, String killReason) {
synchronized (mPackages) {
mPackageName = packageName;
mWeFroze = mFrozenPackages.add(mPackageName);
final PackageSetting ps = mSettings.mPackages.get(mPackageName);
if (ps != null) {
//【1】杀掉父包的进程
killApplication(ps.name, ps.appId, userId, killReason);
}
final PackageParser.Package p = mPackages.get(packageName);
if (p != null && p.childPackages != null) {
final int N = p.childPackages.size();
mChildren = new PackageFreezer[N];
for (int i = 0; i < N; i++) {
//【2】为子包创建 PackageFreezer,并杀掉子包的进程
mChildren[i] = new PackageFreezer(p.childPackages.get(i).packageName,
userId, killReason);
}
} else {
mChildren = null;
}
}
mCloseGuard.open("close");
}
7.4 FileInstallArgs.doPostInstall
清理操作,正常情况不会触发
java
int doPostInstall(int status, int uid) {
//【1】如果安装前的状态不是 PackageManager.INSTALL_SUCCEEDED
if (status != PackageManager.INSTALL_SUCCEEDED) {
//【7.2.1】执行清理操作
cleanUp();
}
return status;
}
7.5 new PostInstallData
又创建了一个 PostInstallData 对象,对 PackageInstalledInfo 做了再次封装:
java
static class PostInstallData {
public InstallArgs args;
public PackageInstalledInfo res;
PostInstallData(InstallArgs _a, PackageInstalledInfo _r) {
args = _a;
res = _r;
}
}
八、PackageHandler.doHandleMessage[POST_INSTALL] - 安装收尾
PackageHandler 会处理 POST_INSTALL 消息,此时已经处于安装收尾阶段:
java
case POST_INSTALL: {
if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1);
//【1】我们在安装开始前,会用 PostInstallData 封装安装结果,并保存到 mRunningInstalls 中
// 在安装结束后,会处理本次的安装结果
PostInstallData data = mRunningInstalls.get(msg.arg1);
final boolean didRestore = (msg.arg2 != 0);
mRunningInstalls.delete(msg.arg1); // 删除掉
if (data != null) {
InstallArgs args = data.args;
PackageInstalledInfo parentRes = data.res;
//【2】本次安装是否授予运行时权限
final boolean grantPermissions = (args.installFlags
& PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0;
//【2】本次安装是否 kill app
final boolean killApp = (args.installFlags
& PackageManager.INSTALL_DONT_KILL_APP) == 0;
final boolean virtualPreload = ((args.installFlags
& PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
final String[] grantedPermissions = args.installGrantPermissions;
// Handle the parent package
//【×8.1】调用 handlePackagePostInstall 继续处理收尾工作
handlePackagePostInstall(parentRes, grantPermissions, killApp,
virtualPreload, grantedPermissions, didRestore,
args.installerPackageName, args.observer);
// Handle the child packages
//【3】处理子包
final int childCount = (parentRes.addedChildPackages != null)
? parentRes.addedChildPackages.size() : 0;
for (int i = 0; i < childCount; i++) {
PackageInstalledInfo childRes = parentRes.addedChildPackages.valueAt(i);
//【×8.1】调用 handlePackagePostInstall 继续处理收尾工作
handlePackagePostInstall(childRes, grantPermissions, killApp,
virtualPreload, grantedPermissions, false /*didRestore*/,
args.installerPackageName, args.observer);
}
// Log tracing if needed
if (args.traceMethod != null) {
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, args.traceMethod,
args.traceCookie);
}
} else {
Slog.e(TAG, "Bogus post-install token " + msg.arg1);
}
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "postInstall", msg.arg1);
} break;
8.1 PackageManagerS.handlePackagePostInstall
处理安装收尾工作:
java
private void handlePackagePostInstall(PackageInstalledInfo res, boolean grantPermissions,
boolean killApp, boolean virtualPreload, String[] grantedPermissions,
boolean launchedForRestore, String installerPackage,
IPackageInstallObserver2 installObserver) {
//【1】当安装结果为 success 后,会进入后续的处理
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
// Send the removed broadcasts
//【1.1】如果是 move pacakge,那么发送 removed 广播
if (res.removedInfo != null) {
res.removedInfo.sendPackageRemovedBroadcasts(killApp);
}
// Now that we successfully installed the package, grant runtime
// permissions if requested before broadcasting the install. Also
// for legacy apps in permission review mode we clear the permission
// review flag which is used to emulate runtime permissions for
// legacy apps.
//【1.2】如果安装时指定了授予运行时权限,并且应用的目标 sdk 支持运行时权限,那就授予运行时权限
if (grantPermissions) {
final int callingUid = Binder.getCallingUid();
mPermissionManager.grantRequestedRuntimePermissions(
res.pkg, res.newUsers, grantedPermissions, callingUid,
mPermissionCallback);
}
//【1.3】判断安装方式,是更新安装,还是全新安装!
// 我们知道,如果 res.removedInfo 不为 null 的话,一定是覆盖更新
final boolean update = res.removedInfo != null
&& res.removedInfo.removedPackage != null;
final String installerPackageName =
res.installerPackageName != null
? res.installerPackageName
: res.removedInfo != null
? res.removedInfo.installerPackageName
: null;
// If this is the first time we have child packages for a disabled privileged
// app that had no children, we grant requested runtime permissions to the new
// children if the parent on the system image had them already granted.
//【1.4】如果被 disable 的特权应用之前没有子包,这是第一次有子包,那么我们会授予新的子包
// 运行时权限,如果旧的特权应用之前已经授予
if (res.pkg.parentPackage != null) {
final int callingUid = Binder.getCallingUid();
mPermissionManager.grantRuntimePermissionsGrantedToDisabledPackage(
res.pkg, callingUid, mPermissionCallback);
}
synchronized (mPackages) {
mInstantAppRegistry.onPackageInstalledLPw(res.pkg, res.newUsers);
}
final String packageName = res.pkg.applicationInfo.packageName;
// Determine the set of users who are adding this package for
// the first time vs. those who are seeing an update.
//【1.5】决定在那些 user 下是第一次安装,那些用户下是覆盖更新
int[] firstUserIds = EMPTY_INT_ARRAY;
int[] firstInstantUserIds = EMPTY_INT_ARRAY;
int[] updateUserIds = EMPTY_INT_ARRAY;
int[] instantUserIds = EMPTY_INT_ARRAY;
final boolean allNewUsers = res.origUsers == null || res.origUsers.length == 0;
final PackageSetting ps = (PackageSetting) res.pkg.mExtras;
for (int newUser : res.newUsers) {
final boolean isInstantApp = ps.getInstantApp(newUser);
if (allNewUsers) {
if (isInstantApp) {
firstInstantUserIds = ArrayUtils.appendInt(firstInstantUserIds, newUser);
} else {
firstUserIds = ArrayUtils.appendInt(firstUserIds, newUser);
}
continue;
}
// res.newUsers 表示本次安装新增加的目标 user
// res.origUsers 标志之前安装的目标 user
boolean isNew = true;
for (int origUser : res.origUsers) {
if (origUser == newUser) {
isNew = false;
break;
}
}
if (isNew) {
if (isInstantApp) {
firstInstantUserIds = ArrayUtils.appendInt(firstInstantUserIds, newUser);
} else {
firstUserIds = ArrayUtils.appendInt(firstUserIds, newUser);
}
} else {
if (isInstantApp) {
instantUserIds = ArrayUtils.appendInt(instantUserIds, newUser);
} else {
updateUserIds = ArrayUtils.appendInt(updateUserIds, newUser);
}
}
}
// Send installed broadcasts if the package is not a static shared lib.
if (res.pkg.staticSharedLibName == null) {
mProcessLoggingHandler.invalidateProcessLoggingBaseApkHash(res.pkg.baseCodePath);
// Send added for users that see the package for the first time
// sendPackageAddedForNewUsers also deals with system apps
int appId = UserHandle.getAppId(res.uid);
boolean isSystem = res.pkg.applicationInfo.isSystemApp();
sendPackageAddedForNewUsers(packageName, isSystem || virtualPreload,
virtualPreload /*startReceiver*/, appId, firstUserIds, firstInstantUserIds);
// Send added for users that don't see the package for the first time
//【1.5.1】给第一次安装的用户发送 ACTION_PACKAGE_ADDED 广播
Bundle extras = new Bundle(1);
extras.putInt(Intent.EXTRA_UID, res.uid);
if (update) {
//【1.5.2】给覆盖更新的用户发送 ACTION_PACKAGE_ADDED 广播,带 EXTRA_REPLACING 属性
extras.putBoolean(Intent.EXTRA_REPLACING, true);
}
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, 0 /*flags*/,
null /*targetPackage*/, null /*finishedReceiver*/,
updateUserIds, instantUserIds);
if (installerPackageName != null) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, 0 /*flags*/,
installerPackageName, null /*finishedReceiver*/,
updateUserIds, instantUserIds);
}
// if the required verifier is defined, but, is not the installer of record
// for the package, it gets notified
final boolean notifyVerifier = mRequiredVerifierPackage != null
&& !mRequiredVerifierPackage.equals(installerPackageName);
if (notifyVerifier) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, 0 /*flags*/,
mRequiredVerifierPackage, null /*finishedReceiver*/,
updateUserIds, instantUserIds);
}
// Send replaced for users that don't see the package for the first time
//【1.5.3】给覆盖更新的用户发送 ACTION_PACKAGE_REPLACED / ACTION_MY_PACKAGE_REPLACED 广播
if (update) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
packageName, extras, 0 /*flags*/,
null /*targetPackage*/, null /*finishedReceiver*/,
updateUserIds, instantUserIds);
if (installerPackageName != null) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
extras, 0 /*flags*/,
installerPackageName, null /*finishedReceiver*/,
updateUserIds, instantUserIds);
}
if (notifyVerifier) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
extras, 0 /*flags*/,
mRequiredVerifierPackage, null /*finishedReceiver*/,
updateUserIds, instantUserIds);
}
sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
null /*package*/, null /*extras*/, 0 /*flags*/,
packageName /*targetPackage*/,
null /*finishedReceiver*/, updateUserIds, instantUserIds);
} else if (launchedForRestore && !isSystemApp(res.pkg)) {
// First-install and we did a restore, so we're responsible for the
// first-launch broadcast.
//【1.5.4】如果是第一次安装,同时我们要做一个恢复操作,并且 apk 不是系统应用
// 那么我们会发送 ACTION_PACKAGE_FIRST_LAUNCH 广播
if (DEBUG_BACKUP) {
Slog.i(TAG, "Post-restore of " + packageName
+ " sending FIRST_LAUNCH in " + Arrays.toString(firstUserIds));
}
sendFirstLaunchBroadcast(packageName, installerPackage,
firstUserIds, firstInstantUserIds);
}
// Send broadcast package appeared if forward locked/external for all users
// treat asec-hosted packages like removable media on upgrade
if (res.pkg.isForwardLocked() || isExternal(res.pkg)) {
if (DEBUG_INSTALL) {
Slog.i(TAG, "upgrading pkg " + res.pkg
+ " is ASEC-hosted -> AVAILABLE");
}
final int[] uidArray = new int[]{res.pkg.applicationInfo.uid};
ArrayList<String> pkgList = new ArrayList<>(1);
pkgList.add(packageName);
sendResourcesChangedBroadcast(true, true, pkgList, uidArray, null);
}
}
// Work that needs to happen on first install within each user
//【1.6】针对 firstUsers 做一些权限恢复和默认浏览器设置
if (firstUserIds != null && firstUserIds.length > 0) {
synchronized (mPackages) {
for (int userId : firstUserIds) {
// If this app is a browser and it's newly-installed for some
// users, clear any default-browser state in those users. The
// app's nature doesn't depend on the user, so we can just check
// its browser nature in any user and generalize.
//【1.6.1】默认浏览器设置
if (packageIsBrowser(packageName, userId)) {
mSettings.setDefaultBrowserPackageNameLPw(null, userId);
}
// We may also need to apply pending (restored) runtime
// permission grants within these users.
//【1.6.2】处理那些正在等待或者需要恢复的运行时权限授予
mSettings.applyPendingPermissionGrantsLPw(packageName, userId);
}
}
}
if (allNewUsers && !update) {
notifyPackageAdded(packageName);
}
// Log current value of "unknown sources" setting
EventLog.writeEvent(EventLogTags.UNKNOWN_SOURCES_ENABLED,
getUnknownSourcesSettings());
// Remove the replaced package's older resources safely now
// We delete after a gc for applications on sdcard.
if (res.removedInfo != null && res.removedInfo.args != null) {
// 触发 GC 回收资源
Runtime.getRuntime().gc();
synchronized (mInstallLock) {
//【5.8.1.1】移除掉更新后的旧 apk
res.removedInfo.args.doPostDeleteLI(true);
}
} else {
// Force a gc to clear up things. Ask for a background one, it's fine to go on
// and not block here.
VMRuntime.getRuntime().requestConcurrentGC();
}
// Notify DexManager that the package was installed for new users.
// The updated users should already be indexed and the package code paths
// should not change.
// Don't notify the manager for ephemeral apps as they are not expected to
// survive long enough to benefit of background optimizations.
for (int userId : firstUserIds) {
PackageInfo info = getPackageInfo(packageName, /*flags*/ 0, userId);
// There's a race currently where some install events may interleave with an uninstall.
// This can lead to package info being null (b/36642664).
if (info != null) {
mDexManager.notifyPackageInstalled(info, userId);
}
}
}
// If someone is watching installs - notify them
//【*8.2】通知观察者安装的结果,这里的 installObserver 是我们之前创建的 localObsever
if (installObserver != null) {
try {
Bundle extras = extrasForInstallResult(res);
installObserver.onPackageInstalled(res.name, res.returnCode,
res.returnMsg, extras);
} catch (RemoteException e) {
Slog.i(TAG, "Observer no longer exists.");
}
}
}
我们看到,这里涉及到了几个重要的广播:
- Intent.ACTION_PACKAGE_ADDED:当有应用程序第一次安装时,会发送该广播给对应的 firstUsers!
- 携带数据:Intent.EXTRA_UID,值为 apk uid;
- Intent.ACTION_PACKAGE_REPLACED:当有应用程序被覆盖安装时,会发送该广播给对应的 updateUsers!
- 携带数据:Intent.EXTRA_UID,
- 携带数据:Intent.EXTRA_REPLACING,置为 true;
- Intent.ACTION_MY_PACKAGE_REPLACED:当有应用程序被覆盖安装时,会发送该广播给对应的 updateUsers 下被更新的 pkg!
- 携带数据:packageName,被更新的应用包;
8.1.1 FileInstallArgs.doPostDeleteLI - 删除被更新的旧 apk
java
boolean doPostDeleteLI(boolean delete) {
// XXX err, shouldn't we respect the delete flag?
//【*8.1.2】清除 apk 文件 和 dex 文件
cleanUpResourcesLI();
return true;
}
8.1.2 FileInstallArgs.cleanUpResourcesLI
java
void cleanUpResourcesLI() {
// Try enumerating all code paths before deleting
List<String> allCodePaths = Collections.EMPTY_LIST;
if (codeFile != null && codeFile.exists()) {
try {
//【1】收集 apk path
final PackageLite pkg = PackageParser.parsePackageLite(codeFile, 0);
allCodePaths = pkg.getAllCodePaths();
} catch (PackageParserException e) {
// Ignored; we tried our best
}
}
//【2】清除 apk
cleanUp();
//【3】清除 dex files
removeDexFiles(allCodePaths, instructionSets);
}
8.2 IPackageInstallObserver2.onPackageInstalled
这里的 installObserver 是我们在 4.3 PackageInstallerSession.commitLocked 中创建的另一个 Observer
位置:./frameworks/base/services/core/java/com/android/server/pm/PackageInstallerSession.java
java
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) {
destroyInternal();
dispatchSessionFinished(returnCode, msg, extras);
}
};
8.2.1 PackageInstallerSession.destroyInternal
关闭文件桥,删除文件拷贝:
java
private void destroyInternal() {
synchronized (mLock) {
mSealed = true;
mDestroyed = true;
// Force shut down all bridges
for (RevocableFileDescriptor fd : mFds) {
fd.revoke();
}
//【1】关闭之前打开的文件桥对象
for (FileBridge bridge : mBridges) {
bridge.forceClose();
}
}
if (stageDir != null) {
try {
//【2】删除之前的文件拷贝目录
mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
} catch (InstallerException ignored) {
}
}
}
8.2.2 PackageInstallerSession.dispatchSessionFinished
处理回调,通知监听者:
java
private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) {
final IPackageInstallObserver2 observer;
final String packageName;
synchronized (mLock) {
mFinalStatus = returnCode;
mFinalMessage = msg;
observer = mRemoteObserver;
packageName = mPackageName;
}
if (observer != null) {
// Execute observer.onPackageInstalled on different tread as we don't want callers
// inside the system server have to worry about catching the callbacks while they are
// calling into the session
final SomeArgs args = SomeArgs.obtain();
args.arg1 = packageName;
args.arg2 = msg;
args.arg3 = extras;
args.arg4 = observer;
args.argi1 = returnCode;
//【*4.1.2】触发 mRemoteObserver 回调
mHandler.obtainMessage(MSG_ON_PACKAGE_INSTALLED, args).sendToTarget();
}
final boolean success = (returnCode == PackageManager.INSTALL_SUCCEEDED);
// Send broadcast to default launcher only if it's a new install
final boolean isNewInstall = extras == null || !extras.getBoolean(Intent.EXTRA_REPLACING);
if (success && isNewInstall) {
mPm.sendSessionCommitBroadcast(generateInfo(), userId);
}
//【*8.2.2.2】回调触发
mCallback.onSessionFinished(this, success);
}
在前面 4.1 commit 事务的时候,我们创建了一个 PackageInstallObserverAdapter,并将其保存到了 PackageInstallerSession.mRemoteObserver 中,这里首先会触发 mRemoteObserver 的回调
在 3.1.4.1 new InternalCallback 的时候,我们在创建 PackageInstallerSession 时,传入了一个回调对象 InternalCallback:
java
private final InternalCallback mInternalCallback = new InternalCallback();
InternalCallback 类定义在 PackageInstallerService 中,该对象的引用会被保存到 PackageInstallerSession.mCallback 变量中
8.2.2.2 InternalCallback.onSessionFinished
这里我们重点关于 onSessionFinished 方法:
java
public void onSessionFinished(final PackageInstallerSession session, boolean success) {
//【×8.2.2.2.1】注册者回调
mCallbacks.notifySessionFinished(session.sessionId, session.userId, success);
mInstallHandler.post(new Runnable() {
@Override
public void run() {
synchronized (mSessions) {
//【1】从 PackageInstallerService 中的 mSessions 移除了该 Session;
mSessions.remove(session.sessionId);
//【2】将该 Sesssion 添加到历史中;
addHistoricalSessionLocked(session);
final File appIconFile = buildAppIconFile(session.sessionId);
if (appIconFile.exists()) {
appIconFile.delete();
}
//【×3.1.6.1】持久化事务记录文件
writeSessionsLocked();
}
}
});
}
我们看到,在 InternalCallback 中又回调了另外一个 Callback mCallbacks,它也是 PackageInstallerService 的内部类:
8.2.2.2.1 Callback.notifySessionFinished
前面我们分析过,Callback 本质上就是一个 Handler,这里就是向其所在的线程发送消息:
java
public void notifySessionFinished(int sessionId, int userId, boolean success) {
obtainMessage(MSG_SESSION_FINISHED, sessionId, userId, success).sendToTarget();
}
在 3.1.4.2 Callbacks.notifySessionXXXX 中,我们分析过,最终其实是很将安装的结果分发给了注册在 Callback 中的所有远程回调:
java
private final RemoteCallbackList<IPackageInstallerCallback>
mCallbacks = new RemoteCallbackList<>();