美文网首页
Android10 hiddenapi 相关代码

Android10 hiddenapi 相关代码

作者: 曾经灬 | 来源:发表于2021-12-30 19:34 被阅读0次
    
    art/runtime/native/java_lang_Class.cc
    static jobject Class_getDeclaredMethodInternal(JNIEnv* env, jobject javaThis,
                                                   jstring name, jobjectArray args) {
      ScopedFastNativeObjectAccess soa(env);
      StackHandleScope<1> hs(soa.Self());
      DCHECK_EQ(Runtime::Current()->GetClassLinker()->GetImagePointerSize(), kRuntimePointerSize);
      DCHECK(!Runtime::Current()->IsActiveTransaction());
      Handle<mirror::Method> result = hs.NewHandle(
          mirror::Class::GetDeclaredMethodInternal<kRuntimePointerSize, false>(
              soa.Self(),
              DecodeClass(soa, javaThis),
              soa.Decode<mirror::String>(name),
              soa.Decode<mirror::ObjectArray<mirror::Class>>(args),
              GetHiddenapiAccessContextFunction(soa.Self())));
      if (result == nullptr || ShouldDenyAccessToMember(result->GetArtMethod(), soa.Self())) {
        return nullptr;
      }
      return soa.AddLocalReference<jobject>(result.Get());
    }
    
    
    
    xref: /art/libdexfile/dex/hidden_api_access_flags.h
    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  
    
    
    
    
    art/runtime/hidden_api.h
    template<typename T>
    inline bool ShouldDenyAccessToMember(T* member,
                                         const std::function<AccessContext()>& fn_get_access_context,
                                         AccessMethod access_method)
        REQUIRES_SHARED(Locks::mutator_lock_) {
      DCHECK(member != nullptr);
    
      // Get the runtime flags encoded in member's access flags.
      // Note: this works for proxy methods because they inherit access flags from their
      // respective interface methods.
      const uint32_t runtime_flags = GetRuntimeFlags(member);
    
      // Exit early if member is public API. This flag is also set for non-boot class
      // path fields/methods.
      if ((runtime_flags & kAccPublicApi) != 0) {
        return false;
      }
    
      // Determine which domain the caller and callee belong to.
      // This can be *very* expensive. This is why ShouldDenyAccessToMember
      // should not be called on every individual access.
      const AccessContext caller_context = fn_get_access_context();
      const AccessContext callee_context(member->GetDeclaringClass());
    
      // Non-boot classpath callers should have exited early.
      DCHECK(!callee_context.IsApplicationDomain());
    
      // Check if the caller is always allowed to access members in the callee context.
      if (caller_context.CanAlwaysAccess(callee_context)) {
        return false;
      }
    
      // Check if this is platform accessing core platform. We may warn if `member` is
      // not part of core platform API.
      switch (caller_context.GetDomain()) {
        case Domain::kApplication: {
          DCHECK(!callee_context.IsApplicationDomain());
    
          // Exit early if access checks are completely disabled.
          EnforcementPolicy policy = Runtime::Current()->GetHiddenApiEnforcementPolicy();
          if (policy == EnforcementPolicy::kDisabled) {
            return false;
          }
    
          // If this is a proxy method, look at the interface method instead.
          member = detail::GetInterfaceMemberIfProxy(member);
    
          // Decode hidden API access flags from the dex file.
          // This is an O(N) operation scaling with the number of fields/methods
          // in the class. Only do this on slow path and only do it once.
          ApiList api_list(detail::GetDexFlags(member));
          DCHECK(api_list.IsValid());
    
          // Member is hidden and caller is not exempted. Enter slow path.
          return detail::ShouldDenyAccessToMemberImpl(member, api_list, access_method);
        }
    
        case Domain::kPlatform: {
          DCHECK(callee_context.GetDomain() == Domain::kCorePlatform);
    
          // Member is part of core platform API. Accessing it is allowed.
          if ((runtime_flags & kAccCorePlatformApi) != 0) {
            return false;
          }
    
          // Allow access if access checks are disabled.
          EnforcementPolicy policy = Runtime::Current()->GetCorePlatformApiEnforcementPolicy();
          if (policy == EnforcementPolicy::kDisabled) {
            return false;
          }
    
          // If this is a proxy method, look at the interface method instead.
          member = detail::GetInterfaceMemberIfProxy(member);
    
          // Access checks are not disabled, report the violation.
          // This may also add kAccCorePlatformApi to the access flags of `member`
          // so as to not warn again on next access.
          return detail::HandleCorePlatformApiViolation(member,
                                                        caller_context,
                                                        access_method,
                                                        policy);
        }
    
        case Domain::kCorePlatform: {
          LOG(FATAL) << "CorePlatform domain should be allowed to access all domains";
          UNREACHABLE();
        }
      }
    }
    
    
    /art/runtime/hidden_api.cc
    template<typename T>
    bool ShouldDenyAccessToMemberImpl(T* member, ApiList api_list, AccessMethod access_method) {
      DCHECK(member != nullptr);
      Runtime* runtime = Runtime::Current();
    
      EnforcementPolicy policy = runtime->GetHiddenApiEnforcementPolicy();
      DCHECK(policy != EnforcementPolicy::kDisabled)
          << "Should never enter this function when access checks are completely disabled";
    
      const bool deny_access =
          (policy == EnforcementPolicy::kEnabled) &&
          IsSdkVersionSetAndMoreThan(runtime->GetTargetSdkVersion(),
                                     api_list.GetMaxAllowedSdkVersion());
    
      MemberSignature member_signature(member);
    
      // Check for an exemption first. Exempted APIs are treated as white list.
      if (member_signature.IsExempted(runtime->GetHiddenApiExemptions())) {
        // Avoid re-examining the exemption list next time.
        // Note this results in no warning for the member, which seems like what one would expect.
        // Exemptions effectively adds new members to the whitelist.
        MaybeUpdateAccessFlags(runtime, member, kAccPublicApi);
        return false;
      }
    
      if (access_method != AccessMethod::kNone) {
        // Print a log message with information about this class member access.
        // We do this if we're about to deny access, or the app is debuggable.
        if (kLogAllAccesses || deny_access || runtime->IsJavaDebuggable()) {
          member_signature.WarnAboutAccess(access_method, api_list, deny_access);
        }
    
        // If there is a StrictMode listener, notify it about this violation.
        member_signature.NotifyHiddenApiListener(access_method);
    
        // If event log sampling is enabled, report this violation.
        if (kIsTargetBuild && !kIsTargetLinux) {
          uint32_t eventLogSampleRate = runtime->GetHiddenApiEventLogSampleRate();
          // Assert that RAND_MAX is big enough, to ensure sampling below works as expected.
          static_assert(RAND_MAX >= 0xffff, "RAND_MAX too small");
          if (eventLogSampleRate != 0) {
            const uint32_t sampled_value = static_cast<uint32_t>(std::rand()) & 0xffff;
            if (sampled_value < eventLogSampleRate) {
              member_signature.LogAccessToEventLog(sampled_value, access_method, deny_access);
            }
          }
        }
    
        // If this access was not denied, move the member into whitelist and skip
        // the warning the next time the member is accessed.
        if (!deny_access) {
          MaybeUpdateAccessFlags(runtime, member, kAccPublicApi);
        }
      }
    
      return deny_access;
    }
    
    
    78  MemberSignature::MemberSignature(ArtField* field) {
    79    class_name_ = field->GetDeclaringClass()->GetDescriptor(&tmp_);
    80    member_name_ = field->GetName();
    81    type_signature_ = field->GetTypeDescriptor();
    82    type_ = kField;
    83  }
    84  
    85  MemberSignature::MemberSignature(ArtMethod* method) {
    86    // If this is a proxy method, print the signature of the interface method.
    87    method = method->GetInterfaceMethodIfProxy(
    88        Runtime::Current()->GetClassLinker()->GetImagePointerSize());
    89  
    90    class_name_ = method->GetDeclaringClass()->GetDescriptor(&tmp_);
    91    member_name_ = method->GetName();
    92    type_signature_ = method->GetSignature().ToString();
    93    type_ = kMethod;
    94  }
    95  
    96  inline std::vector<const char*> MemberSignature::GetSignatureParts() const {
    97    if (type_ == kField) {
    98      return { class_name_.c_str(), "->", member_name_.c_str(), ":", type_signature_.c_str() };
    99    } else {
    100      DCHECK_EQ(type_, kMethod);
    101      return { class_name_.c_str(), "->", member_name_.c_str(), type_signature_.c_str() };
    102    }
    103  }
    104  
    105  bool MemberSignature::DoesPrefixMatch(const std::string& prefix) const {
    106    size_t pos = 0;
    107    for (const char* part : GetSignatureParts()) {
    108      size_t count = std::min(prefix.length() - pos, strlen(part));
    109      if (prefix.compare(pos, count, part, 0, count) == 0) {
    110        pos += count;
    111      } else {
    112        return false;
    113      }
    114    }
    115    // We have a complete match if all parts match (we exit the loop without
    116    // returning) AND we've matched the whole prefix.
    117    return pos == prefix.length();
    118  }
    
    

    相关文章

      网友评论

          本文标题:Android10 hiddenapi 相关代码

          本文链接:https://www.haomeiwen.com/subject/hdcwqrtx.html