中小企业网站制作是什么,个人简历网站模板免费,家庭办厂3一8万项目,定制软件下载一、PackageInstalllerService流程分析
下面来分析下 PackageInstallerService 中的逻辑#xff0c;我们先来看看 PackageInstallerService 的创建#xff0c;当然#xff0c;这部分的逻辑是在开机的时候#xff0c;这里我们再回顾下#xff1a; 位置#xff1a;./frame…一、PackageInstalllerService流程分析
下面来分析下 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 对应的 HandlermInstallHandler new Handler(mInstallThread.getLooper());//创建了 Callbacks 实例用于处理安装回调传入了子线程的 LoopdermCallbacks 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 这里就不在过多分析我们继续看
1.1 PackageInstallerS.createSession(Internal) - 创建事务 Overridepublic 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 是否属于 uidif (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 isnt 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】给本次安装分配一个事务 idsessionId allocateSessionIdLocked();}final long createdMillis System.currentTimeMillis();// Were 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].tmpstageDir buildStageDir(params.volumeUuid, sessionId, isInstant);} else {// 如果是外置会直接返回 smdl sessionId .tmpstageCid 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】持久化事务 SessionwriteSessionsAsync();return sessionId;}1.2 PackageInstallerS.getSessionCount
获得 installerUid 创建的 Session 总数 private static int getSessionCount(SparseArrayPackageInstallerSession 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】匹配创建者的 uidif (session.getInstallerUid() installerUid) {count;}}return count;}PackageInstallerService 有两个 SparseBooleanArray 成员变量
//mSessions 保存了所有正在处理的 Session 实例下标为创建事务的 uid值为 PackageInstallerSession 是对 Session 的封装GuardedBy(mSessions)private final SparseArrayPackageInstallerSession mSessions new SparseArray();
//mHistoricalSessions 保存了所有已经处理的 Session 实例下标为创建事务的 uid值为 PackageInstallerSession 是对 Session 的封装/** Historical sessions kept around for debugging purposes */GuardedBy(mSessions)private final ListString mHistoricalSessions new ArrayList();1.3 PackageInstallerS.allocateSessionIdLocked
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 的封装
1.4 PackageInstallerS.buildStageDir private File buildStageDir(String volumeUuid, int sessionId, boolean isEphemeral) {final File stagingDir buildStagingDir(volumeUuid, isEphemeral);
//在安装时创建的临时文件目录是 /data/app/vmdl[sessionId].tmpreturn new File(stagingDir, vmdl sessionId .tmp);}PackageInstallerS.buildStagingDir buildStagingDir 用于返回文件根目录 private File buildStagingDir(String volumeUuid, boolean isEphemeral) {//【1】默认情况返回的是 /data/app 目录return Environment.getDataAppDirectory(volumeUuid);}1.5 new PackageInstallerSession - 事务实例
创建 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].tmpthis.stageCid stageCid; // 默认为 nullif ((stageDir null) (stageCid null)) {throw new IllegalArgumentException(Exactly one of stageDir or stageCid stage must be set);}mPrepared prepared; // 传入 falseif (sealed) { // 传入 falsesynchronized (mLock) {try {sealAndValidateLocked();} catch (PackageManagerException | IOException e) {destroyInternal();throw new IllegalArgumentException(e);}}}final long identity Binder.clearCallingIdentity();try {//【1】获得 container 的 uid 和 gidfinal 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 possibleif ((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 abovethrow new PackageManagerException(e);}// Read transfers from the original owner stay open, but as the sessions 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;1.5.1 new InternalCallback
在创建 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() {Overridepublic 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 its not critical enough to block for.//【*3.1.6】更新持久化文件writeSessionsAsync();}public void onSessionSealedBlocking(PackageInstallerSession session) {// Its very important that we block until weve 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】初始化 CallbacksmCallbacks new Callbacks(mInstallThread.getLooper());//...}1.5.2 new Callbacks
Callbacks 是 Handler 的子类持有子线程 mInstallThread 的 looperCallbacks 是在 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】监听安装状态的观察者 listprivate final RemoteCallbackListIPackageInstallerCallbackmCallbacks 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);}1.5.3 Callbacks.notifySessionXXXX
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
1.5.4 Callbacks.handleMessage Overridepublic 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 profilesif (userId user.getIdentifier()) {try {//【*3.1.4.1.3】分发 Session 消息给观察者invokeCallback(callback, msg);} catch (RemoteException ignored) {}}}mCallbacks.finishBroadcast();}最后调用了 invokeCallback其实可以看到 IPackageInstallerCallback 针对于不同的消息也有不同的接口
1.5.5 Callbacks.invokeCallback 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;}}1.6 PackageInstallerS.writeSessionsAsync - 持久化事务
private void writeSessionsAsync() {IoThread.getHandler().post(new Runnable() {Overridepublic void run() {synchronized (mSessions) {//【1.6.1】将事务记录到 mSessionsFile 文件中writeSessionsLocked();}}});}1.6.1 PackageInstallerS.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】写入所有的 Sessionssession.write(out, mSessionsDir);}out.endTag(null, TAG_SESSIONS);out.endDocument();mSessionsFile.finishWrite(fos);} catch (IOException e) {if (fos ! null) {mSessionsFile.failWrite(fos);}}}
1.6.2 doWriteInternal
位置./frameworks/base/services/core/java/com/android/server/pm/PackageInstallerSession.java 这里的name传入的是base.apk Overridepublic 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(); //确保权限是rootassertPreparedAndNotSealedLocked(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 laterif (!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, were 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);// Were 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();}}二、commit - 提交事务核心入口
在android 9 adb安装过程学习一 的4.2.3.1中分析了commit的函数 Overridepublic 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 olderdestroyInternal();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 weve sealed ourselves to prevent// mutations of any hard links we create. We do this without holding// the session lock, since otherwise its a lock inversion.mCallback.onSessionSealedBlocking(this);}}mActiveCount 加 1表示该事务处于活跃状态直到安装完成 这里的 PackageInstallObserverAdapter.getBinder() 返回是一个服务端 Stub 桩对象
2.1 new PackageInstallObserverAdapter
PackageInstallObserverAdapter 定义在 PackageInstallService 中 static class PackageInstallObserverAdapter extends PackageInstallObserver {private final Context mContext; // 系统进程的上下文private final IntentSender mTarget; // 前面创建的 IntentSender 实例private final int mSessionId; // 事务的 idprivate 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() {Overridepublic void onUserActionRequired(Intent intent) {//【1.1】调用子类的 onUserActionRequired 方法PackageInstallObserver.this.onUserActionRequired(intent);}Overridepublic 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当安装完成后会回调该接口 Overridestatic class PackageInstallObserverAdapter extends PackageInstallObserver {//...public void onUserActionRequired(Intent intent) {final Intent fillIn new Intent();//【1】事务 idfillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId);//【2】当前的状态PackageInstaller.STATUS_PENDING_USER_ACTIONfillIn.putExtra(PackageInstaller.EXTRA_STATUS,PackageInstaller.STATUS_PENDING_USER_ACTION);// 额外的 intentfillIn.putExtra(Intent.EXTRA_INTENT, intent);try {//【*2.9.4.1】发送 intent其实这里我们知道该 intent 会发送到前面的 LocalIntentReceiver//关于这个额外的 Intent我们后面会看到mTarget.sendIntent(mContext, 0, fillIn, null, null);} catch (SendIntentException ignored) {}}Overridepublic 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 会发送到前面的 LocalIntentReceivermTarget.sendIntent(mContext, 0, fillIn, null, null);} catch (SendIntentException ignored) {}}};2.2 send MSG_COMMIT
在./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() {Overridepublic boolean handleMessage(Message msg) {//【1】获得要安装的应用的信息如果是第一次安装的话那么二者返回的均为 nullswitch (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;2.3 commitLocked
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// havent been overridden.//【3】如果安装方式是继承已存在的 apk那我们就要尝试基于已有的安装进行安装这个一般用于安装和卸载 split apkif (params.mode SessionParams.MODE_INHERIT_EXISTING) {try {final ListFile 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 的话不行的话就 copyif (isLinkPossible(fromFiles, toDir)) {if (!mResolvedInstructionSets.isEmpty()) {final File oatDir new File(toDir, oat);createOatDirs(mResolvedInstructionSets, oatDir);}// pre-create lib dirs for linking if necessaryif (!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】执行拷贝其实是将已经存在的目录的 apkoat 文件拷贝到了这个目录// 对于要 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());// Weve 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() {Overridepublic void onUserActionRequired(Intent intent) {throw new IllegalStateException();}Overridepublic 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);}2.3.1 resolveStageDirLocked /*** 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;}2.3.2 validateInstallLocked在PackageInstallerSession被调用
校验安装有效性这里的 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 文件// 去除后缀将前缀名保存到 removeSplitListfinal File[] removedFiles mResolvedStageDir.listFiles(sRemovedFilter);final ListString 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 ArraySetString 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 为 nullif (!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 weve 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,Couldnt obtain signatures from base APK);}}}//【5】处理安装模式if (params.mode SessionParams.MODE_FULL_INSTALL) {// Full installs must include a base package//【5.1】全量安装必须要有 base.apkif (!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如果没有指定安装的 apkif (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 weve seen compiled output for.// If were 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 isnt an ISA subdir.if (!ArrayUtils.contains(instructionSets, archSubDir.getName())) {continue;}// 将要继承的 oat 目录文件名添加到 mResolvedInstructionSetsmResolvedInstructionSets.add(archSubDir.getName());ListFile oatFiles Arrays.asList(archSubDir.listFiles());if (!oatFiles.isEmpty()) {// 将要继承的 odex 相关文件添加到 mResolvedInheritedFilesmResolvedInheritedFiles.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 ListFile 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);// shouldnt be possible, but lets avoid inheriting these to be safelibDirsToInherit.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 的 splitNamebase 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 中
2.3.2.1 assertApkConsistentLocked
校验 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);}}
2.3.3 closeInternal(false);
close 方法很简单将事务的 mActiveCount 引用计数自减 1同时回调 Overridepublic 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);}}2.3.4 computeProgressLocked 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);}}2.3.5 extractNativeLibraries
提取本地的 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 slateNativeLibraryHelper.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我们先不过多关注其实现