xref: /aosp_15_r20/art/libartbase/base/hiddenapi_flags.h (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2018 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #ifndef ART_LIBARTBASE_BASE_HIDDENAPI_FLAGS_H_
18*795d594fSAndroid Build Coastguard Worker #define ART_LIBARTBASE_BASE_HIDDENAPI_FLAGS_H_
19*795d594fSAndroid Build Coastguard Worker 
20*795d594fSAndroid Build Coastguard Worker #include "sdk_version.h"
21*795d594fSAndroid Build Coastguard Worker 
22*795d594fSAndroid Build Coastguard Worker #include <vector>
23*795d594fSAndroid Build Coastguard Worker 
24*795d594fSAndroid Build Coastguard Worker #include "android-base/logging.h"
25*795d594fSAndroid Build Coastguard Worker #include "base/bit_utils.h"
26*795d594fSAndroid Build Coastguard Worker #include "base/dumpable.h"
27*795d594fSAndroid Build Coastguard Worker #include "base/macros.h"
28*795d594fSAndroid Build Coastguard Worker #include "base/hiddenapi_stubs.h"
29*795d594fSAndroid Build Coastguard Worker 
30*795d594fSAndroid Build Coastguard Worker namespace art {
31*795d594fSAndroid Build Coastguard Worker namespace hiddenapi {
32*795d594fSAndroid Build Coastguard Worker 
33*795d594fSAndroid Build Coastguard Worker // Helper methods used inside ApiList. These were moved outside of the ApiList
34*795d594fSAndroid Build Coastguard Worker // class so that they can be used in static_asserts. If they were inside, they
35*795d594fSAndroid Build Coastguard Worker // would be part of an unfinished type.
36*795d594fSAndroid Build Coastguard Worker namespace helper {
37*795d594fSAndroid Build Coastguard Worker   // Casts enum value to uint32_t.
38*795d594fSAndroid Build Coastguard Worker   template<typename T>
ToUint(T val)39*795d594fSAndroid Build Coastguard Worker   constexpr uint32_t ToUint(T val) { return static_cast<uint32_t>(val); }
40*795d594fSAndroid Build Coastguard Worker 
41*795d594fSAndroid Build Coastguard Worker   // Returns uint32_t with one bit set at an index given by an enum value.
42*795d594fSAndroid Build Coastguard Worker   template<typename T>
ToBit(T val)43*795d594fSAndroid Build Coastguard Worker   constexpr uint32_t ToBit(T val) { return 1u << ToUint(val); }
44*795d594fSAndroid Build Coastguard Worker 
45*795d594fSAndroid Build Coastguard Worker   // Returns a bit mask with `size` least significant bits set.
BitMask(uint32_t size)46*795d594fSAndroid Build Coastguard Worker   constexpr uint32_t BitMask(uint32_t size) { return (1u << size) - 1; }
47*795d594fSAndroid Build Coastguard Worker 
48*795d594fSAndroid Build Coastguard Worker   // Returns a bit mask formed from an enum defining kMin and kMax. The values
49*795d594fSAndroid Build Coastguard Worker   // are assumed to be indices of min/max bits and the resulting bitmask has
50*795d594fSAndroid Build Coastguard Worker   // bits [kMin, kMax] set.
51*795d594fSAndroid Build Coastguard Worker   template<typename T>
BitMask()52*795d594fSAndroid Build Coastguard Worker   constexpr uint32_t BitMask() {
53*795d594fSAndroid Build Coastguard Worker     return BitMask(ToUint(T::kMax) + 1) & (~BitMask(ToUint(T::kMin)));
54*795d594fSAndroid Build Coastguard Worker   }
55*795d594fSAndroid Build Coastguard Worker 
56*795d594fSAndroid Build Coastguard Worker   // Returns true if `val` is a bitwise subset of `mask`.
MatchesBitMask(uint32_t val,uint32_t mask)57*795d594fSAndroid Build Coastguard Worker   constexpr bool MatchesBitMask(uint32_t val, uint32_t mask) { return (val & mask) == val; }
58*795d594fSAndroid Build Coastguard Worker 
59*795d594fSAndroid Build Coastguard Worker   // Returns true if the uint32_t value of `val` is a bitwise subset of `mask`.
60*795d594fSAndroid Build Coastguard Worker   template<typename T>
MatchesBitMask(T val,uint32_t mask)61*795d594fSAndroid Build Coastguard Worker   constexpr bool MatchesBitMask(T val, uint32_t mask) { return MatchesBitMask(ToUint(val), mask); }
62*795d594fSAndroid Build Coastguard Worker 
63*795d594fSAndroid Build Coastguard Worker   // Returns the number of values defined in an enum, assuming the enum defines
64*795d594fSAndroid Build Coastguard Worker   // kMin and kMax and no integer values are skipped between them.
65*795d594fSAndroid Build Coastguard Worker   template<typename T>
NumValues()66*795d594fSAndroid Build Coastguard Worker   constexpr uint32_t NumValues() { return ToUint(T::kMax) - ToUint(T::kMin) + 1; }
67*795d594fSAndroid Build Coastguard Worker 
68*795d594fSAndroid Build Coastguard Worker   // Returns enum value at position i from enum list.
69*795d594fSAndroid Build Coastguard Worker   template <typename T>
GetEnumAt(uint32_t i)70*795d594fSAndroid Build Coastguard Worker   constexpr T GetEnumAt(uint32_t i) {
71*795d594fSAndroid Build Coastguard Worker     return static_cast<T>(ToUint(T::kMin) + i);
72*795d594fSAndroid Build Coastguard Worker   }
73*795d594fSAndroid Build Coastguard Worker 
74*795d594fSAndroid Build Coastguard Worker }  // namespace helper
75*795d594fSAndroid Build Coastguard Worker 
76*795d594fSAndroid Build Coastguard Worker /*
77*795d594fSAndroid Build Coastguard Worker  * This class represents the information whether a field/method is in
78*795d594fSAndroid Build Coastguard Worker  * public API (SDK) or if it isn't, apps targeting which SDK
79*795d594fSAndroid Build Coastguard Worker  * versions are allowed to access it.
80*795d594fSAndroid Build Coastguard Worker  */
81*795d594fSAndroid Build Coastguard Worker class ApiList {
82*795d594fSAndroid Build Coastguard Worker  private:
83*795d594fSAndroid Build Coastguard Worker   // Number of bits reserved for Value in dex flags, and the corresponding bit mask.
84*795d594fSAndroid Build Coastguard Worker   static constexpr uint32_t kValueBitSize = 4;
85*795d594fSAndroid Build Coastguard Worker   static constexpr uint32_t kValueBitMask = helper::BitMask(kValueBitSize);
86*795d594fSAndroid Build Coastguard Worker 
87*795d594fSAndroid Build Coastguard Worker   enum class Value : uint32_t {
88*795d594fSAndroid Build Coastguard Worker     // Values independent of target SDK version of app
89*795d594fSAndroid Build Coastguard Worker     kSdk =    0,
90*795d594fSAndroid Build Coastguard Worker     kUnsupported =     1,
91*795d594fSAndroid Build Coastguard Worker     kBlocked =    2,
92*795d594fSAndroid Build Coastguard Worker 
93*795d594fSAndroid Build Coastguard Worker     // Values dependent on target SDK version of app. Put these last as
94*795d594fSAndroid Build Coastguard Worker     // their list will be extended in future releases.
95*795d594fSAndroid Build Coastguard Worker     // The max release code implicitly includes all maintenance releases,
96*795d594fSAndroid Build Coastguard Worker     // e.g. MaxTargetO is accessible to targetSdkVersion <= 27 (O_MR1).
97*795d594fSAndroid Build Coastguard Worker     kMaxTargetO = 3,
98*795d594fSAndroid Build Coastguard Worker     kMaxTargetP = 4,
99*795d594fSAndroid Build Coastguard Worker     kMaxTargetQ = 5,
100*795d594fSAndroid Build Coastguard Worker     kMaxTargetR = 6,
101*795d594fSAndroid Build Coastguard Worker     kMaxTargetS = 7,
102*795d594fSAndroid Build Coastguard Worker 
103*795d594fSAndroid Build Coastguard Worker     // Special values
104*795d594fSAndroid Build Coastguard Worker     kInvalid =      (static_cast<uint32_t>(-1) & kValueBitMask),
105*795d594fSAndroid Build Coastguard Worker     kMin =          kSdk,
106*795d594fSAndroid Build Coastguard Worker     kMax =          kMaxTargetS,
107*795d594fSAndroid Build Coastguard Worker   };
108*795d594fSAndroid Build Coastguard Worker 
109*795d594fSAndroid Build Coastguard Worker   // Additional bit flags after the first kValueBitSize bits in dex flags.
110*795d594fSAndroid Build Coastguard Worker   // These are used for domain-specific API.
111*795d594fSAndroid Build Coastguard Worker   enum class DomainApi : uint32_t {
112*795d594fSAndroid Build Coastguard Worker     kCorePlatformApi = kValueBitSize,
113*795d594fSAndroid Build Coastguard Worker     kTestApi = kValueBitSize + 1,
114*795d594fSAndroid Build Coastguard Worker 
115*795d594fSAndroid Build Coastguard Worker     // Special values
116*795d594fSAndroid Build Coastguard Worker     kMin =             kCorePlatformApi,
117*795d594fSAndroid Build Coastguard Worker     kMax =             kTestApi,
118*795d594fSAndroid Build Coastguard Worker   };
119*795d594fSAndroid Build Coastguard Worker 
120*795d594fSAndroid Build Coastguard Worker   // Bit mask of all domain API flags.
121*795d594fSAndroid Build Coastguard Worker   static constexpr uint32_t kDomainApiBitMask = helper::BitMask<DomainApi>();
122*795d594fSAndroid Build Coastguard Worker 
123*795d594fSAndroid Build Coastguard Worker   // Check that Values fit in the designated number of bits.
124*795d594fSAndroid Build Coastguard Worker   static_assert(kValueBitSize >= MinimumBitsToStore(helper::ToUint(Value::kMax)),
125*795d594fSAndroid Build Coastguard Worker                 "Not enough bits to store all ApiList values");
126*795d594fSAndroid Build Coastguard Worker 
127*795d594fSAndroid Build Coastguard Worker   // Checks that all Values are covered by kValueBitMask.
128*795d594fSAndroid Build Coastguard Worker   static_assert(helper::MatchesBitMask(Value::kMin, kValueBitMask));
129*795d594fSAndroid Build Coastguard Worker   static_assert(helper::MatchesBitMask(Value::kMax, kValueBitMask));
130*795d594fSAndroid Build Coastguard Worker 
131*795d594fSAndroid Build Coastguard Worker   // Assert that Value::kInvalid is larger than the maximum Value.
132*795d594fSAndroid Build Coastguard Worker   static_assert(helper::ToUint(Value::kMax) < helper::ToUint(Value::kInvalid));
133*795d594fSAndroid Build Coastguard Worker 
134*795d594fSAndroid Build Coastguard Worker   // Names corresponding to Values.
135*795d594fSAndroid Build Coastguard Worker   static constexpr const char* kValueNames[] = {
136*795d594fSAndroid Build Coastguard Worker     "sdk",
137*795d594fSAndroid Build Coastguard Worker     "unsupported",
138*795d594fSAndroid Build Coastguard Worker     "blocked",
139*795d594fSAndroid Build Coastguard Worker     "max-target-o",
140*795d594fSAndroid Build Coastguard Worker     "max-target-p",
141*795d594fSAndroid Build Coastguard Worker     "max-target-q",
142*795d594fSAndroid Build Coastguard Worker     "max-target-r",
143*795d594fSAndroid Build Coastguard Worker     "max-target-s",
144*795d594fSAndroid Build Coastguard Worker   };
145*795d594fSAndroid Build Coastguard Worker 
146*795d594fSAndroid Build Coastguard Worker   // A magic marker used by tests to mimic a hiddenapi list which doesn't exist
147*795d594fSAndroid Build Coastguard Worker   // yet.
148*795d594fSAndroid Build Coastguard Worker   static constexpr const char* kFutureValueName = "max-target-future";
149*795d594fSAndroid Build Coastguard Worker 
150*795d594fSAndroid Build Coastguard Worker   // Names corresponding to DomainApis.
151*795d594fSAndroid Build Coastguard Worker   static constexpr const char* kDomainApiNames[] {
152*795d594fSAndroid Build Coastguard Worker     "core-platform-api",
153*795d594fSAndroid Build Coastguard Worker     "test-api",
154*795d594fSAndroid Build Coastguard Worker   };
155*795d594fSAndroid Build Coastguard Worker 
156*795d594fSAndroid Build Coastguard Worker   // Maximum SDK versions allowed to access ApiList of given Value.
157*795d594fSAndroid Build Coastguard Worker   static constexpr SdkVersion kMaxSdkVersions[] {
158*795d594fSAndroid Build Coastguard Worker     /* sdk */ SdkVersion::kMax,
159*795d594fSAndroid Build Coastguard Worker     /* unsupported */ SdkVersion::kMax,
160*795d594fSAndroid Build Coastguard Worker     /* blocklist */ SdkVersion::kMin,
161*795d594fSAndroid Build Coastguard Worker     /* max-target-o */ SdkVersion::kO_MR1,
162*795d594fSAndroid Build Coastguard Worker     /* max-target-p */ SdkVersion::kP,
163*795d594fSAndroid Build Coastguard Worker     /* max-target-q */ SdkVersion::kQ,
164*795d594fSAndroid Build Coastguard Worker     /* max-target-r */ SdkVersion::kR,
165*795d594fSAndroid Build Coastguard Worker     /* max-target-s */ SdkVersion::kS,
166*795d594fSAndroid Build Coastguard Worker   };
167*795d594fSAndroid Build Coastguard Worker 
168*795d594fSAndroid Build Coastguard Worker   explicit ApiList(Value val, uint32_t domain_apis = 0u)
169*795d594fSAndroid Build Coastguard Worker       : dex_flags_(helper::ToUint(val) | domain_apis) {
170*795d594fSAndroid Build Coastguard Worker     DCHECK(GetValue() == val);
171*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(GetDomainApis(), domain_apis);
172*795d594fSAndroid Build Coastguard Worker   }
173*795d594fSAndroid Build Coastguard Worker 
ApiList(DomainApi val)174*795d594fSAndroid Build Coastguard Worker   explicit ApiList(DomainApi val) : ApiList(Value::kInvalid, helper::ToBit(val)) {}
175*795d594fSAndroid Build Coastguard Worker 
GetValue()176*795d594fSAndroid Build Coastguard Worker   Value GetValue() const {
177*795d594fSAndroid Build Coastguard Worker     uint32_t value = (dex_flags_ & kValueBitMask);
178*795d594fSAndroid Build Coastguard Worker 
179*795d594fSAndroid Build Coastguard Worker     // Treat all ones as invalid value
180*795d594fSAndroid Build Coastguard Worker     if (value == helper::ToUint(Value::kInvalid)) {
181*795d594fSAndroid Build Coastguard Worker       return Value::kInvalid;
182*795d594fSAndroid Build Coastguard Worker     } else if (value > helper::ToUint(Value::kMax)) {
183*795d594fSAndroid Build Coastguard Worker       // For future unknown flag values, return unsupported.
184*795d594fSAndroid Build Coastguard Worker       return Value::kUnsupported;
185*795d594fSAndroid Build Coastguard Worker     } else {
186*795d594fSAndroid Build Coastguard Worker       DCHECK_GE(value, helper::ToUint(Value::kMin));
187*795d594fSAndroid Build Coastguard Worker       return static_cast<Value>(value);
188*795d594fSAndroid Build Coastguard Worker     }
189*795d594fSAndroid Build Coastguard Worker   }
190*795d594fSAndroid Build Coastguard Worker 
GetDomainApis()191*795d594fSAndroid Build Coastguard Worker   uint32_t GetDomainApis() const { return (dex_flags_ & kDomainApiBitMask); }
192*795d594fSAndroid Build Coastguard Worker 
193*795d594fSAndroid Build Coastguard Worker   uint32_t dex_flags_;
194*795d594fSAndroid Build Coastguard Worker 
195*795d594fSAndroid Build Coastguard Worker  public:
ApiList()196*795d594fSAndroid Build Coastguard Worker   ApiList() : ApiList(Value::kInvalid) {}
197*795d594fSAndroid Build Coastguard Worker 
ApiList(uint32_t dex_flags)198*795d594fSAndroid Build Coastguard Worker   explicit ApiList(uint32_t dex_flags) : dex_flags_(dex_flags) {
199*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(dex_flags_, (dex_flags_ & kValueBitMask) | (dex_flags_ & kDomainApiBitMask));
200*795d594fSAndroid Build Coastguard Worker   }
201*795d594fSAndroid Build Coastguard Worker 
202*795d594fSAndroid Build Coastguard Worker   // Helpers for conveniently constructing ApiList instances.
Sdk()203*795d594fSAndroid Build Coastguard Worker   static ApiList Sdk() { return ApiList(Value::kSdk); }
Unsupported()204*795d594fSAndroid Build Coastguard Worker   static ApiList Unsupported() { return ApiList(Value::kUnsupported); }
Blocked()205*795d594fSAndroid Build Coastguard Worker   static ApiList Blocked() { return ApiList(Value::kBlocked); }
MaxTargetO()206*795d594fSAndroid Build Coastguard Worker   static ApiList MaxTargetO() { return ApiList(Value::kMaxTargetO); }
MaxTargetP()207*795d594fSAndroid Build Coastguard Worker   static ApiList MaxTargetP() { return ApiList(Value::kMaxTargetP); }
MaxTargetQ()208*795d594fSAndroid Build Coastguard Worker   static ApiList MaxTargetQ() { return ApiList(Value::kMaxTargetQ); }
MaxTargetR()209*795d594fSAndroid Build Coastguard Worker   static ApiList MaxTargetR() { return ApiList(Value::kMaxTargetR); }
MaxTargetS()210*795d594fSAndroid Build Coastguard Worker   static ApiList MaxTargetS() { return ApiList(Value::kMaxTargetS); }
CorePlatformApi()211*795d594fSAndroid Build Coastguard Worker   static ApiList CorePlatformApi() { return ApiList(DomainApi::kCorePlatformApi); }
TestApi()212*795d594fSAndroid Build Coastguard Worker   static ApiList TestApi() { return ApiList(DomainApi::kTestApi); }
213*795d594fSAndroid Build Coastguard Worker 
GetDexFlags()214*795d594fSAndroid Build Coastguard Worker   uint32_t GetDexFlags() const { return dex_flags_; }
GetIntValue()215*795d594fSAndroid Build Coastguard Worker   uint32_t GetIntValue() const { return helper::ToUint(GetValue()) - helper::ToUint(Value::kMin); }
216*795d594fSAndroid Build Coastguard Worker 
217*795d594fSAndroid Build Coastguard Worker   // Returns the ApiList with a flag of a given name, or an empty ApiList if not matched.
FromName(const std::string & str)218*795d594fSAndroid Build Coastguard Worker   static ApiList FromName(const std::string& str) {
219*795d594fSAndroid Build Coastguard Worker     for (uint32_t i = 0; i < kValueCount; ++i) {
220*795d594fSAndroid Build Coastguard Worker       if (str == kValueNames[i]) {
221*795d594fSAndroid Build Coastguard Worker         return ApiList(helper::GetEnumAt<Value>(i));
222*795d594fSAndroid Build Coastguard Worker       }
223*795d594fSAndroid Build Coastguard Worker     }
224*795d594fSAndroid Build Coastguard Worker     for (uint32_t i = 0; i < kDomainApiCount; ++i) {
225*795d594fSAndroid Build Coastguard Worker       if (str == kDomainApiNames[i]) {
226*795d594fSAndroid Build Coastguard Worker         return ApiList(helper::GetEnumAt<DomainApi>(i));
227*795d594fSAndroid Build Coastguard Worker       }
228*795d594fSAndroid Build Coastguard Worker     }
229*795d594fSAndroid Build Coastguard Worker     if (str == kFutureValueName) {
230*795d594fSAndroid Build Coastguard Worker       static_assert(helper::ToUint(Value::kMax) + 1 < helper::ToUint(Value::kInvalid));
231*795d594fSAndroid Build Coastguard Worker       return ApiList(helper::ToUint(Value::kMax) + 1);
232*795d594fSAndroid Build Coastguard Worker     }
233*795d594fSAndroid Build Coastguard Worker     return ApiList();
234*795d594fSAndroid Build Coastguard Worker   }
235*795d594fSAndroid Build Coastguard Worker 
236*795d594fSAndroid Build Coastguard Worker   // Parses a vector of flag names into a single ApiList value. If successful,
237*795d594fSAndroid Build Coastguard Worker   // returns true and assigns the new ApiList to `out_api_list`.
FromNames(std::vector<std::string>::iterator begin,std::vector<std::string>::iterator end,ApiList * out_api_list)238*795d594fSAndroid Build Coastguard Worker   static bool FromNames(std::vector<std::string>::iterator begin,
239*795d594fSAndroid Build Coastguard Worker                         std::vector<std::string>::iterator end,
240*795d594fSAndroid Build Coastguard Worker                         /* out */ ApiList* out_api_list) {
241*795d594fSAndroid Build Coastguard Worker     ApiList api_list;
242*795d594fSAndroid Build Coastguard Worker     for (std::vector<std::string>::iterator it = begin; it != end; it++) {
243*795d594fSAndroid Build Coastguard Worker       ApiList current = FromName(*it);
244*795d594fSAndroid Build Coastguard Worker       if (current.IsEmpty() || !api_list.CanCombineWith(current)) {
245*795d594fSAndroid Build Coastguard Worker         if (ApiStubs::IsStubsFlag(*it)) {
246*795d594fSAndroid Build Coastguard Worker         // Ignore flags which correspond to the stubs from where the api
247*795d594fSAndroid Build Coastguard Worker         // originates (i.e. system-api, test-api, public-api), as they are not
248*795d594fSAndroid Build Coastguard Worker         // relevant at runtime
249*795d594fSAndroid Build Coastguard Worker           continue;
250*795d594fSAndroid Build Coastguard Worker         }
251*795d594fSAndroid Build Coastguard Worker         return false;
252*795d594fSAndroid Build Coastguard Worker       }
253*795d594fSAndroid Build Coastguard Worker       api_list |= current;
254*795d594fSAndroid Build Coastguard Worker     }
255*795d594fSAndroid Build Coastguard Worker     if (out_api_list != nullptr) {
256*795d594fSAndroid Build Coastguard Worker       *out_api_list = api_list;
257*795d594fSAndroid Build Coastguard Worker     }
258*795d594fSAndroid Build Coastguard Worker     return true;
259*795d594fSAndroid Build Coastguard Worker   }
260*795d594fSAndroid Build Coastguard Worker 
261*795d594fSAndroid Build Coastguard Worker   bool operator==(const ApiList& other) const { return dex_flags_ == other.dex_flags_; }
262*795d594fSAndroid Build Coastguard Worker   bool operator!=(const ApiList& other) const { return !(*this == other); }
263*795d594fSAndroid Build Coastguard Worker   bool operator<(const ApiList& other) const { return dex_flags_ < other.dex_flags_; }
264*795d594fSAndroid Build Coastguard Worker   bool operator>(const ApiList& other) const { return dex_flags_ > other.dex_flags_; }
265*795d594fSAndroid Build Coastguard Worker 
266*795d594fSAndroid Build Coastguard Worker   // In order to correctly handle flagged changes from Unsupported to the Sdk, where both will be
267*795d594fSAndroid Build Coastguard Worker   // set when the flag is enabled, consider Sdk to take precedence over any form of unsupported.
268*795d594fSAndroid Build Coastguard Worker   // Note, this is not necessary in the inverse direction, because API flagging does not currently
269*795d594fSAndroid Build Coastguard Worker   // support API removal. Moving from the blocklist to unsupported is also a case we don't have to
270*795d594fSAndroid Build Coastguard Worker   // consider.
271*795d594fSAndroid Build Coastguard Worker   // If this is true, the conflict resolves to Value::kSdk.
is_conflicting_flags_acceptable(Value x,Value y)272*795d594fSAndroid Build Coastguard Worker   static bool is_conflicting_flags_acceptable(Value x, Value y) {
273*795d594fSAndroid Build Coastguard Worker     const auto predicate_non_symmetric = [] (auto l, auto r) {
274*795d594fSAndroid Build Coastguard Worker       if (l != Value::kSdk) return false;
275*795d594fSAndroid Build Coastguard Worker       switch (r) {
276*795d594fSAndroid Build Coastguard Worker         case Value::kSdk:
277*795d594fSAndroid Build Coastguard Worker         case Value::kUnsupported:
278*795d594fSAndroid Build Coastguard Worker         case Value::kMaxTargetO:
279*795d594fSAndroid Build Coastguard Worker         case Value::kMaxTargetP:
280*795d594fSAndroid Build Coastguard Worker         case Value::kMaxTargetQ:
281*795d594fSAndroid Build Coastguard Worker         case Value::kMaxTargetR:
282*795d594fSAndroid Build Coastguard Worker         case Value::kMaxTargetS:
283*795d594fSAndroid Build Coastguard Worker           return true;
284*795d594fSAndroid Build Coastguard Worker         default:
285*795d594fSAndroid Build Coastguard Worker           return false;
286*795d594fSAndroid Build Coastguard Worker       }
287*795d594fSAndroid Build Coastguard Worker     };
288*795d594fSAndroid Build Coastguard Worker     return predicate_non_symmetric(x, y) || predicate_non_symmetric(y, x);
289*795d594fSAndroid Build Coastguard Worker   }
290*795d594fSAndroid Build Coastguard Worker 
291*795d594fSAndroid Build Coastguard Worker   // Returns true if combining this ApiList with `other` will succeed.
CanCombineWith(const ApiList & other)292*795d594fSAndroid Build Coastguard Worker   bool CanCombineWith(const ApiList& other) const {
293*795d594fSAndroid Build Coastguard Worker     const Value val1 = GetValue();
294*795d594fSAndroid Build Coastguard Worker     const Value val2 = other.GetValue();
295*795d594fSAndroid Build Coastguard Worker     return (val1 == val2) || (val1 == Value::kInvalid) || (val2 == Value::kInvalid) ||
296*795d594fSAndroid Build Coastguard Worker            is_conflicting_flags_acceptable(val1, val2);
297*795d594fSAndroid Build Coastguard Worker   }
298*795d594fSAndroid Build Coastguard Worker 
299*795d594fSAndroid Build Coastguard Worker   // Combine two ApiList instances.
300*795d594fSAndroid Build Coastguard Worker   ApiList operator|(const ApiList& other) {
301*795d594fSAndroid Build Coastguard Worker     // DomainApis are not mutually exclusive. Simply OR them.
302*795d594fSAndroid Build Coastguard Worker     const uint32_t domain_apis = GetDomainApis() | other.GetDomainApis();
303*795d594fSAndroid Build Coastguard Worker 
304*795d594fSAndroid Build Coastguard Worker     // Values are mutually exclusive. Check if `this` and `other` have the same Value
305*795d594fSAndroid Build Coastguard Worker     // or if at most one is set.
306*795d594fSAndroid Build Coastguard Worker     const Value val1 = GetValue();
307*795d594fSAndroid Build Coastguard Worker     const Value val2 = other.GetValue();
308*795d594fSAndroid Build Coastguard Worker     if (val1 == val2) {
309*795d594fSAndroid Build Coastguard Worker       return ApiList(val1, domain_apis);
310*795d594fSAndroid Build Coastguard Worker     } else if (val1 == Value::kInvalid) {
311*795d594fSAndroid Build Coastguard Worker       return ApiList(val2, domain_apis);
312*795d594fSAndroid Build Coastguard Worker     } else if (val2 == Value::kInvalid) {
313*795d594fSAndroid Build Coastguard Worker       return ApiList(val1, domain_apis);
314*795d594fSAndroid Build Coastguard Worker     } else if (is_conflicting_flags_acceptable(val1, val2)) {
315*795d594fSAndroid Build Coastguard Worker       return ApiList(Value::kSdk, domain_apis);
316*795d594fSAndroid Build Coastguard Worker     } else {
317*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Invalid combination of values " << Dumpable(ApiList(val1))
318*795d594fSAndroid Build Coastguard Worker           << " and " << Dumpable(ApiList(val2));
319*795d594fSAndroid Build Coastguard Worker       UNREACHABLE();
320*795d594fSAndroid Build Coastguard Worker     }
321*795d594fSAndroid Build Coastguard Worker   }
322*795d594fSAndroid Build Coastguard Worker 
323*795d594fSAndroid Build Coastguard Worker   const ApiList& operator|=(const ApiList& other) {
324*795d594fSAndroid Build Coastguard Worker     (*this) = (*this) | other;
325*795d594fSAndroid Build Coastguard Worker     return *this;
326*795d594fSAndroid Build Coastguard Worker   }
327*795d594fSAndroid Build Coastguard Worker 
328*795d594fSAndroid Build Coastguard Worker   // Returns true if all flags set in `other` are also set in `this`.
Contains(const ApiList & other)329*795d594fSAndroid Build Coastguard Worker   bool Contains(const ApiList& other) const {
330*795d594fSAndroid Build Coastguard Worker     return ((other.GetValue() == Value::kInvalid) || (GetValue() == other.GetValue())) &&
331*795d594fSAndroid Build Coastguard Worker            helper::MatchesBitMask(other.GetDomainApis(), GetDomainApis());
332*795d594fSAndroid Build Coastguard Worker   }
333*795d594fSAndroid Build Coastguard Worker 
334*795d594fSAndroid Build Coastguard Worker   // Returns true whether the configuration is valid for runtime use.
IsValid()335*795d594fSAndroid Build Coastguard Worker   bool IsValid() const { return GetValue() != Value::kInvalid; }
336*795d594fSAndroid Build Coastguard Worker 
337*795d594fSAndroid Build Coastguard Worker   // Returns true when no ApiList is specified and no domain_api flags either.
IsEmpty()338*795d594fSAndroid Build Coastguard Worker   bool IsEmpty() const { return (GetValue() == Value::kInvalid) && (GetDomainApis() == 0); }
339*795d594fSAndroid Build Coastguard Worker 
340*795d594fSAndroid Build Coastguard Worker   // Returns true if the ApiList is on blocklist.
IsBlocked()341*795d594fSAndroid Build Coastguard Worker   bool IsBlocked() const {
342*795d594fSAndroid Build Coastguard Worker     return GetValue() == Value::kBlocked;
343*795d594fSAndroid Build Coastguard Worker   }
344*795d594fSAndroid Build Coastguard Worker 
IsSdkApi()345*795d594fSAndroid Build Coastguard Worker   bool IsSdkApi() const {
346*795d594fSAndroid Build Coastguard Worker     return GetValue() == Value::kSdk;
347*795d594fSAndroid Build Coastguard Worker   }
348*795d594fSAndroid Build Coastguard Worker 
349*795d594fSAndroid Build Coastguard Worker   // Returns true if the ApiList is a test API.
IsTestApi()350*795d594fSAndroid Build Coastguard Worker   bool IsTestApi() const {
351*795d594fSAndroid Build Coastguard Worker     return helper::MatchesBitMask(helper::ToBit(DomainApi::kTestApi), dex_flags_);
352*795d594fSAndroid Build Coastguard Worker   }
353*795d594fSAndroid Build Coastguard Worker 
354*795d594fSAndroid Build Coastguard Worker   // Returns the maximum target SDK version allowed to access this ApiList.
GetMaxAllowedSdkVersion()355*795d594fSAndroid Build Coastguard Worker   SdkVersion GetMaxAllowedSdkVersion() const { return kMaxSdkVersions[GetIntValue()]; }
356*795d594fSAndroid Build Coastguard Worker 
Dump(std::ostream & os)357*795d594fSAndroid Build Coastguard Worker   void Dump(std::ostream& os) const {
358*795d594fSAndroid Build Coastguard Worker     bool is_first = true;
359*795d594fSAndroid Build Coastguard Worker 
360*795d594fSAndroid Build Coastguard Worker     if (IsEmpty()) {
361*795d594fSAndroid Build Coastguard Worker       os << "invalid";
362*795d594fSAndroid Build Coastguard Worker       return;
363*795d594fSAndroid Build Coastguard Worker     }
364*795d594fSAndroid Build Coastguard Worker 
365*795d594fSAndroid Build Coastguard Worker     if (GetValue() != Value::kInvalid) {
366*795d594fSAndroid Build Coastguard Worker       os << kValueNames[GetIntValue()];
367*795d594fSAndroid Build Coastguard Worker       is_first = false;
368*795d594fSAndroid Build Coastguard Worker     }
369*795d594fSAndroid Build Coastguard Worker 
370*795d594fSAndroid Build Coastguard Worker     const uint32_t domain_apis = GetDomainApis();
371*795d594fSAndroid Build Coastguard Worker     for (uint32_t i = 0; i < kDomainApiCount; i++) {
372*795d594fSAndroid Build Coastguard Worker       if (helper::MatchesBitMask(helper::ToBit(helper::GetEnumAt<DomainApi>(i)), domain_apis)) {
373*795d594fSAndroid Build Coastguard Worker         if (is_first) {
374*795d594fSAndroid Build Coastguard Worker           is_first = false;
375*795d594fSAndroid Build Coastguard Worker         } else {
376*795d594fSAndroid Build Coastguard Worker           os << ",";
377*795d594fSAndroid Build Coastguard Worker         }
378*795d594fSAndroid Build Coastguard Worker         os << kDomainApiNames[i];
379*795d594fSAndroid Build Coastguard Worker       }
380*795d594fSAndroid Build Coastguard Worker     }
381*795d594fSAndroid Build Coastguard Worker 
382*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(IsEmpty(), is_first);
383*795d594fSAndroid Build Coastguard Worker   }
384*795d594fSAndroid Build Coastguard Worker 
385*795d594fSAndroid Build Coastguard Worker   // Number of valid enum values in Value.
386*795d594fSAndroid Build Coastguard Worker   static constexpr uint32_t kValueCount = helper::NumValues<Value>();
387*795d594fSAndroid Build Coastguard Worker   // Number of valid enum values in DomainApi.
388*795d594fSAndroid Build Coastguard Worker   static constexpr uint32_t kDomainApiCount = helper::NumValues<DomainApi>();
389*795d594fSAndroid Build Coastguard Worker   // Total number of possible enum values, including invalid, in Value.
390*795d594fSAndroid Build Coastguard Worker   static constexpr uint32_t kValueSize = (1u << kValueBitSize) + 1;
391*795d594fSAndroid Build Coastguard Worker 
392*795d594fSAndroid Build Coastguard Worker   // Check min and max values are calculated correctly.
393*795d594fSAndroid Build Coastguard Worker   static_assert(Value::kMin == helper::GetEnumAt<Value>(0));
394*795d594fSAndroid Build Coastguard Worker   static_assert(Value::kMax == helper::GetEnumAt<Value>(kValueCount - 1));
395*795d594fSAndroid Build Coastguard Worker 
396*795d594fSAndroid Build Coastguard Worker   static_assert(DomainApi::kMin == helper::GetEnumAt<DomainApi>(0));
397*795d594fSAndroid Build Coastguard Worker   static_assert(DomainApi::kMax == helper::GetEnumAt<DomainApi>(kDomainApiCount - 1));
398*795d594fSAndroid Build Coastguard Worker };
399*795d594fSAndroid Build Coastguard Worker 
400*795d594fSAndroid Build Coastguard Worker inline std::ostream& operator<<(std::ostream& os, ApiList value) {
401*795d594fSAndroid Build Coastguard Worker   value.Dump(os);
402*795d594fSAndroid Build Coastguard Worker   return os;
403*795d594fSAndroid Build Coastguard Worker }
404*795d594fSAndroid Build Coastguard Worker 
405*795d594fSAndroid Build Coastguard Worker }  // namespace hiddenapi
406*795d594fSAndroid Build Coastguard Worker }  // namespace art
407*795d594fSAndroid Build Coastguard Worker 
408*795d594fSAndroid Build Coastguard Worker 
409*795d594fSAndroid Build Coastguard Worker #endif  // ART_LIBARTBASE_BASE_HIDDENAPI_FLAGS_H_
410