Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 24bb806b authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes from topic "required-feature-tag"

* changes:
  Teach PackageManager to handle <required-(not-)feature>
  Teach appt2 to handle <required-(not-)feature>
parents b522c02e 48e47d1a
Loading
Loading
Loading
Loading
+93 −15
Original line number Diff line number Diff line
@@ -1080,14 +1080,57 @@ public class ParsingPackageUtils {
                }
            }

            final String requiredFeature = sa.getNonConfigurationString(
                    R.styleable.AndroidManifestUsesPermission_requiredFeature, 0);
            final ArraySet<String> requiredFeatures = new ArraySet<>();
            String feature = sa.getNonConfigurationString(
                    com.android.internal.R.styleable.AndroidManifestUsesPermission_requiredFeature,
                    0);
            if (feature != null) {
                requiredFeatures.add(feature);
            }

            final String requiredNotfeature = sa.getNonConfigurationString(
                    R.styleable.AndroidManifestUsesPermission_requiredNotFeature,
            final ArraySet<String> requiredNotFeatures = new ArraySet<>();
            feature = sa.getNonConfigurationString(
                    com.android.internal.R.styleable
                            .AndroidManifestUsesPermission_requiredNotFeature,
                    0);
            if (feature != null) {
                requiredNotFeatures.add(feature);
            }

            XmlUtils.skipCurrentTag(parser);
            final 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;
                }

                final ParseResult<?> result;
                switch (parser.getName()) {
                    case "required-feature":
                        result = parseRequiredFeature(input, res, parser);
                        if (result.isSuccess()) {
                            requiredFeatures.add((String) result.getResult());
                        }
                        break;

                    case "required-not-feature":
                        result = parseRequiredNotFeature(input, res, parser);
                        if (result.isSuccess()) {
                            requiredNotFeatures.add((String) result.getResult());
                        }
                        break;

                    default:
                        result = ParsingUtils.unknownTag("<uses-permission>", pkg, parser, input);
                        break;
                }

                if (result.isError()) {
                    return input.error(result);
                }
            }

            // Can only succeed from here on out
            ParseResult<ParsingPackage> success = input.success(pkg);
@@ -1100,18 +1143,23 @@ public class ParsingPackageUtils {
                return success;
            }

            // Only allow requesting this permission if the platform supports the given feature.
            if (requiredFeature != null && mCallback != null && !mCallback.hasFeature(
                    requiredFeature)) {
            if (mCallback != null) {
                // Only allow requesting this permission if the platform supports all of the
                // "required-feature"s.
                for (int i = requiredFeatures.size() - 1; i >= 0; i--) {
                    if (!mCallback.hasFeature(requiredFeatures.valueAt(i))) {
                        return success;
                    }
                }

            // Only allow requesting this permission if the platform doesn't support the given
            // feature.
            if (requiredNotfeature != null && mCallback != null
                    && mCallback.hasFeature(requiredNotfeature)) {
                // Only allow requesting this permission if the platform does not supports any of
                // the "required-not-feature"s.
                for (int i = requiredNotFeatures.size() - 1; i >= 0; i--) {
                    if (mCallback.hasFeature(requiredNotFeatures.valueAt(i))) {
                        return success;
                    }
                }
            }

            if (!pkg.getRequestedPermissions().contains(name)) {
                pkg.addRequestedPermission(name.intern());
@@ -1127,6 +1175,36 @@ public class ParsingPackageUtils {
        }
    }

    private ParseResult<String> parseRequiredFeature(ParseInput input, Resources res,
            AttributeSet attrs) {
        final TypedArray sa = res.obtainAttributes(attrs,
                com.android.internal.R.styleable.AndroidManifestRequiredFeature);
        try {
            final String featureName = sa.getString(
                    R.styleable.AndroidManifestRequiredFeature_name);
            return TextUtils.isEmpty(featureName)
                    ? input.error("Feature name is missing from <required-feature> tag.")
                    : input.success(featureName);
        } finally {
            sa.recycle();
        }
    }

    private ParseResult<String> parseRequiredNotFeature(ParseInput input, Resources res,
            AttributeSet attrs) {
        final TypedArray sa = res.obtainAttributes(attrs,
                com.android.internal.R.styleable.AndroidManifestRequiredNotFeature);
        try {
            final String featureName = sa.getString(
                    R.styleable.AndroidManifestRequiredNotFeature_name);
            return TextUtils.isEmpty(featureName)
                    ? input.error("Feature name is missing from <required-not-feature> tag.")
                    : input.success(featureName);
        } finally {
            sa.recycle();
        }
    }

    private static ParseResult<ParsingPackage> parseUsesConfiguration(ParseInput input,
            ParsingPackage pkg, Resources res, XmlResourceParser parser) {
        ConfigurationInfo cPref = new ConfigurationInfo();
+16 −0
Original line number Diff line number Diff line
@@ -2016,6 +2016,22 @@
        <attr name="requiredNotFeature" format="string" />
    </declare-styleable>

    <!-- <code>required-feature</code> and <code>required-not-feature</code> elements inside
         <code>uses-permission<code/> can be used to request the permission based on the fact
         whether the system supports or does not support certain features.
         If multiple <code>required-feature</code> and/or <code>required-not-feature</code> elements
         are present, the permission will be “requested” only if the system supports all of the
         listed "required-features" and does not support any of the "required-not-features".
         -->
    <declare-styleable name="AndroidManifestRequiredFeature">
        <!-- The name of the feature. -->
        <attr name="name" />
    </declare-styleable>
    <declare-styleable name="AndroidManifestRequiredNotFeature">
        <!-- The name of the feature. -->
        <attr name="name" />
    </declare-styleable>

    <!-- The <code>uses-configuration</code> tag specifies
         a specific hardware configuration value used by the application.
         For example an application might specify that it requires
+120 −77
Original line number Diff line number Diff line
@@ -1063,17 +1063,23 @@ class UsesPermission : public ManifestExtractor::Element {
 public:
  UsesPermission() = default;
  std::string name;
  std::string requiredFeature;
  std::string requiredNotFeature;
  std::vector<std::string> requiredFeatures;
  std::vector<std::string> requiredNotFeatures;
  int32_t required = true;
  int32_t maxSdkVersion = -1;

  void Extract(xml::Element* element) override {
    name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
    requiredFeature = GetAttributeStringDefault(
        FindAttribute(element, REQUIRED_FEATURE_ATTR), "");
    requiredNotFeature = GetAttributeStringDefault(
        FindAttribute(element, REQUIRED_NOT_FEATURE_ATTR), "");
    std::string feature =
        GetAttributeStringDefault(FindAttribute(element, REQUIRED_FEATURE_ATTR), "");
    if (!feature.empty()) {
      requiredFeatures.push_back(feature);
    }
    feature = GetAttributeStringDefault(FindAttribute(element, REQUIRED_NOT_FEATURE_ATTR), "");
    if (!feature.empty()) {
      requiredNotFeatures.push_back(feature);
    }

    required = GetAttributeIntegerDefault(FindAttribute(element, REQUIRED_ATTR), 1);
    maxSdkVersion = GetAttributeIntegerDefault(
        FindAttribute(element, MAX_SDK_VERSION_ATTR), -1);
@@ -1090,13 +1096,13 @@ class UsesPermission : public ManifestExtractor::Element {
      if (maxSdkVersion >= 0) {
        printer->Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion));
      }
      if (!requiredFeature.empty()) {
        printer->Print(StringPrintf(" requiredFeature='%s'", requiredFeature.data()));
      printer->Print("\n");
      for (const std::string& requiredFeature : requiredFeatures) {
        printer->Print(StringPrintf("  required-feature='%s'\n", requiredFeature.data()));
      }
      if (!requiredNotFeature.empty()) {
        printer->Print(StringPrintf(" requiredNotFeature='%s'", requiredNotFeature.data()));
      for (const std::string& requiredNotFeature : requiredNotFeatures) {
        printer->Print(StringPrintf("  required-not-feature='%s'\n", requiredNotFeature.data()));
      }
      printer->Print("\n");
      if (required == 0) {
        printer->Print(StringPrintf("optional-permission: name='%s'", name.data()));
        if (maxSdkVersion >= 0) {
@@ -1116,6 +1122,38 @@ class UsesPermission : public ManifestExtractor::Element {
  }
};

/** Represents <required-feature> elements. **/
class RequiredFeature : public ManifestExtractor::Element {
 public:
  RequiredFeature() = default;
  std::string name;

  void Extract(xml::Element* element) override {
    name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
    auto parent_stack = extractor()->parent_stack();
    if (!name.empty() && ElementCast<UsesPermission>(parent_stack[0])) {
      UsesPermission* uses_permission = ElementCast<UsesPermission>(parent_stack[0]);
      uses_permission->requiredFeatures.push_back(name);
    }
  }
};

/** Represents <required-not-feature> elements. **/
class RequiredNotFeature : public ManifestExtractor::Element {
 public:
  RequiredNotFeature() = default;
  std::string name;

  void Extract(xml::Element* element) override {
    name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
    auto parent_stack = extractor()->parent_stack();
    if (!name.empty() && ElementCast<UsesPermission>(parent_stack[0])) {
      UsesPermission* uses_permission = ElementCast<UsesPermission>(parent_stack[0]);
      uses_permission->requiredNotFeatures.push_back(name);
    }
  }
};

/** Represents <uses-permission-sdk-23> elements. **/
class UsesPermissionSdk23 : public ManifestExtractor::Element {
 public:
@@ -1845,7 +1883,8 @@ bool ManifestExtractor::Dump(text::Printer* printer, IDiagnostics* diag) {
      for (xml::Element* child : element->GetChildElements()) {
        if (child->name == "uses-permission" || child->name == "uses-permission-sdk-23"
            || child->name == "permission") {
          auto permission_element = ManifestExtractor::Element::Inflate(this, child);
          // Inflate the element and its descendants
          auto permission_element = Visit(child);
          manifest->AddChild(permission_element);
        }
      }
@@ -2239,6 +2278,7 @@ T* ElementCast(ManifestExtractor::Element* element) {
  const std::unordered_map<std::string, bool> kTagCheck = {
      {"action", std::is_base_of<Action, T>::value},
      {"activity", std::is_base_of<Activity, T>::value},
      {"additional-certificate", std::is_base_of<AdditionalCertificate, T>::value},
      {"application", std::is_base_of<Application, T>::value},
      {"category", std::is_base_of<Category, T>::value},
      {"compatible-screens", std::is_base_of<CompatibleScreens, T>::value},
@@ -2253,22 +2293,23 @@ T* ElementCast(ManifestExtractor::Element* element) {
      {"permission", std::is_base_of<Permission, T>::value},
      {"provider", std::is_base_of<Provider, T>::value},
      {"receiver", std::is_base_of<Receiver, T>::value},
      {"required-feature", std::is_base_of<RequiredFeature, T>::value},
      {"required-not-feature", std::is_base_of<RequiredNotFeature, T>::value},
      {"screen", std::is_base_of<Screen, T>::value},
      {"service", std::is_base_of<Service, T>::value},
      {"static-library", std::is_base_of<StaticLibrary, T>::value},
      {"supports-gl-texture", std::is_base_of<SupportsGlTexture, T>::value},
      {"supports-input", std::is_base_of<SupportsInput, T>::value},
      {"supports-screens", std::is_base_of<SupportsScreen, T>::value},
      {"uses-configuration", std::is_base_of<UsesConfiguarion, T>::value},
      {"uses-feature", std::is_base_of<UsesFeature, T>::value},
    {"uses-permission", std::is_base_of<UsesPermission, T>::value},
    {"uses-permission-sdk-23", std::is_base_of<UsesPermissionSdk23, T>::value},
      {"uses-library", std::is_base_of<UsesLibrary, T>::value},
      {"uses-native-library", std::is_base_of<UsesNativeLibrary, T>::value},
      {"uses-package", std::is_base_of<UsesPackage, T>::value},
    {"static-library", std::is_base_of<StaticLibrary, T>::value},
    {"uses-static-library", std::is_base_of<UsesStaticLibrary, T>::value},
    {"additional-certificate", std::is_base_of<AdditionalCertificate, T>::value},
      {"uses-permission", std::is_base_of<UsesPermission, T>::value},
      {"uses-permission-sdk-23", std::is_base_of<UsesPermissionSdk23, T>::value},
      {"uses-sdk", std::is_base_of<UsesSdkBadging, T>::value},
    {"uses-native-library", std::is_base_of<UsesNativeLibrary, T>::value},
      {"uses-static-library", std::is_base_of<UsesStaticLibrary, T>::value},
  };

  auto check = kTagCheck.find(element->tag());
@@ -2290,6 +2331,7 @@ std::unique_ptr<ManifestExtractor::Element> ManifestExtractor::Element::Inflate(
      kTagCheck = {
          {"action", &CreateType<Action>},
          {"activity", &CreateType<Activity>},
          {"additional-certificate", &CreateType<AdditionalCertificate>},
          {"application", &CreateType<Application>},
          {"category", &CreateType<Category>},
          {"compatible-screens", &CreateType<CompatibleScreens>},
@@ -2304,22 +2346,23 @@ std::unique_ptr<ManifestExtractor::Element> ManifestExtractor::Element::Inflate(
          {"permission", &CreateType<Permission>},
          {"provider", &CreateType<Provider>},
          {"receiver", &CreateType<Receiver>},
          {"required-feature", &CreateType<RequiredFeature>},
          {"required-not-feature", &CreateType<RequiredNotFeature>},
          {"screen", &CreateType<Screen>},
          {"service", &CreateType<Service>},
          {"static-library", &CreateType<StaticLibrary>},
          {"supports-gl-texture", &CreateType<SupportsGlTexture>},
          {"supports-input", &CreateType<SupportsInput>},
          {"supports-screens", &CreateType<SupportsScreen>},
          {"uses-configuration", &CreateType<UsesConfiguarion>},
          {"uses-feature", &CreateType<UsesFeature>},
    {"uses-permission", &CreateType<UsesPermission>},
    {"uses-permission-sdk-23", &CreateType<UsesPermissionSdk23>},
          {"uses-library", &CreateType<UsesLibrary>},
    {"static-library", &CreateType<StaticLibrary>},
    {"uses-static-library", &CreateType<UsesStaticLibrary>},
          {"uses-native-library", &CreateType<UsesNativeLibrary>},
          {"uses-package", &CreateType<UsesPackage>},
    {"additional-certificate", &CreateType<AdditionalCertificate>},
          {"uses-permission", &CreateType<UsesPermission>},
          {"uses-permission-sdk-23", &CreateType<UsesPermissionSdk23>},
          {"uses-sdk", &CreateType<UsesSdkBadging>},
    {"uses-native-library", &CreateType<UsesNativeLibrary>},
          {"uses-static-library", &CreateType<UsesStaticLibrary>},
      };

  // Attempt to map the xml tag to a element inflater
+2 −0
Original line number Diff line number Diff line
@@ -393,6 +393,8 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor,
  manifest_action["protected-broadcast"];
  manifest_action["adopt-permissions"];
  manifest_action["uses-permission"];
  manifest_action["uses-permission"]["required-feature"].Action(RequiredNameIsNotEmpty);
  manifest_action["uses-permission"]["required-not-feature"].Action(RequiredNameIsNotEmpty);
  manifest_action["uses-permission-sdk-23"];
  manifest_action["permission"];
  manifest_action["permission"]["meta-data"] = meta_data_action;