当前位置: 首页 > article >正文

Android15 am命令 APP安装流程

一. PM 安装命令

使用命令

pm install -r    xxx.apk

 pm命令安装app 会触发PackageManagerShellCommand 中runInstall()方法

frameworks/base/services/core/java/com/android/server/pm/PackageManagerShellCommand.java

1. onCommand 函数:

    public int onCommand(String cmd) {
        if (cmd == null) {
            return handleDefaultCommands(cmd);
        }

        final PrintWriter pw = getOutPrintWriter();
        try {
            switch (cmd) {

                case "install":
                    return runInstall();

}

2. runInstall 函数:

    private int runInstall() throws RemoteException {

        //UNSUPPORTED_INSTALL_CMD_OPTS 就是参数:Set.of( "--multi-package");

        //相当于isMultiPackage 为true
        return doRunInstall(makeInstallParams(UNSUPPORTED_INSTALL_CMD_OPTS));
    }

3. makeInstallParams 函数:

解析参数:

    private InstallParams makeInstallParams(Set<String> unsupportedOptions) {

        // MODE_FULL_INSTALL:安装会话的模式,其暂存的 APK 应该完全替换目标应用的任何现有 APK。
        final SessionParams sessionParams = new SessionParams(SessionParams.MODE_FULL_INSTALL);


        final InstallParams params = new InstallParams();

        params.sessionParams = sessionParams;
        // Allowlist all permissions by default
        sessionParams.installFlags |= PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS;
        // Set package source to other by default. Can be overridden by "--package-source"

       // 默认将包源设置为其他。可以通过“--package-source”覆盖
        sessionParams.setPackageSource(PackageInstaller.PACKAGE_SOURCE_OTHER);

        // Encodes one of the states:
        //  1. Install request explicitly specified --staged, then value will be true.
        //  2. Install request explicitly specified --non-staged, then value will be false.
        //  3. Install request did not specify either --staged or --non-staged, then for APEX
        //      installs the value will be true, and for apk installs it will be false.

        // 对以下状态之一进行编码:
        //  1. 安装请求明确指定 --staged,则值为 true。
        //  2. 安装请求明确指定 --non-staged,则值为 false。
        //  3. 安装请求未指定 --staged 或 --non-staged,则对于 APEX
        //      安装,则值为 true,对于 apk 安装,则值为 false。
        Boolean staged = null;

        String opt;
        boolean replaceExisting = true;
        boolean forceNonStaged = false;
        while ((opt = getNextOption()) != null) {
            if (unsupportedOptions.contains(opt)) {
                throw new IllegalArgumentException("Unsupported option " + opt);
            }
            switch (opt) {
                case "-r": // ignore
                    break;
                case "-R":
                    replaceExisting = false;
                    break;
                case "-i":
                    params.installerPackageName = getNextArg();
                    if (params.installerPackageName == null) {
                        throw new IllegalArgumentException("Missing installer package");
                    }
                    break;
                case "-t":
                    sessionParams.installFlags |= PackageManager.INSTALL_ALLOW_TEST;
                    break;
                case "-f":
                    sessionParams.installFlags |= PackageManager.INSTALL_INTERNAL;
                    break;
                case "-d":
                    sessionParams.installFlags |= PackageManager.INSTALL_REQUEST_DOWNGRADE;
                    break;
                case "-g":
                    sessionParams.installFlags |=
                            PackageManager.INSTALL_GRANT_ALL_REQUESTED_PERMISSIONS;
                    break;
                case "--restrict-permissions":
                    sessionParams.installFlags &=
                            ~PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS;
                    break;
                case "--dont-kill":
                    sessionParams.installFlags |= PackageManager.INSTALL_DONT_KILL_APP;
                    break;
                case "--originating-uri":
                    sessionParams.originatingUri = Uri.parse(getNextArg());
                    break;
                case "--referrer":
                    sessionParams.referrerUri = Uri.parse(getNextArg());
                    break;
                case "-p":
                    sessionParams.mode = SessionParams.MODE_INHERIT_EXISTING;
                    sessionParams.appPackageName = getNextArg();
                    if (sessionParams.appPackageName == null) {
                        throw new IllegalArgumentException("Missing inherit package name");
                    }
                    break;
                case "--pkg":
                    sessionParams.appPackageName = getNextArg();
                    if (sessionParams.appPackageName == null) {
                        throw new IllegalArgumentException("Missing package name");
                    }
                    break;
                case "-S":
                    final long sizeBytes = Long.parseLong(getNextArg());
                    if (sizeBytes <= 0) {
                        throw new IllegalArgumentException("Size must be positive");
                    }
                    sessionParams.setSize(sizeBytes);
                    break;
                case "--abi":
                    sessionParams.abiOverride = checkAbiArgument(getNextArg());
                    break;
                case "--ephemeral":
                case "--instant":
                case "--instantapp":
                    sessionParams.setInstallAsInstantApp(true /*isInstantApp*/);
                    break;
                case "--full":
                    sessionParams.setInstallAsInstantApp(false /*isInstantApp*/);
                    break;
                case "--preload":
                    sessionParams.setInstallAsVirtualPreload();
                    break;
                case "--user":
                    params.userId = UserHandle.parseUserArg(getNextArgRequired());
                    break;
                case "--install-location":
                    sessionParams.installLocation = Integer.parseInt(getNextArg());
                    break;
                case "--install-reason":
                    sessionParams.installReason = Integer.parseInt(getNextArg());
                    break;
                case "--update-ownership":
                    if (params.installerPackageName == null) {
                        // Enabling update ownership enforcement needs an installer. Since the
                        // default installer is null when using adb install, that effectively
                        // disable this enforcement.
                        params.installerPackageName = "com.android.shell";
                    }
                    sessionParams.installFlags |= PackageManager.INSTALL_REQUEST_UPDATE_OWNERSHIP;
                    break;
                case "--force-uuid":
                    sessionParams.installFlags |= PackageManager.INSTALL_FORCE_VOLUME_UUID;
                    sessionParams.volumeUuid = getNextArg();
                    if ("internal".equals(sessionParams.volumeUuid)) {
                        sessionParams.volumeUuid = null;
                    }
                    break;
                case "--force-sdk": // ignore
                    break;
                case "--apex":
                    sessionParams.setInstallAsApex();
                    break;
                case "--force-non-staged":
                    forceNonStaged = true;
                    break;
                case "--multi-package":
                    sessionParams.setMultiPackage();
                    break;
                case "--staged":
                    staged = true;
                    break;
                case "--non-staged":
                    staged = false;
                    break;
                case "--force-queryable":
                    sessionParams.setForceQueryable();
                    break;
                case "--enable-rollback":
                    if (params.installerPackageName == null) {
                        // com.android.shell has the TEST_MANAGE_ROLLBACKS
                        // permission needed to enable rollback for non-module
                        // packages, which is likely what the user wants when
                        // enabling rollback through the shell command. Set
                        // the installer to com.android.shell if no installer
                        // has been provided so that the user doesn't have to
                        // remember to set it themselves.
                        params.installerPackageName = "com.android.shell";
                    }
                    int rollbackStrategy = PackageManager.ROLLBACK_DATA_POLICY_RESTORE;
                    try {
                        rollbackStrategy = Integer.parseInt(peekNextArg());
                        if (rollbackStrategy < PackageManager.ROLLBACK_DATA_POLICY_RESTORE
                                || rollbackStrategy > PackageManager.ROLLBACK_DATA_POLICY_RETAIN) {
                            throw new IllegalArgumentException(
                                    rollbackStrategy + " is not a valid rollback data policy.");
                        }
                        getNextArg(); // pop the argument
                    } catch (NumberFormatException e) {
                        // not followed by a number assume ROLLBACK_DATA_POLICY_RESTORE.
                    }
                    sessionParams.setEnableRollback(true, rollbackStrategy);
                    break;
                case "--rollback-impact-level":
                    if (!Flags.recoverabilityDetection()) {
                        throw new IllegalArgumentException("Unknown option " + opt);
                    }
                    int rollbackImpactLevel = Integer.parseInt(peekNextArg());
                    if (rollbackImpactLevel < PackageManager.ROLLBACK_USER_IMPACT_LOW
                            || rollbackImpactLevel
                                    > PackageManager.ROLLBACK_USER_IMPACT_ONLY_MANUAL) {
                        throw new IllegalArgumentException(
                            rollbackImpactLevel + " is not a valid rollback impact level.");
                    }
                    sessionParams.setRollbackImpactLevel(rollbackImpactLevel);
                case "--staged-ready-timeout":
                    params.stagedReadyTimeoutMs = Long.parseLong(getNextArgRequired());
                    break;
                case "--skip-verification":
                    sessionParams.installFlags |= PackageManager.INSTALL_DISABLE_VERIFICATION;
                    break;
                case "--skip-enable":
                    sessionParams.setApplicationEnabledSettingPersistent();
                    break;
                case "--bypass-low-target-sdk-block":
                    sessionParams.installFlags |=
                            PackageManager.INSTALL_BYPASS_LOW_TARGET_SDK_BLOCK;
                    break;
                case "--ignore-dexopt-profile":
                    sessionParams.installFlags |= PackageManager.INSTALL_IGNORE_DEXOPT_PROFILE;
                    break;
                case "--package-source":
                    sessionParams.setPackageSource(Integer.parseInt(getNextArg()));
                    break;
                case "--dexopt-compiler-filter":
                    sessionParams.dexoptCompilerFilter = getNextArgRequired();
                    // An early check that throws IllegalArgumentException if the compiler filter is
                    // invalid.
                    new DexoptParams.Builder(ReasonMapping.REASON_INSTALL)
                            .setCompilerFilter(sessionParams.dexoptCompilerFilter)
                            .build();
                    break;
                default:
                    throw new IllegalArgumentException("Unknown option " + opt);
            }
        }
        if (staged == null) {
            staged = (sessionParams.installFlags & PackageManager.INSTALL_APEX) != 0;
        }
        if (replaceExisting) {
            sessionParams.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
        }
        if (forceNonStaged) {
            sessionParams.isStaged = false;
            sessionParams.developmentInstallFlags |=
                    PackageManager.INSTALL_DEVELOPMENT_FORCE_NON_STAGED_APEX_UPDATE;
        } else if (staged) {
            sessionParams.setStaged();
        }
        if ((sessionParams.installFlags & PackageManager.INSTALL_APEX) != 0
                && (sessionParams.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0
                && sessionParams.rollbackDataPolicy == PackageManager.ROLLBACK_DATA_POLICY_WIPE) {
            throw new IllegalArgumentException("Data policy 'wipe' is not supported for apex.");
        }
        return params;
    }

 4. doRunInstall 函数:

    private int doRunInstall(final InstallParams params) throws RemoteException {
        final PrintWriter pw = getOutPrintWriter();

        // 默认为:UserHandle.USER_ALL

        int requestUserId = params.userId;
        if (requestUserId != UserHandle.USER_ALL && requestUserId != UserHandle.USER_CURRENT) {
            UserManagerInternal umi =
                    LocalServices.getService(UserManagerInternal.class);
            UserInfo userInfo = umi.getUserInfo(requestUserId);
            if (userInfo == null) {
                pw.println("Failure [user " + requestUserId + " doesn't exist]");
                return 1;
            }
        }

        final boolean isStreaming = params.sessionParams.dataLoaderParams != null;
        final boolean isApex =
                (params.sessionParams.installFlags & PackageManager.INSTALL_APEX) != 0;
        final boolean installArchived =
                (params.sessionParams.installFlags & PackageManager.INSTALL_ARCHIVED) != 0;

       // 将剩余的参数变成集合.

        ArrayList<String> args = getRemainingArgs();

        final boolean fromStdIn = args.isEmpty() || STDIN_PATH.equals(args.get(0));
        final boolean hasSplits = args.size() > 1;

        if (fromStdIn && params.sessionParams.sizeBytes == -1) {
            pw.println("Error: must either specify a package size or an APK file");
            return 1;
        }

        //默认情况下都不会满足

        if (isApex && hasSplits) {
            pw.println("Error: can't specify SPLIT(s) for APEX");
            return 1;
        }

        //默认情况下都不会满足

        if (installArchived) {
            if (hasSplits) {
                pw.println("Error: can't have SPLIT(s) for Archival install");
                return 1;
            }
        }

        if (!isStreaming) {
            if (fromStdIn && hasSplits) {
                pw.println("Error: can't specify SPLIT(s) along with STDIN");
                return 1;
            }

            if (args.isEmpty()) {
                args.add(STDIN_PATH);
            } else {

               //默认会设置参数的大小.
                setParamsSize(params, args);
            }
        }

        //创建session

        final int sessionId = doCreateSession(params.sessionParams,
                params.installerPackageName, params.userId);
        boolean abandonSession = true;
        try {
            if (isStreaming) {
                if (doAddFiles(sessionId, args, params.sessionParams.sizeBytes, isApex,
                        installArchived) != PackageInstaller.STATUS_SUCCESS) {
                    return 1;
                }
            } else {
                if (doWriteSplits(sessionId, args, params.sessionParams.sizeBytes, isApex)
                        != PackageInstaller.STATUS_SUCCESS) {
                    return 1;
                }
            }

            //安装应用开发.
            if (doCommitSession(sessionId, false /*logSuccess*/)
                    != PackageInstaller.STATUS_SUCCESS) {
                return 1;
            }
            abandonSession = false;

            if (params.sessionParams.isStaged && params.stagedReadyTimeoutMs > 0) {
                return doWaitForStagedSessionReady(sessionId, params.stagedReadyTimeoutMs, pw);
            }

            pw.println("Success");
            return 0;
        } finally {
            if (abandonSession) {
                try {
                    doAbandonSession(sessionId, false /*logSuccess*/);
                } catch (Exception ignore) {
                }
            }
        }
    }

 5. setParamsSize 函数:

    private void setParamsSize(InstallParams params, List<String> inPaths) {
        if (params.sessionParams.sizeBytes != -1 || STDIN_PATH.equals(inPaths.get(0))) {
            return;
        }

        long sessionSize = 0;

        ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
        for (String inPath : inPaths) {

            // 获取到apk的路径
            final ParcelFileDescriptor fd = openFileForSystem(inPath, "r");
            if (fd == null) {
                getErrPrintWriter().println("Error: Can't open file: " + inPath);
                throw new IllegalArgumentException("Error: Can't open file: " + inPath);
            }
            try {

               //解析此apk内容。
                ParseResult<ApkLite> apkLiteResult = ApkLiteParseUtils.parseApkLite(
                        input.reset(), fd.getFileDescriptor(), inPath, 0);
                if (apkLiteResult.isError()) {

                   //解析失败,报异常。
                    throw new IllegalArgumentException(
                            "Error: Failed to parse APK file: " + inPath + ": "
                                    + apkLiteResult.getErrorMessage(),
                            apkLiteResult.getException());
                }

                //获取到ApkLite 对象
                final ApkLite apkLite = apkLiteResult.getResult();
                final PackageLite pkgLite = new PackageLite(null, apkLite.getPath(), apkLite,
                        null /* splitNames */, null /* isFeatureSplits */,
                        null /* usesSplitNames */, null /* configForSplit */,
                        null /* splitApkPaths */, null /* splitRevisionCodes */,
                        apkLite.getTargetSdkVersion(), null /* requiredSplitTypes */,
                        null /* splitTypes */);

                 //计算安装文件大小。
                sessionSize += InstallLocationUtils.calculateInstalledSize(pkgLite,
                        params.sessionParams.abiOverride, fd.getFileDescriptor());
            } catch (IOException e) {
                getErrPrintWriter().println("Error: Failed to parse APK file: " + inPath);
                throw new IllegalArgumentException(
                        "Error: Failed to parse APK file: " + inPath, e);
            } finally {
                try {
                    fd.close();
                } catch (IOException e) {
                }
            }
        }

        //将计算文件大小存入。

        params.sessionParams.setSize(sessionSize);
    }

6. openFileForSystem 函数:


    /**
     * Helper for just system services to ask the shell to open an output file.
     * @hide
     */
    public ParcelFileDescriptor openFileForSystem(String path, String mode) {
        if (DEBUG) Slog.d(TAG, "openFileForSystem: " + path + " mode=" + mode);
        try {

           //获取文件,并且具有可打开的权限。
            ParcelFileDescriptor pfd = getShellCallback().openFile(path,
                    "u:r:system_server:s0", mode);
            if (pfd != null) {
                if (DEBUG) Slog.d(TAG, "Got file: " + pfd);

                //获取到此文件
                return pfd;
            }
        } catch (RuntimeException e) {
            if (DEBUG) Slog.d(TAG, "Failure opening file: " + e.getMessage());
            getErrPrintWriter().println("Failure opening file: " + e.getMessage());
        }
        if (DEBUG) Slog.d(TAG, "Error: Unable to open file: " + path);

         //否则就获取不到文件.
        getErrPrintWriter().println("Error: Unable to open file: " + path);

        String suggestedPath = "/data/local/tmp/";
        if (path == null || !path.startsWith(suggestedPath)) {
            getErrPrintWriter().println("Consider using a file under " + suggestedPath);
        }
        return null;
    }

 7. doCreateSession 函数:

    private int doCreateSession(SessionParams params, String installerPackageName, int userId)
            throws RemoteException {

        //默认是USER_ALL
        if (userId == UserHandle.USER_ALL) {
            params.installFlags |= PackageManager.INSTALL_ALL_USERS;
        }
        final int translatedUserId =
                translateUserId(userId, UserHandle.USER_SYSTEM, "doCreateSession");

       // 创建createSession
        final int sessionId = mInterface.getPackageInstaller()
                .createSession(params, installerPackageName, null /*installerAttributionTag*/,
                        translatedUserId);
        return sessionId;
    }

8. createSession 函数:

frameworks/base/services/core/java/com/android/server/pm/PackageInstallerService.java 

    @Override
    public int createSession(SessionParams params, String installerPackageName,
            String callingAttributionTag, int userId) {
        try {
            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");
            }

            // Draft sessions cannot be created through the public API.
            params.installFlags &= ~PackageManager.INSTALL_UNARCHIVE_DRAFT;
            return createSessionInternal(params, installerPackageName, callingAttributionTag,
                    Binder.getCallingUid(), userId);
        } catch (IOException e) {
            throw ExceptionUtils.wrap(e);
        }
    }

9. createSessionInternal 函数:

    int createSessionInternal(SessionParams params, String installerPackageName,
            String installerAttributionTag, int callingUid, int userId)
            throws IOException {
        final Computer snapshot = mPm.snapshotComputer();
        snapshot.enforceCrossUserPermission(callingUid, userId, true, true, "createSession");

        if (mPm.isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {

            // 若包含DISALLOW_INSTALL_APPS, 说明是禁止安装,则直接报错。
            throw new SecurityException("User restriction prevents installing");
        }

        // 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) {

         //安装原因是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");
            }
        }

        // App package name and label length is restricted so that really long strings aren't
        // written to disk.
        if (params.appPackageName != null && !isValidPackageName(params.appPackageName)) {

            //若包名是无效的,直接将包名设置为null.
            params.appPackageName = null;
        }

        params.appLabel = TextUtils.trimToSize(params.appLabel,
                PackageItemInfo.MAX_SAFE_LABEL_LENGTH);

        // Validate requested installer package name.
        if (params.installerPackageName != null && !isValidPackageName(
                params.installerPackageName)) {

           // 若安装包名是无效的,直接直接设置为null
            params.installerPackageName = null;
        }

        // Validate installer package name.
        if (installerPackageName != null && !isValidPackageName(installerPackageName)) {
            installerPackageName = null;
        }

        String requestedInstallerPackageName =
                params.installerPackageName != null ? params.installerPackageName
                        : installerPackageName;

        if (PackageManagerServiceUtils.isRootOrShell(callingUid)
                || PackageInstallerSession.isSystemDataLoaderInstallation(params)
                || PackageManagerServiceUtils.isAdoptedShell(callingUid, mContext)) {
            params.installFlags |= PackageManager.INSTALL_FROM_ADB;
            // adb installs can override the installingPackageName, but not the
            // initiatingPackageName

           //安装来源于adb
            installerPackageName = SHELL_PACKAGE_NAME;
        } else {
            if (callingUid != SYSTEM_UID) {
                // The supplied installerPackageName must always belong to the calling app.

                //若调用者不是system,则要检查权限。
                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) {

                    // 若请求安装包名和安装包名不一致,

                    // 需要判断是否有INSTALL_PACKAGES权限,若没有的话,进行权限检查。
                    mAppOps.checkPackage(callingUid, requestedInstallerPackageName);
                }
            }

           //移除 FLAG:INSTALL_FROM_ADB,INSTALL_ALL_USERS,INSTALL_ARCHIVED

            params.installFlags &= ~PackageManager.INSTALL_FROM_ADB;
            params.installFlags &= ~PackageManager.INSTALL_ALL_USERS;
            params.installFlags &= ~PackageManager.INSTALL_ARCHIVED;

            //增加flag:INSTALL_REPLACE_EXISTING
            params.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
            if ((params.installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0
                    && !mPm.isCallerVerifier(snapshot, 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;
            }

            // developmentInstallFlags can ony be set by shell or root.
            params.developmentInstallFlags = 0;
        }

        String originatingPackageName = null;
        if (params.originatingUid != SessionParams.UID_UNKNOWN
                && params.originatingUid != callingUid) {
            String[] packages = snapshot.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 || PackageManagerServiceUtils.isSystemOrRoot(callingUid)) {
            params.installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE;
        } else {
            params.installFlags &= ~PackageManager.INSTALL_ALLOW_DOWNGRADE;
        }

        if (mDisableVerificationForUid != INVALID_UID) {
            if (callingUid == mDisableVerificationForUid) {
                params.installFlags |= PackageManager.INSTALL_DISABLE_VERIFICATION;
            } else {
                // Clear the flag if current calling uid doesn't match the requested uid.
                params.installFlags &= ~PackageManager.INSTALL_DISABLE_VERIFICATION;
            }
            // Reset the field as this is a one-off request.
            mDisableVerificationForUid = INVALID_UID;
        } else 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;
        }

        if (Flags.rollbackLifetime()) {
            if (params.rollbackLifetimeMillis > 0) {
                if ((params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) == 0) {
                    throw new IllegalArgumentException(
                            "Can't set rollbackLifetimeMillis when rollback is not enabled");
                }
                if (mContext.checkCallingOrSelfPermission(Manifest.permission.MANAGE_ROLLBACKS)
                        != PackageManager.PERMISSION_GRANTED) {
                    throw new SecurityException(
                            "Setting rollback lifetime requires the MANAGE_ROLLBACKS permission");
                }
            } else if (params.rollbackLifetimeMillis < 0) {
                throw new IllegalArgumentException("rollbackLifetimeMillis can't be negative.");
            }
        }

        if (Flags.recoverabilityDetection()) {
            if (params.rollbackImpactLevel == PackageManager.ROLLBACK_USER_IMPACT_HIGH
                    || params.rollbackImpactLevel
                    == PackageManager.ROLLBACK_USER_IMPACT_ONLY_MANUAL) {
                if ((params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) == 0) {
                    throw new IllegalArgumentException(
                            "Can't set rollbackImpactLevel when rollback is not enabled");
                }
                if (mContext.checkCallingOrSelfPermission(Manifest.permission.MANAGE_ROLLBACKS)
                        != PackageManager.PERMISSION_GRANTED) {
                    throw new SecurityException(
                            "Setting rollbackImpactLevel requires the MANAGE_ROLLBACKS permission");
                }
            } else if (params.rollbackImpactLevel < 0) {
                throw new IllegalArgumentException("rollbackImpactLevel can't be negative.");
            }
        }

        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 (PackageManagerServiceUtils.isSystemOrRootOrShell(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_BYPASS_LOW_TARGET_SDK_BLOCK) != 0
                && !PackageManagerServiceUtils.isSystemOrRootOrShell(callingUid)
                && !Build.IS_DEBUGGABLE
                && !PackageManagerServiceUtils.isAdoptedShell(callingUid, mContext)) {
            // If the bypass flag is set, but not running as system root or shell then remove
            // the flag
            params.installFlags &= ~PackageManager.INSTALL_BYPASS_LOW_TARGET_SDK_BLOCK;
        }

        params.installFlags &= ~PackageManager.INSTALL_UNARCHIVE;
        if (isArchivingEnabled() && params.appPackageName != null) {
            PackageStateInternal ps = mPm.snapshotComputer().getPackageStateInternal(
                    params.appPackageName, SYSTEM_UID);
            if (ps != null
                    && PackageArchiver.isArchived(ps.getUserStateOrDefault(userId))
                    && PackageArchiver.getResponsibleInstallerPackage(ps)
                            .equals(requestedInstallerPackageName)) {
                params.installFlags |= PackageManager.INSTALL_UNARCHIVE;
            }
        }

        if ((params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0
                && !PackageManagerServiceUtils.isSystemOrRootOrShell(callingUid)
                && (snapshot.getFlagsForUid(callingUid) & ApplicationInfo.FLAG_SYSTEM)
                == 0) {
            throw new SecurityException(
                    "Only system apps could use the PackageManager.INSTALL_INSTANT_APP flag.");
        }

        if (params.isStaged && !PackageManagerServiceUtils.isSystemOrRootOrShell(callingUid)) {
            if (!mBypassNextStagedInstallerCheck
                    && !isStagedInstallerAllowed(requestedInstallerPackageName)) {
                throw new SecurityException("Installer not allowed to commit staged install");
            }
        }
        if (isApex && !PackageManagerServiceUtils.isSystemOrRootOrShell(callingUid)) {
            if (!mBypassNextStagedInstallerCheck
                    && !isStagedInstallerAllowed(requestedInstallerPackageName)) {
                throw new SecurityException(
                        "Installer not allowed to commit non-staged APEX install");
            }
        }

        mBypassNextStagedInstallerCheck = false;
        mBypassNextAllowedApexUpdateCheck = false;

        if (!params.isMultiPackage) {
            var hasInstallGrantRuntimePermissions = mContext.checkCallingOrSelfPermission(
                    Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS)
                    == PackageManager.PERMISSION_GRANTED;

            // Only system components can circumvent runtime permissions when installing.
            if ((params.installFlags & PackageManager.INSTALL_GRANT_ALL_REQUESTED_PERMISSIONS) != 0
                    && !hasInstallGrantRuntimePermissions) {
                throw new SecurityException("You need the "
                        + Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS
                        + " permission to use the"
                        + " PackageManager.INSTALL_GRANT_ALL_REQUESTED_PERMISSIONS flag");
            }

            var permissionStates = params.getPermissionStates();
            if (!permissionStates.isEmpty()) {
                if (!hasInstallGrantRuntimePermissions) {
                    for (int index = 0; index < permissionStates.size(); index++) {
                        var permissionName = permissionStates.keyAt(index);
                        if (!INSTALLER_CHANGEABLE_APP_OP_PERMISSIONS.contains(permissionName)) {
                            throw new SecurityException("You need the "
                                    + Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS
                                    + " permission to grant runtime permissions for a session");
                        }
                    }
                }
            }

            // 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 (!InstallLocationUtils.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 = InstallLocationUtils.resolveInstallVolume(mContext, params);
                } finally {
                    Binder.restoreCallingIdentity(ident);
                }
            }
        }

        int requestedInstallerPackageUid = INVALID_UID;
        if (requestedInstallerPackageName != null) {
            requestedInstallerPackageUid = snapshot.getPackageUid(requestedInstallerPackageName,
                    0 /* flags */, userId);
        }
        if (requestedInstallerPackageUid == INVALID_UID) {
            // Requested installer package is invalid, reset it
            requestedInstallerPackageName = 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);
            }
            final int existingDraftSessionId =
                    getExistingDraftSessionId(requestedInstallerPackageUid, params, userId);

            sessionId = existingDraftSessionId != SessionInfo.INVALID_ID ? existingDraftSessionId
                    : 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 (!PackageManagerServiceUtils.isRootOrShell(callingUid)) {
                params.forceQueryableOverride = false;
            }
        }

        final var dpmi = LocalServices.getService(DevicePolicyManagerInternal.class);
        if (dpmi != null && dpmi.isUserOrganizationManaged(userId)) {
            params.installFlags |= PackageManager.INSTALL_FROM_MANAGED_USER_OR_PROFILE;
        }

        if (isApex || mContext.checkCallingOrSelfPermission(
                Manifest.permission.ENFORCE_UPDATE_OWNERSHIP) == PackageManager.PERMISSION_DENIED) {
            params.installFlags &= ~PackageManager.INSTALL_REQUEST_UPDATE_OWNERSHIP;
        }

        InstallSource installSource = InstallSource.create(installerPackageName,
                originatingPackageName, requestedInstallerPackageName, requestedInstallerPackageUid,
                requestedInstallerPackageName, installerAttributionTag, params.packageSource);
        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, PackageManager.INSTALL_UNKNOWN, "", null);

        synchronized (mSessions) {
            mSessions.put(sessionId, session);
        }
        mPm.addInstallerPackageName(session.getInstallSource());

        mCallbacks.notifySessionCreated(session.sessionId, session.userId);

        mSettingsWriteRequest.schedule();
        if (LOGD) {
            Slog.d(TAG, "Created session id=" + sessionId + " staged=" + params.isStaged);
        }
        return sessionId;
    }


http://www.kler.cn/a/567061.html

相关文章:

  • anaconda配置pytorch
  • C++ primer plus 第四节 复合类型
  • 深入解析 Svelte:下一代前端框架的革命
  • 前端实现上传图片到OSS(Vue3+vant)
  • 《深入浅出 Vue.js 组件化开发》
  • 设计一个“车速计算”SWC,通过Sender-Receiver端口输出车速信号。
  • Prometheus + Grafana 监控
  • 解决“两数之和”问题:两种实现方法详解
  • 双臂机器人的动力学建模
  • 浅入浅出Selenium DevTools
  • Oracle日常管理(8)——DB日常管理(2)
  • 正大杯攻略|量表类问卷数据分析基本步骤
  • Html5学习教程,从入门到精通,HTML 5 图像语法知识点语法知识点及案例代码(9)
  • #深入了解DNS3和VCTK语音数据集
  • 模拟器游戏多开为什么需要单窗口单IP
  • MES:开启生产制造优秀管理新时代
  • 博客系统完整开发流程
  • LeetCode 每日一题 2025/2/24-2025/3/2
  • 人工智能之数学基础:线性代数中矩阵的运算
  • 国产RISCV64 也能跑AI