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_LIBDEXFILE_DEX_HIDDEN_API_ACCESS_FLAGS_H_ 18 #define ART_LIBDEXFILE_DEX_HIDDEN_API_ACCESS_FLAGS_H_ 19 20 #include "base/bit_utils.h" 21 #include "base/macros.h" 22 #include "dex/modifiers.h" 23 24 namespace art { 25 26 /* This class is used for encoding and decoding access flags of class members 27 * from the boot class path. These access flags might contain additional two bits 28 * of information on whether the given class member should be hidden from apps 29 * and under what circumstances. 30 * 31 * The encoding is different inside DexFile, where we are concerned with size, 32 * and at runtime where we want to optimize for speed of access. The class 33 * provides helper functions to decode/encode both of them. 34 * 35 * Encoding in DexFile 36 * =================== 37 * 38 * First bit is encoded as inversion of visibility flags (public/private/protected). 39 * At most one can be set for any given class member. If two or three are set, 40 * this is interpreted as the first bit being set and actual visibility flags 41 * being the complement of the encoded flags. 42 * 43 * Second bit is either encoded as bit 5 for fields and non-native methods, where 44 * it carries no other meaning. If a method is native (bit 8 set), bit 9 is used. 45 * 46 * Bits were selected so that they never increase the length of unsigned LEB-128 47 * encoding of the access flags. 48 * 49 * Encoding at runtime 50 * =================== 51 * 52 * Two bits are set aside in the uint32_t access flags in the intrinsics ordinal 53 * space (thus intrinsics need to be special-cased). These are two consecutive 54 * bits and they are directly used to store the integer value of the ApiList 55 * enum values. 56 * 57 */ 58 class HiddenApiAccessFlags { 59 public: 60 enum ApiList { 61 kWhitelist = 0, 62 kLightGreylist, 63 kDarkGreylist, 64 kBlacklist, 65 }; 66 DecodeFromDex(uint32_t dex_access_flags)67 static ALWAYS_INLINE ApiList DecodeFromDex(uint32_t dex_access_flags) { 68 DexHiddenAccessFlags flags(dex_access_flags); 69 uint32_t int_value = (flags.IsFirstBitSet() ? 1 : 0) + (flags.IsSecondBitSet() ? 2 : 0); 70 return static_cast<ApiList>(int_value); 71 } 72 RemoveFromDex(uint32_t dex_access_flags)73 static ALWAYS_INLINE uint32_t RemoveFromDex(uint32_t dex_access_flags) { 74 DexHiddenAccessFlags flags(dex_access_flags); 75 flags.SetFirstBit(false); 76 flags.SetSecondBit(false); 77 return flags.GetEncoding(); 78 } 79 EncodeForDex(uint32_t dex_access_flags,ApiList value)80 static ALWAYS_INLINE uint32_t EncodeForDex(uint32_t dex_access_flags, ApiList value) { 81 DexHiddenAccessFlags flags(RemoveFromDex(dex_access_flags)); 82 uint32_t int_value = static_cast<uint32_t>(value); 83 flags.SetFirstBit((int_value & 1) != 0); 84 flags.SetSecondBit((int_value & 2) != 0); 85 return flags.GetEncoding(); 86 } 87 DecodeFromRuntime(uint32_t runtime_access_flags)88 static ALWAYS_INLINE ApiList DecodeFromRuntime(uint32_t runtime_access_flags) { 89 // This is used in the fast path, only DCHECK here. 90 DCHECK_EQ(runtime_access_flags & kAccIntrinsic, 0u); 91 uint32_t int_value = (runtime_access_flags & kAccHiddenApiBits) >> kAccFlagsShift; 92 return static_cast<ApiList>(int_value); 93 } 94 EncodeForRuntime(uint32_t runtime_access_flags,ApiList value)95 static ALWAYS_INLINE uint32_t EncodeForRuntime(uint32_t runtime_access_flags, ApiList value) { 96 CHECK_EQ(runtime_access_flags & kAccIntrinsic, 0u); 97 98 uint32_t hidden_api_flags = static_cast<uint32_t>(value) << kAccFlagsShift; 99 CHECK_EQ(hidden_api_flags & ~kAccHiddenApiBits, 0u); 100 101 runtime_access_flags &= ~kAccHiddenApiBits; 102 return runtime_access_flags | hidden_api_flags; 103 } 104 105 private: 106 static const int kAccFlagsShift = CTZ(kAccHiddenApiBits); 107 static_assert(IsPowerOfTwo((kAccHiddenApiBits >> kAccFlagsShift) + 1), 108 "kAccHiddenApiBits are not continuous"); 109 110 struct DexHiddenAccessFlags { DexHiddenAccessFlagsDexHiddenAccessFlags111 explicit DexHiddenAccessFlags(uint32_t access_flags) : access_flags_(access_flags) {} 112 GetSecondFlagDexHiddenAccessFlags113 ALWAYS_INLINE uint32_t GetSecondFlag() { 114 return ((access_flags_ & kAccNative) != 0) ? kAccDexHiddenBitNative : kAccDexHiddenBit; 115 } 116 IsFirstBitSetDexHiddenAccessFlags117 ALWAYS_INLINE bool IsFirstBitSet() { 118 static_assert(IsPowerOfTwo(0u), "Following statement checks if *at most* one bit is set"); 119 return !IsPowerOfTwo(access_flags_ & kAccVisibilityFlags); 120 } 121 SetFirstBitDexHiddenAccessFlags122 ALWAYS_INLINE void SetFirstBit(bool value) { 123 if (IsFirstBitSet() != value) { 124 access_flags_ ^= kAccVisibilityFlags; 125 } 126 } 127 IsSecondBitSetDexHiddenAccessFlags128 ALWAYS_INLINE bool IsSecondBitSet() { 129 return (access_flags_ & GetSecondFlag()) != 0; 130 } 131 SetSecondBitDexHiddenAccessFlags132 ALWAYS_INLINE void SetSecondBit(bool value) { 133 if (value) { 134 access_flags_ |= GetSecondFlag(); 135 } else { 136 access_flags_ &= ~GetSecondFlag(); 137 } 138 } 139 GetEncodingDexHiddenAccessFlags140 ALWAYS_INLINE uint32_t GetEncoding() const { 141 return access_flags_; 142 } 143 144 uint32_t access_flags_; 145 }; 146 }; 147 148 inline std::ostream& operator<<(std::ostream& os, HiddenApiAccessFlags::ApiList value) { 149 switch (value) { 150 case HiddenApiAccessFlags::kWhitelist: 151 os << "whitelist"; 152 break; 153 case HiddenApiAccessFlags::kLightGreylist: 154 os << "light greylist"; 155 break; 156 case HiddenApiAccessFlags::kDarkGreylist: 157 os << "dark greylist"; 158 break; 159 case HiddenApiAccessFlags::kBlacklist: 160 os << "blacklist"; 161 break; 162 } 163 return os; 164 } 165 166 } // namespace art 167 168 169 #endif // ART_LIBDEXFILE_DEX_HIDDEN_API_ACCESS_FLAGS_H_ 170