1 PackageManagerService启动
SystemServer启动PKMS: 先是在SystemServer.startBootstrapServices()函数中启动PKMS服务,再调用startOtherServices()函数中对dex优化,磁盘管理功能,让PKMS进入systemReady状态。
-
startBootstrapServices。()首先启动Installer服务,也就是安装器,随后判断当前的设备是否处于加密状态,如果是则只是解析核心应用,接着调用PackageManagerService的静态方法main来创建pms对象
- 启动Installer服务
- 获取设备是否加密(手机设置密码),如果设备加密了,则只解析"core"应用
- 调用PKMS main方法初始化PackageManagerService,其中调用PackageManagerService()构造函数创建了PKMS对象
- 如果设备没有加密,操作它。管理A/B OTA dexopting。
private void startBootstrapServices() { ... // 第一步:启动Installer // 阻塞等待installd完成启动,以便有机会创建具有适当权限的关键目录,如/data/user。 // 我们需要在初始化其他服务之前完成此任务。 Installer installer = mSystemServiceManager.startService(Installer.class); mActivityManagerService.setInstaller(installer); ... // 第二步:获取设别是否加密(手机设置密码),如果设备加密了,则只解析"core"应用,mOnlyCore = true,后面会频繁使用该变量进行条件判断 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; } // 第三步:调用main方法初始化PackageManagerService mPackageManagerService = PackageManagerService.main(mSystemContext, installer, mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore); // PKMS是否是第一次启动 mFirstBoot = mPackageManagerService.isFirstBoot(); // 第四步:如果设备没有加密,操作它。管理A/B OTA dexopting。 if (!mOnlyCore) { boolean disableOtaDexopt = SystemProperties.getBoolean("config.disable_otadexopt", false); OtaDexoptService.main(mSystemContext, mPackageManagerService); } ... //初始化PackageManager对象. mPackageManager = mSystemContext.getPackageManager(); ... }
-
startOtherServices
- updatePackagesIfNeeded ,完成dex优化;
- 执行 performFstrimIfNeeded ,完成磁盘维护;
- 调用systemReady,准备就绪。
private void startOtherServices() {
...
if (!mOnlyCore) {
...
// 第五步:如果设备没有加密,执行performDexOptUpgrade,完成dex优化;
mPackageManagerService.updatePackagesIfNeeded();
}
...
// 第六步:最终执行performFstrim,完成磁盘维护
mPackageManagerService.performFstrimIfNeeded();
...
// 第七步:PKMS准备就绪
mPackageManagerService.systemReady();
...
}
1.1 PKMS main方法概述
main函数主要工作:
- 检查Package编译相关系统属性
- 调用PackageManagerService构造方法
- 启用部分应用服务于多用户场景
- 往ServiceManager中注册”package”和”package_native”。
public static PackageManagerService main(Context context, Installer installer, boolean factoryTest, boolean onlyCore) {
```
// Self-check for initial settings.
PackageManagerServiceCompilerMapping.checkProperties();
// 1、创建PMS对象
PackageManagerService m = new PackageManagerServiceEx(context, installer,
factoryTest, onlyCore);
m.enableSystemUserPackages();
// 2、注册PMS对象到ServiceManager中
ServiceManager.addService("package", m);
//3、 创建 PMN对象
final PackageManagerNative pmn = m.new PackageManagerNative();
//4、注册PMN对象
ServiceManager.addService("package_native", pmn);
...
return m;
}
1.2 初始化PackageManager对象.
通过调用ContextImpl.getPackageManager()获取PackageManager对象
@Override
public PackageManager getPackageManager() {
if (mPackageManager != null) {
return mPackageManager;
}
IPackageManager pm = ActivityThread.getPackageManager();
if (pm != null) {
// Doesn't matter if we make more than one instance.
return (mPackageManager = new ApplicationPackageManager(this, pm));
}
return null;
}
getPackageManager方法中使用ActivityThread.getPackageManager()获取前面创建并注册的Binder对象,然后创建ApplicationPackageManager实例
frameworks/base/core/java/android/app/ActivityThread.java
@UnsupportedAppUsage
public static IPackageManager getPackageManager() {
if (sPackageManager != null) {
return sPackageManager;
}
// 获取注册Binder
IBinder b = ServiceManager.getService("package");
// sPackageManager就是服务端PKMS的代理proxy对象
sPackageManager = IPackageManager.Stub.asInterface(b);
return sPackageManager;
}
上面的这段代码, sPackageManager 就是服务端PKMS的 代理proxy对象, 客户端拿到sPackageManager这个代理对象,就可以跨进程调用PKMS中的方法了.
先来小结一下, 从上面的3个过程可以得出以下结论:
1. PMS使用Binder通信机制,最终IPackageManager接口的实现类为PackageManagerService类
2. 系统中获取的PackageManager对象具体实现的子类是ApplicationPackageManager对象
类图:
PKMS初始化时的核心部分为PackageManagerService()构造函数的内容,我们下面就来分析该流程
public static PackageManagerService main(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
// Self-check for initial settings.
//检查Package编译相关系统属性
PackageManagerServiceCompilerMapping.checkProperties();
// 调用PackageManagerService构造方法,
PackageManagerService m = new PackageManagerServiceEx(context, installer,
factoryTest, onlyCore);
//启用部分应用服务于多用户场景
m.enableSystemUserPackages();
//往ServiceManager中注册”package”和”package_native”。
ServiceManager.addService("package", m);
final PackageManagerNative pmn = m.new PackageManagerNative();
ServiceManager.addService("package_native", pmn);
return m;
}
1.3 PKMS构造方法详解
PKMS的构造函数中由两个重要的锁和5个阶段构成
两个重要的锁(mInstallLock、mPackages):
- mInstallLock :用来保护所有安装apk的访问权限,此操作通常涉及繁重的磁盘数据读写等操作,并 且是单线程操作,故有时候会处理很慢, 此锁不会在已经持有mPackages锁的情况下火的,反之,在已经持有mInstallLock锁的情况下,立即 获取mPackages是安全的
- mPackages:用来解析内存中所有apk的package信息及相关状态。
- 5个阶段
- BOOT_PROGRESS_PMS_START(开始阶段)
- BOOT_PROGRESS_PMS_SYSTEM_SCAN_START(扫描系统阶段)
- BOOT_PROGRESS_PMS_DATA_SCAN_START(扫描Data分区阶段)
- BOOT_PROGRESS_PMS_SCAN_END(扫描结束阶段)
- BOOT_PROGRESS_PMS_READY(准备阶段)
1.3.1 BOOT_PROGRESS_PMS_START 开始阶段
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
LockGuard.installLock(mPackages, LockGuard.INDEX_PACKAGES);
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "create package manager");
//第一阶段BOOT_PROGRESS_PMS_START 开始
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
SystemClock.uptimeMillis());
if (mSdkVersion <= 0) {
Slog.w(TAG, "**** ro.build.version.sdk not set!");
}
mContext = context;
// 一般为false,即非工厂生产模式
mFactoryTest = factoryTest;
mOnlyCore = onlyCore; //标记是否只加载核心服务
//1. 构造 DisplayMetrics ,保存分辨率等相关信息
mMetrics = new DisplayMetrics();
//2. 创建Installer对象,与installd交互;
mInstaller = installer;
// Create sub-components that provide services / data. Order here is important.
//创建提供服务/数据的子组件。这里的顺序很重要,使用到了两个重要的同步锁
synchronized (mInstallLock) {
synchronized (mPackages) {
// Expose private service for system components to use.
// 公开系统组件使用的私有服务
// 本地服务
LocalServices.addService(
PackageManagerInternal.class, new PackageManagerInternalImpl());
// 多用户管理服务
sUserManager = new UserManagerService(context, this,
new UserDataPreparer(mInstaller, mInstallLock, mContext, mOnlyCore), mPackages);
//解析所有Android组件类型对象[activities, services, providers and receivers]
mComponentResolver = new ComponentResolver(sUserManager,
LocalServices.getService(PackageManagerInternal.class),
mPackages);
//3. 创建mPermissionManager对象,进行权限管理;
mPermissionManager = PermissionManagerService.create(context,
mPackages /*externalLock*/);
mDefaultPermissionPolicy = mPermissionManager.getDefaultPermissionGrantPolicy();
//创建Settings对象
//构造Settings类,保存安装包信息,清除路径不存在的孤立应用,
// 主要涉及 /data/system/目录的packages.xml,packages-backup.xml, packages.list, packages-stopped.xml,packages-stopped-backup.xml等文件。
mSettings = new Settings(Environment.getDataDirectory(),
mPermissionManager.getPermissionSettings(), mPackages);
}
}
// 添加system, phone, log, nfc, bluetooth, shell,se,networkstack 这8种 shareUserId 到 mSettings;
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);
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;
}
//5. 构造PackageDexOptimizer及DexManager类,处理dex优化
//DexOpt优化
mPackageDexOptimizer = new PackageDexOptimizer(installer, mInstallLock, context,
"*dexopt*");
mDexManager = new DexManager(mContext, this, mPackageDexOptimizer, installer, mInstallLock);
// ART虚拟机管理服务
mArtManagerService = new ArtManagerService(mContext, this, installer, mInstallLock);
mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());
mViewCompiler = new ViewCompiler(mInstallLock, mInstaller);
//权限变化监听器
mOnPermissionChangeListeners = new OnPermissionChangeListeners(
FgThread.get().getLooper());
// 获取默认分辨率
getDefaultDisplayMetrics(context, mMetrics);
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "get system config");
//6.创建SystemConfig实例,获取系统配置信息,配置共享lib库;
// 拿到SystemConfig()的对象,其中会调用SystemConfig的readPermissions()完成权限的读取
SystemConfig systemConfig = SystemConfig.getInstance();
//获取该设备支持的功能,这些功能是从系统配置文件中读取的
mAvailableFeatures = systemConfig.getAvailableFeatures();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
mProtectedPackages = new ProtectedPackages(mContext);
mApexManager = new ApexManager(context);
//启动"PackageManager"线程,负责apk的安装、卸载, 用HanderThread来实现
mHandlerThread = new ServiceThread(TAG,
Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
mHandlerThread.start();
// 应用handler PackageHandler是PKMS中的内部类
mHandler = new PackageHandler(mHandlerThread.getLooper());
// 进程记录handler
mProcessLoggingHandler = new ProcessLoggingHandler();
//Watchdog监听ServiceThread是否超时:10分钟
Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);
// Instant应用注册
mInstantAppRegistry = new InstantAppRegistry(this);
// 共享lib库配置
ArrayMap<String, SystemConfig.SharedLibraryEntry> libConfig
= systemConfig.getSharedLibraries();
final int builtInLibCount = libConfig.size();
for (int i = 0; i < builtInLibCount; i++) {
String name = libConfig.keyAt(i);
SystemConfig.SharedLibraryEntry entry = libConfig.valueAt(i);
addBuiltInSharedLibraryLocked(entry.filename, name);
}
// Now that we have added all the libraries, iterate again to add dependency
// information IFF their dependencies are added.
long undefinedVersion = SharedLibraryInfo.VERSION_UNDEFINED;
for (int i = 0; i < builtInLibCount; i++) {
String name = libConfig.keyAt(i);
SystemConfig.SharedLibraryEntry entry = libConfig.valueAt(i);
final int dependencyCount = entry.dependencies.length;
for (int j = 0; j < dependencyCount; j++) {
final SharedLibraryInfo dependency =
getSharedLibraryInfoLPr(entry.dependencies[j], undefinedVersion);
if (dependency != null) {
getSharedLibraryInfoLPr(name, undefinedVersion).addDependency(dependency);
}
}
}
// 读取安装相关SELinux策略
SELinuxMMAC.readInstallPolicy();
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "loadFallbacks");
// 返回栈加载
FallbackCategoryProvider.loadFallbacks();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "read user settings");
//读取并解析/data/system下的XML文件
//[这段代码 等下下面会分析]
mFirstBoot = !mSettings.readLPw(sUserManager.getUsers(false));
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
// Clean up orphaned packages for which the code path doesn't exist
// and they are an update to a system app - caused by bug/32321269
// 清理代码路径不存在的孤立软件包
final int packageSettingCount = mSettings.mPackages.size();
for (int i = packageSettingCount - 1; i >= 0; i--) {
PackageSetting ps = mSettings.mPackages.valueAt(i);
if (!isExternal(ps) && (ps.codePath == null || !ps.codePath.exists())
&& mSettings.getDisabledSystemPkgLPr(ps.name) != null) {
mSettings.mPackages.removeAt(i);
mSettings.enableSystemPackageLPw(ps.name);
}
}
// 如果不是首次启动,也不是CORE应用,则拷贝预编译的DEX文件
if (!mOnlyCore && mFirstBoot) {
requestCopyPreoptedFiles();
}
.....
.....
//好了到这里第一阶段就分析完了
注释1处, PKMS的构造函数中由两个重要的锁(mInstallLock、mPackages)
mInstallLock :用来保护所有安装apk的访问权限,此操作通常涉及繁重的磁盘数据读写等操作,并且是单线程操作,故有时候会处理很慢.
mPackages: 用来解析内存中所有apk的package信息及相关状态。
重点看看 mFirstBoot = !mSettings.readLPw(sUserManager.getUsers(false)) 这句代码
mSettings.readLPw
**readLPw()会扫描下面5个文件
- "/data/system/packages.xml" 所有安装app信息
- "/data/system/packages-backup.xml" 所有安装app信息之备份的信息记录
- "/data/system/packages.list" 所有安装app信息
- "/data/system/packages-stopped.xml" 所有强制停止app信息
- "/data/system/packages-stopped-backup.xml" 所有强制停止app信息之备份的信息记录**
5个文件共分为三组,简单的作用描述如下:
packages.xml:PKMS扫描完目标文件夹后会创建该文件。当系统进行程序安装、卸载和更新等操作时,均会更新该文件。该文件保存了系统中与package 相关的一些信息。packages.list:描述系统中存在的所有APK的信息。当这些程序有变动时,PKMS就会更新该文件。
packages-stopped.xml:从系统自带的设置程序中进入应用程序页面,然后在选择强制停止 (ForceStop)某个应用时,系统会将该应用的相关信息记录到此文件中。也就是该文件保存系统中被用户强制停止的Package的信息。
这些目录的指向,都是在Settings中的构造函数完成;
Settings(File dataDir, PermissionSettings permission,
Object lock) {
mLock = lock;
mPermissions = permission;
mRuntimePermissionsPersistence = new RuntimePermissionPersistence(mLock);
//mSystemDir指向目录"/data/system"
mSystemDir = new File(dataDir, "system");
//创建 "/data/system"
mSystemDir.mkdirs();
//设置权限
FileUtils.setPermissions(mSystemDir.toString(),
FileUtils.S_IRWXU|FileUtils.S_IRWXG
|FileUtils.S_IROTH|FileUtils.S_IXOTH,
-1, -1);
//(1)指向目录"/data/system/packages.xml"
mSettingsFilename = new File(mSystemDir, "packages.xml");
//(2)指向目录"/data/system/packages-backup.xml
mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
//(3)指向目录"/data/system/packages.list"
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
//(4)指向目录"/data/system/packages-stopped.xml"
mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");
//(5) 指 向 目 录 "/data/system/packages-stopped-backup.xml"
mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
}
好了,到这里 第一阶段的代码分析完成, 我们接下来分析第二阶段
1.3.2 BOOT_PROGRESS_PMS_SYSTEM_SCAN_START 扫描系统阶段
还在直接在源码中注释
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
......
//第二阶段,扫描系统阶段
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
startTime);
// 从init.rc中获取环境变量BOOTCLASSPATH和 SYSTEMSERVERCLASSPATH;
//获取环境变量,init.rc
final String bootClassPath = System.getenv("BOOTCLASSPATH");
final String systemServerClassPath = System.getenv("SYSTEMSERVERCLASSPATH");
if (bootClassPath == null) {
Slog.w(TAG, "No BOOTCLASSPATH found!");
}
if (systemServerClassPath == null) {
Slog.w(TAG, "No SYSTEMSERVERCLASSPATH found!");
}
// 获取system/framework目录
File frameworkDir = new File(Environment.getRootDirectory(), "framework");
// 获取内部版本
final VersionInfo ver = mSettings.getInternalVersion();
// 判断fingerprint是否有更新
mIsUpgrade = !Build.FINGERPRINT.equals(ver.fingerprint);
if (mIsUpgrade) {
logCriticalInfo(Log.INFO,
"Upgrading from " + ver.fingerprint + " to " + Build.FINGERPRINT);
}
// when upgrading from pre-M, promote system app permissions from install to runtime
//对于旧版本升级的情况,将安装时获取权限变更为运行时申请权限;
// 对于Android M之前版本升级上来的情况,需将系统应用程序权限从安装升级到运行时
mPromoteSystemApps =
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.
// 对于Android N之前版本升级上来的情况,需像首次启动一样处理package
mIsPreNUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N;
mIsPreNMR1Upgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N_MR1;
mIsPreQUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.Q;
int preUpgradeSdkVersion = ver.sdkVersion;
// save off the names of pre-existing system packages prior to scanning; we don't
// want to automatically grant runtime permissions for new system apps
// 在扫描之前保存预先存在的系统package的名称,不希望自动为新系统应用授予运行时权限
if (mPromoteSystemApps) {
Iterator<PackageSetting> pkgSettingIter = mSettings.mPackages.values().iterator();
while (pkgSettingIter.hasNext()) {
PackageSetting ps = pkgSettingIter.next();
if (isSystemApp(ps)) {
mExistingSystemPackages.add(ps.name);
}
}
}
// 准备解析package的缓存
mCacheDir = preparePackageParserCache();
// Set flag to monitor and not change apk file paths when
// scanning install directories.
// 设置flag,而不在扫描安装时更改文件路径
int scanFlags = SCAN_BOOTING | SCAN_INITIAL;
if (mIsUpgrade || mFirstBoot) {
scanFlags = scanFlags | SCAN_FIRST_BOOT_OR_UPGRADE;
}
// Collect vendor/product/product_services 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.
//扫描以下路径:
// /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、/oem/priv-app、 /product/priv-app、
// /product/app、/product_services/priv- app、 /product_services/app、/product_services/priv-app
scanDirTracedLI(new File(VENDOR_OVERLAY_DIR),
mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM_DIR,
scanFlags
| SCAN_AS_SYSTEM
| SCAN_AS_VENDOR,
0);
..... //省略相同的scanDirTracedLI方法
//delete tmp files
//(4)清除安装时临时文件以及其他不必要的信息。
deleteTempPackageFiles();
final int cachedSystemApps = PackageParser.sCachedPackageReadCount.get();
// Remove any shared userIDs that have no associated packages
//删除没有关联应用的共享UID标识
mSettings.pruneSharedUsersLPw();
...
...
//好了,到这里第二扫描系统阶段分析完成
}
第二阶段的工作内容:
1 从init.rc中获取环境变量BOOTCLASSPATH和SYSTEMSERVERCLASSPATH;
2 对于旧版本升级的情况,将安装时获取权限变更为运行时申请权限;
3 扫描system/vendor/product/odm/oem等目录的priv-app、app、overlay包;
4 清除安装时临时文件以及其他不必要的信息。
1.3.3 BOOT_PROGRESS_PMS_DATA_SCAN_START(扫描Data分区阶段)
对于不仅仅解析核心应用的情况下,还处理data目录的应用信息,及时更新, 去除不必要的数据。
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
.....
//对于不仅仅解析核心应用的情况下,还处理data目录的应用信息,及时更新,去除不必要的数据。
if (!mOnlyCore) {
//第三阶段 开始扫描data分区
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());
// 如果更新不再存在,则完全删除该应用。否则,撤消其系统权限
for (int i = possiblyDeletedUpdatedSystemApps.size() - 1; i >= 0; --i) {
final String packageName = possiblyDeletedUpdatedSystemApps.get(i);
final PackageParser.Package pkg = mPackages.get(packageName);
final String msg;
....
try {
//扫描apk
scanPackageTracedLI(scanFile, reparseFlags, rescanFlags, 0, null);
} catch (PackageManagerException e) {
Slog.e(TAG, "Failed to parse original system package: "
+ e.getMessage());
}
....
}
// Uncompress and install any stubbed system applications.
// This must be done last to ensure all stubs are replaced or disabled.
// 解压缩并安装任何存根系统应用程序。必须最后执行此操作以确保替换或禁用所有存根
installSystemStubPackages(stubSystemApps, scanFlags);
// Resolve the storage manager.
// 获取storage manager包名
mStorageManagerPackage = getStorageManagerPackageName();
// 解决受保护的action过滤器。只允许setup wizard(开机向导)为这些action 设置高优先级过滤器
mSetupWizardPackage = getSetupWizardPackageName();
// 更新客户端以确保持有正确的共享库路径
updateAllSharedLibrariesLocked(null, Collections.unmodifiableMap(mPackages));
// Now that we know all the packages we are keeping,
// read and update their last usage times.
// 读取并更新要保留的package的上次使用时间
mPackageUsage.read(mPackages);
mCompilerStats.read();
....//到这里第三 扫描data分区阶段完毕
}
再来总结一下:
/data可以称为Data分区,它用来存储所有用户的个人数据和配置文件。下面列出Data分区部分子目录:
目录 | 含义 |
---|---|
app | 存储用户自己安装的App |
data | 存储所有已安装的App数据的目录,每个App都有自己单独的子目录 |
app-private | App的私有存储空间 |
app-lib | 存储所有App的Jni库 |
system | 存放系统配置文件 |
anr | 用于存储ANR发生时系统生成的traces.txt文件 |
第三扫描Data分区阶段主要做了以下几件事:
扫描/data/app和/data/app-private目录下的文件。
遍历possiblyDeletedUpdatedSystemApps列表,如果这个系统App的包信息不在PMS的变量mPackages中,说明是残留的App信息,后续会删除它的数据。如果这个系统App的包信息在mPackages中,说明是存在于Data分区,不属于系统App,那么移除其系统权限。
1.3.4 BOOT_PROGRESS_PMS_SCAN_END 扫描结束阶段
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
.....
//第四阶段 扫描结束阶段
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
SystemClock.uptimeMillis());
....
// 如果这是第一次启动或来自Android M之前的版本的升级,并且它是正常启动,
// 那需要在所有已定义的用户中初始化默认的首选应用程序
if (!onlyCore && (mPromoteSystemApps || mFirstBoot)) {
for (UserInfo user : sUserManager.getUsers(true)) {
mSettings.applyDefaultPreferredAppsLPw(user.id);
primeDomainVerificationsLPw(user.id);
}
}
// 在启动期间确实为系统用户准备存储,因为像SettingsProvider和SystemUI这样的核心系统应用程序无法等待用户启动
final int storageFlags;
if (StorageManager.isFileEncryptedNativeOrEmulated()) {
storageFlags = StorageManager.FLAG_STORAGE_DE;
} else {
storageFlags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
}
....
// 如果是在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)) {
// No apps are running this early, so no need to freeze
clearAppDataLIF(ps.pkg, UserHandle.USER_ALL,
FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL
| Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
}
}
ver.fingerprint = Build.FINGERPRINT;
}
....
//安装Android-Q前的非系统应用程序在Launcher中隐藏他们的图标
if (!onlyCore && mIsPreQUpgrade) {
Slog.i(TAG, "Whitelisting all existing apps to hide their icons");
int size = mSettings.mPackages.size();
for (int i = 0; i < size; i++) {
final PackageSetting ps = mSettings.mPackages.valueAt(i);
if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0) {
continue;
}
ps.disableComponentLPw(PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME,
UserHandle.USER_SYSTEM);
}
}
// 仅在权限或其它默认配置更新后清除
mExistingSystemPackages.clear();
mPromoteSystemApps = false;
// All the changes are done during package scanning.
//所有变更均在扫描过程中完成
ver.databaseVersion = Settings.CURRENT_DATABASE_VERSION;
// can downgrade to reader
//把Settings的内容保存到packages.xml中
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "write settings");
mSettings.writeLPr();
....
// 好了,第四阶段的源码分析完毕
}
第4阶段主要工作:
- sdk版本变更,更新权限;
2. OTA升级后首次启动,清除不必要的缓存数据;- 权限等默认项更新完后,清理相关数据;
- 把Settings的内容保存到packages.xml中,这样此后PMS再次创建时会读到此前保存的Settings的内容。
1.3.5 BOOT_PROGRESS_PMS_READY 准备阶段
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
.....
//第五 准备阶段
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
SystemClock.uptimeMillis());
....
//创建PackageInstallerService对象
mInstallerService = new PackageInstallerService(context, this, mApexManager);
...
// 打开应用之后,及时回收处理
Runtime.getRuntime().gc();
.....//第5阶段完毕
}
第五阶段主要工作有:
创建PackageInstallerService对象, PackageInstallerService是用于管理安装会话的服务,它会为每次安装过程分配一个SessionId
GC回收内存
2 PKMS 的主要职责
1. 应用安装与卸载
- 安装应用:当用户安装一个 APK 文件时,PackageManagerService 负责解析该 APK 文件,检查其有效性(签名、权限等),并将其内容(如 APK 文件、资源文件等)安装到合适的存储位置。
- 卸载应用:当用户卸载应用时,PMS 会移除应用相关的所有文件和数据,包括应用的 APK 文件、缓存文件、数据库等。
1. 应用安装流程
当用户安装一个应用时,PackageManagerService
会执行一系列操作来确保应用被正确地安装、注册和验证。以下是应用安装的主要流程:
(1)接收安装请求
- 安装请求通常由系统应用(如
Settings
应用)或通过命令行工具(如adb install
)发起。 PackageManagerService
会接收到一个installPackage
方法的调用,其中包含 APK 文件的路径。
(2)解析 APK 文件
PackageManagerService
会使用PackageParser
解析 APK 文件,提取 APK 中的AndroidManifest.xml
文件及其内容。Manifest
文件包含了应用程序的基本信息,如包名、权限声明、组件(Activity、Service、Receiver)等。- 在解析过程中,
PackageManagerService
会检查 APK 文件的签名,确保其来源可信,并进行版本检查,防止同名应用的版本冲突。
java
复制代码
// PackageParser 解析 APK 文件
PackageParser.Package pkg = PackageParser.parsePackage(new File(apkPath), 0);
(3)安装路径和文件存储
PackageManagerService
会决定应用的安装路径,通常系统应用安装在/system/app/
或/system/priv-app/
,而用户应用则安装在/data/app/
。- 然后,APK 文件会被复制到相应的存储位置。
(4)权限和组件验证
PackageManagerService
会根据AndroidManifest.xml
中声明的权限检查应用所请求的权限,确保其与系统的权限策略一致。如果应用声明了危险权限(如访问联系人、定位等),则需要用户授权。- 同时,
PackageManagerService
会注册应用中的各个组件(如Activity
、Service
、BroadcastReceiver
等),使其能够在系统中正常工作。
(5)更新数据库
- 应用安装成功后,
PackageManagerService
会将应用的元数据(如包名、版本号、安装路径、权限等)存储在系统的数据库中。通常这部分数据会存储在/data/system/packages.xml
文件中。 - 这样,系统就能通过这些数据快速查找已安装的应用并为其提供后续服务。
(6)广播通知
- 安装完成后,
PackageManagerService
会通过广播通知系统其他组件,表示新应用已安装。其他系统组件(如ActivityManagerService
、WindowManagerService
)会根据这个信息进行相应的处理。
java
复制代码
// 发送安装成功的广播
Intent intent = new Intent(Intent.ACTION_PACKAGE_ADDED);
intent.setData(Uri.fromParts("package", packageName, null));
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
sendBroadcast(intent);
2. 应用卸载流程
卸载应用的流程与安装类似,但是其操作的目标是删除应用及其相关的数据。以下是卸载应用的主要步骤:
(1)接收卸载请求
- 卸载请求可以由用户通过设置应用界面触发,或通过
adb uninstall
命令发起。 PackageManagerService
会接收到uninstallPackage
方法的调用,传入待卸载的应用包名。
(2)查找并验证应用
PackageManagerService
会根据包名查询系统中是否存在该应用。如果找到了该应用,它会继续验证该应用是否可以卸载。例如,某些系统应用或预装应用可能不可卸载。
(3)移除应用的文件和数据
- 应用的 APK 文件会从存储位置(如
/data/app/
或/system/app/
)中删除。 - 系统会清理该应用的相关数据,包括缓存、数据库、配置文件等。如果是用户安装的应用,数据一般存储在
/data/data/<package_name>/
路径下。
java
复制代码
// 删除应用数据和 APK 文件
File appDir = new File(dataDir);
if (appDir.exists()) {
deleteRecursive(appDir);
}
(4)移除应用的组件
PackageManagerService
会注销该应用的所有组件(Activity、Service、Receiver 等),确保系统不会再尝试启动这些组件。
(5)更新数据库
- 删除应用后,
PackageManagerService
会更新系统的数据库,移除该应用的相关元数据,确保系统知道该应用已被卸载。
(6)发送卸载广播
- 卸载完成后,
PackageManagerService
会发送卸载成功的广播,通知其他组件该应用已被移除。
java
复制代码
// 发送卸载成功的广播
Intent intent = new Intent(Intent.ACTION_PACKAGE_REMOVED);
intent.setData(Uri.fromParts("package", packageName, null));
intent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
sendBroadcast(intent);
3 PKMS 管理安装与卸载的关键点
- 权限和签名验证:在安装过程中,PMS 会检查应用的权限声明和签名,确保应用合法并且符合系统要求。
- 应用组件注册:安装后,PMS 会注册应用中的所有组件,使其能够正常运行和与系统交互。
- 应用数据管理:卸载时,PMS 会确保应用的相关文件、数据和组件都被清理干净,避免数据残留。
- 广播通知:每次安装或卸载应用时,PMS 都会广播相关的系统通知,确保其他系统服务和应用程序能够响应这些变化。
2. 查询已安装应用
- 列出已安装应用:PMS 可以查询并返回系统中已安装的应用程序的相关信息,如包名、版本号、安装路径等。
- 获取应用信息:可以通过 PackageManager 查询特定应用的详细信息,如活动(Activity)、服务(Service)、广播接收器(Broadcast Receiver)、权限等。
3. 权限和签名验证
- 权限检查:PMS 会验证安装的应用是否具有所需的权限,只有拥有正确权限的应用才能执行相应的操作。
- 签名验证:安装的应用需要经过签名验证,系统通过验证签名来确保 APK 文件未被篡改,并保证来自合法开发者。
1. 签名验证
签名验证是 Android 安全机制中的重要一环,用于确认 APK 文件的来源和完整性。每个 APK 文件在发布前都需要由开发者进行数字签名,确保应用没有被篡改。
(1)签名验证的目的
- 防止篡改:通过数字签名验证 APK 文件是否被修改。只有在签名匹配时,系统才会信任该 APK 文件。
- 确认来源:通过验证签名,系统可以确认该 APK 来自已知和受信任的开发者。签名用于确保 APK 的来源和开发者身份。
(2)签名验证流程
-
当用户或系统请求安装一个应用时,
PackageManagerService
会对 APK 文件进行签名验证。具体流程如下:- 解析 APK 文件:PMS 会使用
PackageParser
来解析 APK 文件,提取出应用的AndroidManifest.xml
文件,并同时提取出 APK 的签名信息。 - 提取签名信息:系统通过
PackageManager
提取 APK 中的签名信息,通常是一个 X.509 数字证书。 - 检查签名:系统会验证 APK 的签名是否与先前的安装记录匹配。如果 APK 的签名发生变化,则认为该 APK 被篡改,安装会被拒绝。
- 系统签名与开发者签名:如果应用程序来自系统(如系统应用、预装应用),PMS 会检查应用的签名是否与系统签名匹配。如果是用户应用,则会检查应用的签名是否与该应用以前的版本签名一致。
- 解析 APK 文件:PMS 会使用
java
复制代码
// 签名验证过程
PackageParser.Package pkg = PackageParser.parsePackage(new File(apkFile), 0);
Signature[] signatures = pkg.mSignatures;
- 如果应用的签名与上一个版本签名不匹配,系统会拒绝该应用的安装。
(3)签名级别
- 系统签名:当应用是系统应用时,它通常由 Android 系统本身签名。例如,系统服务、系统应用会共享同一签名密钥。系统应用通常安装在
/system/app/
或/system/priv-app/
目录下。 - 开发者签名:开发者签名通常用于普通的第三方应用,签名是开发者使用私钥生成的。开发者签名的 APK 文件在发布到 Google Play 或其他应用市场时,会验证签名的有效性。
(4)多签名验证
- Android 支持多签名,即一个应用可以有多个签名。这对于共享组件或模块化应用场景非常重要。例如,Google 的一些系统应用与其他应用可以共享同一签名,允许它们之间更深度的集成。
- 在安装时,
PackageManagerService
会检查每个签名是否匹配,并确保所有签名符合预期。
java
复制代码
// 多签名验证
Signature[] expectedSignatures = ...;
Signature[] actualSignatures = pkg.mSignatures;
boolean validSignature = Arrays.equals(expectedSignatures, actualSignatures);
2. 权限验证
Android 的权限模型控制应用访问系统资源和其他敏感信息(如联系人、相机、位置等)的权限。PackageManagerService
负责在应用安装时检查权限,并确保应用获得适当的权限。
(1)权限验证的目的
- 保护隐私:限制应用程序对敏感数据和系统资源的访问。
- 系统安全:确保只有获得授权的应用程序才能访问某些特定的功能或数据。
- 防止恶意应用:恶意应用可能试图滥用系统权限,进行恶意行为或窃取用户数据。权限验证是防止这种情况的关键。
(2)权限声明
在 Android 中,每个应用必须在其 AndroidManifest.xml
文件中声明它所需要的权限。例如:
xml
复制代码
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
这些声明会告知系统,应用希望使用某些权限。应用必须先声明权限,才能在运行时请求并使用这些权限。
(3)权限验证流程
-
安装时验证:当一个应用安装时,
PackageManagerService
会检查应用在AndroidManifest.xml
中声明的权限,并验证是否符合系统要求。系统会检查权限是否符合以下条件:- 权限是否已定义:检查应用声明的权限是否已存在于系统的权限列表中。
- 权限是否已授权:检查应用请求的权限是否已经被用户授权。如果是危险权限(如访问联系人、位置等),用户必须明确授权。
- 权限是否适用:确保某些权限(如
WRITE_EXTERNAL_STORAGE
)仅能在特定版本或硬件配置上使用。
-
签名权限:对于一些系统权限或敏感操作(如访问其他应用的数据、签名权限),系统要求这些权限只能由经过签名的应用使用。这意味着,如果两个应用具有相同的签名,它们可以共享权限。
java
复制代码
// 在安装过程中,检查权限
if (pkg.mRequestedPermissions != null) {
for (String permission : pkg.mRequestedPermissions) {
Permission p = mPermissionManager.getPermission(permission);
if (p == null) {
// 权限不存在,拒绝安装
throw new SecurityException("Permission " + permission + " is not defined.");
}
}
}
(4)权限分配和授予
在安装过程中,PackageManagerService
会检查应用的声明权限,并在运行时授予应用所请求的权限。Android 的权限分为两类:
- 普通权限:这些权限对用户的隐私和系统资源的影响较小,系统会自动授予。
- 危险权限:这些权限可能会影响用户隐私或数据安全,系统需要用户明确授权。
对于危险权限,用户必须在运行时进行授权,通常通过 RequestPermission
弹窗进行交互。PackageManagerService
会确保只有在用户授权的情况下,应用才能使用这些权限。
3. 权限和签名的联合验证
在某些情况下,Android 系统要求权限和签名的联合验证。例如,某些权限(如签名权限)只有在应用与其他签名匹配时才会被授予。这种方式可以让系统应用和其他签名匹配的应用共享资源。
- 签名权限:某些权限只能由签名相同的应用授予。这些权限通常是系统权限,要求签名一致的应用共享访问权限。
- 权限授权的范围:某些权限(如访问设备设置)可能只在签名一致的应用之间共享。
java
复制代码
// 确保两个签名一致的应用可以共享某些权限
if (signatureMatches(pkg, otherPkg)) {
grantSignaturePermission(pkg, otherPkg);
}
4 总结
PackageManagerService
通过签名验证和权限验证确保 Android 系统中的应用程序是合法、安全的:
- 签名验证:通过检查 APK 文件的签名来确保应用未被篡改,且来自可信的开发者。多个签名可以共享同一签名,确保系统应用和第三方应用能够正确交互。
- 权限验证:在安装过程中,
PackageManagerService
会检查应用所声明的权限,并确保应用可以获得所需的权限。同时,系统还会验证应用是否具有请求敏感权限的授权,特别是对于危险权限,需要用户明确同意。
这两个机制共同保障了 Android 系统的安全性、隐私保护以及应用管理的完整性
4. 应用更新
- 应用升级:PMS 会处理 APK 的更新,包括将新版本的应用文件覆盖旧版本,同时保留数据和配置等信息。
- 版本管理:管理应用的版本信息,确保同一包名的多个版本可以正确处理。
5. 组件注册与启动
- 注册应用组件:PMS 负责将每个应用的组件(如 Activity、Service、Broadcast Receiver)注册到系统中,使其能够响应系统的调用。
- 启动应用组件:当用户启动应用时,PMS 会根据包名和组件名称来启动应用的相应组件。
6. 应用权限控制
- 权限声明:每个应用可以在其
AndroidManifest.xml
文件中声明需要的权限(如访问互联网、读取联系人等)。PMS 会在安装过程中检查权限声明,并在运行时请求用户授权。 - 权限验证:在应用执行敏感操作时,PMS 会验证应用是否拥有相应的权限。
(1)权限检查与更新
PackageManagerService
会在每次应用安装、卸载和更新时检查权限,确保权限声明和授予的权限与系统策略一致。
- 权限检查:当应用安装时,PMS 会验证应用所请求的权限是否在系统中已定义。如果权限不存在或无效,安装会被拒绝。
- 权限更新:当应用更新时,PMS 会再次检查新的权限声明,确保更新后的应用没有请求不必要或危险的权限。如果权限不符合要求,更新操作会被阻止。
(2)权限数据库管理
PackageManagerService
会将应用的权限数据存储在数据库中,这些数据包括应用的权限声明、授予的权限以及运行时权限请求的状态。这个数据库通常位于 /data/system/packages.xml
文件中。
- 在安装时,系统会根据应用的声明记录权限信息。
- 在卸载时,PMS 会删除与应用相关的权限信息,确保已卸载应用的权限不会继续影响系统。
- 在更新时,PMS 会合并新旧版本的权限信息,确保权限设置的连续性和正确性。
(3)权限冲突处理
当多个应用请求相同的权限时,PackageManagerService
会根据系统的策略来处理权限冲突。例如,如果一个危险权限被多个应用声明,系统会优先考虑最后安装的应用,或者要求用户选择授予哪个应用权限。
(4) 权限授权和回收
(1)授权
- 自动授权:普通权限在安装时会自动授予,PMS 不需要用户干预。
- 用户授权:危险权限在运行时需要用户明确授权,PMS 会在应用请求时触发系统权限请求流程,并记录用户的选择。
(2)回收
- 手动撤销:用户可以通过设备的设置界面手动撤销某个应用的权限。
- 系统回收:当应用被卸载或禁用时,
PackageManagerService
会自动回收该应用的权限数据。
5. PackageManagerService
中的权限管理示例
假设一个应用请求访问位置权限 (ACCESS_FINE_LOCATION
),PackageManagerService
会执行以下步骤:
- 安装阶段:应用声明
ACCESS_FINE_LOCATION
权限。PMS
会检查该权限是否是危险权限,并记录到系统的权限数据库中,但不会立即授予。 - 运行时请求:当应用需要使用位置服务时,它会请求运行时权限。系统会显示权限请求对话框,用户可以选择是否授予。
- 授予/拒绝:如果用户同意,PMS 会记录权限已授予。如果用户拒绝,PMS 会记录权限未授予,并且应用无法访问位置信息。
- 卸载阶段:应用卸载时,PMS 会删除与该应用相关的权限记录。
7. 多用户管理
- 在多用户模式下,PMS 负责管理不同用户的应用程序。每个用户的应用环境是独立的,PMS 需要确保不同用户之间的应用数据和设置不冲突。
8. 跨进程通信
- PMS 通过 Binder 跨进程通信机制向系统中的其他组件提供服务。它允许其他系统服务和应用程序通过
PackageManager
接口与 PMS 交互。
3 PKMS 与其他系统服务的协作
- PowerManagerService:当安装一个应用时,PMS 会通知 PowerManagerService 进行必要的电源管理处理,例如确保在安装过程中设备不会进入休眠状态。
- ActivityManagerService:当启动一个应用时,ActivityManagerService 会与 PackageManagerService 协同工作,通过 PackageManager 获取应用的组件信息,启动指定的
Activity
或Service
。 - PermissionManager:PMS 负责权限的管理和验证,所有的应用在安装时会声明需要的权限,PMS 会在应用运行时验证权限请求。
- SystemServer:在系统启动时,
SystemServer
会启动 PMS,确保所有已安装的应用可以被正常管理和查询。
4 总结
PackageManagerService (PMS) 是 Android 系统中非常重要的服务,负责管理应用的安装、卸载、查询、更新、组件注册等操作。它与多个系统服务协作,确保应用程序的生命周期管理、权限控制、组件交互等工作能够顺利进行。PMS 通过跨进程通信机制(Binder)提供对其他服务和应用程序的支持,并在系统启动时进行初始化。