diff options
Diffstat (limited to 'runtime/hidden_api_access_flags.h')
-rw-r--r-- | runtime/hidden_api_access_flags.h | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/runtime/hidden_api_access_flags.h b/runtime/hidden_api_access_flags.h new file mode 100644 index 0000000000..80a002d96e --- /dev/null +++ b/runtime/hidden_api_access_flags.h @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_HIDDEN_API_ACCESS_FLAGS_H_ +#define ART_RUNTIME_HIDDEN_API_ACCESS_FLAGS_H_ + +#include "base/bit_utils.h" +#include "modifiers.h" + +namespace art { + +/* This class is used for encoding and decoding access flags of class members + * from the boot class path. These access flags might contain additional two bits + * of information on whether the given class member should be hidden from apps + * and under what circumstances. + * + * The encoding is different inside DexFile, where we are concerned with size, + * and at runtime where we want to optimize for speed of access. The class + * provides helper functions to decode/encode both of them. + * + * Encoding in DexFile + * =================== + * + * First bit is encoded as inversion of visibility flags (public/private/protected). + * At most one can be set for any given class member. If two or three are set, + * this is interpreted as the first bit being set and actual visibility flags + * being the complement of the encoded flags. + * + * Second bit is either encoded as bit 5 for fields and non-native methods, where + * it carries no other meaning. If a method is native (bit 8 set), bit 9 is used. + * + * Bits were selected so that they never increase the length of unsigned LEB-128 + * encoding of the access flags. + * + * Encoding at runtime + * =================== + * + * Two bits are set aside in the uint32_t access flags in the intrinsics ordinal + * space (thus intrinsics need to be special-cased). These are two consecutive + * bits and they are directly used to store the integer value of the ApiList + * enum values. + * + */ +class HiddenApiAccessFlags { + public: + enum ApiList { + kWhitelist = 0, + kLightGreylist, + kDarkGreylist, + kBlacklist, + }; + + static ALWAYS_INLINE ApiList DecodeFromDex(uint32_t dex_access_flags) { + DexHiddenAccessFlags flags(dex_access_flags); + uint32_t int_value = (flags.IsFirstBitSet() ? 1 : 0) + (flags.IsSecondBitSet() ? 2 : 0); + return static_cast<ApiList>(int_value); + } + + static ALWAYS_INLINE uint32_t RemoveFromDex(uint32_t dex_access_flags) { + DexHiddenAccessFlags flags(dex_access_flags); + flags.SetFirstBit(false); + flags.SetSecondBit(false); + return flags.GetEncoding(); + } + + static ALWAYS_INLINE uint32_t EncodeForDex(uint32_t dex_access_flags, ApiList value) { + DexHiddenAccessFlags flags(RemoveFromDex(dex_access_flags)); + uint32_t int_value = static_cast<uint32_t>(value); + flags.SetFirstBit((int_value & 1) != 0); + flags.SetSecondBit((int_value & 2) != 0); + return flags.GetEncoding(); + } + + static ALWAYS_INLINE ApiList DecodeFromRuntime(uint32_t runtime_access_flags) { + if ((runtime_access_flags & kAccIntrinsic) != 0) { + return kWhitelist; + } else { + uint32_t int_value = (runtime_access_flags & kAccHiddenApiBits) >> kAccFlagsShift; + return static_cast<ApiList>(int_value); + } + } + + static ALWAYS_INLINE uint32_t EncodeForRuntime(uint32_t runtime_access_flags, ApiList value) { + CHECK_EQ(runtime_access_flags & kAccIntrinsic, 0u); + + uint32_t hidden_api_flags = static_cast<uint32_t>(value) << kAccFlagsShift; + CHECK_EQ(hidden_api_flags & ~kAccHiddenApiBits, 0u); + + runtime_access_flags &= ~kAccHiddenApiBits; + return runtime_access_flags | hidden_api_flags; + } + + private: + static const int kAccFlagsShift = CTZ(kAccHiddenApiBits); + static_assert(IsPowerOfTwo((kAccHiddenApiBits >> kAccFlagsShift) + 1), + "kAccHiddenApiBits are not continuous"); + + struct DexHiddenAccessFlags { + explicit DexHiddenAccessFlags(uint32_t access_flags) : access_flags_(access_flags) {} + + ALWAYS_INLINE uint32_t GetSecondFlag() { + return ((access_flags_ & kAccNative) != 0) ? kAccDexHiddenBitNative : kAccDexHiddenBit; + } + + ALWAYS_INLINE bool IsFirstBitSet() { + static_assert(IsPowerOfTwo(0u), "Following statement checks if *at most* one bit is set"); + return !IsPowerOfTwo(access_flags_ & kAccVisibilityFlags); + } + + ALWAYS_INLINE void SetFirstBit(bool value) { + if (IsFirstBitSet() != value) { + access_flags_ ^= kAccVisibilityFlags; + } + } + + ALWAYS_INLINE bool IsSecondBitSet() { + return (access_flags_ & GetSecondFlag()) != 0; + } + + ALWAYS_INLINE void SetSecondBit(bool value) { + if (value) { + access_flags_ |= GetSecondFlag(); + } else { + access_flags_ &= ~GetSecondFlag(); + } + } + + ALWAYS_INLINE uint32_t GetEncoding() const { + return access_flags_; + } + + uint32_t access_flags_; + }; +}; + +} // namespace art + + +#endif // ART_RUNTIME_HIDDEN_API_ACCESS_FLAGS_H_ |