Home | History | Annotate | Download | only in base
      1 /*
      2  * Copyright (C) 2018 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 #ifndef ART_LIBARTBASE_BASE_HIDDENAPI_FLAGS_H_
     18 #define ART_LIBARTBASE_BASE_HIDDENAPI_FLAGS_H_
     19 
     20 #include "sdk_version.h"
     21 
     22 #include <vector>
     23 
     24 #include "android-base/logging.h"
     25 #include "base/bit_utils.h"
     26 #include "base/dumpable.h"
     27 #include "base/macros.h"
     28 #include "base/hiddenapi_stubs.h"
     29 
     30 namespace art {
     31 namespace hiddenapi {
     32 
     33 // Helper methods used inside ApiList. These were moved outside of the ApiList
     34 // class so that they can be used in static_asserts. If they were inside, they
     35 // would be part of an unfinished type.
     36 namespace helper {
     37   // Casts enum value to uint32_t.
     38   template<typename T>
     39   constexpr uint32_t ToUint(T val) { return static_cast<uint32_t>(val); }
     40 
     41   // Returns uint32_t with one bit set at an index given by an enum value.
     42   template<typename T>
     43   constexpr uint32_t ToBit(T val) { return 1u << ToUint(val); }
     44 
     45   // Returns a bit mask with `size` least significant bits set.
     46   constexpr uint32_t BitMask(uint32_t size) { return (1u << size) - 1; }
     47 
     48   // Returns a bit mask formed from an enum defining kMin and kMax. The values
     49   // are assumed to be indices of min/max bits and the resulting bitmask has
     50   // bits [kMin, kMax] set.
     51   template<typename T>
     52   constexpr uint32_t BitMask() {
     53     return BitMask(ToUint(T::kMax) + 1) & (~BitMask(ToUint(T::kMin)));
     54   }
     55 
     56   // Returns true if `val` is a bitwise subset of `mask`.
     57   constexpr bool MatchesBitMask(uint32_t val, uint32_t mask) { return (val & mask) == val; }
     58 
     59   // Returns true if the uint32_t value of `val` is a bitwise subset of `mask`.
     60   template<typename T>
     61   constexpr bool MatchesBitMask(T val, uint32_t mask) { return MatchesBitMask(ToUint(val), mask); }
     62 
     63   // Returns the number of values defined in an enum, assuming the enum defines
     64   // kMin and kMax and no integer values are skipped between them.
     65   template<typename T>
     66   constexpr uint32_t NumValues() { return ToUint(T::kMax) - ToUint(T::kMin) + 1; }
     67 }  // namespace helper
     68 
     69 /*
     70  * This class represents the information whether a field/method is in
     71  * public API (whitelist) or if it isn't, apps targeting which SDK
     72  * versions are allowed to access it.
     73  */
     74 class ApiList {
     75  private:
     76   // Number of bits reserved for Value in dex flags, and the corresponding bit mask.
     77   static constexpr uint32_t kValueBitSize = 3;
     78   static constexpr uint32_t kValueBitMask = helper::BitMask(kValueBitSize);
     79 
     80   enum class Value : uint32_t {
     81     // Values independent of target SDK version of app
     82     kWhitelist =    0,
     83     kGreylist =     1,
     84     kBlacklist =    2,
     85 
     86     // Values dependent on target SDK version of app. Put these last as
     87     // their list will be extended in future releases.
     88     // The max release code implicitly includes all maintenance releases,
     89     // e.g. GreylistMaxO is accessible to targetSdkVersion <= 27 (O_MR1).
     90     kGreylistMaxO = 3,
     91     kGreylistMaxP = 4,
     92 
     93     // Special values
     94     kInvalid =      (static_cast<uint32_t>(-1) & kValueBitMask),
     95     kMin =          kWhitelist,
     96     kMax =          kGreylistMaxP,
     97   };
     98 
     99   // Additional bit flags after the first kValueBitSize bits in dex flags.
    100   // These are used for domain-specific API.
    101   enum class DomainApi : uint32_t {
    102     kCorePlatformApi = kValueBitSize,
    103 
    104     // Special values
    105     kMin =             kCorePlatformApi,
    106     kMax =             kCorePlatformApi,
    107   };
    108 
    109   // Bit mask of all domain API flags.
    110   static constexpr uint32_t kDomainApiBitMask = helper::BitMask<DomainApi>();
    111 
    112   // Check that Values fit in the designated number of bits.
    113   static_assert(kValueBitSize >= MinimumBitsToStore(helper::ToUint(Value::kMax)),
    114                 "Not enough bits to store all ApiList values");
    115 
    116   // Sanity checks that all Values are covered by kValueBitMask.
    117   static_assert(helper::MatchesBitMask(Value::kMin, kValueBitMask));
    118   static_assert(helper::MatchesBitMask(Value::kMax, kValueBitMask));
    119 
    120   // Assert that Value::kInvalid is larger than the maximum Value.
    121   static_assert(helper::ToUint(Value::kMax) < helper::ToUint(Value::kInvalid));
    122 
    123   // Names corresponding to Values.
    124   static constexpr const char* kValueNames[] = {
    125     "whitelist",
    126     "greylist",
    127     "blacklist",
    128     "greylist-max-o",
    129     "greylist-max-p",
    130   };
    131 
    132   // Names corresponding to DomainApis.
    133   static constexpr const char* kDomainApiNames[] {
    134     "core-platform-api",
    135   };
    136 
    137   // Maximum SDK versions allowed to access ApiList of given Value.
    138   static constexpr SdkVersion kMaxSdkVersions[] {
    139     /* whitelist */ SdkVersion::kMax,
    140     /* greylist */ SdkVersion::kMax,
    141     /* blacklist */ SdkVersion::kMin,
    142     /* greylist-max-o */ SdkVersion::kO_MR1,
    143     /* greylist-max-p */ SdkVersion::kP,
    144   };
    145 
    146   explicit ApiList(Value val, uint32_t domain_apis = 0u)
    147       : dex_flags_(helper::ToUint(val) | domain_apis) {
    148     DCHECK(GetValue() == val);
    149     DCHECK_EQ(GetDomainApis(), domain_apis);
    150   }
    151 
    152   explicit ApiList(DomainApi val) : ApiList(Value::kInvalid, helper::ToBit(val)) {}
    153 
    154   Value GetValue() const {
    155     uint32_t value = (dex_flags_ & kValueBitMask);
    156 
    157     // Treat all ones as invalid value
    158     if (value == helper::ToUint(Value::kInvalid)) {
    159       return Value::kInvalid;
    160     } else {
    161       DCHECK_GE(value, helper::ToUint(Value::kMin));
    162       DCHECK_LE(value, helper::ToUint(Value::kMax));
    163       return static_cast<Value>(value);
    164     }
    165   }
    166 
    167   uint32_t GetDomainApis() const { return (dex_flags_ & kDomainApiBitMask); }
    168 
    169   uint32_t dex_flags_;
    170 
    171  public:
    172   ApiList() : ApiList(Value::kInvalid) {}
    173 
    174   explicit ApiList(uint32_t dex_flags) : dex_flags_(dex_flags) {
    175     DCHECK_EQ(dex_flags_, (dex_flags_ & kValueBitMask) | (dex_flags_ & kDomainApiBitMask));
    176   }
    177 
    178   // Helpers for conveniently constructing ApiList instances.
    179   static ApiList Whitelist() { return ApiList(Value::kWhitelist); }
    180   static ApiList Greylist() { return ApiList(Value::kGreylist); }
    181   static ApiList Blacklist() { return ApiList(Value::kBlacklist); }
    182   static ApiList GreylistMaxO() { return ApiList(Value::kGreylistMaxO); }
    183   static ApiList GreylistMaxP() { return ApiList(Value::kGreylistMaxP); }
    184   static ApiList CorePlatformApi() { return ApiList(DomainApi::kCorePlatformApi); }
    185 
    186   uint32_t GetDexFlags() const { return dex_flags_; }
    187   uint32_t GetIntValue() const { return helper::ToUint(GetValue()) - helper::ToUint(Value::kMin); }
    188 
    189   // Returns the ApiList with a flag of a given name, or an empty ApiList if not matched.
    190   static ApiList FromName(const std::string& str) {
    191     for (uint32_t i = 0; i < kValueCount; ++i) {
    192       if (str == kValueNames[i]) {
    193         return ApiList(static_cast<Value>(i + helper::ToUint(Value::kMin)));
    194       }
    195     }
    196     for (uint32_t i = 0; i < kDomainApiCount; ++i) {
    197       if (str == kDomainApiNames[i]) {
    198         return ApiList(static_cast<DomainApi>(i + helper::ToUint(DomainApi::kMin)));
    199       }
    200     }
    201     return ApiList();
    202   }
    203 
    204   // Parses a vector of flag names into a single ApiList value. If successful,
    205   // returns true and assigns the new ApiList to `out_api_list`.
    206   static bool FromNames(std::vector<std::string>::iterator begin,
    207                         std::vector<std::string>::iterator end,
    208                         /* out */ ApiList* out_api_list) {
    209     ApiList api_list;
    210     for (std::vector<std::string>::iterator it = begin; it != end; it++) {
    211       ApiList current = FromName(*it);
    212       if (current.IsEmpty() || !api_list.CanCombineWith(current)) {
    213         if (ApiStubs::IsStubsFlag(*it)) {
    214         // Ignore flags which correspond to the stubs from where the api
    215         // originates (i.e. system-api, test-api, public-api), as they are not
    216         // relevant at runtime
    217           continue;
    218         }
    219         return false;
    220       }
    221       api_list |= current;
    222     }
    223     if (out_api_list != nullptr) {
    224       *out_api_list = api_list;
    225     }
    226     return true;
    227   }
    228 
    229   bool operator==(const ApiList& other) const { return dex_flags_ == other.dex_flags_; }
    230   bool operator!=(const ApiList& other) const { return !(*this == other); }
    231 
    232   // Returns true if combining this ApiList with `other` will succeed.
    233   bool CanCombineWith(const ApiList& other) const {
    234     const Value val1 = GetValue();
    235     const Value val2 = other.GetValue();
    236     return (val1 == val2) || (val1 == Value::kInvalid) || (val2 == Value::kInvalid);
    237   }
    238 
    239   // Combine two ApiList instances.
    240   ApiList operator|(const ApiList& other) {
    241     // DomainApis are not mutually exclusive. Simply OR them.
    242     const uint32_t domain_apis = GetDomainApis() | other.GetDomainApis();
    243 
    244     // Values are mutually exclusive. Check if `this` and `other` have the same Value
    245     // or if at most one is set.
    246     const Value val1 = GetValue();
    247     const Value val2 = other.GetValue();
    248     if (val1 == val2) {
    249       return ApiList(val1, domain_apis);
    250     } else if (val1 == Value::kInvalid) {
    251       return ApiList(val2, domain_apis);
    252     } else if (val2 == Value::kInvalid) {
    253       return ApiList(val1, domain_apis);
    254     } else {
    255       LOG(FATAL) << "Invalid combination of values " << Dumpable(ApiList(val1))
    256           << " and " << Dumpable(ApiList(val2));
    257       UNREACHABLE();
    258     }
    259   }
    260 
    261   const ApiList& operator|=(const ApiList& other) {
    262     (*this) = (*this) | other;
    263     return *this;
    264   }
    265 
    266   // Returns true if all flags set in `other` are also set in `this`.
    267   bool Contains(const ApiList& other) const {
    268     return ((other.GetValue() == Value::kInvalid) || (GetValue() == other.GetValue())) &&
    269            helper::MatchesBitMask(other.GetDomainApis(), GetDomainApis());
    270   }
    271 
    272   // Returns true whether the configuration is valid for runtime use.
    273   bool IsValid() const { return GetValue() != Value::kInvalid; }
    274 
    275   // Returns true when no ApiList is specified and no domain_api flags either.
    276   bool IsEmpty() const { return (GetValue() == Value::kInvalid) && (GetDomainApis() == 0); }
    277 
    278   // Returns the maximum target SDK version allowed to access this ApiList.
    279   SdkVersion GetMaxAllowedSdkVersion() const { return kMaxSdkVersions[GetIntValue()]; }
    280 
    281   void Dump(std::ostream& os) const {
    282     bool is_first = true;
    283 
    284     if (GetValue() != Value::kInvalid) {
    285       os << kValueNames[GetIntValue()];
    286       is_first = false;
    287     }
    288 
    289     const uint32_t domain_apis = GetDomainApis();
    290     for (uint32_t i = helper::ToUint(DomainApi::kMin); i <= helper::ToUint(DomainApi::kMax); i++) {
    291       if (helper::MatchesBitMask(helper::ToBit(i), domain_apis)) {
    292         if (is_first) {
    293           is_first = false;
    294         } else {
    295           os << ",";
    296         }
    297         os << kDomainApiNames[i];
    298       }
    299     }
    300 
    301     DCHECK_EQ(IsEmpty(), is_first);
    302   }
    303 
    304   static constexpr uint32_t kValueCount = helper::NumValues<Value>();
    305   static constexpr uint32_t kDomainApiCount = helper::NumValues<DomainApi>();
    306 };
    307 
    308 inline std::ostream& operator<<(std::ostream& os, ApiList value) {
    309   value.Dump(os);
    310   return os;
    311 }
    312 
    313 }  // namespace hiddenapi
    314 }  // namespace art
    315 
    316 
    317 #endif  // ART_LIBARTBASE_BASE_HIDDENAPI_FLAGS_H_
    318