Home | History | Annotate | Download | only in dex
      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 
     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 
     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 
     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 
     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 
     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 {
    111     explicit DexHiddenAccessFlags(uint32_t access_flags) : access_flags_(access_flags) {}
    112 
    113     ALWAYS_INLINE uint32_t GetSecondFlag() {
    114       return ((access_flags_ & kAccNative) != 0) ? kAccDexHiddenBitNative : kAccDexHiddenBit;
    115     }
    116 
    117     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 
    122     ALWAYS_INLINE void SetFirstBit(bool value) {
    123       if (IsFirstBitSet() != value) {
    124         access_flags_ ^= kAccVisibilityFlags;
    125       }
    126     }
    127 
    128     ALWAYS_INLINE bool IsSecondBitSet() {
    129       return (access_flags_ & GetSecondFlag()) != 0;
    130     }
    131 
    132     ALWAYS_INLINE void SetSecondBit(bool value) {
    133       if (value) {
    134         access_flags_ |= GetSecondFlag();
    135       } else {
    136         access_flags_ &= ~GetSecondFlag();
    137       }
    138     }
    139 
    140     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