在Android服务之PackageManagerService启动源码分析中介绍了PackageManagerService服务的整个启动过程,启动过程相对来说较为简单,就是构造一个PackageManagerService对象,然后注册到ServiceManager进程中,只是PackageManagerService对象的构造过程比较复杂,任务比较繁重,在前面介绍PackageManagerService构造过程中,介绍到PackageManagerService会扫描系统指定目录下的Apk文件,本文就结合源代码详细介绍PackageManagerService对Apk的整个扫描过程。
private void scanDirLI(File dir, int flags, int scanMode, long currentTime) { String[] files = dir.list(); if (files == null) { Log.d(TAG, "No files in app dir " + dir); return; } int i; for (i=0; i<files.length; i++) { File file = new File(dir, files[i]); //如果不是apk文件,则跳过继续扫描 if (!isPackageFilename(files[i])) { continue; } //解析扫描到的apk文件 PackageParser.Package pkg = scanPackageLI(file, flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime); //如果是系统分区内的无效安装包,则删除该apk文件 if (pkg == null && (flags & PackageParser.PARSE_IS_SYSTEM) == 0 && mLastScanError == PackageManager.INSTALL_FAILED_INVALID_APK) { Slog.w(TAG, "Cleaning up failed install of " + file); file.delete(); } }}该函数用于扫描指定目录下的Apk文件,函数实现比较简单,就是遍历目录下的以.apk为后缀的安装包文件,然后调用另一个scanDirLI函数来对每一个Apk文件进行解析。扫描每个Apk包括两个步骤:
首先是解析Apk中的AndroidManifest.xml文件,然后是更新每一个安装包在PackageManagerService中的设置信息。
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanMode, long currentTime) { mLastScanError = PackageManager.INSTALL_SUCCEEDED; String scanPath = scanFile.getPath(); parseFlags |= mDefParseFlags; //使用PackageParser对象来解析apk安装包 PackageParser pp = new PackageParser(scanPath); pp.setSeparateProcesses(mSeparateProcesses); pp.setOnlyCoreApps(mOnlyCore); //解析当前扫描的apk文件,得到描述apk信息的PackageParser.Package对象 final PackageParser.Package pkg = pp.parsePackage(scanFile, scanPath, mMetrics, parseFlags); if (pkg == null) { mLastScanError = pp.getParseError(); return null; } // /data/app/.delrecord文件用于记录删除的安装包 File delRecord = new File("/data/app/.delrecord"); //如果当前apk文件位于"/system/preloadapp"目录下,并且安装包删除记录文件存在 if(isPreloadApp(scanFile.getParent()) && delRecord.exists()){ //如果当前apk安装包曾经安装过,但已经被删除,则直接返回该apk的描述对象 if(isDeleteApp(pkg.packageName))return pkg; }这部分内容就是对每一个Apk文件的扫描过程,使用PackageParser对象来解析每一个Apk拥有的AndroidManifest.xml文件。
//更新系统中的安装包信息 PackageSetting ps = null; PackageSetting updatedPkg; synchronized (mPackages) { //mSettings.mRenamedPackages中保存了所有安装包的名字变更,以键值对的形式保存安装包新的包名和原始包名: newName-oldName String oldName = mSettings.mRenamedPackages.get(pkg.packageName); if (pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(oldName)) { //mSettings.mPackages中保存了所有安装包的设置信息,以键值对的形式保存每个apk包的包名和设置:name-PackageSetting,这里通过旧包名从mSettings.mPackages中取出该apk原始的PackageSetting对象 ps = mSettings.peekPackageLPr(oldName); } //如果没有原始包设置PackageSetting,则使用apk的当前包名来获取其对应的PackageSetting if (ps == null) { ps = mSettings.peekPackageLPr(pkg.packageName); } //mSettings.mDisabledSysPackages中保存了所有已替换的安装包的设置信息,以键值对的形式保存每个apk包的包名和设置:name-PackageSetting,使用包名从mSettings.mDisabledSysPackages中取得对应的PackageSetting对象 updatedPkg = mSettings.getDisabledSystemPkgLPr(ps != null ? ps.name : pkg.packageName); } //如果是系统安装包 if (updatedPkg != null && (parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) { //如果apk的路径已经更改 if (ps != null && !ps.codePath.equals(scanFile)) { //判断当前apk版本号是否小于原始版本 if (pkg.mVersionCode < ps.versionCode) { // 系统包已经是最新版本,且安装路径不匹配,忽略 mLastScanError = PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE; return null; } else { //更新安装包到系统分区中 synchronized (mPackages) { // 从PackageManagerService的安装包列表中删除该包 mPackages.remove(ps.name); } //创建安装参数InstallArgs InstallArgs args = createInstallArgs(packageFlagsToInstallFlags(ps), ps.codePathString, ps.resourcePathString, ps.nativeLibraryPathString); synchronized (mInstaller) { //清空dex文件及安装包的挂载点 args.cleanUpResourcesLI(); } synchronized (mPackages) { mSettings.enableSystemPackageLPw(ps.name); } } } } if (updatedPkg != null) { parseFlags |= PackageParser.PARSE_IS_SYSTEM; } //安装包校验 if (!collectCertificatesLI(pp, ps, pkg, scanFile, parseFlags)) { Slog.w(TAG, "Failed verifying certificates for package:" + pkg.packageName); return null; } //先前安装过相同包名的apk,但现在作为系统apk来安装 boolean shouldHideSystemApp = false; if (updatedPkg == null && ps != null && (parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0 && !isSystemApp(ps)) { //apk签名匹配,如果失败,清空apk文件及其数据 if (compareSignatures(ps.signatures.mSignatures, pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) { deletePackageLI(pkg.packageName, true, 0, null, false); ps = null; } else {//签名匹配成功 //如果新增的系统apk版本低于先前安装的apk版本 if (pkg.mVersionCode < ps.versionCode) { shouldHideSystemApp = true; } else { //更新系统apk程序,但保持应用数据不变 InstallArgs args = createInstallArgs(packageFlagsToInstallFlags(ps), ps.codePathString, ps.resourcePathString, ps.nativeLibraryPathString); synchronized (mInstaller) { args.cleanUpResourcesLI(); } } } } if (ps != null && !ps.codePath.equals(ps.resourcePath)) { parseFlags |= PackageParser.PARSE_FORWARD_LOCK; } String codePath = null; String resPath = null; if ((parseFlags & PackageParser.PARSE_FORWARD_LOCK) != 0) { if (ps != null && ps.resourcePathString != null) { resPath = ps.resourcePathString; } else { // Should not happen at all. Just log an error. Slog.e(TAG, "Resource path not set for pkg : " + pkg.packageName); } } else { resPath = pkg.mScanPath; } codePath = pkg.mScanPath; // Set application objects path explicitly. setApplicationInfoPaths(pkg, codePath, resPath); //调用另一个scanPackageLI函数 PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE, currentTime); if (shouldHideSystemApp) { synchronized (mPackages) { grantPermissionsLPw(pkg, true); mSettings.disableSystemPackageLPw(pkg.packageName); } } return scannedPkg;}这部分是Apk安装信息的更新过程。Apk文件的扫描过程就是对Apk包中的AndroidManifest文件的解析过程
public Package parsePackage(File sourceFile, String destCodePath, DisplayMetrics metrics, int flags) { mParseError = PackageManager.INSTALL_SUCCEEDED; mArchiveSourcePath = sourceFile.getPath(); if (!sourceFile.isFile()) { Slog.w(TAG, "Skipping dir: " + mArchiveSourcePath); mParseError = PackageManager.INSTALL_PARSE_FAILED_NOT_APK; return null; } if (!isPackageFilename(sourceFile.getName()) && (flags&PARSE_MUST_BE_APK) != 0) { if ((flags&PARSE_IS_SYSTEM) == 0) { Slog.w(TAG, "Skipping non-package file: " + mArchiveSourcePath); } mParseError = PackageManager.INSTALL_PARSE_FAILED_NOT_APK; return null; } XmlResourceParser parser = null; AssetManager assmgr = null; Resources res = null; boolean assetError = true; try { //创建一个资源管理器对象 assmgr = new AssetManager(); int cookie = assmgr.addAssetPath(mArchiveSourcePath); if (cookie != 0) { res = new Resources(assmgr, metrics, null); assmgr.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Build.VERSION.RESOURCES_SDK_INT); //使用XML解析器打开AndroidManifest.xml文件 parser = assmgr.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME); assetError = false; } else { Slog.w(TAG, "Failed adding asset path:"+mArchiveSourcePath); } } catch (Exception e) { Slog.w(TAG, "Unable to read AndroidManifest.xml of " + mArchiveSourcePath, e); } if (assetError) { if (assmgr != null) assmgr.close(); mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST; return null; } String[] errorText = new String[1]; Package pkg = null; Exception errorException = null; try { //解析AndroidManifest.xml文件,得到Package对象 pkg = parsePackage(res, parser, flags, errorText); } catch (Exception e) { errorException = e; mParseError = PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION; } if (pkg == null) { if (!mOnlyCoreApps || mParseError != PackageManager.INSTALL_SUCCEEDED) { if (errorException != null) { Slog.w(TAG, mArchiveSourcePath, errorException); } else { Slog.w(TAG, mArchiveSourcePath + " (at " + parser.getPositionDescription() + "): " + errorText[0]); } if (mParseError == PackageManager.INSTALL_SUCCEEDED) { mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; } } parser.close(); assmgr.close(); return null; } parser.close(); assmgr.close(); pkg.mPath = destCodePath; pkg.mScanPath = mArchiveSourcePath; pkg.mSignatures = null; return pkg;}该函数根据Apk包路径创建一个对应的资源管理器对象AssetManager,通过该对象来访问Apk包中的资源信息,包括AndroidManifest.xml文件。
parser = assmgr.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);通过资源管理器对象打开AndroidManifest.xml文件并且得到XML解析器。接着调用parsePackage函数开始解析AndroidManifest文件。在了解整个解析过程前,先认识一下Android定义的一些用于管理Apk信息的数据结构。
Package用于描述一个Apk的信息,一个Apk应用程序可能包括一系列的Activity,Service,Provider等组件,在Package中同样定义了对应的数据结构来保存这些组件信息。
这里不在沾上整个解析过程的源代码,只介绍解析过程使用的方法及数据结构。在
frameworks/base/core/res/res/values/attrs_manifest.xml文件中定义了AndroidManifest文件中的各个标签或属性
通过遍历AndroidManifest文件,并匹配对应的标签来读取指定标签的属性值,各个标签属性读取方式如下:
TypedArray sa = res.obtainAttributes(attrs,com.android.internal.R.styleable.AndroidManifest);pkg.mVersionCode = sa.getInteger(com.android.internal.R.styleable.AndroidManifest_versionCode, 0);pkg.mVersionName = sa.getNonConfigurationString(com.android.internal.R.styleable.AndroidManifest_versionName, 0);res是Resources对象,通过Resources对象的obtainAttributes方法来读取指定标签的属性内容,比如这里读取AndroidManifest标签的属性
最后根据属性名称从TypedArray中读取对应属性值,各个标签下的属性名称在frameworks/base/core/res/res/values/attrs_manifest.xml文件已经定义。下表为各个标签对应的解析函数:
application | parseApplication()
| ||||||||||||||||||||
permission-group | parsePermissionGroup() | ||||||||||||||||||||
permission | parsePermission() | ||||||||||||||||||||
permission-tree | parsePermissionTree() | ||||||||||||||||||||
uses-permission | parsePackage() | ||||||||||||||||||||
uses-configuration | parsePackage() | ||||||||||||||||||||
uses-feature | parsePackage() | ||||||||||||||||||||
uses-sdk | parsePackage() | ||||||||||||||||||||
supports-screens | parsePackage() | ||||||||||||||||||||
protected-broadcast | parsePackage() | ||||||||||||||||||||
instrumentation | parseInstrumentation() | ||||||||||||||||||||
original-package | parsePackage() | ||||||||||||||||||||
adopt-permissions | parsePackage() | ||||||||||||||||||||
uses-gl-texture | parsePackage() | ||||||||||||||||||||
compatible-screens | parsePackage() | ||||||||||||||||||||
eat-comment | parsePackage() |
在Package类中为每个标签定义了对应的数据结构来保存数据信息,解析XML的目的就是读取AndroidManifest文件中的内容到Package对象中。
Package成员 | 定义的属性 | XML中的标签 | |||||
mVersionCode | AndroidManifest
|
manifest | |||||
mVersionName | |||||||
mSharedUserId | |||||||
mSharedUserLabel | |||||||
installLocation | |||||||
applicationInfo | AndroidManifestApplication | application | |||||
创建PermissionGroup对象并将信息保存该对象的成员Info中,同时将创建的PermissionGroup对象添加到permissionGroups中 | AndroidManifestPermissionGroup
| permission-group | |||||
创建Permission对象并将信息保存该对象的成员Info中,同时将创建的Permission对象添加到permissions中 | AndroidManifestPermission | permission | |||||
创建Permission对象并将信息保存该对象的成员Info中,同时将创建的Permission对象添加到permissions中 | AndroidManifestPermissionTree
| permission-tree | |||||
requestedPermissions 保存权限名称 | AndroidManifestUsesPermission
| uses-permission | |||||
requestedPermissionsRequired | |||||||
创建ConfigurationInfo对象,并将信息保存到该对象中,同时将该对象添加到configPreferences中 | AndroidManifestUsesConfiguration | uses-configuration | |||||
创建FeatureInfo对象,并将信息保存到该对象中,同时将该对象添加到reqFeatures中 | AndroidManifestUsesFeature | uses-feature | |||||
applicationInfo.targetSdkVersion | AndroidManifestUsesSdk | uses-sdk | |||||
applicationInfo | AndroidManifestSupportsScreens | supports-screens | |||||
protectedBroadcasts | AndroidManifestProtectedBroadcast | protected-broadcast | |||||
instrumentation | AndroidManifestInstrumentation | instrumentation | |||||
mOriginalPackages | AndroidManifestOriginalPackage | original-package | |||||
mAdoptPermissions | AndroidManifestOriginalPackage | adopt-permissions | |||||
mAppMetaData | AndroidManifestMetaData | meta-data | |||||
usesLibraries usesOptionalLibraries | AndroidManifestUsesLibrary | uses-library | |||||
activities | AndroidManifestActivityAlias | activity-alias | |||||
AndroidManifestActivity | activity | ||||||
receivers | AndroidManifestActivity | receiver | |||||
services | AndroidManifestService | service | |||||
providers |
| provider |