《Android 源码 installPackage 流程分析》一节着重分析了 apk 安装流程,接下来我们分析 PackageManagerService 启动时都做了些什么?
- 执行 PackageManagerService main 静态方法;
- 调用 PackageManagerService 类 isFirstBoot() 方法;
- 调用 PackageManagerService 类 getUsageStatsIfNoPackageUsageInfo() 方法;
- 调用 PackageManagerService 类 performBootDexOpt() 方法;
- 调用 PackageManagerService 类 systemReady() 方法。
frameworks/base/services/java/com/android/server/SystemServer.java
public final class SystemServer {
......
private PackageManagerService mPackageManagerService;
......
/**
* The main entry point from zygote.
*/
public static void main(String[] args) {
new SystemServer().run();
}
public SystemServer() {
// Check for factory test mode.
mFactoryTestMode = FactoryTest.getMode();
}
private void run() {
......
// Start services.
try {
startBootstrapServices();
startCoreServices();
startOtherServices();
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
}
......
}
......
private void startBootstrapServices() {
......
// 等待 installd 完成启动,以便它有机会创建具有适当权限的关键目录,如/data/user。
// 我们需要在初始化其他服务之前完成此操作。
Installer installer = mSystemServiceManager.startService(Installer.class);
......
// Start the package manager.
Slog.i(TAG, "Package Manager");
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
mFirstBoot = mPackageManagerService.isFirstBoot();
......
}
......
private void startCoreServices() {
......
// UsageStatsService 可用后更新,需要在 performBootDexOpt 之前。
mPackageManagerService.getUsageStatsIfNoPackageUsageInfo();
......
}
......
private void startOtherServices() {
......
try {
mPackageManagerService.performBootDexOpt();
} catch (Throwable e) {
reportWtf("performing boot dexopt", e);
}
......
try {
mPackageManagerService.systemReady();
} catch (Throwable e) {
reportWtf("making Package Manager Service ready", e);
}
......
}
......
}
在 main() 静态方法中:
- 创建 PackageManagerService 对象;
- 将其注册到“服务大管家” ServiceManager,注册字段是"package",以后就可以通过"package"字符串查询“服务大管家”,获取 PackageManagerService 了。
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
public class PackageManagerService extends IPackageManager.Stub {
......
public static PackageManagerService main(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
PackageManagerService m = new PackageManagerService(context, installer,
factoryTest, onlyCore);
ServiceManager.addService("package", m);
return m;
}
......
}
PackageManagerService 构造函数中完成了很多任务包括添加特殊用户名称和UID并关联、获取各种路径(/data/data、/data/app、/data/app-lib、/data/app-asec…)、所有外部库运行 dexopt、framework 路径下的文件运行 dexopt(除了 framework-res.apk 和 core-libart.jar)、扫描各种软件包(供应商overlay程序包、基础 framework(无代码的资源包)、特权系统软件包、普通系统软件包、供应商软件包、OEM软件包)、处理所有不再存在的系统软件包、清除任何不完整的包安装、删除所有没有关联软件包的共享用户ID…
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
public class PackageManagerService extends IPackageManager.Stub {
......
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
......
mContext = context;
mFactoryTest = factoryTest;
mOnlyCore = onlyCore;
mLazyDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
mMetrics = new DisplayMetrics();
mSettings = new Settings(mPackages);
// 添加特殊用户名称和UID并关联,如 "android.uid.system" 和 Process.SYSTEM_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);
......
mInstaller = installer;
mPackageDexOptimizer = new PackageDexOptimizer(this);
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();
mHandler = new PackageHandler(mHandlerThread.getLooper());
Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);
// 返回路径:/data
File dataDir = Environment.getDataDirectory();
mAppDataDir = new File(dataDir, "data");
mAppInstallDir = new File(dataDir, "app");
mAppLib32InstallDir = new File(dataDir, "app-lib");
mAsecInternalPath = new File(dataDir, "app-asec").getPath();
mUserAppDataDir = new File(dataDir, "user");
mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
sUserManager = new UserManagerService(context, this,
mInstallLock, mPackages);
......
mRestoredSettings = mSettings.readLPw(this, sUserManager.getUsers(false),
mSdkVersion, mOnlyCore);
......
// 给 monitor 标志设置,而不在扫描安装目录时更改apk文件路径。
final int scanFlags = SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING | SCAN_INITIAL;
final ArraySet<String> alreadyDexOpted = new ArraySet<String>();
/**
* 将引导类路径中的所有内容添加到进程文件列表中,
* 因为如果需要,在zygote启动期间将运行dexopt。
*/
final String bootClassPath = System.getenv("BOOTCLASSPATH");
final String systemServerClassPath = System.getenv("SYSTEMSERVERCLASSPATH");
if (bootClassPath != null) {
String[] bootClassPathElements = splitString(bootClassPath, ':');
for (String element : bootClassPathElements) {
alreadyDexOpted.add(element);
}
} else {
Slog.w(TAG, "No BOOTCLASSPATH found!");
}
if (systemServerClassPath != null) {
String[] systemServerClassPathElements = splitString(systemServerClassPath, ':');
for (String element : systemServerClassPathElements) {
alreadyDexOpted.add(element);
}
} else {
Slog.w(TAG, "No SYSTEMSERVERCLASSPATH found!");
}
final List<String> allInstructionSets = InstructionSets.getAllInstructionSets();
final String[] dexCodeInstructionSets =
getDexCodeInstructionSets(
allInstructionSets.toArray(new String[allInstructionSets.size()]));
/**
* 确保所有外部库都运行了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 {
int dexoptNeeded = DexFile.getDexOptNeeded(lib, null, dexCodeInstructionSet, false);
if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
alreadyDexOpted.add(lib);
mInstaller.dexopt(lib, Process.SYSTEM_UID, true, dexCodeInstructionSet, dexoptNeeded, false);
}
} catch (FileNotFoundException e) {
Slog.w(TAG, "Library not found: " + lib);
} catch (IOException e) {
Slog.w(TAG, "Cannot dexopt " + lib + "; is it an APK or JAR? "
+ e.getMessage());
}
}
}
}
File frameworkDir = new File(Environment.getRootDirectory(), "framework");
// 我们知道该文件不包含任何代码,因此请不要进行dexopt处理以免产生日志溢出。
alreadyDexOpted.add(frameworkDir.getPath() + "/framework-res.apk");
// 我们知道此文件只是art的启动类路径的一部分,因此请不要进行dexopt处理以免产生日志溢出。
alreadyDexOpted.add(frameworkDir.getPath() + "/core-libart.jar");
/**
* 有许多用Java实现的命令,
* 我们目前需要对它们执行dexopt,
* 以便可以从非root用户shell程序运行它们。
*/
String[] frameworkFiles = frameworkDir.list();
if (frameworkFiles != null) {
// TODO: We could compile these only for the most preferred ABI. We should
// first double check that the dex files for these commands are not referenced
// by other system apps.
for (String dexCodeInstructionSet : dexCodeInstructionSets) {
for (int i=0; i<frameworkFiles.length; i++) {
File libPath = new File(frameworkDir, frameworkFiles[i]);
String path = libPath.getPath();
// 如果我们已经处理过,跳过该文件。
if (alreadyDexOpted.contains(path)) {
continue;
}
// 如果不是我们需要处理(dexopt)的类型,跳过该文件。
if (!path.endsWith(".apk") && !path.endsWith(".jar")) {
continue;
}
try {
int dexoptNeeded = DexFile.getDexOptNeeded(path, null, dexCodeInstructionSet, false);
if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
mInstaller.dexopt(path, Process.SYSTEM_UID, true, dexCodeInstructionSet, dexoptNeeded, false);
}
} catch (FileNotFoundException e) {
Slog.w(TAG, "Jar not found: " + path);
} catch (IOException e) {
Slog.w(TAG, "Exception reading jar: " + path, e);
}
}
}
}
......
// 收集供应商overlay程序包。 (在扫描任何应用程序之前,请执行此操作。)
// 出于安全和版本匹配的原因,仅当overlay包位于VENDOR_OVERLAY_DIR中时,才考虑使用它们
File vendorOverlayDir = new File(VENDOR_OVERLAY_DIR);
scanDirLI(vendorOverlayDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_TRUSTED_OVERLAY, 0);
// 查找基础 framework(无代码的资源包)。
scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_IS_PRIVILEGED,
scanFlags | SCAN_NO_DEX, 0);
// 收集特权系统软件包。
final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
scanDirLI(privilegedAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0);
// 收集普通系统软件包。
final File systemAppDir = new File(Environment.getRootDirectory(), "app");
scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
// 收集所有供应商软件包。
File vendorAppDir = new File("/vendor/app");
try {
vendorAppDir = vendorAppDir.getCanonicalFile();
} catch (IOException e) {
// failed to look up canonical path, continue with original one
}
scanDirLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
// 收集所有OEM程序包。
final File oemAppDir = new File(Environment.getOemDirectory(), "app");
scanDirLI(oemAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");
mInstaller.moveFiles();
// 修剪所有不再存在的系统软件包。
final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<String>();
if (!mOnlyCore) {
Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
while (psit.hasNext()) {
PackageSetting ps = psit.next();
/*
* 如果这不是一个系统应用程序,它不能是一个禁用系统应用程序。
*/
if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
continue;
}
/*
* 如果包被扫描,它不会被删除。
*/
final PackageParser.Package scannedPkg = mPackages.get(ps.name);
if (scannedPkg != null) {
/*
* 如果系统应用程序被扫描并且在禁用包列表中,那么它一定是通过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(ps, true);
mExpectingBetter.put(ps.name, ps.codePath);
}
continue;
}
if (!mSettings.isDisabledSystemPackageLPr(ps.name)) {
psit.remove();
logCriticalInfo(Log.WARN, "System package " + ps.name
+ " no longer exists; wiping its data");
removeDataDirsLI(null, ps.name);
} else {
final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name);
if (disabledPs.codePath == null || !disabledPs.codePath.exists()) {
possiblyDeletedUpdatedSystemApps.add(ps.name);
}
}
}
}
//查找任何不完整的包安装
ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();
//清理 list
for(int i = 0; i < deletePkgsList.size(); i++) {
cleanupInstallFailedPackage(deletePkgsList.get(i));
}
//删除 tmp 文件
deleteTempPackageFiles();
// 删除所有没有关联软件包的共享用户ID
mSettings.pruneSharedUsersLPw();
if (!mOnlyCore) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());
scanDirLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,
scanFlags | SCAN_REQUIRE_KNOWN, 0);
/**
* 删除通过OTA删除的所有更新的系统应用程序的禁用程序包设置。
* 如果它们不是以前更新的应用程序,则将其完全删除。 否则,只需撤销其系统级权限。
*/
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; wiping its data";
removeDataDirsLI(null, deletedAppName);
} 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);
}
/**
* 确保确实出现了我们期望出现在userdata分区上的所有系统应用程序。
*/
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");
final int reparseFlags;
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 {
scanPackageLI(scanFile, reparseFlags, scanFlags, 0, null);
} catch (PackageManagerException e) {
Slog.e(TAG, "Failed to parse original system package: "
+ e.getMessage());
}
}
}
}
mExpectingBetter.clear();
// 既然我们知道了所有的共享库,那么就更新所有客户端以获得正确的库路径。
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 /* force dexopt */, false /* defer dexopt */,
false /* boot complete */);
}
// 现在我们知道了所有要保存的包,读取和更新它们的最后使用时间。
mPackageUsage.readLP();
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
SystemClock.uptimeMillis());
Slog.i(TAG, "Time to scan packages: "
+ ((SystemClock.uptimeMillis()-startTime)/1000f)
+ " seconds");
// 如果平台SDK自上次启动以来发生了变化,我们需要重新授予应用程序权限,以捕捉出现的任何新版本。
// 这是一种黑客行为,这意味着应用程序在某些情况下可以获得用户最初并不明确允许的权限……
// 如果有更好的方法来处理这种情况就好了。
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;
}
updatePermissionsLPw(null, null, StorageManager.UUID_PRIVATE_INTERNAL, updateFlags);
ver.sdkVersion = mSdkVersion;
// 如果这是第一次启动或从pre-M进行的更新,并且是正常启动,
// 则我们需要在所有定义的用户中初始化默认的首选应用程序。
if (!onlyCore && (mPromoteSystemApps || !mRestoredSettings)) {
for (UserInfo user : sUserManager.getUsers(true)) {
mSettings.applyDefaultPreferredAppsLPw(this, user.id);
applyFactoryDefaultBrowserLPw(user.id);
primeDomainVerificationsLPw(user.id);
}
}
// 如果这是OTA之后的第一次引导,并且是正常引导,那么我们需要清除代码缓存目录。
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)) {
deleteCodeCacheDirsLI(ps.volumeUuid, ps.name);
}
}
ver.fingerprint = Build.FINGERPRINT;
}
checkDefaultBrowser();
// 仅在权限和其他默认值已更新后清除
mExistingSystemPackages.clear();
mPromoteSystemApps = false;
// 所有更改都在软件包扫描期间完成。
ver.databaseVersion = Settings.CURRENT_DATABASE_VERSION;
// 可以降级为读
mSettings.writeLPr();
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
SystemClock.uptimeMillis());
mRequiredVerifierPackage = getRequiredVerifierLPr();
mRequiredInstallerPackage = getRequiredInstallerLPr();
mInstallerService = new PackageInstallerService(context, this);
mIntentFilterVerifierComponent = getIntentFilterVerifierComponentNameLPr();
mIntentFilterVerifier = new IntentVerifierProxy(mContext,
mIntentFilterVerifierComponent);
} // synchronized (mPackages)
} // synchronized (mInstallLock)
// 现在,在打开每个应用程序zip压缩包之后,确保它们都被刷新了。
// 不是真的需要,但可以保持整洁。
Runtime.getRuntime().gc();
// 公开私有服务以供系统组件使用。
LocalServices.addService(PackageManagerInternal.class, new PackageManagerInternalImpl());
}
......
}
接下来进入 isFirstBoot() 方法,此方法非常简单仅返回 mRestoredSettings 标志(恢复设置),它是在 PackageManagerService 构造函数中初始化的。
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
public class PackageManagerService extends IPackageManager.Stub {
......
boolean mRestoredSettings;
......
@Override
public boolean isFirstBoot() {
return !mRestoredSettings;
}
......
}
getUsageStatsIfNoPackageUsageInfo() 函数着重更新了一下应用最后一次使用结束时的时间,通过包名从 mPackages 中获取 PackageParser.Package 对象,然后更新。
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
public class PackageManagerService extends IPackageManager.Stub {
......
public void getUsageStatsIfNoPackageUsageInfo() {
if (!mPackageUsage.isHistoricalPackageUsageAvailable()) {
UsageStatsManager usm = (UsageStatsManager) mContext.getSystemService(Context.USAGE_STATS_SERVICE);
if (usm == null) {
throw new IllegalStateException("UsageStatsManager must be initialized");
}
long now = System.currentTimeMillis();
Map<String, UsageStats> stats = usm.queryAndAggregateUsageStats(now - mDexOptLRUThresholdInMills, now);
for (Map.Entry<String, UsageStats> entry : stats.entrySet()) {
String packageName = entry.getKey();
PackageParser.Package pkg = mPackages.get(packageName);
if (pkg == null) {
continue;
}
UsageStats usage = entry.getValue();
// 更新应用最后一次使用结束时的时间
pkg.mLastPackageUsageTimeInMills = usage.getLastTimeUsed();
mPackageUsage.mIsHistoricalPackageUsageAvailable = true;
}
}
}
......
}
fstrim 用于回收(又称为"trim")一个已挂载的文件系统上所有未使用的块。这对于固态硬盘(SSD)和精简配置(thinly-provisioned)的存储设备比较有意义。默认情况下,fstrim 将会回收文件系统上所有未使用的块。但是可以通过选项限定回收的范围和大小。
performBootDexOpt() 函数的作用:
- 判断是否需要磁盘维护,这是通过 fstrim 命令完成的
- 调用 dexopt 优化核心应用、监听预启动完成的系统应用和近期使用的应用,包优化是通过调用 performBootDexOpt 函数的重载版本完成的
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
public class PackageManagerService extends IPackageManager.Stub {
......
@Override
public void performBootDexOpt() {
enforceSystemOrRoot("Only the system can request dexopt be performed");
// 首先,看看我们是否需要 fstrim。
try {
IMountService ms = PackageHelper.getMountService();
if (ms != null) {
final boolean isUpgrade = isUpgrade();
boolean doTrim = isUpgrade;
// 由于系统更新,立即进行磁盘维护
if (doTrim) {
Slog.w(TAG, "Running disk maintenance immediately due to system update");
} else {
// 执行 fstrim 时间间隔,默认值为三天
final long interval = android.provider.Settings.Global.getLong(
mContext.getContentResolver(),
android.provider.Settings.Global.FSTRIM_MANDATORY_INTERVAL,
DEFAULT_MANDATORY_FSTRIM_INTERVAL);
if (interval > 0) {
final long timeSinceLast = System.currentTimeMillis() - ms.lastMaintenance();
// 大于三天触发磁盘维护(doTrim 赋值为 true)
if (timeSinceLast > interval) {
doTrim = true;
Slog.w(TAG, "No disk maintenance in " + timeSinceLast
+ "; running immediately");
}
}
}
if (doTrim) {
// 如果不是第一次启动,界面显示正在优化存储空间。
if (!isFirstBoot()) {
try {
ActivityManagerNative.getDefault().showBootMessage(
mContext.getResources().getString(
R.string.android_upgrading_fstrim), true);
} catch (RemoteException e) {
}
}
// 运行磁盘维护,这是通过 fstrim 命令完成的
ms.runMaintenance();
}
} else {
Slog.e(TAG, "Mount service unavailable!");
}
} catch (RemoteException e) {
// Can't happen; MountService is local
}
final ArraySet<PackageParser.Package> pkgs;
synchronized (mPackages) {
// 清除 Set 中延迟的 dexopt 包。返回清除 dexopt Set 之前的内容(如果不为空)
pkgs = mPackageDexOptimizer.clearDeferredDexOptPackages();
}
if (pkgs != null) {
// 按重要性对应用程序排序以进行dexopt排序。
// 如果设备空间不足,重要的应用程序将获得更高的优先级。
ArrayList<PackageParser.Package> sortedPkgs = new ArrayList<PackageParser.Package>();
// 优先考虑核心应用、。
for (Iterator<PackageParser.Package> it = pkgs.iterator(); it.hasNext();) {
PackageParser.Package pkg = it.next();
if (pkg.coreApp) {
if (DEBUG_DEXOPT) {
Log.i(TAG, "Adding core app " + sortedPkgs.size() + ": " + pkg.packageName);
}
sortedPkgs.add(pkg);
it.remove();
}
}
// 优先考虑监听预启动完成的系统应用程序。
Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
ArraySet<String> pkgNames = getPackageNamesForIntent(intent);
for (Iterator<PackageParser.Package> it = pkgs.iterator(); it.hasNext();) {
PackageParser.Package pkg = it.next();
if (pkgNames.contains(pkg.packageName)) {
if (DEBUG_DEXOPT) {
Log.i(TAG, "Adding pre boot system app " + sortedPkgs.size() + ": " + pkg.packageName);
}
sortedPkgs.add(pkg);
it.remove();
}
}
// 过滤掉最近没有使用的包。
filterRecentlyUsedApps(pkgs);
// 添加所有剩余的应用程序。
for (PackageParser.Package pkg : pkgs) {
if (DEBUG_DEXOPT) {
Log.i(TAG, "Adding app " + sortedPkgs.size() + ": " + pkg.packageName);
}
sortedPkgs.add(pkg);
}
// 懒惰模式下过滤那些最近没有用过的包。
if (mLazyDexOpt) {
filterRecentlyUsedApps(sortedPkgs);
}
int i = 0;
int total = sortedPkgs.size();
File dataDir = Environment.getDataDirectory();
// 获取低存储空间阈值
long lowThreshold = StorageManager.from(mContext).getStorageLowBytes(dataDir);
if (lowThreshold == 0) {
throw new IllegalStateException("Invalid low memory threshold");
}
for (PackageParser.Package pkg : sortedPkgs) {
long usableSpace = dataDir.getUsableSpace();
// 由于存储空间不足,未在其余应用上运行 dexopt
if (usableSpace < lowThreshold) {
Log.w(TAG, "Not running dexopt on remaining apps due to low memory: " + usableSpace);
break;
}
// 完成包优化工作
performBootDexOpt(pkg, ++i, total);
}
}
}
......
}
- 如果不是第一次启动,界面显示 应用:xx / xx。
- 实际优化工作是调用 PackageDexOptimizer 类 performDexOpt 处理的
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
public class PackageManagerService extends IPackageManager.Stub {
......
private void performBootDexOpt(PackageParser.Package pkg, int curr, int total) {
if (DEBUG_DEXOPT) {
Log.i(TAG, "Optimizing app " + curr + " of " + total + ": " + pkg.packageName);
}
if (!isFirstBoot()) {
try {
// 如果不是第一次启动,界面显示 应用:xx / xx。
ActivityManagerNative.getDefault().showBootMessage(
mContext.getResources().getString(R.string.android_upgrading_apk,
curr, total), true);
} catch (RemoteException e) {
}
}
PackageParser.Package p = pkg;
synchronized (mInstallLock) {
// 实际优化工作是调用 PackageDexOptimizer 类 performDexOpt 处理的
mPackageDexOptimizer.performDexOpt(p, null /* 指令集 */,
false /* 强制 dex */, false /* 推迟 */, true /* 包括依赖关系 */,
false /* 启动完成 */);
}
}
......
}
对指定指令集的指定程序包的所有代码路径和库执行 dexopt。performDexOpt() 方法内部调用了 performDexOptLI() 方法,performDexOptLI() 方法内部最终调用 Installer 类 dexopt 完成实际优化动作。
frameworks/base/services/core/java/com/android/server/pm/PackageDexOptimizer.java
final class PackageDexOptimizer {
......
int performDexOpt(PackageParser.Package pkg, String[] instructionSets,
boolean forceDex, boolean defer, boolean inclDependencies, boolean bootComplete) {
ArraySet<String> done;
if (inclDependencies && (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null)) {
done = new ArraySet<String>();
done.add(pkg.packageName);
} else {
done = null;
}
synchronized (mPackageManagerService.mInstallLock) {
final boolean useLock = mSystemReady;
if (useLock) {
mDexoptWakeLock.setWorkSource(new WorkSource(pkg.applicationInfo.uid));
mDexoptWakeLock.acquire();
}
try {
return performDexOptLI(pkg, instructionSets, forceDex, defer, bootComplete, done);
} finally {
if (useLock) {
mDexoptWakeLock.release();
}
}
}
}
private int performDexOptLI(PackageParser.Package pkg, String[] targetInstructionSets,
boolean forceDex, boolean defer, boolean bootComplete, ArraySet<String> done) {
......
final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
for (String dexCodeInstructionSet : dexCodeInstructionSets) {
......
for (String path : paths) {
......
if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
......
final int ret = mPackageManagerService.mInstaller.dexopt(path, sharedGid,
!pkg.isForwardLocked(), pkg.packageName, dexCodeInstructionSet,
dexoptNeeded, vmSafeMode, debuggable, oatDir, bootComplete);
......
}
}
......
}
......
}
......
}
最后再来看 PackageManagerService 类 systemReady() 方法。
- 验证所有 PreferredActivity 组件是否确实存在
- 如果我们升级,在启动之前授予所有默认权限
- 监视外部容量变化
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
public class PackageManagerService extends IPackageManager.Stub {
......
@Override
public void systemReady() {
mSystemReady = true;
// 系统就绪后,读取兼容性模式开关。
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) {
// 验证所有 PreferredActivity 组件是否确实存在。
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();
// 如果我们升级,在启动之前授予所有默认权限。
for (int userId : grantPermissionsUserIds) {
mDefaultPermissionPolicy.grantDefaultPermissions(userId);
}
// 启动任何消息,等待系统就绪
if (mPostSystemReadyMessages != null) {
for (Message msg : mPostSystemReadyMessages) {
msg.sendToTarget();
}
mPostSystemReadyMessages = null;
}
// 监视外部容量变化
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() {
@Override
public 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;
}
@Override
public boolean hasExternalStorage(int uid, String packageName) {
return true;
}
});
}
......
}