summaryrefslogtreecommitdiff
path: root/runtime/hidden_api_access_flags.h
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/hidden_api_access_flags.h')
-rw-r--r--runtime/hidden_api_access_flags.h152
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_