• Android安装过程二 系统进程中PackageInstallerSession对象的创建


      从前面文章Android 安装过程一 界面跳转安装进程中InstallInstalling界面的处理中,我们知道安装进程需要与系统进程交互,调用getPackageManager().getPackageInstaller().createSession(params)得到一个整型id值,这个id值对应着系统进程中PackageInstallerSession对象。系统进程会创建该对象,并且将id值返回。这样安装进程就能通过该id值与系统进程后续继续交互。下面就看看它是怎么创建的。
      getPackageManager()得到的是ApplicationPackageManager对象,getPackageManager().getPackageInstaller()这里得到的是PackageInstaller对象。PackageInstaller对象的成员变量mInstaller是一个Binder代理对象,它实际指向系统进程中PackageManagerService对象的成员mInstallerService,它是一个PackageInstallerService对象。在这里,PackageInstaller对象的成员变量mInstallerPackageName是安装进程应用的包名。成员mAttributionTag是来自Manifest里面的配置,Activity的attributionTags标签配置,它可以“|”分割,这里是取的第一个。成员mUserId是UserId。
      PackageInstaller对象的createSession(params)方法调用的是PackageInstallerService对象的createSession()方法。它的代码在PackageInstallerService.java文件中,如下:

        @Override
        public int createSession(SessionParams params, String installerPackageName,
                String callingAttributionTag, int userId) {
            try {
                return createSessionInternal(params, installerPackageName, callingAttributionTag,
                        userId);
            } catch (IOException e) {
                throw ExceptionUtils.wrap(e);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

      这里参数installerPackageName、callingAttributionTag、userId对应着PackageInstaller对象的上面三个成员变量。
      接着看PackageInstallerService的createSessionInternal()方法,代码比较长,分段看一下,

    代码分段一

    分段一,如下:

        private int createSessionInternal(SessionParams params, String installerPackageName,
                String installerAttributionTag, int userId)
                throws IOException {
            final int callingUid = Binder.getCallingUid();
            mPm.enforceCrossUserPermission(
                    callingUid, userId, true, true, "createSession");
    
            if (mPm.isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
                throw new SecurityException("User restriction prevents installing");
            }
    
            if (params.dataLoaderParams != null
                    && mContext.checkCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2)
                            != PackageManager.PERMISSION_GRANTED) {
                throw new SecurityException("You need the "
                        + "com.android.permission.USE_INSTALLER_V2 permission "
                        + "to use a data loader");
            }
    
            // INSTALL_REASON_ROLLBACK allows an app to be rolled back without requiring the ROLLBACK
            // capability; ensure if this is set as the install reason the app has one of the necessary
            // signature permissions to perform the rollback.
            if (params.installReason == PackageManager.INSTALL_REASON_ROLLBACK) {
                if (mContext.checkCallingOrSelfPermission(Manifest.permission.MANAGE_ROLLBACKS)
                        != PackageManager.PERMISSION_GRANTED &&
                        mContext.checkCallingOrSelfPermission(Manifest.permission.TEST_MANAGE_ROLLBACKS)
                        != PackageManager.PERMISSION_GRANTED) {
                    throw new SecurityException(
                            "INSTALL_REASON_ROLLBACK requires the MANAGE_ROLLBACKS permission or the "
                                    + "TEST_MANAGE_ROLLBACKS permission");
                }
            }
    
    • 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

      这块主要是处理权限。
      用户不能有UserManager.DISALLOW_INSTALL_APPS的限制。
      params.dataLoaderParams和应用的streaming方式安装有关,如果是这种安装方式,需要有相关权限Manifest.permission.USE_INSTALLER_V2。使用该种安装方式,需要V4的签名方式。
      还看到如果设置params.installReason为INSTALL_REASON_ROLLBACK,也就是回退。需要权限MANAGE_ROLLBACKS和TEST_MANAGE_ROLLBACKS这两种的至少一种。

    代码分段二

      代码分段二如下:

            // App package name and label length is restricted so that really long strings aren't
            // written to disk.
            if (params.appPackageName != null
                    && params.appPackageName.length() > SessionParams.MAX_PACKAGE_NAME_LENGTH) {
                params.appPackageName = null;
            }
    
            params.appLabel = TextUtils.trimToSize(params.appLabel,
                    PackageItemInfo.MAX_SAFE_LABEL_LENGTH);
    
            String requestedInstallerPackageName = (params.installerPackageName != null
                    && params.installerPackageName.length() < SessionParams.MAX_PACKAGE_NAME_LENGTH)
                    ? params.installerPackageName : installerPackageName;
    
            if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
                params.installFlags |= PackageManager.INSTALL_FROM_ADB;
                // adb installs can override the installingPackageName, but not the
                // initiatingPackageName
                installerPackageName = null;
            } else {
                if (callingUid != Process.SYSTEM_UID) {
                    // The supplied installerPackageName must always belong to the calling app.
                    mAppOps.checkPackage(callingUid, installerPackageName);
                }
                // Only apps with INSTALL_PACKAGES are allowed to set an installer that is not the
                // caller.
                if (!TextUtils.equals(requestedInstallerPackageName, installerPackageName)) {
                    if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES)
                            != PackageManager.PERMISSION_GRANTED) {
                        mAppOps.checkPackage(callingUid, requestedInstallerPackageName);
                    }
                }
    
                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;
                }
                if (mContext.checkCallingOrSelfPermission(
                        Manifest.permission.INSTALL_TEST_ONLY_PACKAGE)
                        != PackageManager.PERMISSION_GRANTED) {
                    params.installFlags &= ~PackageManager.INSTALL_ALLOW_TEST;
                }
            }
    
            String originatingPackageName = null;
            if (params.originatingUid != SessionParams.UID_UNKNOWN
                    && params.originatingUid != callingUid) {
                String[] packages = mPm.getPackagesForUid(params.originatingUid);
                if (packages != null && packages.length > 0) {
                    // Choose an arbitrary representative package in the case of a shared UID.
                    originatingPackageName = packages[0];
                }
            }
    
            if (Build.IS_DEBUGGABLE || isCalledBySystemOrShell(callingUid)) {
                params.installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE;
            } else {
                params.installFlags &= ~PackageManager.INSTALL_ALLOW_DOWNGRADE;
                params.installFlags &= ~PackageManager.INSTALL_REQUEST_DOWNGRADE;
            }
    
            if ((params.installFlags & ADB_DEV_MODE) != ADB_DEV_MODE) {
                // Only tools under specific conditions (test app installed through ADB, and
                // verification disabled flag specified) can disable verification.
                params.installFlags &= ~PackageManager.INSTALL_DISABLE_VERIFICATION;
            }
    
    • 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

      首先检查安装文件的包名的长度如果超出SessionParams.MAX_PACKAGE_NAME_LENGTH(255)个字符,将它设置为空。
      接着APP的名称如果超过PackageItemInfo.MAX_SAFE_LABEL_LENGTH,将其裁剪到PackageItemInfo.MAX_SAFE_LABEL_LENGTH(1000)长度。
      params.installerPackageName和installerPackageName的区别,params.installerPackageName是安装者的包名,installerPackageName则是安装程序的包名。params.installerPackageName的值需要通过各个Activity通过Intent传递,如果它为空,则将变量requestedInstallerPackageName设置为安装程序的包名。
      如果调用安装的是Process.SHELL_UID或Process.ROOT_UID,会将params.installFlags加上PackageManager.INSTALL_FROM_ADB,并且将安装者的包名installerPackageName设为空。这种情况应该是通过adb直接安装的。
      如果调用者不是Process.SYSTEM_UID(系统进程),会调用mAppOps.checkPackage(callingUid, installerPackageName)这个主要是检查这个installerPackageName是属于调用应用的。如果不属于,会throw出SecurityException。
      接着如果requestedInstallerPackageName不等于installerPackageName,这个是上面params.installerPackageName存在值的情况。如果调用者还没授权Manifest.permission.INSTALL_PACKAGES,则需要检测requestedInstallerPackageName的包是否属于调用者。mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES)就是用来检测调用者的Manifest.permission.INSTALL_PACKAGES权限。
      接下来会将params.installFlags的标识去除INSTALL_FROM_ADB、INSTALL_ALL_USERS,加上INSTALL_REPLACE_EXISTING。
      接下来是处理INSTALL_VIRTUAL_PRELOAD、INSTALL_ALLOW_TEST标识。
      紧接着,是得到最开始安装应用的包名originatingPackageName。就是跳入安装进程之前的那个应用。它的应用uid在params.originatingUid,它是Activity跳转通过Intent之间数据传递过来的。
      下面看到标识INSTALL_ALLOW_DOWNGRADE的设置,如果系统版本是IS_DEBUGGABLE版本,或者调用者是系统进程、root、或者adb,会设置允许降级标识。
      如果params.installFlags标识不存在ADB_DEV_MODE,则将INSTALL_DISABLE_VERIFICATION去除。

    代码分段三

      代码分段三如下:

            boolean isApex = (params.installFlags & PackageManager.INSTALL_APEX) != 0;
            if (isApex) {
                if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGE_UPDATES)
                        == PackageManager.PERMISSION_DENIED
                        && mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES)
                        == PackageManager.PERMISSION_DENIED) {
                    throw new SecurityException("Not allowed to perform APEX updates");
                }
            } else if (params.isStaged) {
                mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, TAG);
            }
    
            if (isApex) {
                if (!mApexManager.isApexSupported()) {
                    throw new IllegalArgumentException(
                        "This device doesn't support the installation of APEX files");
                }
                if (params.isMultiPackage) {
                    throw new IllegalArgumentException("A multi-session can't be set as APEX.");
                }
                if (!params.isStaged
                        && (params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
                    throw new IllegalArgumentException(
                        "Non-staged APEX session doesn't support INSTALL_ENABLE_ROLLBACK");
                }
                if (isCalledBySystemOrShell(callingUid) || mBypassNextAllowedApexUpdateCheck) {
                    params.installFlags |= PackageManager.INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK;
                } else {
                    // Only specific APEX updates (installed through ADB, or for CTS tests) can disable
                    // allowed APEX update check.
                    params.installFlags &= ~PackageManager.INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK;
                }
            }
    
            if ((params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0
                    && !isCalledBySystemOrShell(callingUid)
                    && (mPm.getFlagsForUid(callingUid) & ApplicationInfo.FLAG_SYSTEM) == 0) {
                throw new SecurityException(
                        "Only system apps could use the PackageManager.INSTALL_INSTANT_APP flag.");
            }
    
            if (params.isStaged && !isCalledBySystemOrShell(callingUid)) {
                if (!mBypassNextStagedInstallerCheck
                        && !isStagedInstallerAllowed(requestedInstallerPackageName)) {
                    throw new SecurityException("Installer not allowed to commit staged install");
                }
            }
            if (isApex && !isCalledBySystemOrShell(callingUid)) {
                if (!mBypassNextStagedInstallerCheck
                        && !isStagedInstallerAllowed(requestedInstallerPackageName)) {
                    throw new SecurityException(
                            "Installer not allowed to commit non-staged APEX install");
                }
            }
    
            mBypassNextStagedInstallerCheck = false;
            mBypassNextAllowedApexUpdateCheck = false;
    
            if (!params.isMultiPackage) {
                // Only system components can circumvent runtime permissions when installing.
                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");
                }
    
                // Defensively resize giant app icons
                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);
                    }
                }
    
                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, validity check it, otherwise
                // resolve the best internal or adopted location.
                if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
                    if (!PackageHelper.fitsOnInternal(mContext, params)) {
                        throw new IOException("No suitable internal 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.installFlags |= PackageManager.INSTALL_INTERNAL;
                } else {
                    params.installFlags |= PackageManager.INSTALL_INTERNAL;
    
                    // 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);
                    }
                }
            }
    
    • 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

      APEX文件格式安装是用于较低级别系统模块的安装流程,这里先不涉及。想了解的看这里
      params.isStaged则是这个Session会被安装在下一次重启时,这时要强制检查调用者Manifest.permission.INSTALL_PACKAGES的权限被授予。
      PackageManager.INSTALL_INSTANT_APP是和免安装应用有关,也暂时略过。
      在params.isStaged时,如果调用者不是系统、root、adb,并且没有设置绕过检查,这时要检查安装包是否允许安装,如果不允许,则会报异常。安装包是否允许安装,是通过SystemConfig.getInstance().getWhitelistedStagedInstallers()来控制的,它里面的值来自设置配置文件。
      接着设置mBypassNextStagedInstallerCheck、mBypassNextAllowedApexUpdateCheck成员变量的值为false。
      params.isMultiPackage代表是它可以通过id引用其他的Session。如果它的孩子安装失败,则它们安装失败。
      在params.isMultiPackage为false的情况下,如果params的标识存在INSTALL_GRANT_RUNTIME_PERMISSIONS,则需要检查INSTALL_GRANT_RUNTIME_PERMISSIONS权限,如果是被拒绝的情况下,会抛出异常。
      接着处理图标太大的情况,am.getLauncherLargeIconSize()生成的大小和配置属性大小app_icon_size和屏幕密度相关。如果太大会重新调整它的大小。
      params.mode必定是MODE_FULL_INSTALL或MODE_INHERIT_EXISTING两者中的一个。
      下面处理安装位置。如果明确指定要安装在内部存储,但是内部空间不够安装文件大小,这时会报IO异常。PackageHelper.fitsOnInternal(mContext, params)就是用来检测空间是否足够的。
      如果params.installFlags存在INSTALL_FORCE_VOLUME_UUID标识,则为params.installFlags设置INSTALL_INTERNAL标识。
      其他的情况也为其设置INSTALL_INTERNAL标识。并且为params设置volumeUuid。PackageHelper.resolveInstallVolume(mContext, params)就是得到得到硬盘的uuid。这里注意内部私有的盘的UUID为StorageManager.UUID_PRIVATE_INTERNAL,它是一个null值。

    代码分段四

      代码分段四如下:

            final int sessionId;
            final PackageInstallerSession session;
            synchronized (mSessions) {
                // Check that the installer does not have too many active sessions.
                final int activeCount = getSessionCount(mSessions, callingUid);
                if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES)
                        == PackageManager.PERMISSION_GRANTED) {
                    if (activeCount >= MAX_ACTIVE_SESSIONS_WITH_PERMISSION) {
                        throw new IllegalStateException(
                                "Too many active sessions for UID " + callingUid);
                    }
                } else if (activeCount >= MAX_ACTIVE_SESSIONS_NO_PERMISSION) {
                    throw new IllegalStateException(
                            "Too many active sessions for UID " + callingUid);
                }
                final int historicalCount = mHistoricalSessionsByInstaller.get(callingUid);
                if (historicalCount >= MAX_HISTORICAL_SESSIONS) {
                    throw new IllegalStateException(
                            "Too many historical sessions for UID " + callingUid);
                }
    
                sessionId = allocateSessionIdLocked();
            }
    
            final long createdMillis = System.currentTimeMillis();
            // We're staging to exactly one location
            File stageDir = null;
            String stageCid = null;
            if (!params.isMultiPackage) {
                if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
                    stageDir = buildSessionDir(sessionId, params);
                } else {
                    stageCid = buildExternalStageCid(sessionId);
                }
            }
    
            // reset the force queryable param if it's not called by an approved caller.
            if (params.forceQueryableOverride) {
                if (callingUid != Process.SHELL_UID && callingUid != Process.ROOT_UID) {
                    params.forceQueryableOverride = false;
                }
            }
            InstallSource installSource = InstallSource.create(installerPackageName,
                    originatingPackageName, requestedInstallerPackageName,
                    installerAttributionTag);
            session = new PackageInstallerSession(mInternalCallback, mContext, mPm, this,
                    mSilentUpdatePolicy, mInstallThread.getLooper(), mStagingManager, sessionId,
                    userId, callingUid, installSource, params, createdMillis, 0L, stageDir, stageCid,
                    null, null, false, false, false, false, null, SessionInfo.INVALID_ID,
                    false, false, false, SessionInfo.STAGED_SESSION_NO_ERROR, "");
    
            synchronized (mSessions) {
                mSessions.put(sessionId, session);
            }
    
            mCallbacks.notifySessionCreated(session.sessionId, session.userId);
    
            mSettingsWriteRequest.schedule();
            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

      这块就是创建Session了。在创建之前,首先得到Session的Id值。
      getSessionCount(mSessions, callingUid)得到的是调用应用正在安装应用的数量。这个是有限制的,并且这个限制和调用方获取到INSTALL_PACKAGES权限有关,如果获取到,限制数量是MAX_ACTIVE_SESSIONS_WITH_PERMISSION(1024);如果没有获取到,限制数量是MAX_ACTIVE_SESSIONS_NO_PERMISSION(50)。同时,调用应用的安装总数也是有限制的,MAX_HISTORICAL_SESSIONS(1048576)。如果这些限制存在超了,会报异常。
      下面就调用allocateSessionIdLocked()分配SessionId。
      看一下它的代码:

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

      mAllocatedSessions中保存着之前分配的SessionId。如果分配过,就重新随机分配。生成的SessionId的值范围为1到Integer.MAX_VALUE。并且重新分配超过32次,还没成功,会报异常。
      生成SessionId之后,会生成缓存文件的目录。
      从上面知道,在params.isMultiPackage为false的情况下,params.installFlags都会设置INSTALL_INTERNAL标识。生成的Session目录是使用buildSessionDir(sessionId, params)方法实现,看一下它:

        private File buildSessionDir(int sessionId, SessionParams params) {
            if (params.isStaged || (params.installFlags & PackageManager.INSTALL_APEX) != 0) {
                final File sessionStagingDir = Environment.getDataStagingDirectory(params.volumeUuid);
                return new File(sessionStagingDir, "session_" + sessionId);
            }
            return buildTmpSessionDir(sessionId, params.volumeUuid);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

      在params.isStaged为true,或者是用APEX安装方式时,目录是根据params.volumeUuid得到的一个。这里分params.volumeUuid为null和具体值两种情况。params.volumeUuid为null是内部存储的默认格式,params.volumeUuid为null时生成的目录为"/data/app-staging/session_" + sessionId;params.volumeUuid为具体值生成的目录则为"/mnt/expand/" + volumeUuid + “/app-staging/session_” + sessionId。
      除了上面两种情况,是普通APP安装时,生成的目录也分params.volumeUuid为null和具体值两种情况。params.volumeUuid为null时生成目录为"/data/app/vmdl" + sessionId + “.tmp”,如果不为null,则生成的目录为"/mnt/expand/" + volumeUuid + “/app/vmdl” + sessionId + “.tmp”。
      在params.installFlags未设置INSTALL_INTERNAL标识时,stageCid的值为"smdl" + sessionId + “.tmp”。
      接下来处理params.forceQueryableOverride为true时,如果调用方不为SHELL_UID、ROOT_UID。需要将它设置为false。
      生成一个InstallSource对象。
      生成一个PackageInstallerSession对象。它的生成就是调用它的构造函数,对它的成员变量赋值。
      将PackageInstallerSession对象对象以sessionId为key,放入mSessions中。
      回调接口mCallbacks执行notifySessionCreated(session.sessionId, session.userId)方法。这个回调需要首先注册。
      下面调用mSettingsWriteRequest.schedule()执行,将mSessions中的信息写入文件。这个文件为"/data/system/install_sessions.xml"。
      最后将sessionId返回。

  • 相关阅读:
    [C#]使用 AltCover 获得代码覆盖率 - E2E Test 和 Unit Test
    北邮22信通:二叉树显示路径的两种方法 递归函数保存现场返回现场的实例
    【指针详解】(上)看一遍就会❗❗❗家人们冲❗
    java计算机毕业设计社区人员管理系统(附源码、数据库)
    计算机网络:3数据链路层
    MacOS升级后命令行出现xcrun: error: invalid active developer path报错信息
    【微信小程序入门到精通】— 微信小程序开发工具的安装
    小波神经网络的基本原理,小波神经网络算法原理
    国际阿里云:云服务器灾备方案!!!
    04贪心:最大子序和
  • 原文地址:https://blog.csdn.net/q1165328963/article/details/134100370