Android PMS相关流程

 

本文基于Android9.0

主要从以下几个方面着手:

  1. PMS启动
  2. PMS关键几个成员变量
  3. PMS安装APK
  4. PMS卸载APK

PMS启动

这里我简单的将其分为以下几个步骤:

  • SystemServer通过PMS的main方法启动PMS
  • PMS构造方法中初始化Settings
  • 扫描各个系统目录下APP相关信息
  • SystemServer通过PMS的main方法启动PMS

PMS启动是在SystemServer中,startBootsTrapService方法中

mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
                mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);

这里会转到PMS的main方法:

public static PackageManagerService main(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) {
        // Self-check for initial settings.
        PackageManagerServiceCompilerMapping.checkProperties();

        //PMS构造方法
        PackageManagerService m = new PackageManagerService(context, installer,
                factoryTest, onlyCore);
        m.enableSystemUserPackages();
        ServiceManager.addService("package", m);
        final PackageManagerNative pmn = m.new PackageManagerNative();
        ServiceManager.addService("package_native", pmn);
        return m;
}
  • PMS构造方法中初始化Settings

PMS构造方法:

public PackageManagerService(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) {
    ......
    //Settings的初始化
    mSettings = new Settings(mPermissionManager.getPermissionSettings(), mPackages);
    ......
}

mSettings是全局的,它主要协助PMS保存系统中安装APP包名,权限,四大组件等相关信息的存储,Settings会在/data/system目录下创建相关的文件来保存这些APP相关的信息。

Settings构造函数:

/base/services/core/java/com/android/server/pm/Settings.java
Settings(PermissionSettings permissions, Object lock) {
        this(Environment.getDataDirectory(), permissions, lock);
}

Settings(File dataDir, PermissionSettings permission, Object lock) {
        mLock = lock;
        mPermissions = permission;
        mRuntimePermissionsPersistence = new RuntimePermissionPersistence(mLock);

        mSystemDir = new File(dataDir, "system");
        mSystemDir.mkdirs();
        FileUtils.setPermissions(mSystemDir.toString(),
                FileUtils.S_IRWXU|FileUtils.S_IRWXG
                |FileUtils.S_IROTH|FileUtils.S_IXOTH,
                -1, -1);
        mSettingsFilename = new File(mSystemDir, "packages.xml");
        mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
        mPackageListFilename = new File(mSystemDir, "packages.list");
        FileUtils.setPermissions(mPackageListFilename, 0640, SYSTEM_UID, PACKAGE_INFO_GID);

        final File kernelDir = new File("/config/sdcardfs");
        mKernelMappingFilename = kernelDir.exists() ? kernelDir : null;

        // Deprecated: Needed for migration
        mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");
        mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
}

各个文件的具体内容不做详细的展开。

  • 扫描各个系统目录下APP相关信息
public PackageManagerService(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) {
    ......
    scanDirTracedLI(new File(VENDOR_OVERLAY_DIR),
                    mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM_DIR,
                    scanFlags
                    | SCAN_AS_SYSTEM
                    | SCAN_AS_VENDOR,
                    0);
            scanDirTracedLI(new File(PRODUCT_OVERLAY_DIR),
                    mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM_DIR,
                    scanFlags
                    | SCAN_AS_SYSTEM
                    | SCAN_AS_PRODUCT,
                    0);

            /// M: Support RSC overlay dir
            sPmsExt.scanDirLI(PmsExt.INDEX_RSC_OVERLAY, mDefParseFlags, scanFlags, 0);
            mParallelPackageParserCallback.findStaticOverlayPackages();

            // Find base frameworks (resource packages without code).
            scanDirTracedLI(frameworkDir,
                    mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM_DIR,
                    scanFlags
                    | SCAN_NO_DEX
                    | SCAN_AS_SYSTEM
                    | SCAN_AS_PRIVILEGED,
                    0);
    ......
}

从Android 9,0的代码来看,扫描路径的顺序为:

  1. /vendor/overlay
  2. /product/overlay
  3. /system/framework
  4. /system/priv-app
  5. /system/app
  6. /vendor/priv-app
  7. /vendor/app
  8. /odm/priv-app
  9. /odm/app
  10. /oem/priv-app
  11. /oem/app
  12. /product/priv-app
  13. /product/app
  14. /data/app
  15. /data/private-app

到这里PMS启动的大致流程就结束了。

PMS中主要成员变量

四大组件:

// All available activities, for your resolving pleasure.
    final ActivityIntentResolver mActivities =
            new ActivityIntentResolver();

    // All available receivers, for your resolving pleasure.
    final ActivityIntentResolver mReceivers =
            new ActivityIntentResolver();

    // All available services, for your resolving pleasure.
    final ServiceIntentResolver mServices = new ServiceIntentResolver();

    // All available providers, for your resolving pleasure.
    final ProviderIntentResolver mProviders = new ProviderIntentResolver();

 以上四个变量,分别用于存储APP中的所有四大组件相关信息。

    // Keys are String (package name), values are Package.  This also serves
    // as the lock for the global state.  Methods that must be called with
    // this lock held have the prefix "LP".
    @GuardedBy("mPackages")
    final ArrayMap mPackages =
            new ArrayMap();

 mPackages用于存储系统中安装的所有APP的包相关信息。


    @GuardedBy("mPackages")
    final Settings mSettings;

mSettings前面已经讲过,是辅助PMS管理包相关信息的。

Settings的构造函数已经看过了,功能也已经明了,那么 接下来看看其他几个成员都是在哪儿填充数据的。

mPackages:

方法调用的顺序是:

scanDirTracedLI--》scanDirLI--》scanPackageChildLI--》addForInitLI --》mPakcages.put

 

相关时序图:

Android PMS相关流程_第1张图片

到这里,扫描已经安装的APP信息的时候,就会把Package相关内容,存储到mPackages中。

四大组件:mActivites,mReceivers,mServices,mProviders

 

 方法调用基本流程:

scanDirTracedLI--》scanDirLI--》scanPackageChildLI--》addForInitLI --》scanPackageNewLI-->commitScanResultsLocked-->commitPackageSettings-->mProviders.addProvider(p); mServices.addService(s);mReceivers.addActivity(a, "receiver");mActivities.addActivity(a, "activity");

相关流程图,接上面mPackage路程图继续往后跟踪:

Android PMS相关流程_第2张图片

四大组件相关信息,在PMS启动的时候,扫描安装的APP时,就存储了相关的信息了。 

PMS扫描过程

扫描是在方法scanDirLi方法中:

private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime) {
        //列出当前扫描目录(system/framework、system/app、vendor/app等)下所有的文件
        final File[] files = scanDir.listFiles();
        .....
        //解析安装包,也就是APK文件,是通过ParallelPackageParser对象
        try (ParallelPackageParser parallelPackageParser = new ParallelPackageParser(
                mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir,
                mParallelPackageParserCallback)) {
            // Submit files for parsing in parallel
            int fileCount = 0;
            for (File file : files) {
                final boolean isPackage = (isApkFile(file) || file.isDirectory())
                        && !PackageInstallerService.isStageName(file.getName());
                //如果发现并非是APK文件,则直接跳过当前文件,只处理APK文件
                if (!isPackage) {
                    // Ignore entries which are not packages
                    continue;
                }
                //将每个APK文件的信息提交到阻塞队列(BlockingQueue)
                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.pkg.applicationInfo.isStaticSharedLibrary()) {
                        renameStaticSharedLibraryPackage(parseResult.pkg);
                    }
                    try {
                        if (errorCode == PackageManager.INSTALL_SUCCEEDED) {
                            //执行扫描的后续工作,转到PMS,处理PMS对象中的相关内容
                            scanPackageChildLI(parseResult.pkg, parseFlags, scanFlags,
                                    currentTime, null);
                        }
                    } catch (PackageManagerException e) {
                        errorCode = e.error;
                        Slog.w(TAG, "Failed to scan " + parseResult.scanFile + ": " + e.getMessage());
                    }

    ......
}

ParallelPackageParser的submit方法,其实就是通过PackageParser解析完APK文件之后,放入mQueue这个阻塞队列中:

//ParallelPackageParser.java
/**
     * Submits the file for parsing
     * @param scanFile file to scan
     * @param parseFlags parse falgs
     */
    public void submit(File scanFile, int parseFlags) {
        mService.submit(() -> {
            ParseResult pr = new ParseResult();
            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parallel parsePackage [" + scanFile + "]");
            try {
                PackageParser pp = new PackageParser();
                pp.setSeparateProcesses(mSeparateProcesses);
                pp.setOnlyCoreApps(mOnlyCore);
                pp.setDisplayMetrics(mMetrics);
                pp.setCacheDir(mCacheDir);
                pp.setCallback(mPackageParserCallback);
                pr.scanFile = scanFile;
                pr.pkg = parsePackage(pp, scanFile, parseFlags);
            } catch (Throwable e) {
                pr.throwable = e;
            } finally {
                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
            }
            try {
                mQueue.put(pr);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                // Propagate result to callers of take().
                // This is helpful to prevent main thread from getting stuck waiting on
                // ParallelPackageParser to finish in case of interruption
                mInterruptedInThread = Thread.currentThread().getName();
            }
        });
    }

 具体怎么解析APK文件,请继续跟踪,查看PackageParser.java的parsePakcage方法;扫描过程到这里就结束了。

 安装APK

安装APK流程比较简单,直接上流程图:

Android PMS相关流程_第3张图片

安装APK的整个流程, 基本都是在PMS中,安装时,会先进行拷贝,将安装文件拷贝到特定目录,然后从特定目录进行解析包名等信息进行安装,并不是从原本APK文件所在路径直接安装的,具体细节请参考上面流程图跟踪解析。

卸载APK

卸载APK是从deletePackageX开始的,具体就不做详细跟踪,情况跟安装APK类似,在卸载APK时,会将要卸载的APK中所保安的四大组件从mProviders,mServices,mReceivers,mActivities中删除,相关权限也会删除,packages.xml等文件也会作相应更新。

附上卸载时序图:

Android PMS相关流程_第4张图片

到这里PMS大致的总结就先到这儿。

 

你可能感兴趣的:(PMS)