[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赋值即可。