• 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();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    关于 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
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168

    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;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    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");
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    PackageInstallerS.buildStagingDir
    buildStagingDir 用于返回文件根目录

        private File buildStagingDir(String volumeUuid, boolean isEphemeral) {
        	 //【1】默认情况,返回的是 /data/app 目录
            return Environment.getDataAppDirectory(volumeUuid);
        }
    
    • 1
    • 2
    • 3
    • 4

    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.
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90

    可以看到 PackageInstallerSession 除了用来表示一个 Session 之外,由于继承了 IPackageInstallerSession.Stub,因此其还可以作为服务端的桩对象,进行跨进程的通信
    这里的 DEFAULT_CONTAINER_PACKAGE是一个字符串常量:

    public static final String DEFAULT_CONTAINER_PACKAGE = "com.android.defcontainer";
    
    • 1

    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();
                }
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    可以看到,当 Session 的状态发生变化后,InternalCallback 回调会触发
    同时会回调 mCallbacks 的一些接口,而 mCallbacks 是在 PackageInstallerService 中创建的:

    public PackageInstallerService(Context context, PackageManagerService pm) {
    		//...
    		//【*3.1.4.1.1】初始化 Callbacks!
            mCallbacks = new Callbacks(mInstallThread.getLooper());
            //...
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    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);
            }
    		//...
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    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();
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    本质上是发送不同的 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();
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    最后调用了 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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    1.6 PackageInstallerS.writeSessionsAsync - 持久化事务

    private void writeSessionsAsync() {
            IoThread.getHandler().post(new Runnable() {
                @Override
                public void run() {
                    synchronized (mSessions) {
                     	//【1.6.1】将事务记录到 mSessionsFile 文件中
                        writeSessionsLocked();
                    }
                }
            });
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    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();
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119

    二、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);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    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;
            }
    	//...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    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;
        }
        //...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    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) {
                }
    		}
    	};
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    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);
            //...
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    如果我们直接发送 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;
            }
        };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    PackageInstallerSession 内部有一个 mRemoteObserver 成员变量,后面我们会见到

        @GuardedBy("mLock")
        private IPackageInstallObserver2 mRemoteObserver;
    
    • 1
    • 2

    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);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128

    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;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261

    总结下:
    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");
            }
        }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    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);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    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);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    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);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    对于 lib 的提取,这里涉及到了 NativeLibraryHelper,我们先不过多关注其实现

  • 相关阅读:
    SysML理论知识
    jenkins系列-07.轻易级jpom安装
    揭秘!2024年热门的图标设计工具
    你必须知道的6个免费图片素材网站
    HCIP之BGP的选路原则
    Angular变更检测机制
    洗牌进行时!激光雷达上车背后
    NUC-lib资源学习
    云计算中的过度授权:安全隐患与应对策略
    Redis官方开源的可视化管理工具 - RedisInsight
  • 原文地址:https://blog.csdn.net/ch122633/article/details/134337557