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