Android10 hiddenapi 相关代码


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 result = hs.NewHandle(
      mirror::Class::GetDeclaredMethodInternal(
          soa.Self(),
          DecodeClass(soa, javaThis),
          soa.Decode(name),
          soa.Decode>(args),
          GetHiddenapiAccessContextFunction(soa.Self())));
  if (result == nullptr || ShouldDenyAccessToMember(result->GetArtMethod(), soa.Self())) {
    return nullptr;
  }
  return soa.AddLocalReference(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(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(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(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(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
inline bool ShouldDenyAccessToMember(T* member,
                                     const std::function& 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
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(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 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 相关代码)