[Android][Framework] PackageManagerService之AndroidManifest的解析
- 2020 年 1 月 20 日
- 筆記
前因
最近遇到一个问题,涉及到一个三方应用在系统中的方向显示。三方应用设置了强制竖屏,我需要将其变成横屏。
应用设置屏幕方向有两种方式,一种是在Manifest文件里配置:
android:screenOrientation="portrait"
另一种是通过接口设置。
setRequestedOrientation(int orientation)
通过命令查看三方应用的AndroidManifest.xml文件:
aapt dump xmltree xxxx.apk AndroidManifest.xml
看到应用是在其AndroidManifest.xml文件中指定了应用的方向。
所以,要解决这个问题,就涉及到一个知识点:Andriod系统是如何解析AndroidManifest文件的?
或者说,AndroidManifest是怎么起作用的?
PMS启动后的部分工作
PMS启动之后,首先会设置各种要扫描的目录,然后通过scanDirLI
方法对一些目录比如system/app,data/app,vendor/app进行apk的扫描。
private void scanDirLI(File dir, final int parseFlags, int scanFlags, long currentTime) { final File[] files = dir.listFiles(); for (File file : files) { final boolean isPackage = (isApkFile(file) || file.isDirectory()) && !PackageInstallerService.isStageName(file.getName()); if (!isPackage) { // Ignore entries which are not packages continue; } try { //扫描安装 scanPackageTracedLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK, scanFlags, currentTime, null); } catch (PackageManagerException e) { Slog.w(TAG, "Failed to parse " + file + ": " + e.getMessage()); //删除无效应用的用户数据 if ((parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 && e.error == PackageManager.INSTALL_FAILED_INVALID_APK) { logCriticalInfo(Log.WARN, "Deleting invalid package at " + file); removeCodePathLI(file); } } } }
其中调用了scanPackageTracedLI方法,其实就是跟踪package扫描:
/** * Traces a package scan. * @see #scanPackageLI(File, int, int, long, UserHandle) */ private PackageParser.Package scanPackageTracedLI(File scanFile, final int parseFlags, int scanFlags, long currentTime, UserHandle user) throws PackageManagerException { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage"); try { return scanPackageLI(scanFile, parseFlags, scanFlags, currentTime, user); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } }
接着进入
/** * Traces a package scan. * @see #scanPackageLI(File, int, int, long, UserHandle) */ private PackageParser.Package scanPackageTracedLI(File scanFile, final int parseFlags, int scanFlags, long currentTime, UserHandle user) throws PackageManagerException { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage"); try { return scanPackageLI(scanFile, parseFlags, scanFlags, currentTime, user); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } }
接着进入scanPackageLI。这个方法有两个实现:
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags, long currentTime, UserHandle user); private PackageParser.Package scanPackageLI(PackageParser.Package pkg, int parseFlags, int scanFlags, long currentTime, UserHandle user);
两者唯一的区别是签名列表中第一个参数,第一种实现为File类型的对象,而第二种实现为PackageParser.Package类型的对象。在具体解析某个文件时会先调用第一种实现解析apk文件,再调用第二种实现将解析后的信息保存至PMS:
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags, long currentTime, UserHandle user) throws PackageManagerException { //创建PackageParser PackageParser pp = new PackageParser(); final PackageParser.Package pkg; try { //调用PackageParser的parsePackage方法解析APK文件 pkg = pp.parsePackage(scanFile, parseFlags); } catch (PackageParserException e) {} //调用该方法的第二种实现,将解析后的信息保存至PMS PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanFlags | SCAN_UPDATE_SIGNATURE, currentTime, user); return scannedPkg; }
这里就调用到了PackageParser类的parsePackage方法进行对APK的解析。
PackageParser类
PackageParser类主要负责对应用AndroidManifest.xml文件的解析工作,所以第一个常亮定义就是:
private static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
解析AndroidManifest文件需要对不同xml节点分别解析,所以PackageParser部分的结构是如下形式:
public class PackageParser { public static class Component<II extends IntentInfo> {} public final static class Activity extends Component<ActivityIntentInfo> {} public final static class Instrumentation extends Component<IntentInfo> {} public final static class Permission extends Component<IntentInfo> {} public final static class PermissionGroup extends Component<IntentInfo> {} public final static class Provider extends Component<ProviderIntentInfo> {} public final static class Service extends Component<ServiceIntentInfo> {} }
可以看到,PackageParser为Activity、Service、Provider、Permission等组件在其内部以内部类的方式创建了对应的类,按照解释器模式的定义,这些类其实都对应AndroidManifest.xml文件中的一个标签,其在对该配置文件解析时充分运用了解释器模式分离实现、解释执行的特性。
好了,前面代码流程PMS走到了parsePackage的地方,这个方法是PackageParser最关键的方法,它的实现如下:
/** * Parse the package at the given location. Automatically detects if the * package is a monolithic style (single APK file) or cluster style * (directory of APKs). * <p> * This performs sanity checking on cluster style packages, such as * requiring identical package name and version codes, a single base APK, * and unique split names. * <p> * Note that this <em>does not</em> perform signature verification; that * must be done separately in {@link #collectCertificates(Package, int)}. * * @see #parsePackageLite(File, int) */ public Package parsePackage(File packageFile, int flags) throws PackageParserException { if (packageFile.isDirectory()) { return parseClusterPackage(packageFile, flags); } else { return parseMonolithicPackage(packageFile, flags);//该方法已弃用 } }
下面是parseClusterPackage方法:
/** * Parse all APKs contained in the given directory, treating them as a * single package. This also performs sanity checking, such as requiring * identical package name and version codes, a single base APK, and unique * split names. * <p> * Note that this <em>does not</em> perform signature verification; that * must be done separately in {@link #collectCertificates(Package, int)}. */ private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException { final PackageLite lite = parseClusterPackageLite(packageDir, 0); //... final AssetManager assets = new AssetManager(); try { // Load the base and all splits into the AssetManager // so that resources can be overriden when parsing the manifests. loadApkIntoAssetManager(assets, lite.baseCodePath, flags); //... final File baseApk = new File(lite.baseCodePath); final Package pkg = parseBaseApk(baseApk, assets, flags); //... if (!ArrayUtils.isEmpty(lite.splitNames)) { final int num = lite.splitNames.length; pkg.splitNames = lite.splitNames; pkg.splitCodePaths = lite.splitCodePaths; pkg.splitRevisionCodes = lite.splitRevisionCodes; pkg.splitFlags = new int[num]; pkg.splitPrivateFlags = new int[num]; for (int i = 0; i < num; i++) { parseSplitApk(pkg, i, assets, flags); } } pkg.setCodePath(packageDir.getAbsolutePath()); pkg.setUse32bitAbi(lite.use32bitAbi); return pkg; } finally { IoUtils.closeQuietly(assets); } }
后面是很长的调用路线:
parsePackage->parseClusterPackage->parseBaseApk->parseBaseApkCommon->parseBaseApkChild->parseBaseApplication->parseSplitApk
其中最关键的一个解析方法是parseBaseApkCommon方法,这里就对每一个Tag分别调用对应的parse方法。
/** * This is the common parsing routing for handling parent and child * packages in a base APK. The difference between parent and child * parsing is that some tags are not supported by child packages as * well as some manifest attributes are ignored. The implementation * assumes the calling code has already handled the manifest tag if needed * (this applies to the parent only). * * @param pkg The package which to populate * @param acceptedTags Which tags to handle, null to handle all * @param res Resources against which to resolve values * @param parser Parser of the manifest * @param flags Flags about how to parse * @param outError Human readable error if parsing fails * @return The package if parsing succeeded or null. * * @throws XmlPullParserException * @throws IOException */ private Package parseBaseApkCommon(Package pkg, Set<String> acceptedTags, Resources res, XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException, IOException { mParseInstrumentationArgs = null; mParseActivityArgs = null; mParseServiceArgs = null; mParseProviderArgs = null; int type; boolean foundApp = false; TypedArray sa = res.obtainAttributes(parser, com.android.internal.R.styleable.AndroidManifest); String str = sa.getNonConfigurationString( com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0); if (str != null && str.length() > 0) { String nameError = validateName(str, true, false); //... pkg.mSharedUserId = str.intern(); pkg.mSharedUserLabel = sa.getResourceId( com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0); } pkg.installLocation = sa.getInteger( com.android.internal.R.styleable.AndroidManifest_installLocation, PARSE_DEFAULT_INSTALL_LOCATION); pkg.applicationInfo.installLocation = pkg.installLocation; //... // Resource boolean are -1, so 1 means we don't know the value. int supportsSmallScreens = 1; int supportsNormalScreens = 1; int supportsLargeScreens = 1; int supportsXLargeScreens = 1; int resizeable = 1; int anyDensity = 1; int outerDepth = parser.getDepth(); while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { continue; } String tagName = parser.getName(); if (acceptedTags != null && !acceptedTags.contains(tagName)) { Slog.w(TAG, "Skipping unsupported element under <manifest>: " + tagName + " at " + mArchiveSourcePath + " " + parser.getPositionDescription()); XmlUtils.skipCurrentTag(parser); continue; } if (tagName.equals(TAG_APPLICATION)) { //... if (!parseBaseApplication(pkg, res, parser, flags, outError)) { return null; } } else if (tagName.equals(TAG_OVERLAY)) { //... XmlUtils.skipCurrentTag(parser); } else if (tagName.equals(TAG_KEY_SETS)) { if (!parseKeySets(pkg, res, parser, outError)) { return null; } } else if (tagName.equals(TAG_PERMISSION_GROUP)) { if (parsePermissionGroup(pkg, flags, res, parser, outError) == null) { return null; } } else if (tagName.equals(TAG_PERMISSION)) { if (parsePermission(pkg, res, parser, outError) == null) { return null; } } else if (tagName.equals(TAG_PERMISSION_TREE)) { if (parsePermissionTree(pkg, res, parser, outError) == null) { return null; } } else if (tagName.equals(TAG_USES_PERMISSION)) { if (!parseUsesPermission(pkg, res, parser)) { return null; } } else if (tagName.equals(TAG_USES_PERMISSION_SDK_M) || tagName.equals(TAG_USES_PERMISSION_SDK_23)) { if (!parseUsesPermission(pkg, res, parser)) { return null; } } else if (tagName.equals(TAG_USES_CONFIGURATION)) { //... XmlUtils.skipCurrentTag(parser); } else if (tagName.equals(TAG_USES_FEATURE)) { FeatureInfo fi = parseUsesFeature(res, parser); pkg.reqFeatures = ArrayUtils.add(pkg.reqFeatures, fi); //... XmlUtils.skipCurrentTag(parser); } else if (tagName.equals(TAG_FEATURE_GROUP)) { FeatureGroupInfo group = new FeatureGroupInfo(); ArrayList<FeatureInfo> features = null; final int innerDepth = parser.getDepth(); while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { final String innerTagName = parser.getName(); if (innerTagName.equals("uses-feature")) { FeatureInfo featureInfo = parseUsesFeature(res, parser); //... } else { Slog.w(TAG, "Unknown element under <feature-group>: " + innerTagName + " at " + mArchiveSourcePath + " " + parser.getPositionDescription()); } XmlUtils.skipCurrentTag(parser); } //... } else if (tagName.equals(TAG_USES_SDK)) { //... XmlUtils.skipCurrentTag(parser); } else if (tagName.equals(TAG_SUPPORT_SCREENS)) { //... XmlUtils.skipCurrentTag(parser); } else if (tagName.equals(TAG_PROTECTED_BROADCAST)) { //... XmlUtils.skipCurrentTag(parser); } else if (tagName.equals(TAG_INSTRUMENTATION)) { if (parseInstrumentation(pkg, res, parser, outError) == null) { return null; } } else if (tagName.equals(TAG_ORIGINAL_PACKAGE)) { //... XmlUtils.skipCurrentTag(parser); } else if (tagName.equals(TAG_ADOPT_PERMISSIONS)) { //... XmlUtils.skipCurrentTag(parser); } else if (tagName.equals(TAG_USES_GL_TEXTURE)) { // Just skip this tag XmlUtils.skipCurrentTag(parser); continue; } else if (tagName.equals(TAG_COMPATIBLE_SCREENS)) { // Just skip this tag XmlUtils.skipCurrentTag(parser); continue; } else if (tagName.equals(TAG_SUPPORTS_INPUT)) {// XmlUtils.skipCurrentTag(parser); continue; } else if (tagName.equals(TAG_EAT_COMMENT)) { // Just skip this tag XmlUtils.skipCurrentTag(parser); continue; } else if (tagName.equals(TAG_PACKAGE)) { if (!MULTI_PACKAGE_APK_ENABLED) { XmlUtils.skipCurrentTag(parser); continue; } if (!parseBaseApkChild(pkg, res, parser, flags, outError)) { // If parsing a child failed the error is already set return null; } } else if (tagName.equals(TAG_RESTRICT_UPDATE)) { //... XmlUtils.skipCurrentTag(parser); } else if (RIGID_PARSER) { outError[0] = "Bad element under <manifest>: " + parser.getName(); mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return null; } else { Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName() + " at " + mArchiveSourcePath + " " + parser.getPositionDescription()); XmlUtils.skipCurrentTag(parser); continue; } } //... return pkg; }
可以看到,parsePackage方法的主要作用其实就是对AndroidManifest.xml配置文件中manifest下的每个子节点进行解析,这里主要来看看parseActivity方法是如何对activity节点进行解析的:
private Activity parseActivity(Package owner, Resources res, XmlResourceParser parser, int flags, String[] outError, boolean receiver, boolean hardwareAccelerated) throws XmlPullParserException, IOException { TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestActivity); if (mParseActivityArgs == null) { mParseActivityArgs = new ParseComponentArgs(owner, outError, R.styleable.AndroidManifestActivity_name, R.styleable.AndroidManifestActivity_label, R.styleable.AndroidManifestActivity_icon, R.styleable.AndroidManifestActivity_roundIcon, R.styleable.AndroidManifestActivity_logo, R.styleable.AndroidManifestActivity_banner, mSeparateProcesses, R.styleable.AndroidManifestActivity_process, R.styleable.AndroidManifestActivity_description, R.styleable.AndroidManifestActivity_enabled); } mParseActivityArgs.tag = receiver ? "<receiver>" : "<activity>"; mParseActivityArgs.sa = sa; mParseActivityArgs.flags = flags; Activity a = new Activity(mParseActivityArgs, new ActivityInfo()); if (outError[0] != null) { sa.recycle(); return null; } boolean setExported = sa.hasValue(R.styleable.AndroidManifestActivity_exported); if (setExported) { a.info.exported = sa.getBoolean(R.styleable.AndroidManifestActivity_exported, false); } a.info.theme = sa.getResourceId(R.styleable.AndroidManifestActivity_theme, 0); a.info.uiOptions = sa.getInt(R.styleable.AndroidManifestActivity_uiOptions, a.info.applicationInfo.uiOptions); String parentName = sa.getNonConfigurationString( R.styleable.AndroidManifestActivity_parentActivityName, Configuration.NATIVE_CONFIG_VERSION); if (parentName != null) { String parentClassName = buildClassName(a.info.packageName, parentName, outError); if (outError[0] == null) { a.info.parentActivityName = parentClassName; } else { Log.e(TAG, "Activity " + a.info.name + " specified invalid parentActivityName " + parentName); outError[0] = null; } } String str; str = sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_permission, 0); if (str == null) { a.info.permission = owner.applicationInfo.permission; } else { a.info.permission = str.length() > 0 ? str.toString().intern() : null; } str = sa.getNonConfigurationString( R.styleable.AndroidManifestActivity_taskAffinity, Configuration.NATIVE_CONFIG_VERSION); a.info.taskAffinity = buildTaskAffinityName(owner.applicationInfo.packageName, owner.applicationInfo.taskAffinity, str, outError); a.info.flags = 0; if (sa.getBoolean( R.styleable.AndroidManifestActivity_multiprocess, false)) { a.info.flags |= ActivityInfo.FLAG_MULTIPROCESS; } if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnTaskLaunch, false)) { a.info.flags |= ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH; } if (sa.getBoolean(R.styleable.AndroidManifestActivity_clearTaskOnLaunch, false)) { a.info.flags |= ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH; } if (sa.getBoolean(R.styleable.AndroidManifestActivity_noHistory, false)) { a.info.flags |= ActivityInfo.FLAG_NO_HISTORY; } if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysRetainTaskState, false)) { a.info.flags |= ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE; } if (sa.getBoolean(R.styleable.AndroidManifestActivity_stateNotNeeded, false)) { a.info.flags |= ActivityInfo.FLAG_STATE_NOT_NEEDED; } if (sa.getBoolean(R.styleable.AndroidManifestActivity_excludeFromRecents, false)) { a.info.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS; } if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowTaskReparenting, (owner.applicationInfo.flags&ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING) != 0)) { a.info.flags |= ActivityInfo.FLAG_ALLOW_TASK_REPARENTING; } if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnCloseSystemDialogs, false)) { a.info.flags |= ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS; } if (sa.getBoolean(R.styleable.AndroidManifestActivity_showOnLockScreen, false) || sa.getBoolean(R.styleable.AndroidManifestActivity_showForAllUsers, false)) { a.info.flags |= ActivityInfo.FLAG_SHOW_FOR_ALL_USERS; } if (sa.getBoolean(R.styleable.AndroidManifestActivity_immersive, false)) { a.info.flags |= ActivityInfo.FLAG_IMMERSIVE; } if (sa.getBoolean(R.styleable.AndroidManifestActivity_systemUserOnly, false)) { a.info.flags |= ActivityInfo.FLAG_SYSTEM_USER_ONLY; } if (!receiver) { if (sa.getBoolean(R.styleable.AndroidManifestActivity_hardwareAccelerated, hardwareAccelerated)) { a.info.flags |= ActivityInfo.FLAG_HARDWARE_ACCELERATED; } a.info.launchMode = sa.getInt( R.styleable.AndroidManifestActivity_launchMode, ActivityInfo.LAUNCH_MULTIPLE); a.info.documentLaunchMode = sa.getInt( R.styleable.AndroidManifestActivity_documentLaunchMode, ActivityInfo.DOCUMENT_LAUNCH_NONE); a.info.maxRecents = sa.getInt( R.styleable.AndroidManifestActivity_maxRecents, ActivityManager.getDefaultAppRecentsLimitStatic()); a.info.configChanges = sa.getInt(R.styleable.AndroidManifestActivity_configChanges, 0); a.info.softInputMode = sa.getInt( R.styleable.AndroidManifestActivity_windowSoftInputMode, 0); a.info.persistableMode = sa.getInteger( R.styleable.AndroidManifestActivity_persistableMode, ActivityInfo.PERSIST_ROOT_ONLY); if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowEmbedded, false)) { a.info.flags |= ActivityInfo.FLAG_ALLOW_EMBEDDED; } if (sa.getBoolean(R.styleable.AndroidManifestActivity_autoRemoveFromRecents, false)) { a.info.flags |= ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS; } if (sa.getBoolean(R.styleable.AndroidManifestActivity_relinquishTaskIdentity, false)) { a.info.flags |= ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY; } if (sa.getBoolean(R.styleable.AndroidManifestActivity_resumeWhilePausing, false)) { a.info.flags |= ActivityInfo.FLAG_RESUME_WHILE_PAUSING; } a.info.screenOrientation = sa.getInt( R.styleable.AndroidManifestActivity_screenOrientation, SCREEN_ORIENTATION_UNSPECIFIED); a.info.resizeMode = RESIZE_MODE_UNRESIZEABLE; final boolean appDefault = (owner.applicationInfo.privateFlags & PRIVATE_FLAG_RESIZEABLE_ACTIVITIES) != 0; // This flag is used to workaround the issue with ignored resizeableActivity param when // either targetSdkVersion is not set at all or <uses-sdk> tag is below <application> // tag in AndroidManifest. If this param was explicitly set to 'false' we need to set // corresponding resizeMode regardless of targetSdkVersion value at this point in time. final boolean resizeableSetExplicitly = sa.hasValue(R.styleable.AndroidManifestActivity_resizeableActivity); final boolean resizeable = sa.getBoolean( R.styleable.AndroidManifestActivity_resizeableActivity, appDefault); if (resizeable) { if (sa.getBoolean(R.styleable.AndroidManifestActivity_supportsPictureInPicture, false)) { a.info.resizeMode = RESIZE_MODE_RESIZEABLE_AND_PIPABLE; } else { a.info.resizeMode = RESIZE_MODE_RESIZEABLE; } } else if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N || resizeableSetExplicitly) { a.info.resizeMode = RESIZE_MODE_UNRESIZEABLE; } else if (!a.info.isFixedOrientation() && (a.info.flags & FLAG_IMMERSIVE) == 0) { a.info.resizeMode = RESIZE_MODE_FORCE_RESIZEABLE; } if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysFocusable, false)) { a.info.flags |= FLAG_ALWAYS_FOCUSABLE; } a.info.lockTaskLaunchMode = sa.getInt(R.styleable.AndroidManifestActivity_lockTaskMode, 0); a.info.encryptionAware = a.info.directBootAware = sa.getBoolean( R.styleable.AndroidManifestActivity_directBootAware, false); a.info.requestedVrComponent = sa.getString(R.styleable.AndroidManifestActivity_enableVrMode); } else { a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE; a.info.configChanges = 0; if (sa.getBoolean(R.styleable.AndroidManifestActivity_singleUser, false)) { a.info.flags |= ActivityInfo.FLAG_SINGLE_USER; if (a.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) { Slog.w(TAG, "Activity exported request ignored due to singleUser: " + a.className + " at " + mArchiveSourcePath + " " + parser.getPositionDescription()); a.info.exported = false; setExported = true; } } a.info.encryptionAware = a.info.directBootAware = sa.getBoolean( R.styleable.AndroidManifestActivity_directBootAware, false); } if (a.info.directBootAware) { owner.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE; } sa.recycle(); if (receiver && (owner.applicationInfo.privateFlags &ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) { // A heavy-weight application can not have receives in its main process // We can do direct compare because we intern all strings. if (a.info.processName == owner.packageName) { outError[0] = "Heavy-weight applications can not have receivers in main process"; } } if (outError[0] != null) { return null; } int outerDepth = parser.getDepth(); int type; while ((type=parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { continue; } if (parser.getName().equals("intent-filter")) { ActivityIntentInfo intent = new ActivityIntentInfo(a); if (!parseIntent(res, parser, true, true, intent, outError)) { return null; } if (intent.countActions() == 0) { Slog.w(TAG, "No actions in intent filter at " + mArchiveSourcePath + " " + parser.getPositionDescription()); } else { a.intents.add(intent); } } else if (!receiver && parser.getName().equals("preferred")) { ActivityIntentInfo intent = new ActivityIntentInfo(a); if (!parseIntent(res, parser, false, false, intent, outError)) { return null; } if (intent.countActions() == 0) { Slog.w(TAG, "No actions in preferred at " + mArchiveSourcePath + " " + parser.getPositionDescription()); } else { if (owner.preferredActivityFilters == null) { owner.preferredActivityFilters = new ArrayList<ActivityIntentInfo>(); } owner.preferredActivityFilters.add(intent); } } else if (parser.getName().equals("meta-data")) { if ((a.metaData = parseMetaData(res, parser, a.metaData, outError)) == null) { return null; } } else if (!receiver && parser.getName().equals("layout")) { parseLayout(res, parser, a); } else { if (!RIGID_PARSER) { Slog.w(TAG, "Problem in package " + mArchiveSourcePath + ":"); if (receiver) { Slog.w(TAG, "Unknown element under <receiver>: " + parser.getName() + " at " + mArchiveSourcePath + " " + parser.getPositionDescription()); } else { Slog.w(TAG, "Unknown element under <activity>: " + parser.getName() + " at " + mArchiveSourcePath + " " + parser.getPositionDescription()); } XmlUtils.skipCurrentTag(parser); continue; } else { if (receiver) { outError[0] = "Bad element under <receiver>: " + parser.getName(); } else { outError[0] = "Bad element under <activity>: " + parser.getName(); } return null; } } } if (!setExported) { a.info.exported = a.intents.size() > 0; } return a; }
小结
综上可以了解到,Android应用的AndroidManifest.xml文件是在PMS启动时,扫描Apk的过程中通过PackageParser对Apk进行解析处理。
最后,回到开始的问题,我们需要处理的是对应应用的方向,所以在解析Activity的时候,解析到a.info.screenOrientation
的时候,根据应用的packageName进行对screenOrientation赋值即可。