xref: /aosp_15_r20/frameworks/base/tools/aapt2/link/FeatureFlagsFilter.h (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1 /*
2  * Copyright 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <optional>
20 #include <string>
21 #include <unordered_map>
22 #include <utility>
23 
24 #include "android-base/macros.h"
25 #include "cmd/Util.h"
26 #include "process/IResourceTableConsumer.h"
27 
28 namespace aapt {
29 
30 struct FeatureFlagsFilterOptions {
31   // If true, elements whose featureFlag values are false (i.e., disabled feature) will be removed.
32   bool remove_disabled_elements = true;
33 
34   // If true, `Consume()` will return false (error) if a flag was found that is not in
35   // `feature_flag_values`.
36   bool fail_on_unrecognized_flags = true;
37 
38   // If true, `Consume()` will return false (error) if a flag was found whose value in
39   // `feature_flag_values` is not defined (std::nullopt).
40   bool flags_must_have_value = true;
41 
42   // If true, `Consume()` will return false (error) if a flag was found whose value in
43   // `feature_flag_values` is not readonly.
44   bool flags_must_be_readonly = false;
45 };
46 
47 // Looks for the `android:featureFlag` attribute in each XML element, validates the flag names and
48 // values, and removes elements according to the values in `feature_flag_values`. An element will be
49 // removed if the flag's given value is FALSE. A "!" before the flag name in the attribute indicates
50 // a boolean NOT operation, i.e., an element will be removed if the flag's given value is TRUE. For
51 // example, if the XML is the following:
52 //
53 //   <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android">
54 //     <permission android:name="FOO" android:featureFlag="!flag"
55 //                 android:protectionLevel="normal" />
56 //     <permission android:name="FOO" android:featureFlag="flag"
57 //                 android:protectionLevel="dangerous" />
58 //   </manifest>
59 //
60 // If `feature_flag_values` contains {"flag", true}, then the <permission> element with
61 // protectionLevel="normal" will be removed, and the <permission> element with
62 // protectionLevel="normal" will be kept.
63 //
64 // The `Consume()` function will return false if there is an invalid flag found (see
65 // FeatureFlagsFilterOptions for customizing the filter's validation behavior). Do not use the XML
66 // further if there are errors as there may be elements removed already.
67 class FeatureFlagsFilter : public IXmlResourceConsumer {
68  public:
FeatureFlagsFilter(FeatureFlagValues feature_flag_values,FeatureFlagsFilterOptions options)69   explicit FeatureFlagsFilter(FeatureFlagValues feature_flag_values,
70                               FeatureFlagsFilterOptions options)
71       : feature_flag_values_(std::move(feature_flag_values)), options_(options) {
72   }
73 
74   bool Consume(IAaptContext* context, xml::XmlResource* doc) override;
75 
76  private:
77   DISALLOW_COPY_AND_ASSIGN(FeatureFlagsFilter);
78 
79   const FeatureFlagValues feature_flag_values_;
80   const FeatureFlagsFilterOptions options_;
81 };
82 
83 }  // namespace aapt
84