OSDN Git Service

Merge "Allow max aspect ratio to be specified by meta-data tag." into oc-dr1-dev...
authorBryce Lee <brycelee@google.com>
Thu, 13 Jul 2017 17:55:05 +0000 (17:55 +0000)
committerandroid-build-merger <android-build-merger@google.com>
Thu, 13 Jul 2017 17:55:05 +0000 (17:55 +0000)
am: d0bc21efd5

Change-Id: Idf2bfb1d6c2b70a53ebe46df300be6fe3fce3258

1  2 
core/java/android/content/pm/PackageParser.java

@@@ -27,9 -27,9 +27,9 @@@ import static android.content.pm.Activi
  import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
  import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
  import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED;
 -import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE;
  import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE;
  import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
 +import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE;
  import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
  import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
  import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING;
@@@ -50,9 -50,9 +50,9 @@@ import android.app.ActivityManager
  import android.content.ComponentName;
  import android.content.Intent;
  import android.content.IntentFilter;
 +import android.content.pm.split.DefaultSplitAssetLoader;
  import android.content.pm.split.SplitAssetDependencyLoader;
  import android.content.pm.split.SplitAssetLoader;
 -import android.content.pm.split.DefaultSplitAssetLoader;
  import android.content.res.AssetManager;
  import android.content.res.Configuration;
  import android.content.res.Resources;
@@@ -88,7 -88,6 +88,7 @@@ import android.view.Gravity
  
  import com.android.internal.R;
  import com.android.internal.annotations.VisibleForTesting;
 +import com.android.internal.os.ClassLoaderFactory;
  import com.android.internal.util.ArrayUtils;
  import com.android.internal.util.XmlUtils;
  
@@@ -149,9 -148,8 +149,9 @@@ public class PackageParser 
      private static final String PROPERTY_CHILD_PACKAGES_ENABLED =
              "persist.sys.child_packages_enabled";
  
 +    // TODO: Decide the correct default before O-MR1.
      private static final boolean MULTI_PACKAGE_APK_ENABLED = Build.IS_DEBUGGABLE &&
 -            SystemProperties.getBoolean(PROPERTY_CHILD_PACKAGES_ENABLED, false);
 +            SystemProperties.getBoolean(PROPERTY_CHILD_PACKAGES_ENABLED, true);
  
      private static final int MAX_PACKAGES_PER_APK = 5;
  
      // Temporary workaround; allow meta-data to expose components to instant apps
      private static final String META_DATA_INSTANT_APPS = "instantapps.clients.allowed";
  
+     private static final String METADATA_MAX_ASPECT_RATIO = "android.max_aspect";
      /**
       * Bit mask of all the valid bits that can be set in recreateOnConfigChanges.
       * @hide
          public final boolean extractNativeLibs;
          public final boolean isolatedSplits;
  
 +        public final String classLoaderName;
 +        public final String[] splitClassLoaderNames;
 +
          public PackageLite(String codePath, ApkLite baseApk, String[] splitNames,
                  boolean[] isFeatureSplits, String[] usesSplitNames, String[] configForSplit,
 -                String[] splitCodePaths, int[] splitRevisionCodes) {
 +                String[] splitCodePaths, int[] splitRevisionCodes, String[] splitClassLoaderNames) {
              this.packageName = baseApk.packageName;
              this.versionCode = baseApk.versionCode;
              this.installLocation = baseApk.installLocation;
              this.use32bitAbi = baseApk.use32bitAbi;
              this.extractNativeLibs = baseApk.extractNativeLibs;
              this.isolatedSplits = baseApk.isolatedSplits;
 +
 +            this.classLoaderName = baseApk.classLoaderName;
 +            this.splitClassLoaderNames = splitClassLoaderNames;
          }
  
          public List<String> getAllCodePaths() {
          public final boolean use32bitAbi;
          public final boolean extractNativeLibs;
          public final boolean isolatedSplits;
 +        public final String classLoaderName;
  
          public ApkLite(String codePath, String packageName, String splitName, boolean isFeatureSplit,
                  String configForSplit, String usesSplitName, int versionCode, int revisionCode,
                  int installLocation, List<VerifierInfo> verifiers, Signature[] signatures,
                  Certificate[][] certificates, boolean coreApp, boolean debuggable,
                  boolean multiArch, boolean use32bitAbi, boolean extractNativeLibs,
 -                boolean isolatedSplits) {
 +                boolean isolatedSplits, String classLoaderName) {
              this.codePath = codePath;
              this.packageName = packageName;
              this.splitName = splitName;
              this.use32bitAbi = use32bitAbi;
              this.extractNativeLibs = extractNativeLibs;
              this.isolatedSplits = isolatedSplits;
 +            this.classLoaderName = classLoaderName;
          }
      }
  
 +    /**
 +     * Cached parse state for new components.
 +     *
 +     * Allows reuse of the same parse argument records to avoid GC pressure.  Lifetime is carefully
 +     * scoped to the parsing of a single application element.
 +     */
 +    private static class CachedComponentArgs {
 +        ParseComponentArgs mActivityArgs;
 +        ParseComponentArgs mActivityAliasArgs;
 +        ParseComponentArgs mServiceArgs;
 +        ParseComponentArgs mProviderArgs;
 +    }
 +
 +    /**
 +     * Cached state for parsing instrumentation to avoid GC pressure.
 +     *
 +     * Must be manually reset to null for each new manifest.
 +     */
      private ParsePackageItemArgs mParseInstrumentationArgs;
 -    private ParseComponentArgs mParseActivityArgs;
 -    private ParseComponentArgs mParseActivityAliasArgs;
 -    private ParseComponentArgs mParseServiceArgs;
 -    private ParseComponentArgs mParseProviderArgs;
  
      /** If set to true, we will only allow package files that exactly match
       *  the DTD.  Otherwise, we try to get as much from the package as we
          final ApkLite baseApk = parseApkLite(packageFile, flags);
          final String packagePath = packageFile.getAbsolutePath();
          Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
 -        return new PackageLite(packagePath, baseApk, null, null, null, null, null, null);
 +        return new PackageLite(packagePath, baseApk, null, null, null, null, null, null, null);
      }
  
      static PackageLite parseClusterPackageLite(File packageDir, int flags)
          String[] configForSplits = null;
          String[] splitCodePaths = null;
          int[] splitRevisionCodes = null;
 +        String[] splitClassLoaderNames = null;
          if (size > 0) {
              splitNames = new String[size];
              isFeatureSplits = new boolean[size];
              configForSplits = new String[size];
              splitCodePaths = new String[size];
              splitRevisionCodes = new int[size];
 +            splitClassLoaderNames = new String[size];
  
              splitNames = apks.keySet().toArray(splitNames);
              Arrays.sort(splitNames, sSplitNameComparator);
                  configForSplits[i] = apk.configForSplit;
                  splitCodePaths[i] = apk.codePath;
                  splitRevisionCodes[i] = apk.revisionCode;
 +                splitClassLoaderNames[i] = apk.classLoaderName;
              }
          }
  
          final String codePath = packageDir.getAbsolutePath();
          return new PackageLite(codePath, baseApk, splitNames, isFeatureSplits, usesSplitNames,
 -                configForSplits, splitCodePaths, splitRevisionCodes);
 +                configForSplits, splitCodePaths, splitRevisionCodes, splitClassLoaderNames);
      }
  
      /**
                  pkg.splitPrivateFlags = new int[num];
                  pkg.applicationInfo.splitNames = pkg.splitNames;
                  pkg.applicationInfo.splitDependencies = splitDependencies;
 +                pkg.applicationInfo.classLoaderName = lite.classLoaderName;
 +                pkg.applicationInfo.splitClassLoaderNames = lite.splitClassLoaderNames;
  
                  for (int i = 0; i < num; i++) {
                      final AssetManager splitAssets = assetLoader.getSplitAssetManager(i);
          parsePackageSplitNames(parser, attrs);
  
          mParseInstrumentationArgs = null;
 -        mParseActivityArgs = null;
 -        mParseServiceArgs = null;
 -        mParseProviderArgs = null;
  
          int type;
  
              }
  
              final AttributeSet attrs = parser;
 -            return parseApkLite(apkPath, parser, attrs, flags, signatures, certificates);
 +            return parseApkLite(apkPath, parser, attrs, signatures, certificates);
  
          } catch (XmlPullParserException | IOException | RuntimeException e) {
              Slog.w(TAG, "Failed to parse " + apkPath, e);
      }
  
      private static ApkLite parseApkLite(String codePath, XmlPullParser parser, AttributeSet attrs,
 -            int flags, Signature[] signatures, Certificate[][] certificates)
 +            Signature[] signatures, Certificate[][] certificates)
              throws IOException, XmlPullParserException, PackageParserException {
          final Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs);
  
          boolean isFeatureSplit = false;
          String configForSplit = null;
          String usesSplitName = null;
 +        String classLoaderName = null;
  
          for (int i = 0; i < attrs.getAttributeCount(); i++) {
              final String attr = attrs.getAttributeName(i);
                      if ("extractNativeLibs".equals(attr)) {
                          extractNativeLibs = attrs.getAttributeBooleanValue(i, true);
                      }
 +                    if ("classLoader".equals(attr)) {
 +                        classLoaderName = attrs.getAttributeValue(i);
 +                        if (!ClassLoaderFactory.isValidClassLoaderName(classLoaderName)) {
 +                            throw new PackageParserException(
 +                                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
 +                                    "Invalid class loader name: " + classLoaderName);
 +                        }
 +                    }
                  }
              } else if (TAG_USES_SPLIT.equals(parser.getName())) {
                  if (usesSplitName != null) {
          return new ApkLite(codePath, packageSplit.first, packageSplit.second, isFeatureSplit,
                  configForSplit, usesSplitName, versionCode, revisionCode, installLocation,
                  verifiers, signatures, certificates, coreApp, debuggable, multiArch, use32bitAbi,
 -                extractNativeLibs, isolatedSplits);
 -    }
 -
 -    /**
 -     * Temporary.
 -     */
 -    static public Signature stringToSignature(String str) {
 -        final int N = str.length();
 -        byte[] sig = new byte[N];
 -        for (int i=0; i<N; i++) {
 -            sig[i] = (byte)str.charAt(i);
 -        }
 -        return new Signature(sig);
 +                extractNativeLibs, isolatedSplits, classLoaderName);
      }
  
      /**
              XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException,
              IOException {
          mParseInstrumentationArgs = null;
 -        mParseActivityArgs = null;
 -        mParseServiceArgs = null;
 -        mParseProviderArgs = null;
  
          int type;
          boolean foundApp = false;
          }
  
          final int innerDepth = parser.getDepth();
 +        // IMPORTANT: These must only be cached for a single <application> to avoid components
 +        // getting added to the wrong package.
 +        final CachedComponentArgs cachedArgs = new CachedComponentArgs();
          int type;
          while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                  && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
              if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
  
              String tagName = parser.getName();
              if (tagName.equals("activity")) {
 -                Activity a = parseActivity(owner, res, parser, flags, outError, false,
 +                Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs, false,
                          owner.baseHardwareAccelerated);
                  if (a == null) {
                      mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                  owner.activities.add(a);
  
              } else if (tagName.equals("receiver")) {
 -                Activity a = parseActivity(owner, res, parser, flags, outError, true, false);
 +                Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs,
 +                        true, false);
                  if (a == null) {
                      mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                      return false;
                  owner.receivers.add(a);
  
              } else if (tagName.equals("service")) {
 -                Service s = parseService(owner, res, parser, flags, outError);
 +                Service s = parseService(owner, res, parser, flags, outError, cachedArgs);
                  if (s == null) {
                      mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                      return false;
                  owner.services.add(s);
  
              } else if (tagName.equals("provider")) {
 -                Provider p = parseProvider(owner, res, parser, flags, outError);
 +                Provider p = parseProvider(owner, res, parser, flags, outError, cachedArgs);
                  if (p == null) {
                      mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                      return false;
                  owner.providers.add(p);
  
              } else if (tagName.equals("activity-alias")) {
 -                Activity a = parseActivityAlias(owner, res, parser, flags, outError);
 +                Activity a = parseActivityAlias(owner, res, parser, flags, outError, cachedArgs);
                  if (a == null) {
                      mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                      return false;
              }
          }
  
+         // Must be ran after the entire {@link ApplicationInfo} has been fully processed and after
+         // every activity info has had a chance to set it from its attributes.
+         setMaxAspectRatio(owner);
          modifySharedLibrariesForBackwardCompatibility(owner);
  
          if (hasDomainURLs(owner)) {
  
              ComponentInfo parsedComponent = null;
  
 +            // IMPORTANT: These must only be cached for a single <application> to avoid components
 +            // getting added to the wrong package.
 +            final CachedComponentArgs cachedArgs = new CachedComponentArgs();
              String tagName = parser.getName();
              if (tagName.equals("activity")) {
 -                Activity a = parseActivity(owner, res, parser, flags, outError, false,
 +                Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs, false,
                          owner.baseHardwareAccelerated);
                  if (a == null) {
                      mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                  parsedComponent = a.info;
  
              } else if (tagName.equals("receiver")) {
 -                Activity a = parseActivity(owner, res, parser, flags, outError, true, false);
 +                Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs,
 +                        true, false);
                  if (a == null) {
                      mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                      return false;
                  parsedComponent = a.info;
  
              } else if (tagName.equals("service")) {
 -                Service s = parseService(owner, res, parser, flags, outError);
 +                Service s = parseService(owner, res, parser, flags, outError, cachedArgs);
                  if (s == null) {
                      mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                      return false;
                  parsedComponent = s.info;
  
              } else if (tagName.equals("provider")) {
 -                Provider p = parseProvider(owner, res, parser, flags, outError);
 +                Provider p = parseProvider(owner, res, parser, flags, outError, cachedArgs);
                  if (p == null) {
                      mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                      return false;
                  parsedComponent = p.info;
  
              } else if (tagName.equals("activity-alias")) {
 -                Activity a = parseActivityAlias(owner, res, parser, flags, outError);
 +                Activity a = parseActivityAlias(owner, res, parser, flags, outError, cachedArgs);
                  if (a == null) {
                      mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                      return false;
      }
  
      private Activity parseActivity(Package owner, Resources res,
 -            XmlResourceParser parser, int flags, String[] outError,
 +            XmlResourceParser parser, int flags, String[] outError, CachedComponentArgs cachedArgs,
              boolean receiver, boolean hardwareAccelerated)
              throws XmlPullParserException, IOException {
          TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestActivity);
  
 -        if (mParseActivityArgs == null) {
 -            mParseActivityArgs = new ParseComponentArgs(owner, outError,
 +        if (cachedArgs.mActivityArgs == null) {
 +            cachedArgs.mActivityArgs = new ParseComponentArgs(owner, outError,
                      R.styleable.AndroidManifestActivity_name,
                      R.styleable.AndroidManifestActivity_label,
                      R.styleable.AndroidManifestActivity_icon,
                      R.styleable.AndroidManifestActivity_enabled);
          }
  
 -        mParseActivityArgs.tag = receiver ? "<receiver>" : "<activity>";
 -        mParseActivityArgs.sa = sa;
 -        mParseActivityArgs.flags = flags;
 +        cachedArgs.mActivityArgs.tag = receiver ? "<receiver>" : "<activity>";
 +        cachedArgs.mActivityArgs.sa = sa;
 +        cachedArgs.mActivityArgs.flags = flags;
  
 -        Activity a = new Activity(mParseActivityArgs, new ActivityInfo());
 +        Activity a = new Activity(cachedArgs.mActivityArgs, new ActivityInfo());
          if (outError[0] != null) {
              sa.recycle();
              return null;
                  a.info.flags |= FLAG_ALWAYS_FOCUSABLE;
              }
  
-             setActivityMaxAspectRatio(a.info, sa, owner);
+             if (sa.hasValue(R.styleable.AndroidManifestActivity_maxAspectRatio)
+                     && sa.getType(R.styleable.AndroidManifestActivity_maxAspectRatio)
+                     == TypedValue.TYPE_FLOAT) {
+                 a.setMaxAspectRatio(sa.getFloat(R.styleable.AndroidManifestActivity_maxAspectRatio,
+                         0 /*default*/));
+             }
  
              a.info.lockTaskLaunchMode =
                      sa.getInt(R.styleable.AndroidManifestActivity_lockTaskMode, 0);
  
              a.info.colorMode = sa.getInt(R.styleable.AndroidManifestActivity_colorMode,
                      ActivityInfo.COLOR_MODE_DEFAULT);
 +
 +            if (sa.getBoolean(R.styleable.AndroidManifestActivity_showWhenLocked, false)) {
 +                a.info.flags |= ActivityInfo.FLAG_SHOW_WHEN_LOCKED;
 +            }
 +
 +            if (sa.getBoolean(R.styleable.AndroidManifestActivity_turnScreenOn, false)) {
 +                a.info.flags |= ActivityInfo.FLAG_TURN_SCREEN_ON;
 +            }
 +
          } else {
              a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
              a.info.configChanges = 0;
          }
      }
  
-     private void setActivityMaxAspectRatio(ActivityInfo aInfo, TypedArray sa, Package owner) {
-         if (aInfo.resizeMode == RESIZE_MODE_RESIZEABLE
-                 || aInfo.resizeMode == RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) {
-             // Resizeable activities can be put in any aspect ratio.
-             aInfo.maxAspectRatio = 0;
-             return;
-         }
+     /**
+      * Sets every the max aspect ratio of every child activity that doesn't already have an aspect
+      * ratio set.
+      */
+     private void setMaxAspectRatio(Package owner) {
          // Default to (1.86) 16.7:9 aspect ratio for pre-O apps and unset for O and greater.
          // NOTE: 16.7:9 was the max aspect ratio Android devices can support pre-O per the CDD.
-         float defaultMaxAspectRatio = owner.applicationInfo.targetSdkVersion < O
+         float maxAspectRatio = owner.applicationInfo.targetSdkVersion < O
                  ? DEFAULT_PRE_O_MAX_ASPECT_RATIO : 0;
-         if (owner.applicationInfo.maxAspectRatio != 0 ) {
+         if (owner.applicationInfo.maxAspectRatio != 0) {
              // Use the application max aspect ration as default if set.
-             defaultMaxAspectRatio = owner.applicationInfo.maxAspectRatio;
+             maxAspectRatio = owner.applicationInfo.maxAspectRatio;
+         } else if (owner.mAppMetaData != null
+                 && owner.mAppMetaData.containsKey(METADATA_MAX_ASPECT_RATIO)) {
+             maxAspectRatio = owner.mAppMetaData.getFloat(METADATA_MAX_ASPECT_RATIO, maxAspectRatio);
          }
  
-         aInfo.maxAspectRatio = sa.getFloat(
-                 R.styleable.AndroidManifestActivity_maxAspectRatio, defaultMaxAspectRatio);
-         if (aInfo.maxAspectRatio < 1.0f && aInfo.maxAspectRatio != 0) {
-             // Ignore any value lesser than 1.0.
-             aInfo.maxAspectRatio = 0;
+         for (Activity activity : owner.activities) {
+             // If the max aspect ratio for the activity has already been set, skip.
+             if (activity.hasMaxAspectRatio()) {
+                 continue;
+             }
+             // By default we prefer to use a values defined on the activity directly than values
+             // defined on the application. We do not check the styled attributes on the activity
+             // as it would have already been set when we processed the activity. We wait to process
+             // the meta data here since this method is called at the end of processing the
+             // application and all meta data is guaranteed.
+             final float activityAspectRatio = activity.metaData != null
+                     ? activity.metaData.getFloat(METADATA_MAX_ASPECT_RATIO, maxAspectRatio)
+                     : maxAspectRatio;
+             activity.setMaxAspectRatio(activityAspectRatio);
          }
      }
  
      }
  
      private Activity parseActivityAlias(Package owner, Resources res,
 -            XmlResourceParser parser, int flags, String[] outError)
 +            XmlResourceParser parser, int flags, String[] outError,
 +            CachedComponentArgs cachedArgs)
              throws XmlPullParserException, IOException {
          TypedArray sa = res.obtainAttributes(parser,
                  com.android.internal.R.styleable.AndroidManifestActivityAlias);
              return null;
          }
  
 -        if (mParseActivityAliasArgs == null) {
 -            mParseActivityAliasArgs = new ParseComponentArgs(owner, outError,
 +        if (cachedArgs.mActivityAliasArgs == null) {
 +            cachedArgs.mActivityAliasArgs = new ParseComponentArgs(owner, outError,
                      com.android.internal.R.styleable.AndroidManifestActivityAlias_name,
                      com.android.internal.R.styleable.AndroidManifestActivityAlias_label,
                      com.android.internal.R.styleable.AndroidManifestActivityAlias_icon,
                      0,
                      com.android.internal.R.styleable.AndroidManifestActivityAlias_description,
                      com.android.internal.R.styleable.AndroidManifestActivityAlias_enabled);
 -            mParseActivityAliasArgs.tag = "<activity-alias>";
 +            cachedArgs.mActivityAliasArgs.tag = "<activity-alias>";
          }
  
 -        mParseActivityAliasArgs.sa = sa;
 -        mParseActivityAliasArgs.flags = flags;
 +        cachedArgs.mActivityAliasArgs.sa = sa;
 +        cachedArgs.mActivityAliasArgs.flags = flags;
  
          Activity target = null;
  
          info.windowLayout = target.info.windowLayout;
          info.resizeMode = target.info.resizeMode;
          info.maxAspectRatio = target.info.maxAspectRatio;
          info.encryptionAware = info.directBootAware = target.info.directBootAware;
  
 -        Activity a = new Activity(mParseActivityAliasArgs, info);
 +        Activity a = new Activity(cachedArgs.mActivityAliasArgs, info);
          if (outError[0] != null) {
              sa.recycle();
              return null;
      }
  
      private Provider parseProvider(Package owner, Resources res,
 -            XmlResourceParser parser, int flags, String[] outError)
 +            XmlResourceParser parser, int flags, String[] outError,
 +            CachedComponentArgs cachedArgs)
              throws XmlPullParserException, IOException {
          TypedArray sa = res.obtainAttributes(parser,
                  com.android.internal.R.styleable.AndroidManifestProvider);
  
 -        if (mParseProviderArgs == null) {
 -            mParseProviderArgs = new ParseComponentArgs(owner, outError,
 +        if (cachedArgs.mProviderArgs == null) {
 +            cachedArgs.mProviderArgs = new ParseComponentArgs(owner, outError,
                      com.android.internal.R.styleable.AndroidManifestProvider_name,
                      com.android.internal.R.styleable.AndroidManifestProvider_label,
                      com.android.internal.R.styleable.AndroidManifestProvider_icon,
                      com.android.internal.R.styleable.AndroidManifestProvider_process,
                      com.android.internal.R.styleable.AndroidManifestProvider_description,
                      com.android.internal.R.styleable.AndroidManifestProvider_enabled);
 -            mParseProviderArgs.tag = "<provider>";
 +            cachedArgs.mProviderArgs.tag = "<provider>";
          }
  
 -        mParseProviderArgs.sa = sa;
 -        mParseProviderArgs.flags = flags;
 +        cachedArgs.mProviderArgs.sa = sa;
 +        cachedArgs.mProviderArgs.flags = flags;
  
 -        Provider p = new Provider(mParseProviderArgs, new ProviderInfo());
 +        Provider p = new Provider(cachedArgs.mProviderArgs, new ProviderInfo());
          if (outError[0] != null) {
              sa.recycle();
              return null;
      }
  
      private Service parseService(Package owner, Resources res,
 -            XmlResourceParser parser, int flags, String[] outError)
 +            XmlResourceParser parser, int flags, String[] outError,
 +            CachedComponentArgs cachedArgs)
              throws XmlPullParserException, IOException {
          TypedArray sa = res.obtainAttributes(parser,
                  com.android.internal.R.styleable.AndroidManifestService);
  
 -        if (mParseServiceArgs == null) {
 -            mParseServiceArgs = new ParseComponentArgs(owner, outError,
 +        if (cachedArgs.mServiceArgs == null) {
 +            cachedArgs.mServiceArgs = new ParseComponentArgs(owner, outError,
                      com.android.internal.R.styleable.AndroidManifestService_name,
                      com.android.internal.R.styleable.AndroidManifestService_label,
                      com.android.internal.R.styleable.AndroidManifestService_icon,
                      com.android.internal.R.styleable.AndroidManifestService_process,
                      com.android.internal.R.styleable.AndroidManifestService_description,
                      com.android.internal.R.styleable.AndroidManifestService_enabled);
 -            mParseServiceArgs.tag = "<service>";
 +            cachedArgs.mServiceArgs.tag = "<service>";
          }
  
 -        mParseServiceArgs.sa = sa;
 -        mParseServiceArgs.flags = flags;
 +        cachedArgs.mServiceArgs.sa = sa;
 +        cachedArgs.mServiceArgs.flags = flags;
  
 -        Service s = new Service(mParseServiceArgs, new ServiceInfo());
 +        Service s = new Service(cachedArgs.mServiceArgs, new ServiceInfo());
          if (outError[0] != null) {
              sa.recycle();
              return null;
  
      public final static class Activity extends Component<ActivityIntentInfo> implements Parcelable {
          public final ActivityInfo info;
+         private boolean mHasMaxAspectRatio;
+         private boolean hasMaxAspectRatio() {
+             return mHasMaxAspectRatio;
+         }
  
          public Activity(final ParseComponentArgs args, final ActivityInfo _info) {
              super(args, _info);
              info.packageName = packageName;
          }
  
+         private void setMaxAspectRatio(float maxAspectRatio) {
+             if (info.resizeMode == RESIZE_MODE_RESIZEABLE
+                     || info.resizeMode == RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) {
+                 // Resizeable activities can be put in any aspect ratio.
+                 return;
+             }
+             if (maxAspectRatio < 1.0f && maxAspectRatio != 0) {
+                 // Ignore any value lesser than 1.0.
+                 return;
+             }
+             info.maxAspectRatio = maxAspectRatio;
+             mHasMaxAspectRatio = true;
+         }
          public String toString() {
              StringBuilder sb = new StringBuilder(128);
              sb.append("Activity{");
          public void writeToParcel(Parcel dest, int flags) {
              super.writeToParcel(dest, flags);
              dest.writeParcelable(info, flags | Parcelable.PARCELABLE_ELIDE_DUPLICATES);
+             dest.writeBoolean(mHasMaxAspectRatio);
          }
  
          private Activity(Parcel in) {
              super(in);
              info = in.readParcelable(Object.class.getClassLoader());
+             mHasMaxAspectRatio = in.readBoolean();
  
              for (ActivityIntentInfo aii : intents) {
                  aii.activity = this;