android 9 adb安装过程学习(二)

一、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 对应的 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 这里就不在过多分析,我们继续看

1.1 PackageInstallerS.createSession(Internal) - 创建事务

    @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;
    }

1.2 PackageInstallerS.getSessionCount

获得 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<>();

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].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);
    }

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].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";

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() {
                @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());
        //...
    }

1.5.2 new Callbacks

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);
        }

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

        @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 针对于不同的消息也有不同的接口

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() {
            @Override
            public 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】写入所有的 Sessions
                session.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

    @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();
        }
    }

二、commit - 提交事务核心入口

在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 桩对象

2.1 new PackageInstallObserverAdapter

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) {
            }
		}
	};

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() {
        @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;

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
        // 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);
    }

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 文件!
    	// 去除后缀,将前缀名保存到 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 中

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,同时回调

    @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);
        }
    }

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 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,我们先不过多关注其实现

你可能感兴趣的:(安卓,android,adb,install,Package,Installer,Service,Session)