zoukankan      html  css  js  c++  java
  • Android中应用安装分析

    #1 安装方式

    • 1 安装系统APK和预制APK时,通过PMS的构造函数中安装,即第一次开机时安装应用,没有安装界面。
    • 2 网络下载安装,通过应用商店等,即调用PackageManager.installPackages(),有安装界面。
    • 3 通过adb工具安装,没有安装界面,它通过启动pm脚本的形式,然后调用com.android.commands.pm.Pm类,之后调用到PMS.installStage()完成安装。
    • 4 安装本地apk,有安装界面,由PackageInstaller系统应用安装。
      上述几种方式均通过PackageInstallObserver来监听安装是否成功。

    #2 安装流程分析

    2.1 首次安装

    首次安装即系统第一次开机时安装应用,包括系统应用和预制应用,其最主要过程在PMS构造函数中,

    整个过程关键步骤大致为上述15步,与应用安装相关实际上就是扫描和安装两步。方法调用时序图如图1所示。
    [图1 PMS安装应用时序图]

    • 1 向动态设置中添加系统默认的共享ID(system、phone、log、nfc、bluetooth、shell、se等)。
    • 2 初始化成员变量,如Installer、PackageDexOptimizer、DexManager、ArtManagerService、MoveCallbacks、OnPermissionChangeListeners等,并获取系统配置。
    • 3 启动一个服务类线程。
    • 4 初始化用户管理服务
    • 5 将权限配置传入包管理器
    • 6 清除代码路径不存在的孤立包
    • 7 将系统应用权限从安装态升级为运行时
    • 8 在扫描应用前,手机供应商的覆盖安装包(/overlay)
    • 9 扫描应用目录,依次为特权系统目录 priv-app、普通目录 app、供应商系统目录 vendor/app等
    • 10 解析存储管理器
    • 11 如果是第一次开机,需要初始化用户的默认偏好应用
    • 12 在启动时,为用户准备好存储空间,因为SystemUI等启动不能等待用户
    • 13 安装应用,完成后检查webview,默认浏览器等。
    • 14 启动PackageInstallerService
    • 15 向系统组件暴露私有服务
      下面我们结合代码做详细分析
    1. 判断应用包是否已安装,如果包名存在于uninstalled_deapp.xml中或者已安装,则直接返回null。

    2.2 下载安装

    下载安装可分为两部分:拷贝应用和安装应用。拷贝过程的函数调用时序图如图2所示。
    【图2 下载安装应用程序时序图】

    frameworks层的入口函数为PackageManager.installPackage,由应用市场APP调用,然后调用PMS.installPackageAsUser,然后发送消息INIT_COPY、MCS_BOUND开始复制,调用HandlerParams.startCopy。这个方法主要分两部分,一部分是拷贝应用的执行程序,另一部分是创建应用的数据目录,拷贝部分由handleStartCopy完成。之后调用handlerReturnCode来处理创建数据目录。拷贝部分会调用DefaultContainerService来完成,该服务为那些可能位于可删除空间上的文件提供检查和拷贝功能。当底层设置被移除时,这样设计可以防止系统进程保留打开的文件时,不被内核杀死。

    handleStartcopy实现在PMS内部类InstallParams中,它的功能是调用远程方法获取包信息和安装位置,如有必要则给与默认车辆覆盖安装位置,然后基于安装位置创建安装参数。下面我们结合关键代码做进一步分析。

    首先是拷贝应用过程

    • 1 PMS.installPackageAsUser的功能主要是:根据uid确定installFlags,并校验权限,并构造InstallParam,然后发送INIT_COPY消息。
    @Override
    public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,
            int installFlags, String installerPackageName, int userId) {
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);
    
        final int callingUid = Binder.getCallingUid();
        enforceCrossUserPermission(callingUid, userId,
                true /* requireFullPermission */, true /* checkShell */, "installPackageAsUser");
    
        if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
            try {
                if (observer != null) {
                    observer.onPackageInstalled("", INSTALL_FAILED_USER_RESTRICTED, null, null);
                }
            } catch (RemoteException re) {
            }
            return;
        }
    
        if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
            installFlags |= PackageManager.INSTALL_FROM_ADB;
    
        } else {
            // Caller holds INSTALL_PACKAGES permission, so we're less strict
            // about installerPackageName.
    
            installFlags &= ~PackageManager.INSTALL_FROM_ADB;
            installFlags &= ~PackageManager.INSTALL_ALL_USERS;
        }
    
        UserHandle user;
        if ((installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {
            user = UserHandle.ALL;
        } else {
            user = new UserHandle(userId);
        }
    
        // Only system components can circumvent runtime permissions when installing.
        if ((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 ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0
                || (installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
            throw new IllegalArgumentException(
                    "New installs into ASEC containers no longer supported");
        }
    
        final File originFile = new File(originPath);
        final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile);
    
        final Message msg = mHandler.obtainMessage(INIT_COPY);
        final VerificationInfo verificationInfo = new VerificationInfo(
                null /*originatingUri*/, null /*referrer*/, -1 /*originatingUid*/, callingUid);
        final InstallParams params = new InstallParams(origin, null /*moveInfo*/, observer,
                installFlags, installerPackageName, null /*volumeUuid*/, verificationInfo, user,
                null /*packageAbiOverride*/, null /*grantedPermissions*/,
                null /*certificates*/, PackageManager.INSTALL_REASON_UNKNOWN);
        params.setTraceMethod("installAsUser").setTraceCookie(System.identityHashCode(params));
        msg.obj = params;
    
        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installAsUser",
                System.identityHashCode(msg.obj));
        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
                System.identityHashCode(msg.obj));
    
        mHandler.sendMessage(msg);
    }
    
    
    • 2 之后根据Handler.doHandleMessage调用到InstallParams.handleStartCopy方法,首先检查文件和cid是否已生成,如生成则设置installFlags。
    // [InstallParams.handleStartCopy]
    if (origin.staged) {
        if (origin.file != null) {
            installFlags |= PackageManager.INSTALL_INTERNAL;
            installFlags &= ~PackageManager.INSTALL_EXTERNAL;
        } else if (origin.cid != null) {
            installFlags |= PackageManager.INSTALL_EXTERNAL;
            installFlags &= ~PackageManager.INSTALL_INTERNAL;
        } else {
            throw new IllegalStateException("Invalid stage location");
        }
    }
    
    • 3 然后检查空间大小,如果空间不够则释放无用空间。
    // [InstallParams.handleStartCopy]
    if (!origin.staged && pkgLite.recommendedInstallLocation
                            == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
        // TODO: focus freeing disk space on the target device
        final StorageManager storage = StorageManager.from(mContext);
        final long lowThreshold = storage.getStorageLowBytes(
                Environment.getDataDirectory());
    
        final long sizeBytes = mContainerService.calculateInstalledSize(
                origin.resolvedPath, isForwardLocked(), packageAbiOverride);
    
        try {
            mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0);
            pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath,
                    installFlags, packageAbiOverride);
        } catch (InstallerException e) {
            Slog.w(TAG, "Failed to free cache", e);
        }
    
    
        if (pkgLite.recommendedInstallLocation
                == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
            pkgLite.recommendedInstallLocation
                = PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
        }
    }
    
    • 4 覆盖原有安装位置的文件,并根据返回结果来确定函数的返回值,并设置installFlags。
    // [InstallParams.handleStartCopy]
    // Override with defaults if needed.
    loc = installLocationPolicy(pkgLite);
    if (loc == PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE) {
        ret = PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
    } else if (!onSd && !onInt) {
        // Override install location with flags
        if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
            // Set the flag to install on external media.
            installFlags |= PackageManager.INSTALL_EXTERNAL;
            installFlags &= ~PackageManager.INSTALL_INTERNAL;
        } else if (loc == PackageHelper.RECOMMEND_INSTALL_EPHEMERAL) {
            if (DEBUG_EPHEMERAL) {
                Slog.v(TAG, "...setting INSTALL_EPHEMERAL install flag");
            }
            installFlags |= PackageManager.INSTALL_INSTANT_APP;
            installFlags &= ~(PackageManager.INSTALL_EXTERNAL
                    |PackageManager.INSTALL_INTERNAL);
        } else {
            // Make sure the flag for installing on external
            // media is unset
            installFlags |= PackageManager.INSTALL_INTERNAL;
            installFlags &= ~PackageManager.INSTALL_EXTERNAL;
        }
    }
    
    • 5 确定是否有任何已安装的包验证器,如有,则延迟检测。主要分三步:首先新建一个验证Intent,然后设置相关的信息,之后获取验证器列表,最后向每个验证器发送验证Intent。
    // [InstallParams.handleStartCopy]
    final Intent verification = new Intent( //构造验证Intent
                                Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
        // ......
    
        final PackageVerificationState verificationState = new PackageVerificationState(
                requiredUid, args);
    
        mPendingVerification.append(verificationId, verificationState);
        // 获取验证器列表
        final List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite,
                receivers, verificationState);
    
        DeviceIdleController.LocalService idleController = getDeviceIdleController();
        final long idleDuration = getVerificationTimeout();
    
        /*
         * If any sufficient verifiers were listed in the package
         * manifest, attempt to ask them.
         */
        if (sufficientVerifiers != null) {
            final int N = sufficientVerifiers.size();
            if (N == 0) {
                Slog.i(TAG, "Additional verifiers required, but none installed.");
                ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
            } else {
                for (int i = 0; i < N; i++) {
                    final ComponentName verifierComponent = sufficientVerifiers.get(i);
                    idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
                            verifierComponent.getPackageName(), idleDuration,
                            verifierUser.getIdentifier(), false, "package verifier");
                    // 向每个验证器发送验证Intent
                    final Intent sufficientIntent = new Intent(verification);
                    sufficientIntent.setComponent(verifierComponent);
                    mContext.sendBroadcastAsUser(sufficientIntent, verifierUser);
                }
            }
        }
    
    • 6 向验证器客户端发送intent,只有当验证成功之后才会开启copy工作。如果没有任何验证器则直接拷贝。

    下面为安装过程入口是PMS.processPendingInstall方法,调用时序图如图3
    【图3 下载安装-安装过程图】

    • 1 首先启动一个新线程,然后设置安装信息,处理安装参数,开始安装,并发送关于安装状态的广播,然后处理安装完的事情,比如打印错误信息,清除临时文件等。
    private void processPendingInstall(final InstallArgs args, final int currentStatus) {
        // Queue up an async operation since the package installation may take a little while.
        mHandler.post(new Runnable() {
            public void run() {
                mHandler.removeCallbacks(this);
                 // Result object to be returned
                PackageInstalledInfo res = new PackageInstalledInfo();
                res.setReturnCode(currentStatus);
                res.uid = -1;
                res.pkg = null;
                res.removedInfo = null;
                if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
                    args.doPreInstall(res.returnCode);
                    synchronized (mInstallLock) {
                        installPackageTracedLI(args, res);
                    }
                    args.doPostInstall(res.returnCode, res.uid);
        //......
    }
    
    • 2 installPackageTracedLI是安装过程的核心方法,然后调用installPackageLI.首先检查安装包的完整性并解析安装包。
    //[PMS.installPackageLI]
    // 完整性校验
    if (instantApp && (forwardLocked || onExternal)) {
        Slog.i(TAG, "Incompatible ephemeral install; fwdLocked=" + forwardLocked
                + " external=" + onExternal);
        res.setReturnCode(PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
        return;
    }
    
    // 检索包设置,并解析应用
    final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
            | PackageParser.PARSE_ENFORCE_CODE
            | (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0)
            | (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0)
            | (instantApp ? PackageParser.PARSE_IS_EPHEMERAL : 0)
            | (forceSdk ? PackageParser.PARSE_FORCE_SDK : 0);
    PackageParser pp = new PackageParser();
    pp.setSeparateProcesses(mSeparateProcesses);
    pp.setDisplayMetrics(mMetrics);
    pp.setCallback(mPackageParserCallback);
    
    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
    final PackageParser.Package pkg;
    try {
        //解析安装包
        pkg = pp.parsePackage(tmpPackageFile, parseFlags);
        DexMetadataHelper.validatePackageDexMetadata(pkg);
    } catch (PackageParserException e) {
        res.setError("Failed parse during installPackageLI", e);
        return;
    } finally {
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }
    
    • 3 检查SDK版本和沙箱版本,同时检查是否有静态共享库,如有则需要放在内部存储中。
    //[PMS.installPackageLI]
    //检查SDK版本和沙箱版本
    if (instantApp && pkg.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) {
        Slog.w(TAG, "Instant app package " + pkg.packageName + " does not target O");
        res.setError(INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE,
                "Instant app package must target O");
        return;
    }
    if (instantApp && pkg.applicationInfo.targetSandboxVersion != 2) {
        Slog.w(TAG, "Instant app package " + pkg.packageName
                + " does not target targetSandboxVersion 2");
        res.setError(INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE,
                "Instant app package must use targetSanboxVersion 2");
        return;
    }
    //检查是否有静态共享库
    if (pkg.applicationInfo.isStaticSharedLibrary()) {
        // Static shared libraries have synthetic package names
        renameStaticSharedLibraryPackage(pkg);
    
        // No static shared libs on external storage
        if (onExternal) {
            Slog.i(TAG, "Static shared libs can only be installed on internal storage.");
            res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
                    "Packages declaring static-shared libs cannot be updated");
            return;
        }
    }
    
    • 4 检查是否有子安装包,如有则子安装包也需要检测。
    //[PMS.installPackageLI]
    // If we are installing a clustered package add results for the children
    if (pkg.childPackages != null) {
        synchronized (mPackages) {
            final int childCount = pkg.childPackages.size();
            for (int i = 0; i < childCount; i++) {
                PackageParser.Package childPkg = pkg.childPackages.get(i);
                PackageInstalledInfo childRes = new PackageInstalledInfo();
                childRes.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
                childRes.pkg = childPkg;
                childRes.name = childPkg.packageName;
                PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
                if (childPs != null) {
                    childRes.origUsers = childPs.queryInstalledUsers(
                            sUserManager.getUserIds(), true);
                }
                if ((mPackages.containsKey(childPkg.packageName))) {
                    childRes.removedInfo = new PackageRemovedInfo(this);
                    childRes.removedInfo.removedPackage = childPkg.packageName;
                    childRes.removedInfo.installerPackageName = childPs.installerPackageName;
                }
                if (res.addedChildPackages == null) {
                    res.addedChildPackages = new ArrayMap<>();
                }
                res.addedChildPackages.put(childPkg.packageName, childRes);
            }
        }
    }
    
    • 5 检查安装包是否已存在,如已存在则需要检查旧的父包、沙箱、sdk等是否已为空,否则会报错。
    • 6 校验安装包签名
    //[PMS.installPackageLI]
    PackageSetting signatureCheckPs = ps;
    if (pkg.applicationInfo.isStaticSharedLibrary()) {
        SharedLibraryEntry libraryEntry = getLatestSharedLibraVersionLPr(pkg);
        if (libraryEntry != null) {
            signatureCheckPs = mSettings.getPackageLPr(libraryEntry.apk);
        }
    }
    
    // Quick sanity check that we're signed correctly if updating;
    // we'll check this again later when scanning, but we want to
    // bail early here before tripping over redefined permissions.
    if (shouldCheckUpgradeKeySetLP(signatureCheckPs, scanFlags)) {
        if (!checkUpgradeKeySetLP(signatureCheckPs, pkg)) {
            res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
                    + pkg.packageName + " upgrade keys do not match the "
                    + "previously installed version");
            return;
        }
    } else {
        try {
            verifySignaturesLP(signatureCheckPs, pkg);
        } catch (PackageManagerException e) {
            res.setError(e.error, e.getMessage());
            return;
        }
    }
    
    • 7 设置相关的全向,包括生成权限、移植权限等
    • 8 如果这是一个系统应用,则检查是否在外部存储上或是是否被其他应用替换等
    //[PMS.installPackageLI]
    if (systemApp) {
        if (onExternal) {
            // Abort update; system app can't be replaced with app on sdcard
            res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
                    "Cannot install updates to system apps on sdcard");
            return;
        } else if (instantApp) {
            // Abort update; system app can't be replaced with an instant app
            res.setError(INSTALL_FAILED_INSTANT_APP_INVALID,
                    "Cannot update a system app with an instant app");
            return;
        }
    }
    
    • 9 生成安装包Abi(Application binary interface,应用二进制接口,描述应用程序和操作系统之间或其他应用程序的低级接口)
    //[PMS.installPackageLI]
    try {
        String abiOverride = (TextUtils.isEmpty(pkg.cpuAbiOverride) ?
            args.abiOverride : pkg.cpuAbiOverride);
        final boolean extractNativeLibs = !pkg.isLibrary();
        derivePackageAbi(pkg, new File(pkg.codePath), abiOverride,
                extractNativeLibs, mAppLib32InstallDir);
    } catch (PackageManagerException pme) {
        Slog.e(TAG, "Error deriving application ABI", pme);
        res.setError(INSTALL_FAILED_INTERNAL_ERROR, "Error deriving application ABI");
        return;
    }
    
    • 10更新共享库
    //[PMS.installPackageLI]
    synchronized (mPackages) {
        try {
            updateSharedLibrariesLPr(pkg, null);
        } catch (PackageManagerException e) {
            Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
        }
    }
    
    • 11如有必要,优化dex文件
    //[PMS.installPackageLI]
    final boolean performDexopt = (res.returnCode == PackageManager.INSTALL_SUCCEEDED)
        && !forwardLocked
        && !pkg.applicationInfo.isExternalAsec()
        && (!instantApp || Global.getInt(mContext.getContentResolver(),
        Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)
        && ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0);
    
    if (performDexopt) {
    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
    // Do not run PackageDexOptimizer through the local performDexOpt
    // method because `pkg` may not be in `mPackages` yet.
    //
    // Also, don't fail application installs if the dexopt step fails.
    DexoptOptions dexoptOptions = new DexoptOptions(pkg.packageName,
            REASON_INSTALL,
            DexoptOptions.DEXOPT_BOOT_COMPLETE |
            DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE);
    mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,
            null /* instructionSets */,
            getOrCreateCompilerPackageStats(pkg),
            mDexManager.getPackageUseInfoOrDefault(pkg.packageName),
            dexoptOptions);
    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }
    
    • 12替换安装,则直接安装新包,这里应用时生成应用数据目录。ps:替换安装:其主要过程为更新设置,清除原有的某些APP数据,重新生成相关的app数据目录等步骤,同事要区分系统应用替换和非系统应用替换。而安装新包:则直接更新设置,生成APP数据即可。
    try (PackageFreezer freezer = freezePackageForInstall(pkgName, installFlags,
                    "installPackageLI")) {
        if (replace) {
            if (pkg.applicationInfo.isStaticSharedLibrary()) {
                // Static libs have a synthetic package name containing the version
                // and cannot be updated as an update would get a new package name,
                // unless this is the exact same version code which is useful for
                // development.
                PackageParser.Package existingPkg = mPackages.get(pkg.packageName);
                if (existingPkg != null && existingPkg.mVersionCode != pkg.mVersionCode) {
                    res.setError(INSTALL_FAILED_DUPLICATE_PACKAGE, "Packages declaring "
                            + "static-shared libs cannot be updated");
                    return;
                }
            }
            replacePackageLIF(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
                    installerPackageName, res, args.installReason);
        } else {
            installNewPackageLIF(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
                    args.user, installerPackageName, volumeUuid, res, args.installReason);
        }
    }
    
    • 13 如果是安装一个不存在的包,则调用PMS.installNewPackageLIF方法。首先会检查是否有重复的包名,并更新设置,然后根据安装的结果,如果安装失败则删除安装过程中产生的文件。
    private void installNewPackageLIF(PackageParser.Package pkg, final int policyFlags,
            int scanFlags, UserHandle user, String installerPackageName, String volumeUuid,
            PackageInstalledInfo res, int installReason) {
        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installNewPackage");
    
        // Remember this for later, in case we need to rollback this install
        String pkgName = pkg.packageName;
    
        if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);
    
        synchronized(mPackages) {
            final String renamedPackage = mSettings.getRenamedPackageLPr(pkgName);
            if (renamedPackage != null) {
                // 如果已有相同包名的应用,则报错
                res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName
                        + " without first uninstalling package running as "
                        + renamedPackage);
                return;
            }
            if (mPackages.containsKey(pkgName)) {
                // Don't allow installation over an existing package with the same name.
                res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName
                        + " without first uninstalling.");
                return;
            }
        }
    
        try {
            PackageParser.Package newPackage = scanPackageTracedLI(pkg, policyFlags, scanFlags, System.currentTimeMillis(), user);
    
            updateSettingsLI(newPackage, installerPackageName, null, res, user, installReason);
    
            if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
                prepareAppDataAfterInstallLIF(newPackage);
    
            } else {
                // Remove package from internal structures, but keep around any
                // data that might have already existed
                deletePackageLIF(pkgName, UserHandle.ALL, false, null,
                        PackageManager.DELETE_KEEP_DATA, res.removedInfo, true, null);
            }
        } catch (PackageManagerException e) {
            res.setError("Package couldn't be installed in " + pkg.codePath, e);
        }
    
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }
    
    • 14 然后为已安装的应用准备数据目录,其依次的顺序是
      • PMS.prepareAppDataAfterInstallLIF
      • PMS.prepareAppDataLIF
      • PMS.prepareAppDataLeafLIF
      • Installer.createAppData

    这个方法是PMS与Installer交互的接口函数,这里的数据目录是CE类型。

    private void prepareAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) {
        if (DEBUG_APP_DATA) {
            Slog.v(TAG, "prepareAppData for " + pkg.packageName + " u" + userId + " 0x"
                    + Integer.toHexString(flags));
        }
    
        final String volumeUuid = pkg.volumeUuid;
        final String packageName = pkg.packageName;
        final ApplicationInfo app = pkg.applicationInfo;
        final int appId = UserHandle.getAppId(app.uid);
    
        Preconditions.checkNotNull(app.seInfo);
    
        long ceDataInode = -1;
        try {
            // 调用Installd守护进程的入口
            ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags,
                    appId, app.seInfo, app.targetSdkVersion);
        } catch (InstallerException e) {
            //......
        }
        // Prepare the application profiles.
        mArtManagerService.prepareAppProfiles(pkg, userId);
    
        if ((flags & StorageManager.FLAG_STORAGE_CE) != 0 && ceDataInode != -1) {
            // TODO: mark this structure as dirty so we persist it!
            synchronized (mPackages) {
                final PackageSetting ps = mSettings.mPackages.get(packageName);
                if (ps != null) {
                    ps.setCeDataInode(ceDataInode, userId);
                }
            }
        }
    
        prepareAppDataContentsLeafLIF(pkg, userId, flags);
    }
    
    
    • 15 如果是替换应用,一般情况是应用更新,或者是重新安装。它的主要过程包括:验证签名,如是系统更新则还需要校验hash值,检查共享ID的更改情况,不允许完整更新,更新已被删除数据,最后根据应用是否是系统应用来判断接下去的操作。
    private void replacePackageLIF(PackageParser.Package pkg, final int policyFlags, int scanFlags,
            UserHandle user, String installerPackageName, PackageInstalledInfo res,
            int installReason) {
        final boolean isInstantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
    
        final PackageParser.Package oldPackage;
        final PackageSetting ps;
        final String pkgName = pkg.packageName;
        final int[] allUsers;
        final int[] installedUsers;
    
        // ......
    
        boolean sysPkg = (isSystemApp(oldPackage));
        if (sysPkg) {
            // Set the system/privileged flags as needed
            final boolean privileged =
                    (oldPackage.applicationInfo.privateFlags
                            & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
            final int systemPolicyFlags = policyFlags
                    | PackageParser.PARSE_IS_SYSTEM
                    | (privileged ? PackageParser.PARSE_IS_PRIVILEGED : 0);
    
            replaceSystemPackageLIF(oldPackage, pkg, systemPolicyFlags, scanFlags,
                    user, allUsers, installerPackageName, res, installReason);
        } else {
            replaceNonSystemPackageLIF(oldPackage, pkg, policyFlags, scanFlags,
                    user, allUsers, installerPackageName, res, installReason);
        }
    }
    
    • 16 最后这两个方法均会调用到PMS.prepareAppDataLeafLIF。
    • 17 安装完成后,更新设置,更新安装锁等。

    2.3 adb安装

    关于adb安装,其copy过程与下载安装不同,但安装过程却与下载过程是相同的,这里不做重复分析,需要注意的是adb安装是不能替换安装的,具体原因?

    拷贝过程
    其调用时序图如图4 所示。
    【图4 adb安装-copy过程时序图】

    • 1 adb的入口在com.android.commands.pm.Pm类,那么这是如何调用到这个类的呢,这是adb命令通过adbd守护进程调用到/system/bin/pm这个脚本,其脚本源码如下:
    base=/system
    export CLASSPATh-$base/framework/pm.jar
    exec app_process $base/bin.com.android.commands.pm.Pm "$@"
    
    • 2 Pm类通过脚本启动,执行顺序是main->run->runInstall,然后提交session。
    public static void main(String[] args) {
        int exitCode = 1;
        try {
            exitCode = new Pm().run(args);
        } catch (Exception e) {
            Log.e(TAG, "Error", e);
            System.err.println("Error: " + e);
            if (e instanceof RemoteException) {
                System.err.println(PM_NOT_RUNNING_ERR);
            }
        }
        System.exit(exitCode);
    }
    public int run(String[] args) throws RemoteException {
        boolean validCommand = false;
        if (args.length < 1) {
            return showUsage();
        }
        mAm = IAccountManager.Stub.asInterface(ServiceManager.getService(Context.ACCOUNT_SERVICE));
        mUm = IUserManager.Stub.asInterface(ServiceManager.getService(Context.USER_SERVICE));
        mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
    
        if (mPm == null) {
            System.err.println(PM_NOT_RUNNING_ERR);
            return 1;
        }
        mInstaller = mPm.getPackageInstaller();
    
        mArgs = args;
        String op = args[0];
        mNextArg = 1;
        //......
        if ("install".equals(op)) {
            return runInstall();
        }
        //......
    }
    
    • 3 Pm.runInstall中首先是创建session,然后提交session,代码如下。
        private int runInstall() throws RemoteException {
            long startedTime = SystemClock.elapsedRealtime();
            final InstallParams params = makeInstallParams();
            final String inPath = nextArg();
            if (params.sessionParams.sizeBytes == -1 && !STDIN_PATH.equals(inPath)) {
                File file = new File(inPath);
                if (file.isFile()) {
                    try {
                        ApkLite baseApk = PackageParser.parseApkLite(file, 0);
                        PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null,
                                null, null);
                        params.sessionParams.setSize(
                                PackageHelper.calculateInstalledSize(pkgLite, false,
                                params.sessionParams.abiOverride));
                    } catch (PackageParserException | IOException e) {
                        System.err.println("Error: Failed to parse APK file: " + e);
                        return 1;
                    }
                } else {
                    System.err.println("Error: Can't open non-file: " + inPath);
                    return 1;
                }
            }
    
            final int sessionId = doCreateSession(params.sessionParams,
                    params.installerPackageName, params.userId);
    
            try {
                if (inPath == null && params.sessionParams.sizeBytes == -1) {
                    System.err.println("Error: must either specify a package size or an APK file");
                    return 1;
                }
                if (doWriteSession(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk",
                        false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
                    return 1;
                }
                Pair<String, Integer> status = doCommitSession(sessionId, false /*logSuccess*/);
                if (status.second != PackageInstaller.STATUS_SUCCESS) {
                    return 1;
                }
                Log.i(TAG, "Package " + status.first + " installed in " + (SystemClock.elapsedRealtime()
                        - startedTime) + " ms");
                System.out.println("Success");
                return 0;
            } finally {
                try {
                    mInstaller.abandonSession(sessionId);
                } catch (Exception ignore) {
                }
            }
        }
    
    • 4 这里Pm相当于客户端,接受session的服务端在PackageInstallerSession中,这里利用AIDL来完成传输,其调用过程为:
      • Pm.doCommitSession
      • PackageInstaller.Session.commit
      • IPackageInstallerSession.commit
      • PackageInstallerSession.commit
      • Handler.Callback.handleMessage
      • PackageInstallerSession.commitLock
      • PMS.installStage

    以上关于session传递过程暂不分析,下面我们来详细看下installStage方法。

    • 5 installStage方法主要功能就是构造InstallParam对象,并发送INIT_COPY。
    void installStage(String packageName, File stagedDir, String stagedCid,
            IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,
            String installerPackageName, int installerUid, UserHandle user,
            Certificate[][] certificates) {
        if (DEBUG_EPHEMERAL) {
            if ((sessionParams.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
                Slog.d(TAG, "Ephemeral install of " + packageName);
            }
        }
        final VerificationInfo verificationInfo = new VerificationInfo(
                sessionParams.originatingUri, sessionParams.referrerUri,
                sessionParams.originatingUid, installerUid);
    
        final OriginInfo origin;
        if (stagedDir != null) {
            origin = OriginInfo.fromStagedFile(stagedDir);
        } else {
            origin = OriginInfo.fromStagedContainer(stagedCid);
        }
    
        final Message msg = mHandler.obtainMessage(INIT_COPY);
        final int installReason = fixUpInstallReason(installerPackageName, installerUid,
                sessionParams.installReason);
        final InstallParams params = new InstallParams(origin, null, observer,
                sessionParams.installFlags, installerPackageName, sessionParams.volumeUuid,
                verificationInfo, user, sessionParams.abiOverride,
                sessionParams.grantedRuntimePermissions, certificates, installReason);
        params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
        msg.obj = params;
    
        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStage",
                System.identityHashCode(msg.obj));
        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
                System.identityHashCode(msg.obj));
    
        mHandler.sendMessage(msg);
    }
    
    
    • 6 发送完Handler消息后就与下载安装过程相同了。

    2.4 本地安装

    本地安装参与对象包括PackageInstaller应用,PMS两部分。下面我们就来分析下PackageInstaller是如何调用到PMS中的。函数调用时序图如图5所示。
    【图5 本地安装前提调用时序图】

    • 1 点击文件管理器中的apk文件时,会调用到FolderFragment类的openFile方法,然后调用startActivitySafety方法启动PackageInstallerActivity。
    private void openFile(File f) {  
        final Uri fileUri = Uri.fromFile(f);  
        final Intent intent = new Intent();  
        intent.setAction(android.content.Intent.ACTION_VIEW);  
        intent.putExtra(Intent.EXTRA_TITLE, f.getName());  
        intent.putExtra(EXTRA_ALL_VIDEO_FOLDER, true);  
        Uri contentUri = null;  
        String type = getMIMEType(f);  
        //......  
            if (contentUri != null) {  
                intent.setDataAndType(contentUri, type);  
            } else {  
                intent.setDataAndType(fileUri, type);  
            }  
            try {  
                startActivitySafely(intent);  
            }   
        //......  
    }
    
    • 2 如下为PackageInstallerActivity.onCreate方法源码,其主要过程初始化各个服务的成员变量如PMS,校验session,并加载UI界面,然用户确定是否安装。
    //[PackageInstallerActivity.java]
    protected void onCreate(Bundle icicle) {
        super.onCreate(icicle);
    
        if (icicle != null) {
            mAllowUnknownSources = icicle.getBoolean(ALLOW_UNKNOWN_SOURCES_KEY);
        }
    	//初始化各个关键参数
        mPm = getPackageManager();
        mIpm = AppGlobals.getPackageManager();
        mAppOpsManager = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE);
        mInstaller = mPm.getPackageInstaller();
        mUserManager = (UserManager) getSystemService(Context.USER_SERVICE);
    
        final Intent intent = getIntent();
    
        mCallingPackage = intent.getStringExtra(EXTRA_CALLING_PACKAGE);
        mSourceInfo = intent.getParcelableExtra(EXTRA_ORIGINAL_SOURCE_INFO);
        mOriginatingUid = intent.getIntExtra(Intent.EXTRA_ORIGINATING_UID,
                PackageInstaller.SessionParams.UID_UNKNOWN);
        mOriginatingPackage = (mOriginatingUid != PackageInstaller.SessionParams.UID_UNKNOWN)
                ? getPackageNameForUid(mOriginatingUid) : null;
    
    
        final Uri packageUri;
        //校验session
        if (PackageInstaller.ACTION_CONFIRM_PERMISSIONS.equals(intent.getAction())) {
            final int sessionId = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1);
            final PackageInstaller.SessionInfo info = mInstaller.getSessionInfo(sessionId);
            if (info == null || !info.sealed || info.resolvedBaseCodePath == null) {
                Log.w(TAG, "Session " + mSessionId + " in funky state; ignoring");
                finish();
                return;
            }
    
            mSessionId = sessionId;
            packageUri = Uri.fromFile(new File(info.resolvedBaseCodePath));
            mOriginatingURI = null;
            mReferrerURI = null;
        } else {
            mSessionId = -1;
            packageUri = intent.getData();
            mOriginatingURI = intent.getParcelableExtra(Intent.EXTRA_ORIGINATING_URI);
            mReferrerURI = intent.getParcelableExtra(Intent.EXTRA_REFERRER);
        }
    
        // if there's nothing to do, quietly slip into the ether
        if (packageUri == null) {
            Log.w(TAG, "Unspecified source");
            setPmResult(PackageManager.INSTALL_FAILED_INVALID_URI);
            finish();
            return;
        }
    
        if (DeviceUtils.isWear(this)) {
            showDialogInner(DLG_NOT_SUPPORTED_ON_WEAR);
            return;
        }
    
        boolean wasSetUp = processPackageUri(packageUri);
        if (!wasSetUp) {
            return;
        }
    
        // 加载UI界面
        bindUi(R.layout.install_confirm, false);
        checkIfAllowedAndInitiateInstall();
    }
    
    • 3 当用户点击安装按钮时,响应函数为PackageInstallerActivity.onClick方法,
    //[PackageInstallerActivity.java]
    public void onClick(View v) {
        if (v == mOk) {
            if (mOk.isEnabled()) {
                if (mOkCanInstall || mScrollView == null) {
                    if (mSessionId != -1) {
                        mInstaller.setPermissionsResult(mSessionId, true);
                        finish();
                    } else {
                        startInstall();
                    }
                } else {
                    mScrollView.pageScroll(View.FOCUS_DOWN);
                }
            }
        } else if (v == mCancel) {
            // Cancel and finish
            setResult(RESULT_CANCELED);
            if (mSessionId != -1) {
                mInstaller.setPermissionsResult(mSessionId, false);
            }
            finish();
        }
    }
    
    • 4 之后调用 PackageInstallerActivity.startInstall方法,构造Intent,然后启动InstallInstalling,并销毁PackageInstallerActivity。
    private void startInstall() {
        // Start subactivity to actually install the application
        Intent newIntent = new Intent();
        newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
                mPkgInfo.applicationInfo);
        newIntent.setData(mPackageURI);
        newIntent.setClass(this, InstallInstalling.class);
        String installerPackageName = getIntent().getStringExtra(
                Intent.EXTRA_INSTALLER_PACKAGE_NAME);
        if (mOriginatingURI != null) {
            newIntent.putExtra(Intent.EXTRA_ORIGINATING_URI, mOriginatingURI);
        }
        if (mReferrerURI != null) {
            newIntent.putExtra(Intent.EXTRA_REFERRER, mReferrerURI);
        }
        if (mOriginatingUid != PackageInstaller.SessionParams.UID_UNKNOWN) {
            newIntent.putExtra(Intent.EXTRA_ORIGINATING_UID, mOriginatingUid);
        }
        if (installerPackageName != null) {
            newIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME,
                    installerPackageName);
        }
        if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
            newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
            newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
        }
        if(localLOGV) Log.i(TAG, "downloaded app uri="+mPackageURI);
        startActivity(newIntent);
        finish();
    }
    
    • 5 之后启动InstallInstalling,因为Activity中的默认成员方法的执行顺序是onCreate->onStart->onResume...其中onCreate的方法中主要过程包括:
      • 1 获取待安装应用信息
      • 2 根据应用安装与否决定如何调用方法
      • 3 如果已存在,则直接调用PackageManager.installExistingPackage
      • 4 如果不存在则构造session
      • 5 之后则为安装事件广播添加一个监测
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        setContentView(R.layout.install_installing);
        // 获取待安装应用信息
        ApplicationInfo appInfo = getIntent()
                .getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);
        mPackageURI = getIntent().getData();
        // 如果应用已存在,则使用这条路径安装
        if ("package".equals(mPackageURI.getScheme())) {
            try {
                getPackageManager().installExistingPackage(appInfo.packageName);
                launchSuccess();
            } catch (PackageManager.NameNotFoundException e) {
                launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
            }
        } else { //否则使用session提交安装应用
            final File sourceFile = new File(mPackageURI.getPath());
            PackageUtil.initSnippetForNewApp(this, PackageUtil.getAppSnippet(this, appInfo,
                    sourceFile), R.id.app_snippet);
            // 如果session已存在,则获取sessionId等数据
            if (savedInstanceState != null) {
                mSessionId = savedInstanceState.getInt(SESSION_ID);
                mInstallId = savedInstanceState.getInt(INSTALL_ID);
    
                // Reregister for result; might instantly call back if result was delivered while
                // activity was destroyed
                try {
                    InstallEventReceiver.addObserver(this, mInstallId,
                            this::launchFinishBasedOnResult);
                } catch (EventResultPersister.OutOfIdsException e) {
                    // Does not happen
                }
            } else { // 否则创建session
                PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
                        PackageInstaller.SessionParams.MODE_FULL_INSTALL);
                // ......
                try {
                    mInstallId = InstallEventReceiver
                            .addObserver(this, EventResultPersister.GENERATE_NEW_ID,
                                    this::launchFinishBasedOnResult);
                } catch (EventResultPersister.OutOfIdsException e) {
                    launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
                }
                //创建session
                try {
                    mSessionId = getPackageManager().getPackageInstaller().createSession(params);
                } catch (IOException e) {
                    launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
                }
            }
            //......
            mSessionCallback = new InstallSessionCallback();
        }
    }
    
    • 6 InstallInstalling.onStart中注册回调函数,然后onResume中执行AsyncTask。
    @Override
    protected void onResume() {
        super.onResume();
    
        // This is the first onResume in a single life of the activity
        if (mInstallingTask == null) {
            PackageInstaller installer = getPackageManager().getPackageInstaller();
            PackageInstaller.SessionInfo sessionInfo = installer.getSessionInfo(mSessionId);
            //如果session非空,则执行AsyncTask
            if (sessionInfo != null && !sessionInfo.isActive()) {
                mInstallingTask = new InstallingAsyncTask();
                mInstallingTask.execute();
            } else {
                // we will receive a broadcast when the install is finished
                mCancelButton.setEnabled(false);
                setFinishOnTouchOutside(false);
            }
        }
    }
    
    • 7 AsyncTask是Android提供的一种轻量级的异步类,执行过程可以表示为5个阶段。
      • 1 准备执行,onPreExecute()
      • 2 正在后台执行,doInBackgroud()
      • 3 进度更新,onProcessUpdate()
      • 4 完成后台任务,onPostExecute()
      • 5 取消任务,onCacelled()

    此处重写了方法onPostExecute方法,源码如下。

    @Override
    protected void onPostExecute(PackageInstaller.Session session) {
        if (session != null) {
            Intent broadcastIntent = new Intent(BROADCAST_ACTION);
            broadcastIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
            broadcastIntent.setPackage(
                    getPackageManager().getPermissionControllerPackageName());
            broadcastIntent.putExtra(EventResultPersister.EXTRA_ID, mInstallId);
    
            PendingIntent pendingIntent = PendingIntent.getBroadcast(
                    InstallInstalling.this,
                    mInstallId,
                    broadcastIntent,
                    PendingIntent.FLAG_UPDATE_CURRENT);
            //提交session
            session.commit(pendingIntent.getIntentSender());
            mCancelButton.setEnabled(false);
            setFinishOnTouchOutside(false);
        } else {
            getPackageManager().getPackageInstaller().abandonSession(mSessionId);
    
            if (!isCancelled()) {
                launchFailure(PackageManager.INSTALL_FAILED_INVALID_APK, null);
            }
        }
    }
    
    • 8 session对象传输顺序为:
      • 1 PackageInstaller.Session.commit
      • 2 IPackageInstallerSession.commit
      • 3 PackageInstallerSession.commit
      • 4 Handler.Callback.handleMessage
      • 5 PackageInstallerSession.commitLock
      • 6 PMS.installStage
        这里是不是似曾相识,这一步跟Adb安装的第4步几乎相同,之后就调用installStage方法完成安装。

    #3 总结

    安装应用的场景就是上述所示的PMS构造函数安装、adb安装、网络下载安装、本地安装。其最终的入口为PMS.prepareAppDataLeafLIF,然后调用Installer类完成安装,这里涉及到System_server到Installd守护进程的转移。

  • 相关阅读:
    Java实现 蓝桥杯VIP 算法提高 交换Easy
    Java实现 蓝桥杯VIP 算法提高 多项式输出
    Java实现 蓝桥杯VIP 算法提高 多项式输出
    Java实现 蓝桥杯VIP 算法提高 多项式输出
    Java实现 蓝桥杯VIP 算法提高 多项式输出
    Java实现 蓝桥杯VIP 算法提高 多项式输出
    Java实现 蓝桥杯VIP 算法训练 矩阵乘方
    QT中给各控件增加背景图片(可缩放可旋转)的几种方法
    回调函数实现类似QT中信号机制
    std::string的Copy-on-Write:不如想象中美好(VC不使用这种方式,而使用对小字符串更友好的SSO实现)
  • 原文地址:https://www.cnblogs.com/z1987/p/8974719.html
Copyright © 2011-2022 走看看