概述

PackageManagerService,是Android系统中核心服务之一,管理着所有跟package相关的工作,常见的比如安装、卸载应用。 PKMS服务也是通过binder进行通信,IPackageManager.aidl由工具转换后自动生成binder的服务端IPackageManager.Stub和客户端IPackageManager.Stub.Proxy,具体关系如下:

Binder服务端:PackageManagerService继承于IPackageManager.Stub;
Binder客户端:ApplicationPackageManager(简称APM)的成员变量mPM继承于IPackageManager.Stub.Proxy; 本身APM是继承于PackageManager对象。

Android系统启动过程中,一路启动到SystemServer后,便可以启动framework的各大服务,本篇博客将介绍PKMS的启动过程(基于安卓7.0源码)。

PackageManagerService的启动

SystemServer启动过程中涉及到的PKMS代码如下:

private void startBootstrapServices() {//启动installer服务Installer installer = mSystemServiceManager.startService(Installer.class);...//处于加密状态则仅仅解析核心应用String cryptState = SystemProperties.get("vold.decrypt");if (ENCRYPTING_STATE.equals(cryptState)) {mOnlyCore = true; // ENCRYPTING_STATE = "trigger_restart_min_framework"} else if (ENCRYPTED_STATE.equals(cryptState)) {mOnlyCore = true; // ENCRYPTED_STATE = "1"}//创建PKMS对象mPackageManagerService = PackageManagerService.main(mSystemContext, installer,mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);//PKMS是否首次启动mFirstBoot = mPackageManagerService.isFirstBoot();mPackageManager = mSystemContext.getPackageManager();...
}

PackageManagerService与其他所有的服务一样,也是由SystemServer启动,它也是java层服务之一,PKMS.main()过程主要是创建PKMS服务,并注册到ServiceManager。

整个system_server进程启动过程,涉及PKMS服务的主要几个动作如下,接下来分别讲解每个过程
PKMS.main()
PKMS.performBootDexOpt
PKMS.systemReady

PKMS.main()

public static PackageManagerService main(Context context, Installer installer,boolean factoryTest, boolean onlyCore) {// Self-check for initial settings.PackageManagerServiceCompilerMapping.checkProperties();//构造一个包管理服务对象PackageManagerService m = new PackageManagerService(context, installer,factoryTest, onlyCore);m.enableSystemUserPackages();// Disable any carrier apps. We do this very early in boot to prevent the apps from being// disabled after already being started.CarrierAppUtils.disableCarrierAppsUntilPrivileged(context.getOpPackageName(), m,UserHandle.USER_SYSTEM);//将包管理服务对象添加到ServiceManagerServiceManager.addService("package", m);return m;
}

该方法的主要功能创建PKMS对象,并将其注册到ServiceManager。 关于PKMS对象的构造方法很长,分为以下几个阶段,每个阶段会输出相应的EventLog: 除了阶段1的开头部分代码,后续代码都是同时持有同步锁mPackages和mInstallLock的过程中执行的。

阶段1:BOOT_PROGRESS_PMS_START
阶段2:BOOT_PROGRESS_PMS_SYSTEM_SCAN_START
阶段3:BOOT_PROGRESS_PMS_DATA_SCAN_START
阶段4:BOOT_PROGRESS_PMS_SCAN_END
阶段5:BOOT_PROGRESS_PMS_READY

阶段1:BOOT_PROGRESS_PMS_START

阶段1 PMS_START有两部分组成,由无需加锁的前部分和同时持有两个锁的后半部分,先来说说前半部分:
前半部分

//向事件日志写入事件,标识PackageManagerService启动
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,SystemClock.uptimeMillis());
//SDK版本检查
if (mSdkVersion <= 0) {Slog.w(TAG, "**** ro.build.version.sdk not set!");
}mContext = context;
//开机模式是否为工厂模式
mFactoryTest = factoryTest;
//是否仅启动内核
mOnlyCore = onlyCore;
//构造DisplayMetrics对象以便获取尺寸数据
mMetrics = new DisplayMetrics();
//构造Settings对象存储运行时的设置信息
mSettings = new Settings(mPackages);
//添加一些用户uid
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);
//判断是否在不同的进程
String separateProcesses = SystemProperties.get("debug.separate_processes");
if (separateProcesses != null && separateProcesses.length() > 0) {if ("*".equals(separateProcesses)) {mDefParseFlags = PackageParser.PARSE_IGNORE_PROCESSES;mSeparateProcesses = null;Slog.w(TAG, "Running with debug.separate_processes: * (ALL)");} else {mDefParseFlags = 0;mSeparateProcesses = separateProcesses.split(",");Slog.w(TAG, "Running with debug.separate_processes: "+ separateProcesses);}
} else {mDefParseFlags = 0;mSeparateProcesses = null;
}
//installer由SystemServer构造,这里通过该对象与底层进行通信,进行具体安装与卸载的操作
mInstaller = installer;
//创建PackageDexOptimizer,该类用于辅助进行dex优化
mPackageDexOptimizer = new PackageDexOptimizer(installer, mInstallLock, context,"*dexopt*");
mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());mOnPermissionChangeListeners = new OnPermissionChangeListeners(FgThread.get().getLooper());getDefaultDisplayMetrics(context, mMetrics);
//获取系统配置信息
SystemConfig systemConfig = SystemConfig.getInstance();
mGlobalGids = systemConfig.getGlobalGids();
mSystemPermissions = systemConfig.getSystemPermissions();
mAvailableFeatures = systemConfig.getAvailableFeatures();

接下来,再来看看后半部分:

synchronized (mInstallLock) {
// writer
synchronized (mPackages) {//启动消息处理线程mHandlerThread = new ServiceThread(TAG,Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);mHandlerThread.start();//通过消息处理线程的Looper对象构造一个处理消息的Handler对象mHandler = new PackageHandler(mHandlerThread.getLooper());mProcessLoggingHandler = new ProcessLoggingHandler();//使用看门狗检测当前消息处理线程Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);//获取当前的Data目录File dataDir = Environment.getDataDirectory();mAppInstallDir = new File(dataDir, "app");mAppLib32InstallDir = new File(dataDir, "app-lib");mEphemeralInstallDir = new File(dataDir, "app-ephemeral");mAsecInternalPath = new File(dataDir, "app-asec").getPath();mDrmAppPrivateInstallDir = new File(dataDir, "app-private");//构造UserManagerService对象,创建用户管理服务sUserManager = new UserManagerService(context, this, mPackages);// Propagate permission configuration in to package manager.//读取权限配置文件中的信息,保存到mPermissions这个ArrayMap中ArrayMap<String, SystemConfig.PermissionEntry> permConfig= systemConfig.getPermissions();for (int i=0; i<permConfig.size(); i++) {SystemConfig.PermissionEntry perm = permConfig.valueAt(i);BasePermission bp = mSettings.mPermissions.get(perm.name);if (bp == null) {bp = new BasePermission(perm.name, "android", BasePermission.TYPE_BUILTIN);mSettings.mPermissions.put(perm.name, bp);}if (perm.gids != null) {bp.setGids(perm.gids, perm.perUser);}}//获取所有外部libArrayMap<String, String> libConfig = systemConfig.getSharedLibraries();for (int i=0; i<libConfig.size(); i++) {mSharedLibraries.put(libConfig.keyAt(i),new SharedLibraryEntry(libConfig.valueAt(i), null));}//尝试读取mac_permissions.xml并解析mFoundPolicyFile = SELinuxMMAC.readInstallPolicy();//读取并解析packages-backup.xml等文件mRestoredSettings = mSettings.readLPw(sUserManager.getUsers(false));//判断是否自定义的解析界面String customResolverActivity = Resources.getSystem().getString(R.string.config_customResolverActivity);if (TextUtils.isEmpty(customResolverActivity)) {customResolverActivity = null;} else {mCustomResolverComponentName = ComponentName.unflattenFromString(customResolverActivity);}................
}

这个过程涉及的几个重要变量:

创建Settings

在阶段1中创建了Settings对象,我们看看里面做了什么

Settings(File dataDir, Object lock) {mLock = lock;mRuntimePermissionsPersistence = new RuntimePermissionPersistence(mLock);mSystemDir = new File(dataDir, "system");mSystemDir.mkdirs();//创建/data/systemFileUtils.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 migrationmStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
}

此处mSystemDir是指目录/data/system,在该目录有以下5个文件:

SystemConfig
阶段1中还调用SystemConfig.getInstance()方法来获取SystemConfig

public static SystemConfig getInstance() {synchronized (SystemConfig.class) {if (sInstance == null) {sInstance = new SystemConfig();}return sInstance;}
}
SystemConfig() {// Read configuration from systemreadPermissions(Environment.buildPath(Environment.getRootDirectory(), "etc", "sysconfig"), ALLOW_ALL);// Read configuration from the old permissions dirreadPermissions(Environment.buildPath(Environment.getRootDirectory(), "etc", "permissions"), ALLOW_ALL);// Allow ODM to customize system configs around libs, features and appsint odmPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_APP_CONFIGS;readPermissions(Environment.buildPath(Environment.getOdmDirectory(), "etc", "sysconfig"), odmPermissionFlag);readPermissions(Environment.buildPath(Environment.getOdmDirectory(), "etc", "permissions"), odmPermissionFlag);// Only allow OEM to customize featuresreadPermissions(Environment.buildPath(Environment.getOemDirectory(), "etc", "sysconfig"), ALLOW_FEATURES);readPermissions(Environment.buildPath(Environment.getOemDirectory(), "etc", "permissions"), ALLOW_FEATURES);
}

readPermissions()解析指定目录下的所有xml文件,比如将标签所指的动态库保存到 PKMS的成员变量mSharedLibraries。可见,SystemConfig创建过程是对以下这六个目录中的所有xml进行解析:
/system/etc/sysconfig
/system/etc/permissions
/odm/etc/sysconfig
/odm/etc/permissions
/oem/etc/sysconfig
/oem/etc/permissions

SystemConfig.readPermissions

void readPermissions(File libraryDir, int permissionFlag) {// Read permissions from given directory.if (!libraryDir.exists() || !libraryDir.isDirectory()) {if (permissionFlag == ALLOW_ALL) {Slog.w(TAG, "No directory " + libraryDir + ", skipping");}return;}if (!libraryDir.canRead()) {Slog.w(TAG, "Directory " + libraryDir + " cannot be read");return;}// Iterate over the files in the directory and scan .xml filesFile platformFile = null;for (File f : libraryDir.listFiles()) {// We'll read platform.xml lastif (f.getPath().endsWith("etc/permissions/platform.xml")) {platformFile = f;continue;}if (!f.getPath().endsWith(".xml")) {Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring");continue;}if (!f.canRead()) {Slog.w(TAG, "Permissions library file " + f + " cannot be read");continue;}readPermissionsFromXml(f, permissionFlag);}// Read platform permissions last so it will take precedenceif (platformFile != null) {readPermissionsFromXml(platformFile, permissionFlag);}
}

该方法是解析指定目录下所有的具有可读权限的,且以xml后缀文件。

阶段2:BOOT_PROGRESS_PMS_SYSTEM_SCAN_START

 //标记扫描开始的时间long startTime = SystemClock.uptimeMillis();//将扫描开始的事件写入日志EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,startTime);// Set flag to monitor and not change apk file paths when// scanning install directories.//设置扫描的模式final int scanFlags = SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING | SCAN_INITIAL;//获取java启动类库的路径final String bootClassPath = System.getenv("BOOTCLASSPATH");//获取systemServer的路径final String systemServerClassPath = System.getenv("SYSTEMSERVERCLASSPATH");if (bootClassPath == null) {Slog.w(TAG, "No BOOTCLASSPATH found!");}if (systemServerClassPath == null) {Slog.w(TAG, "No SYSTEMSERVERCLASSPATH found!");}final List<String> allInstructionSets = InstructionSets.getAllInstructionSets();final String[] dexCodeInstructionSets =getDexCodeInstructionSets(allInstructionSets.toArray(new String[allInstructionSets.size()]));/*** Ensure all external libraries have had dexopt run on them.*///确保所有的外部lib都被dexopt优化if (mSharedLibraries.size() > 0) {// NOTE: For now, we're compiling these system "shared libraries"// (and framework jars) into all available architectures. It's possible// to compile them only when we come across an app that uses them (there's// already logic for that in scanPackageLI) but that adds some complexity.for (String dexCodeInstructionSet : dexCodeInstructionSets) {for (SharedLibraryEntry libEntry : mSharedLibraries.values()) {final String lib = libEntry.path;if (lib == null) {continue;}try {// Shared libraries do not have profiles so we perform a full// AOT compilation (if needed).int dexoptNeeded = DexFile.getDexOptNeeded(lib, dexCodeInstructionSet,getCompilerFilterForReason(REASON_SHARED_APK),false /* newProfile */);if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {mInstaller.dexopt(lib, Process.SYSTEM_UID, dexCodeInstructionSet,dexoptNeeded, DEXOPT_PUBLIC /*dexFlags*/,getCompilerFilterForReason(REASON_SHARED_APK),StorageManager.UUID_PRIVATE_INTERNAL,SKIP_SHARED_LIBRARY_CHECK);}} catch (FileNotFoundException e) {Slog.w(TAG, "Library not found: " + lib);} catch (IOException | InstallerException e) {Slog.w(TAG, "Cannot dexopt " + lib + "; is it an APK or JAR? "+ e.getMessage());}}}}File frameworkDir = new File(Environment.getRootDirectory(), "framework");final VersionInfo ver = mSettings.getInternalVersion();mIsUpgrade = !Build.FINGERPRINT.equals(ver.fingerprint);// when upgrading from pre-M, promote system app permissions from install to runtimemPromoteSystemApps =mIsUpgrade && ver.sdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1;// When upgrading from pre-N, we need to handle package extraction like first boot,// as there is no profiling data available.mIsPreNUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N;// save off the names of pre-existing system packages prior to scanning; we don't// want to automatically grant runtime permissions for new system appsif (mPromoteSystemApps) {Iterator<PackageSetting> pkgSettingIter = mSettings.mPackages.values().iterator();while (pkgSettingIter.hasNext()) {PackageSetting ps = pkgSettingIter.next();if (isSystemApp(ps)) {mExistingSystemPackages.add(ps.name);}}}// Collect vendor overlay packages.// (Do this before scanning any apps.)// For security and version matching reason, only consider// overlay packages if they reside in VENDOR_OVERLAY_DIR.//收集供应商包名:/vendor/overlayFile vendorOverlayDir = new File(VENDOR_OVERLAY_DIR);scanDirTracedLI(vendorOverlayDir, mDefParseFlags| PackageParser.PARSE_IS_SYSTEM| PackageParser.PARSE_IS_SYSTEM_DIR| PackageParser.PARSE_TRUSTED_OVERLAY, scanFlags | SCAN_TRUSTED_OVERLAY, 0);// Find base frameworks (resource packages without code).//扫描frameworkDir目录下的apk进行安装,扫描模式为非优化模式scanDirTracedLI(frameworkDir, mDefParseFlags| PackageParser.PARSE_IS_SYSTEM| PackageParser.PARSE_IS_SYSTEM_DIR| PackageParser.PARSE_IS_PRIVILEGED,scanFlags | SCAN_NO_DEX, 0);// Collected privileged system packages.final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");scanDirTracedLI(privilegedAppDir, mDefParseFlags| PackageParser.PARSE_IS_SYSTEM| PackageParser.PARSE_IS_SYSTEM_DIR| PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0);// Collect ordinary system packages.final File systemAppDir = new File(Environment.getRootDirectory(), "app");scanDirTracedLI(systemAppDir, mDefParseFlags| PackageParser.PARSE_IS_SYSTEM| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);// Collect all vendor packages.File vendorAppDir = new File("/vendor/app");try {vendorAppDir = vendorAppDir.getCanonicalFile();} catch (IOException e) {// failed to look up canonical path, continue with original one}scanDirTracedLI(vendorAppDir, mDefParseFlags| PackageParser.PARSE_IS_SYSTEM| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);// Collect all OEM packages.final File oemAppDir = new File(Environment.getOemDirectory(), "app");scanDirTracedLI(oemAppDir, mDefParseFlags| PackageParser.PARSE_IS_SYSTEM| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);// Prune any system packages that no longer exist.//构造一个List来存放不存在的packages路径final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<String>();if (!mOnlyCore) {//遍历mSettings.mPackagesIterator<PackageSetting> psit = mSettings.mPackages.values().iterator();while (psit.hasNext()) {PackageSetting ps = psit.next();/** If this is not a system app, it can't be a* disable system app.*///如果不是系统app,不处理if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {continue;}/** If the package is scanned, it's not erased.*/final PackageParser.Package scannedPkg = mPackages.get(ps.name);if (scannedPkg != null) {/** If the system app is both scanned and in the* disabled packages list, then it must have been* added via OTA. Remove it from the currently* scanned package so the previously user-installed* application can be scanned.*///如果在disable列表中,那么,说明它是通过OTA方式进行升级更新添加的,因此,清楚相应数据if (mSettings.isDisabledSystemPackageLPr(ps.name)) {logCriticalInfo(Log.WARN, "Expecting better updated system app for "+ ps.name + "; removing system app.  Last known codePath="+ ps.codePathString + ", installStatus=" + ps.installStatus+ ", versionCode=" + ps.versionCode + "; scanned versionCode="+ scannedPkg.mVersionCode);//移除其信息removePackageLI(scannedPkg, true);mExpectingBetter.put(ps.name, ps.codePath);}continue;}//如果不在disable列表中,则直接清楚相应的数据if (!mSettings.isDisabledSystemPackageLPr(ps.name)) {psit.remove();logCriticalInfo(Log.WARN, "System package " + ps.name+ " no longer exists; it's data will be wiped");// Actual deletion of code and data will be handled by later// reconciliation step} else {//否则,通过codePath判断其是否有可能被更新或删除final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name);if (disabledPs.codePath == null || !disabledPs.codePath.exists()) {possiblyDeletedUpdatedSystemApps.add(ps.name);}}}}//look for any incomplete package installations//获取未完成安装的apk包的PackageSetting列表ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();//清除未安装的安装包for (int i = 0; i < deletePkgsList.size(); i++) {// Actual deletion of code and data will be handled by later// reconciliation stepfinal String packageName = deletePkgsList.get(i).name;logCriticalInfo(Log.WARN, "Cleaning up incompletely installed app: " + packageName);synchronized (mPackages) {mSettings.removePackageLPw(packageName);}}//delete tmp files//清除临时文件deleteTempPackageFiles();// Remove any shared userIDs that have no associated packages//清除在mSettings中没有被使用的SharedUserSettingsmSettings.pruneSharedUsersLPw();

环境变量: 那可通过adb shell env来查看系统所有的环境变量及相应值。也可通过命令adb shell echo $SYSTEMSERVERCLASSPATH。
SYSTEMSERVERCLASSPATH:主要包括/system/framework目录下services.jar,ethernet-service.jar,wifi-service.jar这3个文件。
BOOTCLASSPATH:该环境变量内容较多,不同ROM可能有所不同,常见内容包含/system/framework目录下的framework.jar,ext.jar,core-libart.jar,telephony-common.jar,ims-common.jar,core-junit.jar等文件。

scanDirLI(): 扫描指定目录下的apk文件,最终调用PackageParser.parseBaseApk来完成AndroidManifest.xml文件的解析,生成Application, activity,service,broadcast, provider等信息。
/vendor/overlay
/system/framework
/system/priv-app
/system/app
/vendor/priv-app
/vendor/app
/oem/app

阶段3:BOOT_PROGRESS_PMS_DATA_SCAN_START

// Remove any shared userIDs that have no associated packages
//清除在mSettings中没有被使用的SharedUserSettings
mSettings.pruneSharedUsersLPw();
//如果是普通模式,则需要进行一些额外处理
if (!mOnlyCore) {EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,SystemClock.uptimeMillis());//扫描该目录scanDirTracedLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);scanDirTracedLI(mDrmAppPrivateInstallDir, mDefParseFlags| PackageParser.PARSE_FORWARD_LOCK,scanFlags | SCAN_REQUIRE_KNOWN, 0);scanDirLI(mEphemeralInstallDir, mDefParseFlags| PackageParser.PARSE_IS_EPHEMERAL,scanFlags | SCAN_REQUIRE_KNOWN, 0);/*** Remove disable package settings for any updated system* apps that were removed via an OTA. If they're not a* previously-updated app, remove them completely.* Otherwise, just revoke their system-level permissions.*///后面这部分代码逻辑简单,就是遍历possiblyDeletedUpdatedSystemApps,处理通过OTA更新和删除的APK文件for (String deletedAppName : possiblyDeletedUpdatedSystemApps) {PackageParser.Package deletedPkg = mPackages.get(deletedAppName);mSettings.removeDisabledSystemPackageLPw(deletedAppName);String msg;if (deletedPkg == null) {msg = "Updated system package " + deletedAppName+ " no longer exists; it's data will be wiped";// Actual deletion of code and data will be handled by later// reconciliation step} else {msg = "Updated system app + " + deletedAppName+ " no longer present; removing system privileges for "+ deletedAppName;deletedPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;PackageSetting deletedPs = mSettings.mPackages.get(deletedAppName);deletedPs.pkgFlags &= ~ApplicationInfo.FLAG_SYSTEM;}logCriticalInfo(Log.WARN, msg);}/*** 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");int reparseFlags = mDefParseFlags;if (FileUtils.contains(privilegedAppDir, scanFile)) {reparseFlags = PackageParser.PARSE_IS_SYSTEM| PackageParser.PARSE_IS_SYSTEM_DIR| PackageParser.PARSE_IS_PRIVILEGED;} else if (FileUtils.contains(systemAppDir, scanFile)) {reparseFlags = PackageParser.PARSE_IS_SYSTEM| PackageParser.PARSE_IS_SYSTEM_DIR;} else if (FileUtils.contains(vendorAppDir, scanFile)) {reparseFlags = PackageParser.PARSE_IS_SYSTEM| PackageParser.PARSE_IS_SYSTEM_DIR;} else if (FileUtils.contains(oemAppDir, scanFile)) {reparseFlags = PackageParser.PARSE_IS_SYSTEM| PackageParser.PARSE_IS_SYSTEM_DIR;} else {Slog.e(TAG, "Ignoring unexpected fallback path " + scanFile);continue;}mSettings.enableSystemPackageLPw(packageName);try {scanPackageTracedLI(scanFile, reparseFlags, scanFlags, 0, null);} catch (PackageManagerException e) {Slog.e(TAG, "Failed to parse original system package: "+ e.getMessage());}}}
}
mExpectingBetter.clear();// Resolve protected action filters. Only the setup wizard is allowed to
// have a high priority filter for these actions.
mSetupWizardPackage = getSetupWizardPackageName();
if (mProtectedFilters.size() > 0) {if (DEBUG_FILTERS && mSetupWizardPackage == null) {Slog.i(TAG, "No setup wizard;"+ " All protected intents capped to priority 0");}for (ActivityIntentInfo filter : mProtectedFilters) {if (filter.activity.info.packageName.equals(mSetupWizardPackage)) {if (DEBUG_FILTERS) {Slog.i(TAG, "Found setup wizard;"+ " allow priority " + filter.getPriority() + ";"+ " package: " + filter.activity.info.packageName+ " activity: " + filter.activity.className+ " priority: " + filter.getPriority());}// skip setup wizard; allow it to keep the high priority filtercontinue;}Slog.w(TAG, "Protected action; cap priority to 0;"+ " package: " + filter.activity.info.packageName+ " activity: " + filter.activity.className+ " origPrio: " + filter.getPriority());filter.setPriority(0);}
}
mDeferProtectedFilters = false;
mProtectedFilters.clear();// Now that we know all of the shared libraries, update all clients to have
// the correct library paths.
//给需要使用shared libraries的package找到相应的路径,并将其保存至package的usesLibraryFiles中
updateAllSharedLibrariesLPw();for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) {// NOTE: We ignore potential failures here during a system scan (like// the rest of the commands above) because there's precious little we// can do about it. A settings error is reported, though.adjustCpuAbisForSharedUserLPw(setting.packages, null /* scanned package */,false /* boot complete */);
}// Now that we know all the packages we are keeping,
// read and update their last usage times.
mPackageUsage.readLP();

当mOnlyCore = false时,则scanDirLI()还会收集如下目录中的apk
/data/app
/data/app-private

阶段4:BOOT_PROGRESS_PMS_SCAN_END

EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,SystemClock.uptimeMillis());Slog.i(TAG, "Time to scan packages: "+ ((SystemClock.uptimeMillis()-startTime)/1000f)+ " seconds");// If the platform SDK has changed since the last time we booted,// we need to re-grant app permission to catch any new ones that// appear.  This is really a hack, and means that apps can in some// cases get permissions that the user didn't initially explicitly// allow...  it would be nice to have some better way to handle// this situation.int updateFlags = UPDATE_PERMISSIONS_ALL;if (ver.sdkVersion != mSdkVersion) {Slog.i(TAG, "Platform changed from " + ver.sdkVersion + " to "+ mSdkVersion + "; regranting permissions for internal storage");updateFlags |= UPDATE_PERMISSIONS_REPLACE_PKG | UPDATE_PERMISSIONS_REPLACE_ALL;}//当sdk版本不一致时,,更新相关信息,并给需要使用权限的apk分配相应的权限updatePermissionsLPw(null, null, StorageManager.UUID_PRIVATE_INTERNAL, updateFlags);ver.sdkVersion = mSdkVersion;// If this is the first boot or an update from pre-M, and it is a normal// boot, then we need to initialize the default preferred apps across// all defined users.//当这是ota后的首次启动,正常启动则需要清除目录的缓存代码if (!onlyCore && (mPromoteSystemApps || !mRestoredSettings)) {for (UserInfo user : sUserManager.getUsers(true)) {mSettings.applyDefaultPreferredAppsLPw(this, user.id);applyFactoryDefaultBrowserLPw(user.id);primeDomainVerificationsLPw(user.id);}}// Prepare storage for system user really early during boot,// since core system apps like SettingsProvider and SystemUI// can't wait for user to startfinal int storageFlags;if (StorageManager.isFileEncryptedNativeOrEmulated()) {storageFlags = StorageManager.FLAG_STORAGE_DE;} else {storageFlags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;}reconcileAppsDataLI(StorageManager.UUID_PRIVATE_INTERNAL, UserHandle.USER_SYSTEM,storageFlags);// If this is first boot after an OTA, and a normal boot, then// we need to clear code cache directories.// Note that we do *not* clear the application profiles. These remain valid// across OTAs and are used to drive profile verification (post OTA) and// profile compilation (without waiting to collect a fresh set of profiles).if (mIsUpgrade && !onlyCore) {Slog.i(TAG, "Build fingerprint changed; clearing code caches");for (int i = 0; i < mSettings.mPackages.size(); i++) {final PackageSetting ps = mSettings.mPackages.valueAt(i);if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, ps.volumeUuid)) {// No apps are running this early, so no need to freezeclearAppDataLIF(ps.pkg, UserHandle.USER_ALL,StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE| Installer.FLAG_CLEAR_CODE_CACHE_ONLY);}}ver.fingerprint = Build.FINGERPRINT;}checkDefaultBrowser();// clear only after permissions and other defaults have been updated//当权限和其他默认项都完成更新,则清理相关信息mExistingSystemPackages.clear();mPromoteSystemApps = false;// All the changes are done during package scanning.ver.databaseVersion = Settings.CURRENT_DATABASE_VERSION;// can downgrade to reader//信息写回packages.xml文件mSettings.writeLPr();// Perform dexopt on all apps that mark themselves as coreApps. We do this pretty// early on (before the package manager declares itself as early) because other// components in the system server might ask for package contexts for these apps.//// Note that "onlyCore" in this context means the system is encrypted or encrypting// (i.e, that the data partition is unavailable).if ((isFirstBoot() || isUpgrade() || VMRuntime.didPruneDalvikCache()) && !onlyCore) {long start = System.nanoTime();List<PackageParser.Package> coreApps = new ArrayList<>();for (PackageParser.Package pkg : mPackages.values()) {if (pkg.coreApp) {coreApps.add(pkg);}}int[] stats = performDexOpt(coreApps, false,getCompilerFilterForReason(REASON_CORE_APP));final int elapsedTimeSeconds =(int) TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - start);MetricsLogger.histogram(mContext, "opt_coreapps_time_s", elapsedTimeSeconds);if (DEBUG_DEXOPT) {Slog.i(TAG, "Dex-opt core apps took : " + elapsedTimeSeconds + " seconds (" +stats[0] + ", " + stats[1] + ", " + stats[2] + ")");}// TODO: Should we log these stats to tron too ?// MetricsLogger.histogram(mContext, "opt_coreapps_num_dexopted", stats[0]);// MetricsLogger.histogram(mContext, "opt_coreapps_num_skipped", stats[1]);// MetricsLogger.histogram(mContext, "opt_coreapps_num_failed", stats[2]);// MetricsLogger.histogram(mContext, "opt_coreapps_num_total", coreApps.size());}

阶段5:BOOT_PROGRESS_PMS_READY

EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,SystemClock.uptimeMillis());if (!mOnlyCore) {mRequiredVerifierPackage = getRequiredButNotReallyRequiredVerifierLPr();mRequiredInstallerPackage = getRequiredInstallerLPr();mIntentFilterVerifierComponent = getIntentFilterVerifierComponentNameLPr();mIntentFilterVerifier = new IntentVerifierProxy(mContext,mIntentFilterVerifierComponent);mServicesSystemSharedLibraryPackageName = getRequiredSharedLibraryLPr(PackageManager.SYSTEM_SHARED_LIBRARY_SERVICES);mSharedSystemSharedLibraryPackageName = getRequiredSharedLibraryLPr(PackageManager.SYSTEM_SHARED_LIBRARY_SHARED);} else {mRequiredVerifierPackage = null;mRequiredInstallerPackage = null;mIntentFilterVerifierComponent = null;mIntentFilterVerifier = null;mServicesSystemSharedLibraryPackageName = null;mSharedSystemSharedLibraryPackageName = null;}mInstallerService = new PackageInstallerService(context, this);final ComponentName ephemeralResolverComponent = getEphemeralResolverLPr();final ComponentName ephemeralInstallerComponent = getEphemeralInstallerLPr();// both the installer and resolver must be present to enable ephemeralif (ephemeralInstallerComponent != null && ephemeralResolverComponent != null) {if (DEBUG_EPHEMERAL) {Slog.i(TAG, "Ephemeral activated; resolver: " + ephemeralResolverComponent+ " installer:" + ephemeralInstallerComponent);}mEphemeralResolverComponent = ephemeralResolverComponent;mEphemeralInstallerComponent = ephemeralInstallerComponent;setUpEphemeralInstallerActivityLP(mEphemeralInstallerComponent);mEphemeralResolverConnection =new EphemeralResolverConnection(mContext, mEphemeralResolverComponent);} else {if (DEBUG_EPHEMERAL) {final String missingComponent =(ephemeralResolverComponent == null)? (ephemeralInstallerComponent == null)? "resolver and installer": "resolver": "installer";Slog.i(TAG, "Ephemeral deactivated; missing " + missingComponent);}mEphemeralResolverComponent = null;mEphemeralInstallerComponent = null;mEphemeralResolverConnection = null;}mEphemeralApplicationRegistry = new EphemeralApplicationRegistry(this);} // synchronized (mPackages)} // synchronized (mInstallLock)// Now after opening every single application zip, make sure they// are all flushed.  Not really needed, but keeps things nice and// tidy.Runtime.getRuntime().gc();// The initial scanning above does many calls into installd while// holding the mPackages lock, but we're mostly interested in yelling// once we have a booted system.mInstaller.setWarnIfHeld(mPackages);// Expose private service for system components to use.LocalServices.addService(PackageManagerInternal.class, new PackageManagerInternalImpl());

PKMS初始化完成阶段,还会创建一个PackageInstaller服务。

public PackageInstallerService(Context context, PackageManagerService pm) {mContext = context;mPm = pm;//创建名为”PackageInstaller“的Handler线程mInstallThread = new HandlerThread(TAG);mInstallThread.start();mInstallHandler = new Handler(mInstallThread.getLooper());mCallbacks = new Callbacks(mInstallThread.getLooper());mSessionsFile = new AtomicFile(new File(Environment.getSystemSecureDirectory(), "install_sessions.xml"));mSessionsDir = new File(Environment.getSystemSecureDirectory(), "install_sessions");mSessionsDir.mkdirs();synchronized (mSessions) {readSessionsLocked();reconcileStagesLocked(StorageManager.UUID_PRIVATE_INTERNAL);final ArraySet<File> unclaimedIcons = newArraySet(mSessionsDir.listFiles());for (int i = 0; i < mSessions.size(); i++) {final PackageInstallerSession session = mSessions.valueAt(i);unclaimedIcons.remove(buildAppIconFile(session.sessionId));}for (File icon : unclaimedIcons) {icon.delete();}}
}

PKMS初始化过程,分为5个阶段:
PMS_START阶段:
创建Settings对象;
将6类shareUserId到mSettings;
初始化SystemConfig;
创建名为“PackageManager”的handler线程mHandlerThread;
创建UserManagerService多用户管理服务;
通过解析4大目录中的xmL文件构造共享mSharedLibraries;
PMS_SYSTEM_SCAN_START阶段:
扫描系统apk;
PMS_DATA_SCAN_START阶段:
扫描/data/app目录下的apk;
扫描/data/app-private目录下的apk;
PMS_SCAN_END阶段:
将上述信息写回/data/system/packages.xml;
PMS_READY阶段:
创建服务PackageInstallerService;

PKMS.systemReady

@Overridepublic void systemReady() {mSystemReady = true;// Read the compatibilty setting when the system is ready.boolean compatibilityModeEnabled = android.provider.Settings.Global.getInt(mContext.getContentResolver(),android.provider.Settings.Global.COMPATIBILITY_MODE, 1) == 1;PackageParser.setCompatibilityModeEnabled(compatibilityModeEnabled);if (DEBUG_SETTINGS) {Log.d(TAG, "compatibility mode:" + compatibilityModeEnabled);}int[] grantPermissionsUserIds = EMPTY_INT_ARRAY;synchronized (mPackages) {// Verify that all of the preferred activity components actually// exist.  It is possible for applications to be updated and at// that point remove a previously declared activity component that// had been set as a preferred activity.  We try to clean this up// the next time we encounter that preferred activity, but it is// possible for the user flow to never be able to return to that// situation so here we do a sanity check to make sure we haven't// left any junk around.ArrayList<PreferredActivity> removed = new ArrayList<PreferredActivity>();for (int i=0; i<mSettings.mPreferredActivities.size(); i++) {PreferredIntentResolver pir = mSettings.mPreferredActivities.valueAt(i);removed.clear();for (PreferredActivity pa : pir.filterSet()) {if (mActivities.mActivities.get(pa.mPref.mComponent) == null) {removed.add(pa);}}if (removed.size() > 0) {for (int r=0; r<removed.size(); r++) {PreferredActivity pa = removed.get(r);Slog.w(TAG, "Removing dangling preferred activity: "+ pa.mPref.mComponent);pir.removeFilter(pa);}mSettings.writePackageRestrictionsLPr(mSettings.mPreferredActivities.keyAt(i));}}for (int userId : UserManagerService.getInstance().getUserIds()) {if (!mSettings.areDefaultRuntimePermissionsGrantedLPr(userId)) {grantPermissionsUserIds = ArrayUtils.appendInt(grantPermissionsUserIds, userId);}}}sUserManager.systemReady();//多用户服务// If we upgraded grant all default permissions before kicking off.//升级所有已获取的默认权限for (int userId : grantPermissionsUserIds) {mDefaultPermissionPolicy.grantDefaultPermissions(userId);}// Kick off any messages waiting for system ready//处理所有等待系统准备就绪的消息if (mPostSystemReadyMessages != null) {for (Message msg : mPostSystemReadyMessages) {msg.sendToTarget();}mPostSystemReadyMessages = null;}// Watch for external volumes that come and go over time//观察外部存储设备final StorageManager storage = mContext.getSystemService(StorageManager.class);storage.registerListener(mStorageListener);mInstallerService.systemReady();mPackageDexOptimizer.systemReady();MountServiceInternal mountServiceInternal = LocalServices.getService(MountServiceInternal.class);mountServiceInternal.addExternalStoragePolicy(new MountServiceInternal.ExternalStorageMountPolicy() {@Overridepublic int getMountMode(int uid, String packageName) {if (Process.isIsolated(uid)) {return Zygote.MOUNT_EXTERNAL_NONE;}if (checkUidPermission(WRITE_MEDIA_STORAGE, uid) == PERMISSION_GRANTED) {return Zygote.MOUNT_EXTERNAL_DEFAULT;}if (checkUidPermission(READ_EXTERNAL_STORAGE, uid) == PERMISSION_DENIED) {return Zygote.MOUNT_EXTERNAL_DEFAULT;}if (checkUidPermission(WRITE_EXTERNAL_STORAGE, uid) == PERMISSION_DENIED) {return Zygote.MOUNT_EXTERNAL_READ;}return Zygote.MOUNT_EXTERNAL_WRITE;}@Overridepublic boolean hasExternalStorage(int uid, String packageName) {return true;}});// Now that we're mostly running, clean up stale users and appsreconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL);reconcileApps(StorageManager.UUID_PRIVATE_INTERNAL);}

至此,PackageManagerService启动流程分析完毕,如有错误之处,欢迎留言指正。

PackageManagerService启动流程源码解析相关推荐

  1. NioEventLoop启动流程源码解析

    NioEventLoop的启动时机是在服务端的NioServerSocketChannel中的ServerSocketChannel初始化完成,且注册在NioEventLoop后执行的, 下一步就是去 ...

  2. Kernel启动流程源码解析 1 head.S

    bootloader在跳转到kernel前,需要确保如下设置: MMU = off, D-cache = off, I-cache = on or off x0 = physical address ...

  3. SpringSecurity启动流程源码解析

    前面两期我讲了SpringSecurity认证流程和SpringSecurity鉴权流程,今天是第三期,是SpringSecurity的收尾工作,讲SpringSecurity的启动流程. 就像很多电 ...

  4. Kernel启动流程源码解析 2 head.S

    __cpu_setup.定义kernel\arch\arm64\mm\proc.S中. #define MAIR(attr, mt)    ((attr) << ((mt) * 8)) / ...

  5. Android Launcher启动应用程序流程源码解析

    带着问题看源码 点击桌面Launcher图标后做了哪些工作? 应用程序什么时候被创建的? Application和MainActivity的onCreate()方法什么时候被调用的? 概述 在Andr ...

  6. Doris FE启动流程源码详细解析

    Doris FE启动流程源码详细解析 一.简介 Apache Doris是一个现代化的MPP分析型数据库产品.仅需亚秒级响应时间即可获得查询结果,有效地支持实时数据分析.Apache Doris的分布 ...

  7. swoole 启动流程_EasySwoole 服务启动过程以及主体设计流程源码解析

    EasySwoole 服务启动过程以及主体设计流程源码解析 本文主要讲解EasySwoole 服务的启动过程,会通过源码片段讲解主体的设计流程 命令启动 当我们通过php easyswoole sta ...

  8. BroadcastReceiver的跨进程注册、接收流程源码解析

    根据<Activity跨进程启动流程源码探究>我们可以清楚以下几点: 1)Context的通用实现是在ContextIml这个类中 2)Activity的启动过程需要借助ActivityM ...

  9. 云原生小课堂|Envoy请求流程源码解析(三):请求解析

    ​ 前言 Envoy 是一款面向 Service Mesh 的高性能网络代理服务.它与应用程序并行运行,通过以平台无关的方式提供通用功能来抽象网络.当基础架构中的所有服务流量都通过 Envoy 网格时 ...

  10. SpringBoot2 | SpringBoot启动流程源码分析(一)

    首页 博客 专栏·视频 下载 论坛 问答 代码 直播 能力认证 高校 会员中心 收藏 动态 消息 创作中心 SpringBoot2 | SpringBoot启动流程源码分析(一) 置顶 张书康 201 ...

最新文章

  1. Spring Cloud(五)断路器监控(Hystrix Dashboard)
  2. [译] PHP7 数组:HashTable
  3. controller调用controller的方法_SpringCloud Alibaba微服务实战三 - 服务调用
  4. 【C++】简约的for循环
  5. jquery_pagination分页插件的使用
  6. MyBatis在insert插入操作时返回主键ID
  7. ASP.NET中利用ashx实现图片防盗链
  8. 浅析jQuery中常用的元素查找方法总结
  9. 分页存储过程2005
  10. 数据结构和算法 D3
  11. 运筹优化(十九)--决策论基础及其最优化求解
  12. 拓端tecdat|约会数据动态可视化分析:R语言使用ggplot和ganimate制作的动画图
  13. 我假装考上了浙江大学
  14. 四川多多开店:拼多多如何检查聊天记录
  15. 好用的远程登录服务器工具
  16. arch yaourt安装
  17. TDChat国内ChatGPT镜像网站最新网站入口地址
  18. ​PC电脑流行的主要原因
  19. MSM261S4030H0R
  20. 为jupyter的Markdown标题生成大纲目录

热门文章

  1. 数独解法-变形数独(第三讲:数独进阶方法(摒除))
  2. linux 服务器时钟同步设置
  3. Python学习之Craps赌博游戏篇
  4. 华为防火墙配置(双机热备)
  5. SmartOS——与众不同的虚拟化技术
  6. MT6573默认锁屏界面修改
  7. 2.13navigation导航系统
  8. JS短文 | 3分钟了解下 JS Sets 集合
  9. 连接数据库查询数据的工具类(底层实现)——以查询Phoenix为例
  10. 简述T568A和T568B的区别