下面来分析下 PackageInstallerService 中的逻辑,我们先来看看 PackageInstallerService 的创建,当然,这部分的逻辑是在开机的时候,这里我们再回顾下:
位置:./frameworks/base/services/core/java/com/android/server/pm/PackageInstallerService.java
public PackageInstallerService(Context context, PackageManagerService pm) {
mContext = context;
mPm = pm;
mPermissionManager = LocalServices.getService(PermissionManagerInternal.class);
//【1】启动了一个 HandlerThread 线程
mInstallThread = new HandlerThread(TAG);
mInstallThread.start();
//【2】创建了 mInstallThread 对应的 Handler
mInstallHandler = new Handler(mInstallThread.getLooper());
//创建了 Callbacks 实例,用于处理安装回调,传入了子线程的 Loopder
mCallbacks = new Callbacks(mInstallThread.getLooper());
//【3】创建了 sessions 本地持久化文件和目录对象
mSessionsFile = new AtomicFile(
new File(Environment.getDataSystemDirectory(), "install_sessions.xml"),
"package-session");
mSessionsDir = new File(Environment.getDataSystemDirectory(), "install_sessions");
mSessionsDir.mkdirs();
}
关于 PackageInstallerService 这里就不在过多分析,我们继续看
@Override
public int createSession(SessionParams params, String installerPackageName, int userId) {
try {
//createSession 方法调用了 createSessionInternal 方法
return createSessionInternal(params, installerPackageName, userId);
} catch (IOException e) {
throw ExceptionUtils.wrap(e);
}
}
private int createSessionInternal(SessionParams params, String installerPackageName, int userId)
throws IOException {
final int callingUid = Binder.getCallingUid();
//【1】权限检查
mPermissionManager.enforceCrossUserPermission(
callingUid, userId, true, true, "createSession");
//【2】用户操作检查
if (mPm.isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
throw new SecurityException("User restriction prevents installing");
}
//【3】如果调用进程的 uid 是 SHELL_UID 或者 ROOT_UID,那么 installFlags 增加 INSTALL_FROM_ADB
// 表示通过 adb 进行安装
if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
params.installFlags |= PackageManager.INSTALL_FROM_ADB;
} else {
// Only apps with INSTALL_PACKAGES are allowed to set an installer that is not the
// caller.
// 如果不是 shell or root,校验下 package 是否属于 uid
if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES) !=
PackageManager.PERMISSION_GRANTED) {
mAppOps.checkPackage(callingUid, installerPackageName);
}
// 取消 INSTALL_FROM_ADB 和 INSTALL_ALL_USERS 标志位,设置 INSTALL_REPLACE_EXISTING 标志位
params.installFlags &= ~PackageManager.INSTALL_FROM_ADB;
params.installFlags &= ~PackageManager.INSTALL_ALL_USERS;
params.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
if ((params.installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0
&& !mPm.isCallerVerifier(callingUid)) {
params.installFlags &= ~PackageManager.INSTALL_VIRTUAL_PRELOAD;
}
}
// Only system components can circumvent runtime permissions when installing.
//【4】如果 installFlags 设置了 INSTALL_GRANT_RUNTIME_PERMISSIONS 标志位,那需要判断调用者是否有
// INSTALL_GRANT_RUNTIME_PERMISSIONS 权限
if ((params.installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0
&& mContext.checkCallingOrSelfPermission(Manifest.permission
.INSTALL_GRANT_RUNTIME_PERMISSIONS) == PackageManager.PERMISSION_DENIED) {
throw new SecurityException("You need the "
+ "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS permission "
+ "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag");
}
if ((params.installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0
|| (params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
throw new IllegalArgumentException(
"New installs into ASEC containers no longer supported");
}
// Defensively resize giant app icons //【5】调整应用的 icon 图标
if (params.appIcon != null) {
final ActivityManager am = (ActivityManager) mContext.getSystemService(
Context.ACTIVITY_SERVICE);
final int iconSize = am.getLauncherLargeIconSize();
if ((params.appIcon.getWidth() > iconSize * 2)
|| (params.appIcon.getHeight() > iconSize * 2)) {
params.appIcon = Bitmap.createScaledBitmap(params.appIcon, iconSize, iconSize,
true);
}
}
//【6】检查 mode 取值是否正确
switch (params.mode) {
case SessionParams.MODE_FULL_INSTALL:
case SessionParams.MODE_INHERIT_EXISTING:
break;
default:
throw new IllegalArgumentException("Invalid install mode: " + params.mode);
}
// If caller requested explicit location, sanity check it, otherwise
// resolve the best internal or adopted location.
//【7】根据 installFlags 设置,调整安装位置,如果用户显示设置了位置,系统会对其进行检查,否则
// 系统会选择合适的位置
if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
//【7.1】如果显式指定内置,判断是否合适安装
if (!PackageHelper.fitsOnInternal(mContext, params)) {
throw new IOException("No suitable internal storage available");
}
} else if ((params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
//【7.2】如果显式指定外置,判断是否合适安装
if (!PackageHelper.fitsOnExternal(mContext, params)) {
throw new IOException("No suitable external storage available");
}
} else if ((params.installFlags & PackageManager.INSTALL_FORCE_VOLUME_UUID) != 0) {
// For now, installs to adopted media are treated as internal from
// an install flag point-of-view.
params.setInstallFlagsInternal();
} else {
// For now, installs to adopted media are treated as internal from
// an install flag point-of-view.
//【7.4】默认情况下,进入这里,setInstallFlagsInternal 方法会设置 INSTALL_INTERNAL 标志位
params.setInstallFlagsInternal();
// Resolve best location for install, based on combination of
// requested install flags, delta size, and manifest settings.
// 选择最好的位置来安装
final long ident = Binder.clearCallingIdentity();
try {
params.volumeUuid = PackageHelper.resolveInstallVolume(mContext, params);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
final int sessionId;
final PackageInstallerSession session;
synchronized (mSessions) {
// Sanity check that installer isn't going crazy
//【*1.2】判断,同一个 uid 是否有过多的正在处理的 Session,如果超过了 1024 个,那当前就不能执行安装
final int activeCount = getSessionCount(mSessions, callingUid);
if (activeCount >= MAX_ACTIVE_SESSIONS) {
throw new IllegalStateException(
"Too many active sessions for UID " + callingUid);
}
// 同样。判断同一个 uid,是否已经提交了过多的 Session,如果超过了 1048576 个,那当前就不能执行安装
final int historicalCount = mHistoricalSessionsByInstaller.get(callingUid);
if (historicalCount >= MAX_HISTORICAL_SESSIONS) {
throw new IllegalStateException(
"Too many historical sessions for UID " + callingUid);
}
//【*1.3】给本次安装分配一个事务 id
sessionId = allocateSessionIdLocked();
}
final long createdMillis = System.currentTimeMillis();
// We're staging to exactly one location
//【8】决定安装目录,因为默认是内置空间,这里会直接进入 buildStageDir 方法
File stageDir = null;
String stageCid = null;
if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
final boolean isInstant =
(params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
//【*1.4】创建文件临时目录;/data/app/vmdl[sessionId].tmp
stageDir = buildStageDir(params.volumeUuid, sessionId, isInstant);
} else {
// 如果是外置,会直接返回 "smdl" + sessionId + ".tmp"
stageCid = buildExternalStageCid(sessionId);
}
//【*1.5】创建 PackageInstallerSession 对象
session = new PackageInstallerSession(mInternalCallback, mContext, mPm,
mInstallThread.getLooper(), sessionId, userId, installerPackageName, callingUid,
params, createdMillis, stageDir, stageCid, false, false);
synchronized (mSessions) {
//【9】将新创建的 PackageInstallerSession 添加到 mSessions 集合中
mSessions.put(sessionId, session);
}
//【*1.6】通知有新的事务创建了,这里是直接回调 Callback 的接口
mCallbacks.notifySessionCreated(session.sessionId, session.userId);
//【*1.7】持久化事务 Session
writeSessionsAsync();
return sessionId;
}
获得 installerUid 创建的 Session 总数
private static int getSessionCount(SparseArray<PackageInstallerSession> sessions,
int installerUid) {
int count = 0;
final int size = sessions.size();
for (int i = 0; i < size; i++) {
final PackageInstallerSession session = sessions.valueAt(i);
//【1】匹配创建者的 uid
if (session.getInstallerUid() == installerUid) {
count++;
}
}
return count;
}
PackageInstallerService 有两个 SparseBooleanArray 成员变量:
//mSessions 保存了所有正在处理的 Session 实例,下标为创建事务的 uid,值为 PackageInstallerSession 是对 Session 的封装
@GuardedBy("mSessions")
private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>();
//mHistoricalSessions 保存了所有已经处理的 Session 实例,下标为创建事务的 uid,值为 PackageInstallerSession 是对 Session 的封装
/** Historical sessions kept around for debugging purposes */
@GuardedBy("mSessions")
private final List<String> mHistoricalSessions = new ArrayList<>();
allocateSessionIdLocked 方法用于给新的 Session 分配 id
@GuardedBy("mSessions")
private int allocateSessionIdLocked() {
int n = 0;
int sessionId;
do {
sessionId = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1;
if (!mAllocatedSessions.get(sessionId, false)) {
mAllocatedSessions.put(sessionId, true);
return sessionId;
}
} while (n++ < 32);
throw new IllegalStateException("Failed to allocate session ID");
}
//PackageInstallerService 还有一个 SparseBooleanArray 成员变量
/** All sessions allocated */
@GuardedBy("mSessions")
private final SparseBooleanArray mAllocatedSessions = new SparseBooleanArray();
//mAllocatedSessions 保存了所有的 Session 实例,包括正在处理和已经处理的(mSessions 和 mHistoricalSessions)
//下标为创建事务的 uid,值为 PackageInstallerSession 是对 Session 的封装
private File buildStageDir(String volumeUuid, int sessionId, boolean isEphemeral) {
final File stagingDir = buildStagingDir(volumeUuid, isEphemeral);
//在安装时,创建的临时文件目录是 /data/app/vmdl[sessionId].tmp
return new File(stagingDir, "vmdl" + sessionId + ".tmp");
}
PackageInstallerS.buildStagingDir
buildStagingDir 用于返回文件根目录
private File buildStagingDir(String volumeUuid, boolean isEphemeral) {
//【1】默认情况,返回的是 /data/app 目录
return Environment.getDataAppDirectory(volumeUuid);
}
创建 PackageInstallerSession,对前面的 SessionParams 再次封装
位置:./frameworks/base/services/core/java/com/android/server/pm/PackageInstallerService.java
public class PackageInstallerSession extends IPackageInstallerSession.Stub {
public PackageInstallerSession(PackageInstallerService.InternalCallback callback,
Context context, PackageManagerService pm, Looper looper, int sessionId, int userId,
String installerPackageName, int installerUid, SessionParams params, long createdMillis,
File stageDir, String stageCid, boolean prepared, boolean sealed) {
//这个callback是mInternalCallback 回调
mCallback = callback;
mContext = context;
mPm = pm;
//【2】创建 Handler 绑定到子线程 mInstallThread,该子线程是在 PackageInstallerService 构造器中创建的
//【*4.2】这里通过 mHandlerCallback 指定了一个回调函数
mHandler = new Handler(looper, mHandlerCallback);
//【3】基本属性保存
this.sessionId = sessionId;
this.userId = userId;
mOriginalInstallerUid = installerUid;
mInstallerPackageName = installerPackageName;
mInstallerUid = installerUid;
this.params = params;
this.createdMillis = createdMillis;
this.stageDir = stageDir; // 内置临时目录:/data/app/vmdl[sessionId].tmp
this.stageCid = stageCid; // 默认为 null
if ((stageDir == null) == (stageCid == null)) {
throw new IllegalArgumentException(
"Exactly one of stageDir or stageCid stage must be set");
}
mPrepared = prepared; // 传入 false
if (sealed) { // 传入 false
synchronized (mLock) {
try {
sealAndValidateLocked();
} catch (PackageManagerException | IOException e) {
destroyInternal();
throw new IllegalArgumentException(e);
}
}
}
final long identity = Binder.clearCallingIdentity();
try {
//【1】获得 container 的 uid 和 gid
final int uid = mPm.getPackageUid(PackageManagerService.DEFAULT_CONTAINER_PACKAGE,
PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
defaultContainerGid = UserHandle.getSharedAppGid(uid);
} finally {
Binder.restoreCallingIdentity(identity);
}
// attempt to bind to the DefContainer as early as possible
if ((params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
mHandler.sendMessage(mHandler.obtainMessage(MSG_EARLY_BIND));
}
}
@GuardedBy("mLock")
private void sealAndValidateLocked() throws PackageManagerException, IOException {
assertNoWriteFileTransfersOpenLocked();
assertPreparedAndNotDestroyedLocked("sealing of session");
final PackageInfo pkgInfo = mPm.getPackageInfo(
params.appPackageName, PackageManager.GET_SIGNATURES
| PackageManager.MATCH_STATIC_SHARED_LIBRARIES /*flags*/, userId);
resolveStageDirLocked();
mSealed = true;
// Verify that stage looks sane with respect to existing application.
// This currently only ensures packageName, versionCode, and certificate
// consistency.
//验证阶段相对于现有应用程序是否正常。
//这目前只能确保packageName、versionCode和证书的一致性。
try {
validateInstallLocked(pkgInfo);
} catch (PackageManagerException e) {
throw e;
} catch (Throwable e) {
// Convert all exceptions into package manager exceptions as only those are handled
// in the code above
throw new PackageManagerException(e);
}
// Read transfers from the original owner stay open, but as the session's data
// cannot be modified anymore, there is no leak of information.
}
}
可以看到 PackageInstallerSession 除了用来表示一个 Session 之外,由于继承了 IPackageInstallerSession.Stub,因此其还可以作为服务端的桩对象,进行跨进程的通信
这里的 DEFAULT_CONTAINER_PACKAGE是一个字符串常量:
public static final String DEFAULT_CONTAINER_PACKAGE = "com.android.defcontainer";
在创建 PackageInstallerSession 时,我们传入了一个回调对象 InternalCallback:
private final InternalCallback mInternalCallback = new InternalCallback();
//InternalCallback 类定义在 PackageInstallerService 中:
class InternalCallback {
public void onSessionBadgingChanged(PackageInstallerSession session) {
mCallbacks.notifySessionBadgingChanged(session.sessionId, session.userId);
//【*3.1.6】更新持久化文件
writeSessionsAsync();
}
//【1】当 Session 的活跃状态发生变化时,回调触发
public void onSessionActiveChanged(PackageInstallerSession session, boolean active) {
mCallbacks.notifySessionActiveChanged(session.sessionId, session.userId, active);
}
//【2】当 Session 的进度发生了变化,会触发该方法
public void onSessionProgressChanged(PackageInstallerSession session, float progress) {
mCallbacks.notifySessionProgressChanged(session.sessionId, session.userId, progress);
}
//【3】当 Session 完成后,会触发该方法
public void onSessionFinished(final PackageInstallerSession session, boolean success) {
mCallbacks.notifySessionFinished(session.sessionId, session.userId, success);
mInstallHandler.post(new Runnable() {
@Override
public void run() {
synchronized (mSessions) {
mSessions.remove(session.sessionId);
addHistoricalSessionLocked(session);
final File appIconFile = buildAppIconFile(session.sessionId);
if (appIconFile.exists()) {
appIconFile.delete();
}
//【*3.1.6.1】更新持久化文件
writeSessionsLocked();
}
}
});
}
public void onSessionPrepared(PackageInstallerSession session) {
// We prepared the destination to write into; we want to persist
// this, but it's not critical enough to block for.
//【*3.1.6】更新持久化文件
writeSessionsAsync();
}
public void onSessionSealedBlocking(PackageInstallerSession session) {
// It's very important that we block until we've recorded the
// session as being sealed, since we never want to allow mutation
// after sealing.
synchronized (mSessions) {
//【*3.1.6.1】更新持久化文件
writeSessionsLocked();
}
}
}
可以看到,当 Session 的状态发生变化后,InternalCallback 回调会触发
同时会回调 mCallbacks 的一些接口,而 mCallbacks 是在 PackageInstallerService 中创建的:
public PackageInstallerService(Context context, PackageManagerService pm) {
//...
//【*3.1.4.1.1】初始化 Callbacks!
mCallbacks = new Callbacks(mInstallThread.getLooper());
//...
}
Callbacks 是 Handler 的子类,持有子线程 mInstallThread 的 looper,Callbacks 是在
private static class Callbacks extends Handler {
//【1】内部会处理的消息
private static final int MSG_SESSION_CREATED = 1;
private static final int MSG_SESSION_BADGING_CHANGED = 2;
private static final int MSG_SESSION_ACTIVE_CHANGED = 3;
private static final int MSG_SESSION_PROGRESS_CHANGED = 4;
private static final int MSG_SESSION_FINISHED = 5;
//【2】监听安装状态的观察者 list
private final RemoteCallbackList<IPackageInstallerCallback>
mCallbacks = new RemoteCallbackList<>();
public Callbacks(Looper looper) {
super(looper);
}
//...
}
Callbacks 内部有一个 list,保存了所有监听 Session 状态变化的观察者,同时提供了 register 接口,动态注册观察者
public void register(IPackageInstallerCallback callback, int userId) {
mCallbacks.register(callback, new UserHandle(userId));
}
public void unregister(IPackageInstallerCallback callback) {
mCallbacks.unregister(callback);
}
Callbacks 内部有如下的 notify 接口,来通知 Session 的状态变化
private void notifySessionCreated(int sessionId, int userId) {
obtainMessage(MSG_SESSION_CREATED, sessionId, userId).sendToTarget();
}
private void notifySessionBadgingChanged(int sessionId, int userId) {
obtainMessage(MSG_SESSION_BADGING_CHANGED, sessionId, userId).sendToTarget();
}
private void notifySessionActiveChanged(int sessionId, int userId, boolean active) {
obtainMessage(MSG_SESSION_ACTIVE_CHANGED, sessionId, userId, active).sendToTarget();
}
private void notifySessionProgressChanged(int sessionId, int userId, float progress) {
obtainMessage(MSG_SESSION_PROGRESS_CHANGED, sessionId, userId, progress).sendToTarget();
}
public void notifySessionFinished(int sessionId, int userId, boolean success) {
obtainMessage(MSG_SESSION_FINISHED, sessionId, userId, success).sendToTarget();
}
本质上是发送不同的 msg
@Override
public void handleMessage(Message msg) {
final int userId = msg.arg2;
final int n = mCallbacks.beginBroadcast();
for (int i = 0; i < n; i++) {
//【1】遍历所有的观察者
final IPackageInstallerCallback callback = mCallbacks.getBroadcastItem(i);
final UserHandle user = (UserHandle) mCallbacks.getBroadcastCookie(i);
// TODO: dispatch notifications for slave profiles
if (userId == user.getIdentifier()) {
try {
//【*3.1.4.1.3】分发 Session 消息给观察者
invokeCallback(callback, msg);
} catch (RemoteException ignored) {
}
}
}
mCallbacks.finishBroadcast();
}
最后调用了 invokeCallback,其实可以看到 IPackageInstallerCallback 针对于不同的消息也有不同的接口
private void invokeCallback(IPackageInstallerCallback callback, Message msg)
throws RemoteException {
final int sessionId = msg.arg1;
switch (msg.what) {
case MSG_SESSION_CREATED:
callback.onSessionCreated(sessionId);
break;
case MSG_SESSION_BADGING_CHANGED:
callback.onSessionBadgingChanged(sessionId);
break;
case MSG_SESSION_ACTIVE_CHANGED:
callback.onSessionActiveChanged(sessionId, (boolean) msg.obj);
break;
case MSG_SESSION_PROGRESS_CHANGED:
callback.onSessionProgressChanged(sessionId, (float) msg.obj);
break;
case MSG_SESSION_FINISHED:
callback.onSessionFinished(sessionId, (boolean) msg.obj);
break;
}
}
private void writeSessionsAsync() {
IoThread.getHandler().post(new Runnable() {
@Override
public void run() {
synchronized (mSessions) {
//【1.6.1】将事务记录到 mSessionsFile 文件中
writeSessionsLocked();
}
}
});
}
mSessionsFile 在 PackageInstallerService 构造器中有见过:/data/system/install_sessions.xml
private void writeSessionsLocked() {
if (LOGD) Slog.v(TAG, "writeSessionsLocked()");
FileOutputStream fos = null;
try {
fos = mSessionsFile.startWrite();
XmlSerializer out = new FastXmlSerializer();
out.setOutput(fos, StandardCharsets.UTF_8.name());
out.startDocument(null, true);
out.startTag(null, TAG_SESSIONS); //【1】写入 sessions 标签
final int size = mSessions.size();
for (int i = 0; i < size; i++) {
final PackageInstallerSession session = mSessions.valueAt(i);
//【*3.1.6.2】写入所有的 Sessions
session.write(out, mSessionsDir);
}
out.endTag(null, TAG_SESSIONS);
out.endDocument();
mSessionsFile.finishWrite(fos);
} catch (IOException e) {
if (fos != null) {
mSessionsFile.failWrite(fos);
}
}
}
位置:"./frameworks/base/services/core/java/com/android/server/pm/PackageInstallerSession.java"
这里的name传入的是base.apk
@Override
public void write(String name, long offsetBytes, long lengthBytes,
ParcelFileDescriptor fd) {
try { //继续调用doWriteInternal方法处理
doWriteInternal(name, offsetBytes, lengthBytes, fd);
} catch (IOException e) {
throw ExceptionUtils.wrap(e);
}
}
private ParcelFileDescriptor doWriteInternal(String name, long offsetBytes, long lengthBytes,
ParcelFileDescriptor incomingFd) throws IOException {
// Quick sanity check of state, and allocate a pipe for ourselves. We
// then do heavy disk allocation outside the lock, but this open pipe
// will block any attempted install transitions.
final RevocableFileDescriptor fd;
final FileBridge bridge;
final File stageDir;
synchronized (mLock) {
assertCallerIsOwnerOrRootLocked(); //确保权限是root
assertPreparedAndNotSealedLocked("openWrite");
if (PackageInstaller.ENABLE_REVOCABLE_FD) {
fd = new RevocableFileDescriptor();
bridge = null;
mFds.add(fd);
} else {
fd = null;
bridge = new FileBridge();
mBridges.add(bridge);
}
//【1】创建 /data/app/vmdl[sessionId].tmp/base.apk 对应的文件对象
stageDir = resolveStageDirLocked();
}
try {
// Use installer provided name for now; we always rename later
if (!FileUtils.isValidExtFilename(name)) {
throw new IllegalArgumentException("Invalid name: " + name);
}
final File target;
final long identity = Binder.clearCallingIdentity();
try {
//【1】创建 /data/app/vmdl[sessionId].tmp/base.apk 对应的文件对象
target = new File(stageDir, name);
} finally {
Binder.restoreCallingIdentity(identity);
}
// TODO: this should delegate to DCS so the system process avoids
// holding open FDs into containers.
//【2】返回其文件描述符
final FileDescriptor targetFd = Os.open(target.getAbsolutePath(),
O_CREAT | O_WRONLY, 0644);
Os.chmod(target.getAbsolutePath(), 0644);
// If caller specified a total length, allocate it for them. Free up
// cache space to grow, if needed.
//【3】如果指定了大小,那么这里会做一次空间回收
if (stageDir != null && lengthBytes > 0) {
mContext.getSystemService(StorageManager.class).allocateBytes(targetFd, lengthBytes,
PackageHelper.translateAllocateFlags(params.installFlags));
}
if (offsetBytes > 0) {
Os.lseek(targetFd, offsetBytes, OsConstants.SEEK_SET);
}
if (incomingFd != null) {
switch (Binder.getCallingUid()) {
case android.os.Process.SHELL_UID:
case android.os.Process.ROOT_UID:
break;
default:
throw new SecurityException("Reverse mode only supported from shell");
}
// In "reverse" mode, we're streaming data ourselves from the
// incoming FD, which means we never have to hand out our
// sensitive internal FD. We still rely on a "bridge" being
// inserted above to hold the session active.
try {
final Int64Ref last = new Int64Ref(0);
FileUtils.copy(incomingFd.getFileDescriptor(), targetFd, (long progress) -> {
if (params.sizeBytes > 0) {
final long delta = progress - last.value;
last.value = progress;
addClientProgress((float) delta / (float) params.sizeBytes);
}
}, null, lengthBytes);
} finally {
IoUtils.closeQuietly(targetFd);
IoUtils.closeQuietly(incomingFd);
// We're done here, so remove the "bridge" that was holding
// the session active.
synchronized (mLock) {
if (PackageInstaller.ENABLE_REVOCABLE_FD) {
mFds.remove(fd);
} else {
mBridges.remove(bridge);
}
}
}
return null;
} else if (PackageInstaller.ENABLE_REVOCABLE_FD) {
fd.init(mContext, targetFd);
return fd.getRevocableFileDescriptor();
} else {
//【4】使用 FileBridge 封装文件描述符
bridge.setTargetFile(targetFd);
bridge.start();
return new ParcelFileDescriptor(bridge.getClientSocket());
}
} catch (ErrnoException e) {
throw e.rethrowAsIOException();
}
}
在android 9 adb安装过程学习(一) 的4.2.3.1中分析了commit的函数:
@Override
public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
Preconditions.checkNotNull(statusReceiver);
final boolean wasSealed;
synchronized (mLock) {
assertCallerIsOwnerOrRootLocked();
assertPreparedAndNotDestroyedLocked("commit");
//【*4.2.1】创建了一个 PackageInstallObserverAdapter 实例
// 会将前面创建的 IntentSender 实例,作为参数传入
final PackageInstallObserverAdapter adapter = new PackageInstallObserverAdapter(
mContext, statusReceiver, sessionId,
isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked(), userId);
mRemoteObserver = adapter.getBinder();
if (forTransfer) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, null);
if (mInstallerUid == mOriginalInstallerUid) {
throw new IllegalArgumentException("Session has not been transferred");
}
} else {
if (mInstallerUid != mOriginalInstallerUid) {
throw new IllegalArgumentException("Session has been transferred");
}
}
wasSealed = mSealed;
if (!mSealed) {
// 校验所有的写操作都已经完成了,正常情况下,是肯定完成了的
try {
sealAndValidateLocked();
} catch (IOException e) {
throw new IllegalArgumentException(e);
} catch (PackageManagerException e) {
// Do now throw an exception here to stay compatible with O and older
destroyInternal();
dispatchSessionFinished(e.error, ExceptionUtils.getCompleteMessage(e), null);
return;
}
}
// Client staging is fully done at this point
//【1】由于此时文件已经拷贝完成,这里更新进度为完成
mClientProgress = 1f;
//【*4.2.3.5】通知结果
computeProgressLocked(true);
// This ongoing commit should keep session active, even though client
// will probably close their end.
//【2】活跃计数 +1,表示该 Session 处于活跃状态
mActiveCount.incrementAndGet();
mCommitted = true;
//【*4.2.2】发送 MSG_COMMIT 消息
mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
}
if (!wasSealed) {
// Persist the fact that we've sealed ourselves to prevent
// mutations of any hard links we create. We do this without holding
// the session lock, since otherwise it's a lock inversion.
mCallback.onSessionSealedBlocking(this);
}
}
mActiveCount 加 1,表示该事务处于活跃状态,直到安装完成
这里的 PackageInstallObserverAdapter.getBinder() 返回是一个服务端 Stub 桩对象
PackageInstallObserverAdapter 定义在 PackageInstallService 中:
static class PackageInstallObserverAdapter extends PackageInstallObserver {
private final Context mContext; // 系统进程的上下文
private final IntentSender mTarget; // 前面创建的 IntentSender 实例
private final int mSessionId; // 事务的 id
private final boolean mShowNotification; // 是否显示通知,取决于安装者是否是设备用户
private final int mUserId;
public PackageInstallObserverAdapter(Context context, IntentSender target, int sessionId,
boolean showNotification, int userId) {
mContext = context;
mTarget = target;
mSessionId = sessionId;
mShowNotification = showNotification;
mUserId = userId;
}
//...
PackageInstallObserverAdapter 继承了 PackageInstallObserver
public class PackageInstallObserver {
//【1】服务端桩对象
private final IPackageInstallObserver2.Stub mBinder = new IPackageInstallObserver2.Stub() {
@Override
public void onUserActionRequired(Intent intent) {
//【1.1】调用子类的 onUserActionRequired 方法
PackageInstallObserver.this.onUserActionRequired(intent);
}
@Override
public void onPackageInstalled(String basePackageName, int returnCode,
String msg, Bundle extras) {
//【1.2】调用子类的 onPackageInstalled 方法
PackageInstallObserver.this.onPackageInstalled(basePackageName, returnCode, msg,
extras);
}
};
/** {@hide} */
public IPackageInstallObserver2 getBinder() {
//【2】用于返回服务端桩对象
return mBinder;
}
//...
}
PackageInstallObserverAdapter 继承了 PackageInstallObserver,并覆写了以下两个方法:
覆写 onUserActionRequired,当安装过程需要用户参与授权时,会回调该接口,此时会中断安装,事务从 active 变为 idle 状态
覆写 onPackageInstalled,当安装完成后,会回调该接口
@Override
static class PackageInstallObserverAdapter extends PackageInstallObserver {
//...
public void onUserActionRequired(Intent intent) {
final Intent fillIn = new Intent();
//【1】事务 id
fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId);
//【2】当前的状态:PackageInstaller.STATUS_PENDING_USER_ACTION
fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
PackageInstaller.STATUS_PENDING_USER_ACTION);
// 额外的 intent
fillIn.putExtra(Intent.EXTRA_INTENT, intent);
try {
//【*2.9.4.1】发送 intent,其实,这里我们知道,该 intent 会发送到前面的 LocalIntentReceiver
//关于这个额外的 Intent,我们后面会看到
mTarget.sendIntent(mContext, 0, fillIn, null, null);
} catch (SendIntentException ignored) {
}
}
@Override
public void onPackageInstalled(String basePackageName, int returnCode, String msg,
Bundle extras) {
//【1】当安装成功,并且需要弹出通知时,会在这里显示通知
if (PackageManager.INSTALL_SUCCEEDED == returnCode && mShowNotification) {
boolean update = (extras != null) && extras.getBoolean(Intent.EXTRA_REPLACING);
Notification notification = buildSuccessNotification(mContext,
mContext.getResources()
.getString(update ? R.string.package_updated_device_owner :
R.string.package_installed_device_owner),
basePackageName,
mUserId);
if (notification != null) {
NotificationManager notificationManager = (NotificationManager)
mContext.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(basePackageName,
SystemMessage.NOTE_PACKAGE_STATE,
notification);
}
}
//【2】创建一个 intent,保存了安装结果等信息
final Intent fillIn = new Intent();
fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, basePackageName);
fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId);
fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
PackageManager.installStatusToPublicStatus(returnCode));
fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
PackageManager.installStatusToString(returnCode, msg));
fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);
if (extras != null) {
final String existing = extras.getString(
PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE);
if (!TextUtils.isEmpty(existing)) {
fillIn.putExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME, existing);
}
}
try {
//【*2.9.4.1】发送 intent,其实,这里我们知道,该 intent 会发送到前面的 LocalIntentReceiver
mTarget.sendIntent(mContext, 0, fillIn, null, null);
} catch (SendIntentException ignored) {
}
}
};
在"./frameworks/base/services/core/java/com/android/server/pm/PackageInstallerSession.java"
的commit函数最后:
mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
mHandler 的初始化是在 PackageInstallerSession 的构造器中:
public PackageInstallerSession(PackageInstallerService.InternalCallback callback,
Context context, PackageManagerService pm, Looper looper, int sessionId, int userId,
String installerPackageName, int installerUid, SessionParams params, long createdMillis,
File stageDir, String stageCid, boolean prepared, boolean sealed) {
mCallback = callback;
mContext = context;
mPm = pm;
//【*4.2.1】handler 会处理该消息,我们看到,其传入了一个 mHandlerCallback 回调
mHandler = new Handler(looper, mHandlerCallback);
//...
}
如果我们直接发送 MSG_COMMIT 消息,回调 mHandlerCallback 会立刻触发
Handler.Callback.handleMessage[MSG_COMMIT]
private final Handler.Callback mHandlerCallback = new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
//【1】获得要安装的应用的信息,如果是第一次安装的话,那么二者返回的均为 null
switch (msg.what) {
case MSG_EARLY_BIND:
earlyBindToDefContainer();
break;
case MSG_COMMIT:
synchronized (mLock) {
try {
//【*4.2.3】调用 commitLocked 处理
commitLocked();
} catch (PackageManagerException e) {
final String completeMsg = ExceptionUtils.getCompleteMessage(e);
Slog.e(TAG,
"Commit of session " + sessionId + " failed: " + completeMsg);
destroyInternal();
dispatchSessionFinished(e.error, completeMsg, null);
}
}
break;
case MSG_ON_PACKAGE_INSTALLED:
final SomeArgs args = (SomeArgs) msg.obj;
final String packageName = (String) args.arg1;
final String message = (String) args.arg2;
final Bundle extras = (Bundle) args.arg3;
//【2】获得前面 PackageInstallObserverAdapter 内部的 PackageInstallObserver2 桩对象
final IPackageInstallObserver2 observer = (IPackageInstallObserver2) args.arg4;
final int returnCode = args.argi1;
args.recycle();
try {
observer.onPackageInstalled(packageName, returnCode, message, extras);
} catch (RemoteException ignored) {
}
break;
}
return true;
}
};
PackageInstallerSession 内部有一个 mRemoteObserver 成员变量,后面我们会见到
@GuardedBy("mLock")
private IPackageInstallObserver2 mRemoteObserver;
@GuardedBy("mLock")
private void commitLocked()
throws PackageManagerException {
if (mDestroyed) {
throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed");
}
if (!mSealed) {
throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session not sealed");
}
// 非 null 校验
Preconditions.checkNotNull(mPackageName);
Preconditions.checkNotNull(mSigningDetails);
Preconditions.checkNotNull(mResolvedBaseFile);
//【1】mPermissionsAccepted 为 true,那么用户就可以静默安装了,如果为 false,那么就需要用户确认权限
if (needToAskForPermissionsLocked()) {
// User needs to accept permissions; give installer an intent they
// can use to involve user.
//【1.1】这里会创建一个 intent, action 为 PackageInstaller.ACTION_CONFIRM_PERMISSIONS
// 目标应用是 PackageInstaller,这里会先进入 packageinstaller 中确认权限信息
final Intent intent = new Intent(PackageInstaller.ACTION_CONFIRM_PERMISSIONS);
intent.setPackage(mContext.getPackageManager().getPermissionControllerPackageName());
intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId); // 事务 id 也要从传递过去
try {
//【*4.2.1.1】回调了 PackageInstallObserverAdapter 的 onUserActionRequired 接口
// 将 intent 传递过去
mRemoteObserver.onUserActionRequired(intent);
} catch (RemoteException ignored) {
}
// 关闭事务,使其从active变为idle状态
closeInternal(false);
// 停止安装,等待用户确认权限,用户在 PackageInstaller 点击安装,安装会继续
return;
}
// Inherit any packages and native libraries from existing install that
// haven't been overridden.
//【3】如果安装方式是继承已存在的 apk,那我们就要尝试基于已有的安装进行安装,这个一般用于安装和卸载 split apk
if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
try {
final List<File> fromFiles = mResolvedInheritedFiles;
final File toDir = resolveStageDirLocked(); // 这是我们本次安装的目录
if (LOGD) Slog.d(TAG, "Inherited files: " + mResolvedInheritedFiles);
if (!mResolvedInheritedFiles.isEmpty() && mInheritedFilesBase == null) {
throw new IllegalStateException("mInheritedFilesBase == null");
}
//【3.1】如果可以直接建立 link 的话,不行的话,就 copy
if (isLinkPossible(fromFiles, toDir)) {
if (!mResolvedInstructionSets.isEmpty()) {
final File oatDir = new File(toDir, "oat");
createOatDirs(mResolvedInstructionSets, oatDir);
}
// pre-create lib dirs for linking if necessary
if (!mResolvedNativeLibPaths.isEmpty()) {
for (String libPath : mResolvedNativeLibPaths) {
// "/lib/arm64" -> ["lib", "arm64"]
final int splitIndex = libPath.lastIndexOf('/');
if (splitIndex < 0 || splitIndex >= libPath.length() - 1) {
Slog.e(TAG, "Skipping native library creation for linking due to "
+ "invalid path: " + libPath);
continue;
}
final String libDirPath = libPath.substring(1, splitIndex);
final File libDir = new File(toDir, libDirPath);
if (!libDir.exists()) {
NativeLibraryHelper.createNativeLibrarySubdir(libDir);
}
final String archDirPath = libPath.substring(splitIndex + 1);
NativeLibraryHelper.createNativeLibrarySubdir(
new File(libDir, archDirPath));
}
}
linkFiles(fromFiles, toDir, mInheritedFilesBase);
} else {
// TODO: this should delegate to DCS so the system process
// avoids holding open FDs into containers.
//【3.2】执行拷贝,其实是将已经存在的目录的 apk,oat 文件拷贝到了这个目录!
// 对于要 remove 的文件,则会跳过拷贝
copyFiles(fromFiles, toDir);
}
} catch (IOException e) {
throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
"Failed to inherit existing install", e);
}
}
// TODO: surface more granular state from dexopt
//【4】更新进度
mInternalProgress = 0.5f;
//【*4.2.3.5】通知结果
computeProgressLocked(true);
// Unpack native libraries
//【*4.2.3.6】提取 lib 库文件到目录中
extractNativeLibraries(mResolvedStageDir, params.abiOverride, mayInheritNativeLibs());
// We've reached point of no return; call into PMS to install the stage.
// Regardless of success or failure we always destroy session.
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) {
//【*5.8.2.1】删除目录文件
destroyInternal();
//【*5.8.2.2】处理回调,通知监听者
dispatchSessionFinished(returnCode, msg, extras);
}
};
//【6】处理要安装的目标设别用户
final UserHandle user;
if ((params.installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {
user = UserHandle.ALL;
} else {
user = new UserHandle(userId);
}
mRelinquished = true;
//【×5.1】然后继续安装
mPm.installStage(mPackageName, stageDir, localObserver, params,
mInstallerPackageName, mInstallerUid, user, mSigningDetails);
}
/**
* Resolve the actual location where staged data should be written. This
* might point at an ASEC mount point, which is why we delay path resolution
* until someone actively works with the session.
*/
@GuardedBy("mLock")
private File resolveStageDirLocked() throws IOException {
if (mResolvedStageDir == null) {
if (stageDir != null) {
//【1】将之前保存的目录 stageDir 值赋给 mResolvedStageDir 并返回
mResolvedStageDir = stageDir;
} else {
throw new IOException("Missing stageDir");
}
}
return mResolvedStageDir;
}
校验安装有效性,这里的 mResolvedStageDir 就是前面的 /data/app/vmdl[sessionId].tmp 目录
@GuardedBy("mLock")
private void validateInstallLocked(@Nullable PackageInfo pkgInfo)
throws PackageManagerException {
mPackageName = null;
mVersionCode = -1;
mSigningDetails = PackageParser.SigningDetails.UNKNOWN;
mResolvedBaseFile = null;
mResolvedStagedFiles.clear();
mResolvedInheritedFiles.clear();
try {
resolveStageDirLocked();
} catch (IOException e) {
throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
"Failed to resolve stage location", e);
}
//【1】返回 /data/app/vmdl[sessionId].tmp 目录下所有的 .removed 文件!
// 去除后缀,将前缀名保存到 removeSplitList
final File[] removedFiles = mResolvedStageDir.listFiles(sRemovedFilter);
final List<String> removeSplitList = new ArrayList<>();
if (!ArrayUtils.isEmpty(removedFiles)) {
for (File removedFile : removedFiles) {
final String fileName = removedFile.getName();
final String splitName = fileName.substring(
0, fileName.length() - REMOVE_SPLIT_MARKER_EXTENSION.length());
removeSplitList.add(splitName);
}
}
//【2】返回 /data/app/vmdl[sessionId].tmp 目录下所有的非 .removed 文件!
// 并判断是否正常,如果该目录下没有任何 apk 和 .removed 文件,那么抛出异常
final File[] addedFiles = mResolvedStageDir.listFiles(sAddedFilter);
if (ArrayUtils.isEmpty(addedFiles) && removeSplitList.size() == 0) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged");
}
// Verify that all staged packages are internally consistent
//【3】遍历该目录下的非 .removed 文件,解析其中的 apk 文件,也就是我们之前 copy 到这里的目标文件!
// 卸载和安装 split 都会进入这里
final ArraySet<String> stagedSplits = new ArraySet<>();
for (File addedFile : addedFiles) {
final ApkLite apk;
try {
//【3.1】解析要安装的 apk,具体的流程这里就不分析了
apk = PackageParser.parseApkLite(
addedFile, PackageParser.PARSE_COLLECT_CERTIFICATES);
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
}
//【3.2】将其添加到 stagedSplits 中,注意 base.apk 的 apk.splitName 为 null
if (!stagedSplits.add(apk.splitName)) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Split " + apk.splitName + " was defined multiple times");
}
// Use first package to define unknown values
//【3.3】将第一个被解析 apk 的包名,版本号,签名,证书保存下载,这个目录下的其他 apk
// 的这几项要和其保持一致
if (mPackageName == null) {
mPackageName = apk.packageName;
mVersionCode = apk.getLongVersionCode();
}
if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) {
mSigningDetails = apk.signingDetails;
}
//【*2.3.2.1】校验 apk 关联性
assertApkConsistentLocked(String.valueOf(addedFile), apk);
// Take this opportunity to enforce uniform naming
//【3.4】设置 apk 文件的目标名称
final String targetName;
if (apk.splitName == null) {
targetName = "base" + APK_FILE_EXTENSION; // 一般情况下,我们只装 base.apk
} else {
targetName = "split_" + apk.splitName + APK_FILE_EXTENSION; // 对于 split_xxx.apk 名称是这样的
}
if (!FileUtils.isValidExtFilename(targetName)) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Invalid filename: " + targetName);
}
//【3.5】当 addedFile 命名不标准的话,会改名
final File targetFile = new File(mResolvedStageDir, targetName);
maybeRenameFile(addedFile, targetFile);
// Base is coming from session
//【3.6】找到了 base apk,将其保存到 mResolvedBaseFile,同时将其添加到 mResolvedStagedFiles 中
if (apk.splitName == null) {
mResolvedBaseFile = targetFile;
}
mResolvedStagedFiles.add(targetFile);
final File dexMetadataFile = DexMetadataHelper.findDexMetadataForFile(addedFile);
if (dexMetadataFile != null) {
if (!FileUtils.isValidExtFilename(dexMetadataFile.getName())) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Invalid filename: " + dexMetadataFile);
}
final File targetDexMetadataFile = new File(mResolvedStageDir,
DexMetadataHelper.buildDexMetadataPathForApk(targetName));
mResolvedStagedFiles.add(targetDexMetadataFile);
maybeRenameFile(dexMetadataFile, targetDexMetadataFile);
}
}
//【4】处理 .removed 文件(卸载 split apk,才会进入这里)
if (removeSplitList.size() > 0) {
if (pkgInfo == null) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Missing existing base package for " + mPackageName);
}
// validate split names marked for removal
//【4.1】找不到 split apk,抛出异常
for (String splitName : removeSplitList) {
if (!ArrayUtils.contains(pkgInfo.splitNames, splitName)) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Split not found: " + splitName);
}
}
// ensure we've got appropriate package name, version code and signatures
// 再次获得要安装的应用的包名,版本号,签名
if (mPackageName == null) {
mPackageName = pkgInfo.packageName;
mVersionCode = pkgInfo.getLongVersionCode();
}
if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) {
try {
mSigningDetails = ApkSignatureVerifier.plsCertsNoVerifyOnlyCerts(
pkgInfo.applicationInfo.sourceDir,
PackageParser.SigningDetails.SignatureSchemeVersion.JAR);
} catch (PackageParserException e) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Couldn't obtain signatures from base APK");
}
}
}
//【5】处理安装模式
if (params.mode == SessionParams.MODE_FULL_INSTALL) {
// Full installs must include a base package
//【5.1】全量安装必须要有 base.apk
if (!stagedSplits.contains(null)) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Full install must include a base package");
}
} else {
// Partial installs must be consistent with existing install
//【5.2】部分安装必须基于现有的安装(卸载和安装 split apk 也会进入这里)
if (pkgInfo == null || pkgInfo.applicationInfo == null) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Missing existing base package for " + mPackageName);
}
//【5.3】获得已存在的 apk 安装信息,这里会解析主 apk 的安装信息
final PackageLite existing;
final ApkLite existingBase;
ApplicationInfo appInfo = pkgInfo.applicationInfo;
try {
existing = PackageParser.parsePackageLite(new File(appInfo.getCodePath()), 0);
existingBase = PackageParser.parseApkLite(new File(appInfo.getBaseCodePath()),
PackageParser.PARSE_COLLECT_CERTIFICATES);
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
}
//【*4.3.2.1】再次校验要本次要安装的 apk 和已存在的 apk 是有关联,包括包名,签名,版本号
assertApkConsistentLocked("Existing base", existingBase);
// Inherit base if not overridden
//【5.4】继承已有的 base apk,如果没有指定安装的 apk
if (mResolvedBaseFile == null) {
mResolvedBaseFile = new File(appInfo.getBaseCodePath());
mResolvedInheritedFiles.add(mResolvedBaseFile);
// Inherit the dex metadata if present.
final File baseDexMetadataFile =
DexMetadataHelper.findDexMetadataForFile(mResolvedBaseFile);
if (baseDexMetadataFile != null) {
mResolvedInheritedFiles.add(baseDexMetadataFile);
}
}
// Inherit splits if not overridden
//【5.5】继承已有的 split apk,要继承的 split apk 不能是在 removeSplitList 列表中
if (!ArrayUtils.isEmpty(existing.splitNames)) {
for (int i = 0; i < existing.splitNames.length; i++) {
final String splitName = existing.splitNames[i];
final File splitFile = new File(existing.splitCodePaths[i]);
final boolean splitRemoved = removeSplitList.contains(splitName);
if (!stagedSplits.contains(splitName) && !splitRemoved) {
mResolvedInheritedFiles.add(splitFile);
// Inherit the dex metadata if present.
final File splitDexMetadataFile =
DexMetadataHelper.findDexMetadataForFile(splitFile);
if (splitDexMetadataFile != null) {
mResolvedInheritedFiles.add(splitDexMetadataFile);
}
}
}
}
// Inherit compiled oat directory.
//【5.6】继承已有的 oat 相关文件
final File packageInstallDir = (new File(appInfo.getBaseCodePath())).getParentFile();
mInheritedFilesBase = packageInstallDir;
final File oatDir = new File(packageInstallDir, "oat");
if (oatDir.exists()) {
final File[] archSubdirs = oatDir.listFiles();
// Keep track of all instruction sets we've seen compiled output for.
// If we're linking (and not copying) inherited files, we can recreate the
// instruction set hierarchy and link compiled output.
if (archSubdirs != null && archSubdirs.length > 0) {
final String[] instructionSets = InstructionSets.getAllDexCodeInstructionSets();
for (File archSubDir : archSubdirs) {
// Skip any directory that isn't an ISA subdir.
if (!ArrayUtils.contains(instructionSets, archSubDir.getName())) {
continue;
}
// 将要继承的 oat 目录文件名添加到 mResolvedInstructionSets
mResolvedInstructionSets.add(archSubDir.getName());
List<File> oatFiles = Arrays.asList(archSubDir.listFiles());
if (!oatFiles.isEmpty()) {
// 将要继承的 odex 相关文件添加到 mResolvedInheritedFiles
mResolvedInheritedFiles.addAll(oatFiles);
}
}
}
}
// Inherit native libraries for DONT_KILL sessions.
if (mayInheritNativeLibs() && removeSplitList.isEmpty()) {
File[] libDirs = new File[]{
new File(packageInstallDir, NativeLibraryHelper.LIB_DIR_NAME),
new File(packageInstallDir, NativeLibraryHelper.LIB64_DIR_NAME)};
for (File libDir : libDirs) {
if (!libDir.exists() || !libDir.isDirectory()) {
continue;
}
final List<File> libDirsToInherit = new LinkedList<>();
for (File archSubDir : libDir.listFiles()) {
if (!archSubDir.isDirectory()) {
continue;
}
String relLibPath;
try {
relLibPath = getRelativePath(archSubDir, packageInstallDir);
} catch (IOException e) {
Slog.e(TAG, "Skipping linking of native library directory!", e);
// shouldn't be possible, but let's avoid inheriting these to be safe
libDirsToInherit.clear();
break;
}
if (!mResolvedNativeLibPaths.contains(relLibPath)) {
mResolvedNativeLibPaths.add(relLibPath);
}
libDirsToInherit.addAll(Arrays.asList(archSubDir.listFiles()));
}
mResolvedInheritedFiles.addAll(libDirsToInherit);
}
}
}
}
总结下:
1、返回 /data/app/vmdl[sessionId].tmp 目录下所有的 .removed 文件,去除后缀,将前缀名保存到 removeSplitList
2、/data/app/vmdl[sessionId].tmp 目录下必须要有 apk 文件或者 .removed 文件
3、遍历该目录下的非 .removed 文件,对其 packagename versionCode 和签名做关联校验
4、stagedSplits 用于保存该目录下的所有 apk 的 splitName,base apk 的 splitName 为 null
5、mResolvedBaseFile 用于保存 base apk
6、mResolvedStagedFiles 用于保存目录下所有的 apk
7、removeSplitList 大于 0,说明有要移除的 split apk,前提是主 apk 要有 split apk
8、对于 MODE_FULL_INSTALL,全量安装,必须要有 base apk
9、对于 MODE_INHERIT_EXISTING,继承安装,会再次解析主 apk,收集那些不在 removeSplitList 列表中的 splitApk 路径到 mResolvedInheritedFiles 中
校验 apk 的一致性,ApkLite apk 为扫描到的文件
@GuardedBy("mLock")
private void assertApkConsistentLocked(String tag, ApkLite apk)
throws PackageManagerException {
//【1】扫描到的 apk 的包名必须和该目录下第一个被扫描到的 apk 包名保持一致
if (!mPackageName.equals(apk.packageName)) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " package "
+ apk.packageName + " inconsistent with " + mPackageName);
}
//【2】如果是要继承已安装的 apk,那么包名要一样
if (params.appPackageName != null && !params.appPackageName.equals(apk.packageName)) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
+ " specified package " + params.appPackageName
+ " inconsistent with " + apk.packageName);
}
//【3】扫描到的 apk 的版本号必须和该目录下第一个被扫描到的 apk 版本号保持一致
if (mVersionCode != apk.getLongVersionCode()) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
+ " version code " + apk.versionCode + " inconsistent with "
+ mVersionCode);
}
//【4】扫描到的 apk 的签名必须和该目录下第一个被扫描到的 apk 签名保持一致
if (!mSigningDetails.signaturesMatchExactly(apk.signingDetails)) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
tag + " signatures are inconsistent");
}
}
close 方法很简单,将事务的 mActiveCount 引用计数自减 1,同时回调
@Override
public void close() {
closeInternal(true);
}
private void closeInternal(boolean checkCaller) {
int activeCount;
synchronized (mLock) {
if (checkCaller) {
assertCallerIsOwnerOrRootLocked();
}
activeCount = mActiveCount.decrementAndGet();
}
if (activeCount == 0) {
mCallback.onSessionActiveChanged(this, false);
}
}
@GuardedBy("mLock")
private void computeProgressLocked(boolean forcePublish) {
//【1】计算进度
mProgress = MathUtils.constrain(mClientProgress * 0.8f, 0f, 0.8f)
+ MathUtils.constrain(mInternalProgress * 0.2f, 0f, 0.2f);
// Only publish when meaningful change
//【2】更新进度
if (forcePublish || Math.abs(mProgress - mReportedProgress) >= 0.01) {
mReportedProgress = mProgress;
//【*3.1.4.2】同时通知事务观察者,进度的变化
mCallback.onSessionProgressChanged(this, mProgress);
}
}
提取本地的 lib 库文件
private static void extractNativeLibraries(File packageDir, String abiOverride, boolean inherit)
throws PackageManagerException {
//【1】libDir 指向 /data/app/vmdl[id].tmp/lib 目录,这里是删除目录下存在的 lib 库文件
final File libDir = new File(packageDir, NativeLibraryHelper.LIB_DIR_NAME);
if (!inherit) {
// Start from a clean slate
NativeLibraryHelper.removeNativeBinariesFromDirLI(libDir, true);
}
NativeLibraryHelper.Handle handle = null;
try {
//【2】创建 lib 子目录,并将应用程序中的 lib 库拷贝到该目录下
handle = NativeLibraryHelper.Handle.create(packageDir);
final int res = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libDir,
abiOverride);
if (res != PackageManager.INSTALL_SUCCEEDED) {
throw new PackageManagerException(res,
"Failed to extract native libraries, res=" + res);
}
} catch (IOException e) {
throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
"Failed to extract native libraries", e);
} finally {
IoUtils.closeQuietly(handle);
}
}
对于 lib 的提取,这里涉及到了 NativeLibraryHelper,我们先不过多关注其实现