在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中的标签 |
|||||
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 |