深入理解Android Framework(四)- Framework重要服务之PackageManagerService(一) PMS启动流程

681 阅读5分钟

PackageManagerServices(程序包管理服务)是安卓系统核心服务之一,简称PMS,在安卓系统中负责管理应用,常见的比如安装、卸载应用等,本章将结合安卓11源码梳理PMS相关流程。

1、启动PMS服务

PMS作为系统核心服务之一,其启动流程位于frameworks/base/services/java/com/android/server/SystemServer.java,相关代码如下:

// 在startBootstrapServices下启动PMS
private void startBootstrapServices(@NonNull TimingsTraceAndSlog t) {
    // 启动installer,该服务会创建具有适当权限的关键目录,如/data/user
    // installer服务必须在其他服务启动之前启动
    t.traceBegin("StartInstaller");
    Installer installer = mSystemServiceManager.startService(Installer.class);
    t.traceEnd();
    ...
    // 启动PMS
    t.traceBegin("StartPackageManagerService");
    try {
        Watchdog.getInstance().pauseWatchingCurrentThread("packagemanagermain");
        mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
        domainVerificationService, mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);

    } finally {
        Watchdog.getInstance().resumeWatchingCurrentThread("packagemanagermain");
    }
}
// 在startOtherServices下确保PMS启动完成
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
    t.traceBegin("MakePackageManagerServiceReady");
    mPackageManagerService.systemReady();
    t.traceEnd();
}

2、PMS启动流程

PMS在SystemServer.java中被启动后,会前往 frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java中继续其启动流程,PMS的Main函数如下:

public static PackageManagerService main(Context context, Installer installer,@NonNull DomainVerificationService domainVerificationService, boolean factoryTest,boolean onlyCore) {
    // 检查初始化配置
    PackageManagerServiceCompilerMapping.checkProperties();
    ...
    Injector injector = new Injector(
    context, lock, installer, installLock, new PackageAbiHelperImpl(),
    backgroundHandler,
    SYSTEM_PARTITIONS,
    (i, pm) -> new ComponentResolver(i.getUserManagerService(), pm.mPmInternal, lock),
    (i, pm) -> PermissionManagerService.create(context,i.getSystemConfig().getAvailableFeatures()),
    // 创建多用户管理服务
    (i, pm) -> new UserManagerService(context, pm,
            new UserDataPreparer(installer, installLock, context, onlyCore),
            lock),
    // 初始化Settings对象
    (i, pm) -> new Settings(Environment.getDataDirectory(),
            RuntimePermissionsPersistence.createInstance(),
            i.getPermissionManagerServiceInternal(),
            domainVerificationService, lock),
    (i, pm) -> AppsFilter.create(pm.mPmInternal, i),
    (i, pm) -> (PlatformCompat) ServiceManager.getService("platform_compat"),
    (i, pm) -> SystemConfig.getInstance(),
    (i, pm) -> new PackageDexOptimizer(i.getInstaller(), i.getInstallLock(),
            i.getContext(), "*dexopt*"),
    (i, pm) -> new DexManager(i.getContext(), pm, i.getPackageDexOptimizer(),
            i.getInstaller(), i.getInstallLock()),
    (i, pm) -> new ArtManagerService(i.getContext(), pm, i.getInstaller(),
            i.getInstallLock()),
    (i, pm) -> ApexManager.getInstance(),
    (i, pm) -> new ViewCompiler(i.getInstallLock(), i.getInstaller()),
     ...
}

PMS的构造方法代码较多,可以分为5个阶段:

2.1、 PMS_START阶段

public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest,final String buildFingerprint, final boolean isEngBuild,final boolean isUserDebugBuild, final int sdkVersion, final String incrementalVersion) {
    ...
    // 打印启动日志
    EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START, SystemClock.uptimeMillis());
    ...
    // 创建Settings对象
    mSettings = injector.getSettings();
    ...
    // 调用addSharedUserLPw函数添加共享ID
    t.traceBegin("addSharedUsers");
    mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
        ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
        ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
        ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,
        ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,
        ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
        ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    mSettings.addSharedUserLPw("android.uid.se", SE_UID,
        ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    mSettings.addSharedUserLPw("android.uid.networkstack", NETWORKSTACK_UID,
        ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    mSettings.addSharedUserLPw("android.uid.uwb", UWB_UID,
        ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    t.traceEnd();
  }

总体来说,PMS_START阶段可以分为以下几个部分

  • 获取Settings类,这个类在Android中是在PMS的Main函数下初始化的,Settings的具体构造函数如下:
Settings(File dataDir, RuntimePermissionsPersistence runtimePermissionsPersistence,
        LegacyPermissionDataProvider permissionDataProvider,
        @NonNull DomainVerificationManagerInternal domainVerificationManager,
        @NonNull PackageManagerTracedLock lock)  {
        ...
        // 创建/data/system文件夹
        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");
        mDomainVerificationManager = domainVerificationManager;
        registerObservers();
        mSnapshot = makeCache();     
}

/data/system目录下存在以下5个文件:

文件功能
packages.xml记录所有安装app的信息
packages-backup.xml备份文件
packages-stopped.xml记录系统被强制停止的文件
packages-stopped-backup.xml备份文件
packages.list记录应用的数据信息
  • 向Settings中添加信息
  • 获取系统配置信息,包括全局属性、groupid以及系统权限。将一些类进行绑定,包括:PackageDexOptimizer (dex优化工具类) 、 DexManager(dex管理类)、PackageHandler(建立package相关操作的消息循环)等
  • 创建data下的各种目录

2.2、 PMS_SYSTEM_SCAN_START阶段

public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest,final String buildFingerprint, final boolean isEngBuild,final boolean isUserDebugBuild, final int sdkVersion, final String incrementalVersion) {
        ...
    // 打印启动日志
    EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START, startTime);
    // 读取环境变量BOOTCLASSPATH,用于之后的类加载和优化
    final String bootClassPath = System.getenv("BOOTCLASSPATH");
    final String systemServerClassPath = System.getenv("SYSTEMSERVERCLASSPATH");
    ...
    // 在system/下创建framework目录
    File frameworkDir = new File(Environment.getRootDirectory(), "framework");
    ...
    // 在扫描APK之前准备APEX包信息
    mApexManager.scanApexPackagesTraced(packageParser, executorService);
    // 在vendor/product/system_ext分区的收集包名
    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);
    }

可以看出,这里的主要工作是对系统区进行扫描,扫描顺序是OverlayFolder -> frameworkDir -> PrivAppFolder -> AppFolder(), 这里主要操作如下:

  1. 扫描各个系统分区的的App
  2. 解析系统App信息
  3. 把解析结果存储起来,存储在PMS的相关属性和mSettings里

2.3、 PMS_DATA_SCAN_START阶段

这里就是对/data/app进行了扫描,主要工作与扫描系统App目录是一样的,只是细节处理上有些不同。除此之外还做了一些收尾工作。

/*
     * Make sure all system apps that we expected to appear on
     * the userdata partition actually showed up. If they never
     * appeared, crawl back and revive the system version.
     */
    for (int i = 0; i < mExpectingBetter.size(); i++) {
        final String packageName = mExpectingBetter.keyAt(i);
        if (!mPackages.containsKey(packageName)) {
            final File scanFile = mExpectingBetter.valueAt(i);

            logCriticalInfo(Log.WARN, "Expected better " + packageName
                    + " but never showed up; reverting to system");

            @ParseFlags int reparseFlags = 0;
            @ScanFlags int rescanFlags = 0;
            for (int i1 = mDirsToScanAsSystem.size() - 1; i1 >= 0; i1--) {
                final ScanPartition partition = mDirsToScanAsSystem.get(i1);
                if (partition.containsPrivApp(scanFile)) {
                    reparseFlags = systemParseFlags;
                    rescanFlags = systemScanFlags | SCAN_AS_PRIVILEGED
                            | partition.scanFlag;
                    break;
                }
                if (partition.containsApp(scanFile)) {
                    reparseFlags = systemParseFlags;
                    rescanFlags = systemScanFlags | partition.scanFlag;
                    break;
                }
            }
            if (rescanFlags == 0) {
                Slog.e(TAG, "Ignoring unexpected fallback path " + scanFile);
                continue;
            }
            ```
            // 将packageName对应的包设置数据(PackageSetting)添加到mSettings的mPackages中
            mSettings.enableSystemPackageLPw(packageName);

            try {
                ```
                // 扫描系统App的升级包
                scanPackageTracedLI(scanFile, reparseFlags, rescanFlags, 0, null);
            } catch (PackageManagerException e) {
                Slog.e(TAG, "Failed to parse original system package: "
                        + e.getMessage());
            }
        }
    }

2.4、 PMS_SCAN_END阶段

这里主要做了如下几件事情:

1.如果SDK版本发生了变化(升级系统),重新对App进行授权

2.为系统核心服务准备存储空间

3.如果是升级后第一次正常启动,需要清除代码缓存,但不是会清除应用的配置文件

4.把更新后的信息写回对应的xml文件中

// 打印相关日志

EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,SystemClock.uptimeMillis());
Slog.i(TAG, "Time to scan packages: "+ ((SystemClock.uptimeMillis()-startTime)/1000f)+ " seconds");
// 如果SDK版本发生了变化(升级系统),重新对App进行授权
final boolean sdkUpdated = (ver.sdkVersion != mSdkVersion);
if (sdkUpdated) {
    Slog.i(TAG, "Platform changed from " + ver.sdkVersion + " to "
            + mSdkVersion + "; regranting permissions for internal storage");
}
mPermissionManager.updateAllPermissions(
        StorageManager.UUID_PRIVATE_INTERNAL, sdkUpdated);
ver.sdkVersion = mSdkVersion;
// 如果是首次启动或者从6.0以前的系统升级,初始化用户首选App
if (!mOnlyCore && (mPromoteSystemApps || mFirstBoot)) {
    for (UserInfo user : mInjector.getUserManagerInternal().getUsers(true)) {
        mSettings.applyDefaultPreferredAppsLPw(user.id);
        primeDomainVerificationsLPw(user.id);
    }
}

2.5、 PMS_READY阶段

这里又对一些属性进行了赋值。

// Initialize InstantAppRegistry's Instant App list for all users.
    final int[] userIds = UserManagerService.getInstance().getUserIds();
    for (AndroidPackage pkg : mPackages.values()) {
        if (pkg.isSystem()) {
            continue;
        }
        for (int userId : userIds) {
            final PackageSetting ps = getPackageSetting(pkg.getPackageName());
            if (ps == null || !ps.getInstantApp(userId) || !ps.getInstalled(userId)) {
                continue;
            }
            mInstantAppRegistry.addInstantAppLPw(userId, ps.appId);
        }
    }

    // Prepare a supplier of package parser for the staging manager to parse apex file
    // during the staging installation.
    final Supplier<PackageParser2> apexParserSupplier = () -> new PackageParser2(
            mSeparateProcesses, mOnlyCore, mMetrics, null /* cacheDir */,
            mPackageParserCallback);
    mInstallerService = new PackageInstallerService(mContext, this, apexParserSupplier);
    final Pair<ComponentName, String> instantAppResolverComponent =
            getInstantAppResolverLPr();
    if (instantAppResolverComponent != null) {
        if (DEBUG_INSTANT) {
            Slog.d(TAG, "Set ephemeral resolver: " + instantAppResolverComponent);
        }
        mInstantAppResolverConnection = new InstantAppResolverConnection(
                mContext, instantAppResolverComponent.first,
                instantAppResolverComponent.second);
        mInstantAppResolverSettingsComponent =
                getInstantAppResolverSettingsLPr(instantAppResolverComponent.first);
    } else {
        mInstantAppResolverConnection = null;
        mInstantAppResolverSettingsComponent = null;
    }
    updateInstantAppInstallerLocked(null);

    // 读取并更新dex文件的使用情况
    final Map<Integer, List<PackageInfo>> userPackages = new HashMap<>();
    for (int userId : userIds) {
        userPackages.put(userId, getInstalledPackages(/*flags*/ 0, userId).getList());
    }
    mDexManager.load(userPackages);
    if (mIsUpgrade) {
        FrameworkStatsLog.write(
                FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
                BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_INIT_TIME,
                SystemClock.uptimeMillis() - startTime);
    }
} // synchronized (mLock)
} // synchronized (mInstallLock)
// CHECKSTYLE:ON IndentationCheck

mModuleInfoProvider = new ModuleInfoProvider(mContext, this);

// Uncork cache invalidations and allow clients to cache package information.
PackageManager.uncorkPackageInfoCache();

t.traceBegin("GC");
Runtime.getRuntime().gc();
t.traceEnd();
mInstaller.setWarnIfHeld(mLock);

PackageParser.readConfigUseRoundIcon(mContext.getResources());

mServiceStartWithDelay = SystemClock.uptimeMillis() + (60 * 1000L);

以上就是对PMS的启动总体流程做了大致的梳理,其中一些值得关注的细节将在之后的文章中逐一介绍和分析。