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