android PKMS服务

前面我们介绍过Android AMS服务,今天我们看一下PKMS(PackageManagerService)服务,PKMS也是android系统中核心服务之一,负责应用程序的安装,卸载,信息查询等工作。

PKMS的启动

首先启动创建PKMS:

private void startBootstrapServices() { 
    ... 
    // code 1 启动Installer 
    // 我们需要在初始化其他服务之前完成此任务。 
    Installer installer = mSystemServiceManager.startService(Installer.class);
    ...
    mActivityManagerService.setInstaller(installer);
    
    ... 
    // code 2 获取设备是否加密(手机设置密码),如果加密了,则只解析"core"应用,mOnlyCore = true,后面会频繁使用该变量进行条件判断 (android 14已去除)
    String cryptState = VoldProperties.decrypt().orElse("");
    if (ENCRYPTING_STATE.equals(cryptState)) {
        Slog.w(TAG, "Detected encryption in progress - only parsing core apps");
        mOnlyCore = true;
    } else if (ENCRYPTED_STATE.equals(cryptState)) {
        Slog.w(TAG, "Device encrypted - only parsing core apps");
        mOnlyCore = true;
    }
    // code 3 调用main方法初始化PackageManagerService 
    mPackageManagerService = PackageManagerService.main(mSystemContext, installer, mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
    // PKMS是否是第一次启动
    mFirstBoot = mPackageManagerService.isFirstBoot(); 
    mPackageManager = mSystemContext.getPackageManager();
    // code 4 如果设备没有加密,执行OtaDexoptService.main。 
    if (!mOnlyCore) {
        boolean disableOtaDexopt = SystemProperties.getBoolean("config.disable_otadexopt", false); 
        OtaDexoptService.main(mSystemContext, mPackageManagerService); 
    }
    ... 
}


    
private void startOtherServices() {
    ...
    //检查system app是否需要更新,需要则更新
    mPackageManagerService.updatePackagesIfNeeded();
    ...

    //检查system app是否需要fs裁剪
    mPackageManagerService.performFstrimIfNeeded();
    ...

    //最后system Ready通知其他服务ready设置相关信息
    mPackageManagerService.systemReady();
    ...
}

在startBootstrpServices中,会做以下几件事情:

  1. 启动Installer服务
  2. 获取设备是否加密(手机设置密码),如果设备加密了,则只解析"core"应用(在android14中被删除)
  3. 调用PKMS main方法初始化PackageManagerService,其中调用PackageManagerService()构造函数创建了PKMS对象
  4. 如果设备没有加密,执行OtaDexoptService.main。

我们继续看PackageManagerService.main:

public static PackageManagerService main(Context context,
                                         Installer installer, @NonNull DomainVerificationService domainVerificationService,
                                         boolean factoryTest) {
    // code 1 检查Package编译相关系统属性
    PackageManagerServiceCompilerMapping.checkProperties();
    ...
    // code 2 调用PackageManagerService构造方法
    PackageManagerService m = new PackageManagerService(injector, factoryTest,
            PackagePartitions.FINGERPRINT, Build.IS_ENG, Build.IS_USERDEBUG,
            Build.VERSION.SDK_INT, Build.VERSION.INCREMENTAL);
    ...
    m.installAllowlistedSystemPackages();
    IPackageManagerImpl iPackageManager = m.new IPackageManagerImpl();
    // code 3 往ServiceManager中注册”package”和”package_native”
    ServiceManager.addService("package", iPackageManager);
    final PackageManagerNative pmn = new PackageManagerNative(m);
    ServiceManager.addService("package_native", pmn);
    return m;
}

在构造方法中会处理很多的逻辑:

初始化Settings

扫描各个系统目录下APP相关信息

public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest) {
    PackageManager.disableApplicationInfoCache();
    PackageManager.disablePackageInfoCache();
    ...
    //code 1 setting保存系统中安装APP包名,权限,四大组件等相关信息的存储
    mSettings = injector.getSettings();
    ...
    // CHECKSTYLE:OFF IndentationCheck
    synchronized (mInstallLock) {
        // writer
        synchronized (mLock) {
            ...
            // Collect vendor/product/system_ext overlay packages. (Do this before scanning
            // any apps.)
            // For security and version matching reason, only consider overlay packages if they
            // reside in the right directory.
            for (int i = mDirsToScanAsSystem.size() - 1; i >= 0; i--) {
                final ScanPartition partition = mDirsToScanAsSystem.get(i);
                if (partition.getOverlayFolder() == null) {
                    continue;
                }
                scanDirTracedLI(partition.getOverlayFolder(), systemParseFlags,
                        systemScanFlags | partition.scanFlag, 0,
                        packageParser, executorService);
            }

            scanDirTracedLI(frameworkDir, systemParseFlags,
                    systemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0,
                    packageParser, executorService);
            if (!mPackages.containsKey("android")) {
                throw new IllegalStateException(
                        "Failed to load frameworks package; check log for warnings");
            }
            for (int i = 0, size = mDirsToScanAsSystem.size(); i < size; i++) {
                final ScanPartition partition = mDirsToScanAsSystem.get(i);
                if (partition.getPrivAppFolder() != null) {
                    scanDirTracedLI(partition.getPrivAppFolder(), systemParseFlags,
                            systemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag, 0,
                            packageParser, executorService);
                }
                scanDirTracedLI(partition.getAppFolder(), systemParseFlags,
                        systemScanFlags | partition.scanFlag, 0,
                        packageParser, executorService);
            }
            ...
            if (!mOnlyCore) {
                EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
                        SystemClock.uptimeMillis());
                scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0,
                        packageParser, executorService);

            }
            packageParser.close();
            ...
        }
    }
}



继续执行scanDirTraceLI

private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags,
        long currentTime, PackageParser2 packageParser, ExecutorService executorService) {
    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
    try {
        scanDirLI(scanDir, parseFlags, scanFlags, currentTime, packageParser, executorService);
    } finally {
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }
}

继续执行scanDirLI

private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime,
                       PackageParser2 packageParser, ExecutorService executorService) {
    final File[] files = scanDir.listFiles();
    if (ArrayUtils.isEmpty(files)) {
        Log.d(TAG, "No files in app dir " + scanDir);
        return;
    }

    if (DEBUG_PACKAGE_SCANNING) {
        Log.d(TAG, "Scanning app dir " + scanDir + " scanFlags=" + scanFlags
                + " flags=0x" + Integer.toHexString(parseFlags));
    }

    ParallelPackageParser parallelPackageParser =
            new ParallelPackageParser(packageParser, executorService);

    // Submit files for parsing in parallel
    int fileCount = 0;
    for (File file : files) {
        final boolean isPackage = (isApkFile(file) || file.isDirectory())
                && !PackageInstallerService.isStageName(file.getName());
        if (!isPackage) {
            // Ignore entries which are not packages
            continue;
        }
        parallelPackageParser.submit(file, parseFlags);
        fileCount++;
    }

    // Process results one by one
    for (; fileCount > 0; fileCount--) {
        ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
        Throwable throwable = parseResult.throwable;
        int errorCode = PackageManager.INSTALL_SUCCEEDED;

        if (throwable == null) {
            // TODO(toddke): move lower in the scan chain
            // Static shared libraries have synthetic package names
            if (parseResult.parsedPackage.isStaticSharedLibrary()) {
                renameStaticSharedLibraryPackage(parseResult.parsedPackage);
            }
            try {
                addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags,
                        currentTime, null);
            } catch (PackageManagerException e) {
                errorCode = e.error;
                Slog.w(TAG, "Failed to scan " + parseResult.scanFile + ": " + e.getMessage());
            }
        } else if (throwable instanceof PackageParserException) {
            PackageParserException e = (PackageParserException)
                    throwable;
            errorCode = e.error;
            Slog.w(TAG, "Failed to parse " + parseResult.scanFile + ": " + e.getMessage());
        } else {
            throw new IllegalStateException("Unexpected exception occurred while parsing "
                    + parseResult.scanFile, throwable);
        }

        if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0 && errorCode != INSTALL_SUCCEEDED) {
            mApexManager.reportErrorWithApkInApex(scanDir.getAbsolutePath());
        }

        // Delete invalid userdata apps
        if ((scanFlags & SCAN_AS_SYSTEM) == 0
                && errorCode != PackageManager.INSTALL_SUCCEEDED) {
            logCriticalInfo(Log.WARN,
                    "Deleting invalid package at " + parseResult.scanFile);
            removeCodePathLI(parseResult.scanFile);
        }
    }
}

扫描路径的顺序

/vendor/overlay
/product/overlay
/product_services/overlay
/odm/overlay
/oem/overlay
/system/framework
/system/priv-app
/system/app
/vendor/priv-app
/vendor/app
/odm/priv-app
/odm/app
/oem/app
/product/priv-app
/product/app
/product_services/priv-app
/product_services/app

PKMS安装APK

Binder.execTransact->
Binder.execTransactInternal->
PackageManagerService.onTransact->
IPackageManager$Stub.onTransact->
Binder.onTransact->
Binder.shellCommand->
PackageManagerService.onShellCommand->
ShellCommand.exec->
PackageManagerShellCommand.onCommand->
PackageManagerShellCommand.runInstall->
PackageManagerShellCommand.doRunInstall->
PackageManagerShellCommand.doCommitSession->
PackageInstaller$Session.commit->
PackageInstallerSession.commit->
PackageInstallerSession.dispatchStreamValidateAndCommit->(mHandler.obtainMessage(MSG_STREAM_VALIDATE_AND_COMMIT))
PackageInstallerSession.handleStreamValidateAndCommit->mHandler.obtainMessage(MSG_INSTALL)
PackageInstallerSession.handleInstall->
PackageInstallerSession.installNonStagedLocked->
PackageManagerService.installStage->mHandler.obtainMessage(INIT_COPY)
PackageManagerService$HandlerParams.startCopy

我们通过上面的代码可以看到,最终会执行到PackageManagerService$HandlerParams.startCopy:

final void startCopy() {
    if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
    handleStartCopy();
    handleReturnCode();
}

继续执行handleReturnCode,最终会调用ParsingPackageUtils.parsePackage:

PackageManagerService$HandlerParams.startCopy->
PackageManagerService.handleReturnCode->
PackageManagerService.processPendingInstall->
PackageManagerService.processInstallRequestsAsync->
PackageManagerService.installPackagesTracedLI->
PackageManagerService.installPackagesLI->
PackageManagerService.scanPackageTracedLI->
PackageManagerService.scanPackageLI->
PackageParser2.parsePackage->
ParsingPackageUtils.parsePackage

我们看一下parsePackage的逻辑: 

​
public ParseResult<ParsingPackage> parsePackage(ParseInput input, File packageFile,
                                                int flags)
        throws PackageParserException {
    if (packageFile.isDirectory()) {
        return parseClusterPackage(input, packageFile, flags);
    } else {
        return parseMonolithicPackage(input, packageFile, flags);
    }
}

​

上面代码中,如果参数是packageFile 是一个目录,就会执行parseClusterPackage(),否则执行 parseMonolithicPackage() 来处理。对于关联的多个apk 会放到一个目录下,来查看parseClusterPackage():

private ParseResult<ParsingPackage> parseClusterPackage(ParseInput input, File packageDir,
                                                        int flags) {
    //获取应用目录的PackageLite 对象,这个对象中分开保存了目录下的核心应用名称以及其他非核心应用的名称
    ParseResult<PackageParser.PackageLite> liteResult =
            ApkLiteParseUtils.parseClusterPackageLite(input, packageDir, 0);
    if (liteResult.isError()) {
        return input.error(liteResult);
    }

    final PackageParser.PackageLite lite = liteResult.getResult();
    if (mOnlyCoreApps && !lite.coreApp) {
        return input.error(INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED,
                "Not a coreApp: " + packageDir);
    }

    // Build the split dependency tree.
    SparseArray<int[]> splitDependencies = null;
    final SplitAssetLoader assetLoader;
    if (lite.isolatedSplits && !ArrayUtils.isEmpty(lite.splitNames)) {
        try {
            splitDependencies =
                    SplitAssetDependencyLoader.createDependenciesFromPackage(lite);
            assetLoader = new SplitAssetDependencyLoader(lite, splitDependencies, flags);
        } catch (SplitAssetDependencyLoader.IllegalDependencyException e) {
            return input.error(INSTALL_PARSE_FAILED_BAD_MANIFEST, e.getMessage());
        }
    } else {
        assetLoader = new DefaultSplitAssetLoader(lite, flags);
    }
    try {
        //需要AssetManager 对象
        final AssetManager assets = assetLoader.getBaseAssetManager();
        final File baseApk = new File(lite.baseCodePath);
        ParseResult<ParsingPackage> result = parseBaseApk(input, baseApk,
                lite.codePath, assets, flags);
        if (result.isError()) {
            return input.error(result);
        }
        //对于apk 进行分析,得到Package 对象
        ParsingPackage pkg = result.getResult();
        if (!ArrayUtils.isEmpty(lite.splitNames)) {
            pkg.asSplit(
                    lite.splitNames,
                    lite.splitCodePaths,
                    lite.splitRevisionCodes,
                    splitDependencies
            );
            final int num = lite.splitNames.length;
            for (int i = 0; i < num; i++) {
                final AssetManager splitAssets = assetLoader.getSplitAssetManager(i);
                parseSplitApk(input, pkg, i, splitAssets, flags);
            }
        }
        
        pkg.setUse32BitAbi(lite.use32bitAbi);
        return input.success(pkg);
    } catch (PackageParserException e) {
        return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
                "Failed to load assets: " + lite.baseCodePath, e);
    } finally {
        IoUtils.closeQuietly(assetLoader);
    }
}

parseClusterPackage() 方法中先执行parseClusterPackageLite() 方法对目录下的apk 文件进行初步分析,主要是区分出核心应用和非核心应用。核心应用只有一个,非核心应用可以没有或者多个,非核心应用的作用是用来保存资源和代码。

接下来调用parseBaseApk() 方法对核心应用进行分析,并生成Package 对象,对非核心的应用调用 parseSpliteApk() 方法来分析,分析的结果会放到前面的 Package 对象中。 parseBaseApk() 方法实际上是主要是分析AndroidManifest.xml 文件:

private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, File apkFile,
                                                 String codePath, AssetManager assets, int flags) {
    final String apkPath = apkFile.getAbsolutePath();
    ...
    final int cookie = assets.findCookieForPath(apkPath);
    ...
    try (XmlResourceParser parser = assets.openXmlResourceParser(cookie,
            PackageParser.ANDROID_MANIFEST_FILENAME)) { // code 1
        final Resources res = new Resources(assets, mDisplayMetrics, null);
    
        ParseResult<ParsingPackage> result = parseBaseApk(input, apkPath, codePath, res,
                parser, flags);
        ...
        final ParsingPackage pkg = result.getResult();
        ...
        pkg.setVolumeUuid(volumeUuid);
        ...
        return input.success(pkg);
    } catch(Exception e){
        return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
        "Failed to read manifest from "+apkPath,e);
    }
}

在code1处主要分析XmlResourceParser对象,也就是获得一个 XML 资源解析对象,该对象解析的是 APK 中的 AndroidManifest.xml 文件

parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);

查看PackageParser文件可知,这个地方的ANDROID_MANIFEST_FILENAME 为

 public static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";

继续执行parseBaseApk:

ParsingPackageUtils.parsePackage->
ParsingPackageUtils.parseClusterPackage->
ParsingPackageUtils.parseBaseApk->
ParsingPackageUtils.parseBaseApk->
ParsingPackageUtils.parseBaseApkTags->
ParsingPackageUtils.parseBaseApplication->
ParsedActivityUtils.parseActivityOrReceiver

最终会执行到ParsingPackageUtils.parseBaseApplication:

private ParseResult<ParsingPackage> parseBaseApplication(ParseInput input,
                                                         ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags)
        throws XmlPullParserException, IOException {
    ...
    switch (tagName) {
        case "activity":
            isActivity = true;
            // fall-through
        case "receiver":
            ParseResult<ParsedActivity> activityResult =
                    ParsedActivityUtils.parseActivityOrReceiver(mSeparateProcesses, pkg,
                            res, parser, flags, PackageParser.sUseRoundIcon, input);

            if (activityResult.isSuccess()) {
                ParsedActivity activity = activityResult.getResult();
                if (isActivity) {
                    hasActivityOrder |= (activity.getOrder() != 0);
                    pkg.addActivity(activity);
                } else {
                    hasReceiverOrder |= (activity.getOrder() != 0);
                    pkg.addReceiver(activity);
                }
            }

            result = activityResult;
            break;
        case "service":
            ParseResult<ParsedService> serviceResult =
                    ParsedServiceUtils.parseService(mSeparateProcesses, pkg, res, parser,
                            flags, PackageParser.sUseRoundIcon, input);
            if (serviceResult.isSuccess()) {
                ParsedService service = serviceResult.getResult();
                hasServiceOrder |= (service.getOrder() != 0);
                pkg.addService(service);
            }

            result = serviceResult;
            break;
        case "provider":
            ParseResult<ParsedProvider> providerResult =
                    ParsedProviderUtils.parseProvider(mSeparateProcesses, pkg, res, parser,
                            flags, PackageParser.sUseRoundIcon, input);
            if (providerResult.isSuccess()) {
                pkg.addProvider(providerResult.getResult());
            }

            result = providerResult;
            break;
        case "activity-alias":
            activityResult = ParsedActivityUtils.parseActivityAlias(pkg, res,
                    parser, PackageParser.sUseRoundIcon, input);
            if (activityResult.isSuccess()) {
                ParsedActivity activity = activityResult.getResult();
                hasActivityOrder |= (activity.getOrder() != 0);
                pkg.addActivity(activity);
            }

            result = activityResult;
            break;
        default:
            result = parseBaseAppChildTag(input, tagName, pkg, res, parser, flags);
            break;
    }
    ...
}

 在这个地方就完成了activity,service,receiver等四大组件的注册。

总结

  • 清单文件的解析过程,一般是由PKMS来完成,触发PKMS的执行的分为两个部分:
    1. 在系统启动的过程中,会启动 SystemServer 进程,而SystemServer进程会启动各种服务,这些服务包括PKMS,在启动PKMS的时候就会扫码apk 安装路径下面的apk,然后解析AndroidManifest文件,并做持久化存储;
    2. app 安装的过程中,也会触发PKMS对 apk进行检测,调用类似的流程解析 AndroidManifest文件。Receiver的解析,都只是整个AndroidManifest解析过 程中的一个环节。
  • android系统启动之后会解析系统特定目录下的apk文件,并执行解析;
  • 解析Manifest流程:Zygote进程 –> SystemServer进程 –> PackgeManagerService服务 –>  scanPackageLI方法 –> PackageParser2.parserPackage方法;
  • 解析完成Manifest之后会将apk的Manifest信息保存在Settings对象中并持久化,删除软件时,信息会被删除,新安装的apk会重复调用scanPackageLI。
  • 21
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值