• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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