PKMS
源代码基于android11
PKMS定义
它是android系统中核心服务之一,负责管理应用程序,其中应用程序的安装、卸载、信息查询等工作均是它来完成。
它工作的大致流程是:android系统在开机时会启动PKMS,PKMS服务扫描特定的目录,寻找apk压缩包,解析获取安装信息,然后完成程序的安装。
PKMS启动流程
-
SystemServer -> main();
-
SystemServer -> tartBootstrapServices();启动系统引导服务
-
PackageManagerService -> main();在main中做了如下事情。
- 创建PKMS -> 进入构造器
- 创建PackageHandler [line-2958]处理Package相关信息,效验、安装、卸载等。
- scanDirTracedLI [line-3098] 扫描磁盘目录下apk文件
//main方法执行完之后,将pkms服务添加到SM中ServiceManager.addService("package", m); -
SystemServer -> startOtherServices();
-
PackageManagerService -> updatePackagesIfNeeded() 完成dex优化
-
PackageManagerService -> performFstrimIfNeeded() 磁盘管理功能。
-
PackageManagerService -> systemReady(); pkms已经完成启动,并准备就绪。
PKMS构造中代码分析
在PKMS的构造器中大概有一千多行代码,主要找重点。 其中重要阶段点如下(根据EventLog来区分):
- BOOT_PROGRESS_PMS_START -->PMS启动
- BOOT_PROGRESS_PMS_SYSTEM_SCAN_START -->扫描系统System目录
- BOOT_PROGRESS_PMS_DATA_SCAN_START -->扫描系统Data目录
- BOOT_PROGRESS_PMS_SCAN_END --> 扫描结束
- BOOT_PROGRESS_PMS_READY --> PMS准备就绪
下面具体走代码来分析。
PKMS构造第一阶段:BOOT_PROGRESS_PMS_START
第一阶段大致做了如下工作:
-
构造DisplayMetrics,保存分辨率等相关信息
-
创建Installer对象
-
创建PermissionManager权限管理类
-
创建Setting类,保存安装包信息。主要涉及data/system目录的packages.xml、package-backup、package.list、packages-stopped.xml、packages-stopped-backup.xml文件
-
创建PackageManager的handler线程,循环处理外部安装等相关信息。
mMetrics = new DisplayMetrics(); mInstaller = injector.getInstaller(); mPermissionManager = injector.getPermissionManagerServiceInternal(); mSettings = injector.getSettings(); ······· synchronized (mLock) { mHandlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/); mHandlerThread.start(); mHandler = new PackageHandler(mHandlerThread.getLooper()); Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT); ······· }
PKMS构造第二阶段:BOOT_PROGRESS_PMS_SYSTEM_SCAN_START
此阶段做了如下工作:
-
从init.rc中获取系统环境变量BOOTCLASSPATH和SYSTEMSERVERCLASSPATH;(通过adb shell --> export 可以查看android系统所有环境变量)
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START, startTime); final String bootClassPath = System.getenv("BOOTCLASSPATH"); final String systemServerClassPath = System.getenv("SYSTEMSERVERCLASSPATH"); -
对旧版本升级的情况,将安装时获取权限变更为运行时申请权限
-
扫码system、vendor、product、odm、oem 等目录下的priv-app、app、overlay 包。
// Collect vendor/product/system_ext 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. for (int i = mDirsToScanAsSystem.size() - 1; i >= 0; i--) { final ScanPartition partition = mDirsToScanAsSystem.get(i); if (partition.getOverlayFolder() == null) { continue; } scanDirTracedLI(partition.getOverlayFolder(), systemParseFlags, systemScanFlags | partition.scanFlag, 0, packageParser, executorService); } scanDirTracedLI(frameworkDir, systemParseFlags, systemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0, packageParser, executorService); for (int i = 0, size = mDirsToScanAsSystem.size(); i < size; i++) { final ScanPartition partition = mDirsToScanAsSystem.get(i); if (partition.getPrivAppFolder() != null) { scanDirTracedLI(partition.getPrivAppFolder(), systemParseFlags, systemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag, 0, packageParser, executorService); } scanDirTracedLI(partition.getAppFolder(), systemParseFlags, systemScanFlags | partition.scanFlag, 0, packageParser, executorService); }
PKMS构造第三阶段:BOOT_PROGRESS_PMS_DATA_SCAN_START
在扫描完system目录之后,系统还需要扫描data目录,及时更新,去除不必要的数据。
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());
scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0,
packageParser, executorService);
其中scanDirTracedLI就是关键的扫描方法,而mAppInstallDir变量值为data目录:
/** Directory where installed applications are stored */
private static final File sAppInstallDir =
new File(Environment.getDataDirectory(), "app");
PKMS构造第四阶段:BOOT_PROGRESS_PMS_SCAN_END
在扫描完成之后,大致做了如下工作
-
SDK变化之后,更新权限[line-3428]
final boolean sdkUpdated = (ver.sdkVersion != mSdkVersion); if (sdkUpdated) { Slog.i(TAG, "Platform changed from " + ver.sdkVersion + " to " + mSdkVersion + "; regranting permissions for internal storage"); } mPermissionManager.updateAllPermissions( StorageManager.UUID_PRIVATE_INTERNAL, sdkUpdated); ver.sdkVersion = mSdkVersion; -
OTA升级后第一次启动清楚不必要的缓存数据[line-3501]
if (mIsUpgrade && !mOnlyCore) { 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 | Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES); } } ver.fingerprint = Build.FINGERPRINT; } -
权限等默认项更新完毕之后,清理相关数据
// clear only after permissions and other defaults have been updated mPromoteSystemApps = false; -
更新Package.xml文件。
mSettings.writeLPr();
PKMS构造第五阶段:BOOT_PROGRESS_PMS_READY
第五阶段是GC垃圾回收和其他一些细节。
//得到特权控制包
mRequiredPermissionControllerPackage = getRequiredPermissionControllerLPr();
···
//内存回收
Runtime.getRuntime().gc();
解析APK流程
解析的流程我们需要从PKMS中的 scanDirTracedLI 开始。
-
PackageManagerService -> scanDirTracedLI()
-
PackageManagerService -> scanDirLI()
-
ParallelPackageParser -> submit()
-
ParallelPackageParser -> parsePackage()
-
PackageParser2 -> parsePackage();
android11之前是PackageParser,而在android11开始,解析apk相关的工作都是从PackageParser2开始。不过PackageParser中的相关代码并没有删除。
如果有缓存的解析文件,会直接return。
-
ParsingPackageUtils -> parsePackage()
//分别解析文件夹和文件,android11走的是文件夹,最后会走到parseBaseApk()方法中。 public ParseResult<ParsingPackage> parsePackage(ParseInput input, File packageFile, int flags) throws PackageParserException { if (packageFile.isDirectory()) { return parseClusterPackage(input, packageFile, flags); } else { return parseMonolithicPackage(input, packageFile, flags); } } -
ParsingPackageUtils -> parseClusterPackage()
-
ApkLiteParseUtils -> parseClusterPackageLite();返回PackageParser.PackageLite对象。
-
ApkLiteParseUtils -> parseApkLite();
-
ApkLiteParseUtils -> parseApkLiteInner();
//打开清单文件。 parser = apkAssets.openXml(PackageParser.ANDROID_MANIFEST_FILENAME); //ANDROID_MANIFEST_FILENAME变量值 /** File name in an APK for the Android manifest. */ public static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml"; -
ApkLiteParseUtils -> parseApkLite(); 对清单文件轻度解析,只解析了如versionCode、targetSdkVersion、CoreApp等外层字段
ApkLiteParseUtils执行完,ParsingPackageUtils得到了PackageLite对象后继续往下走。
- ParsingPackageUtils -> parseBaseApk()
- ParsingPackageUtils -> parseBaseApkTags()
- ParsingPackageUtils -> parseBaseApplication()
进入到parseBaseApplication中后,就开始全面解析清单文件了。
经常见到的activity、receiver、service、contentprovide等都在此处解析。
解析完成将所有信息保存在ParsingPackage中返回,最后到PackageParser2中进行缓存。
AndroidManifast.xml解析流程的时序图
apk安装流程
做系统开发,直接push到系统目录,然后机器重启就可以了。
做应用层开发,基本都是使用的adb install 安装。
我们直接查看adb install的代码流程。
在PKMS中,onShellCommand()方法就是接收adb命令的。
-
adb install xxx.apk
-
PackageManagerService -> onShellCommand();
-
PackageManagerShellCommand -> exec() -> onCommand() -> runInstall() -> doRunInstall() 在doRunInstall方法中,有两个重要的地方。
//创建Session
final int sessionId = doCreateSession(params.sessionParams,
params.installerPackageName, params.userId);
//创建一个临时的apk,把原来的apk保存到刚刚创建的临时apk中。
if (doWriteSplits(sessionId, args, params.sessionParams.sizeBytes, isApex)
!= PackageInstaller.STATUS_SUCCESS) {
return 1;
}
private int doWriteSplits(int sessionId, ArrayList<String> splitPaths, long sessionSizeBytes,
boolean isApex) throws RemoteException {
final boolean multipleSplits = splitPaths.size() > 1;
for (String splitPath : splitPaths) {
String splitName = multipleSplits ? new File(splitPath).getName()
: "base." + (isApex ? "apex" : "apk");
if (doWriteSplit(sessionId, splitPath, sessionSizeBytes, splitName,
false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
return 1;
}
}
return 0;
}
-
PackageInstallerService -> createSession(); 创建好session后,继续往下执行。
-
PackageManagerShellCommand -> doWriteSplits();
-
PackageManagerShellCommand -> doCommitSession();
-
PackageInstaller.Session -> commit();
-
PackageInstallerSession -> commit(); -> dispathStreamValidataAndCommit();
private void dispatchStreamValidateAndCommit() { //发送消息 mHandler.obtainMessage(MSG_STREAM_VALIDATE_AND_COMMIT).sendToTarget(); } -
PackageInstallerSession -> handleStreamValidateAndCommit()
mHandler.obtainMessage(MSG_INSTALL).sendToTarget(); -
PackageInstallerSession -> handleInstall() -> installNonStagedLocked()
-
PackageManagerService -> installStage();回调到了PKMS中。
void installStage(ActiveInstallSession activeInstallSession) { if (DEBUG_INSTANT) { if ((activeInstallSession.getSessionParams().installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) { Slog.d(TAG, "Ephemeral install of " + activeInstallSession.getPackageName()); } } final Message msg = mHandler.obtainMessage(INIT_COPY); final InstallParams params = new InstallParams(activeInstallSession); params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params)); msg.obj = params; Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStage", System.identityHashCode(msg.obj)); Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall", System.identityHashCode(msg.obj)); mHandler.sendMessage(msg); } -
PackageManagerService -> mHandler.obtainMessage(INIT_COPY);
-
HandlerParams -> startCopy()
final void startCopy() { if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this); handleStartCopy(); handleReturnCode(); } -
PackageManagerService.InstallParams -> handleStartCopy()
-
PackageManagerService.InstallParams -> handleReturnCode()
-
PackageManagerService -> processPendingInstall()
-
PackageManagerService -> processInstallRequestsAsync()
-
PackageManagerService -> installPackagesTracedLI();
-
PackageManagerService -> installPackagesLI();走apk解析流程
- PackageInstallerService -> preparePackageLI()
- PackageParser2 -> parsePackage() 解析AndroidManifast.xml文件。
- PackageInstallerService -> scanPackageTracedLI();
- PackageInstallerService -> scanPackageNewLI();
- PackageInstallerService -> commitPackagesLocked()
- PackageInstallerService -> updateSettingsLI
installPackagesLI 继续往下执行
- PackageManagerService -> scanPackageTracedLI();
- PackageManagerService -> scanPackageNewLI();
回到PackageManagerService的processInstallRequestsAsync()方法继续往下执行
-
PackageManagerService -> restoreAndPostInstall()
-
PackageManagerService -> performRollbackManagerRestore
-
RollbackManagerServiceImpl -> snapshotAndRestoreUserData();
-
PackageManagerService -> finishPackageInstall()
@Override public void finishPackageInstall(int token, boolean didLaunch) { enforceSystemOrRoot("Only the system is allowed to finish installs"); if (DEBUG_INSTALL) { Slog.v(TAG, "BM finishing package install for " + token); } Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "restore", token); final Message msg = mHandler.obtainMessage(POST_INSTALL, token, didLaunch ? 1 : 0); mHandler.sendMessage(msg); } -
发送POST_INSTALL消息。
-
PackageManagerService -> handlePackagePostInstall();在这个方法中发送一系列广播,通知其他模块,完成了 apk的安装。
APK安装时序图
总结
pkms是android中非常重要的一个服务,管理所有的安装包,对程序的安装、卸载、权限控制等都由它来进行操作。
目前只跟了PKMS的启动流程、清单解析流程以及apk安装流程,后期有时间会跟一下其他细节分支代码。
最后
本文只做学习记录,如有问题,感谢指出。
参考文章: