• 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_RUNTIME_HIDDEN_API_H_
18 #define ART_RUNTIME_HIDDEN_API_H_
19 
20 #include "art_field.h"
21 #include "art_method.h"
22 #include "base/hiddenapi_domain.h"
23 #include "base/hiddenapi_flags.h"
24 #include "base/locks.h"
25 #include "intrinsics_enum.h"
26 #include "jni/jni_internal.h"
27 #include "mirror/class-inl.h"
28 #include "reflection.h"
29 #include "runtime.h"
30 #include "well_known_classes.h"
31 
32 namespace art {
33 namespace hiddenapi {
34 
35 // Hidden API enforcement policy
36 // This must be kept in sync with ApplicationInfo.ApiEnforcementPolicy in
37 // frameworks/base/core/java/android/content/pm/ApplicationInfo.java
38 enum class EnforcementPolicy {
39   kDisabled             = 0,
40   kJustWarn             = 1,  // keep checks enabled, but allow everything (enables logging)
41   kEnabled              = 2,  // ban conditionally blocked & blocklist
42   kMax = kEnabled,
43 };
44 
EnforcementPolicyFromInt(int api_policy_int)45 inline EnforcementPolicy EnforcementPolicyFromInt(int api_policy_int) {
46   DCHECK_GE(api_policy_int, 0);
47   DCHECK_LE(api_policy_int, static_cast<int>(EnforcementPolicy::kMax));
48   return static_cast<EnforcementPolicy>(api_policy_int);
49 }
50 
51 // Hidden API access method
52 // Thist must be kept in sync with VMRuntime.HiddenApiUsageLogger.ACCESS_METHOD_*
53 enum class AccessMethod {
54   kNone = 0,  // internal test that does not correspond to an actual access by app
55   kReflection = 1,
56   kJNI = 2,
57   kLinking = 3,
58 };
59 
60 // Represents the API domain of a caller/callee.
61 class AccessContext {
62  public:
63   // Initialize to either the fully-trusted or fully-untrusted domain.
AccessContext(bool is_trusted)64   explicit AccessContext(bool is_trusted)
65       : klass_(nullptr),
66         dex_file_(nullptr),
67         domain_(ComputeDomain(is_trusted)) {}
68 
69   // Initialize from class loader and dex file (via dex cache).
AccessContext(ObjPtr<mirror::ClassLoader> class_loader,ObjPtr<mirror::DexCache> dex_cache)70   AccessContext(ObjPtr<mirror::ClassLoader> class_loader, ObjPtr<mirror::DexCache> dex_cache)
71       REQUIRES_SHARED(Locks::mutator_lock_)
72       : klass_(nullptr),
73         dex_file_(GetDexFileFromDexCache(dex_cache)),
74         domain_(ComputeDomain(class_loader, dex_file_)) {}
75 
76   // Initialize from class loader and dex file (only used by tests).
AccessContext(ObjPtr<mirror::ClassLoader> class_loader,const DexFile * dex_file)77   AccessContext(ObjPtr<mirror::ClassLoader> class_loader, const DexFile* dex_file)
78       : klass_(nullptr),
79         dex_file_(dex_file),
80         domain_(ComputeDomain(class_loader, dex_file_)) {}
81 
82   // Initialize from Class.
AccessContext(ObjPtr<mirror::Class> klass)83   explicit AccessContext(ObjPtr<mirror::Class> klass)
84       REQUIRES_SHARED(Locks::mutator_lock_)
85       : klass_(klass),
86         dex_file_(GetDexFileFromDexCache(klass->GetDexCache())),
87         domain_(ComputeDomain(klass, dex_file_)) {}
88 
GetClass()89   ObjPtr<mirror::Class> GetClass() const { return klass_; }
GetDexFile()90   const DexFile* GetDexFile() const { return dex_file_; }
GetDomain()91   Domain GetDomain() const { return domain_; }
IsApplicationDomain()92   bool IsApplicationDomain() const { return domain_ == Domain::kApplication; }
93 
94   // Returns true if this domain is always allowed to access the domain of `callee`.
CanAlwaysAccess(const AccessContext & callee)95   bool CanAlwaysAccess(const AccessContext& callee) const {
96     return IsDomainMoreTrustedThan(domain_, callee.domain_);
97   }
98 
99  private:
GetDexFileFromDexCache(ObjPtr<mirror::DexCache> dex_cache)100   static const DexFile* GetDexFileFromDexCache(ObjPtr<mirror::DexCache> dex_cache)
101       REQUIRES_SHARED(Locks::mutator_lock_) {
102     return dex_cache.IsNull() ? nullptr : dex_cache->GetDexFile();
103   }
104 
ComputeDomain(bool is_trusted)105   static Domain ComputeDomain(bool is_trusted) {
106     return is_trusted ? Domain::kCorePlatform : Domain::kApplication;
107   }
108 
ComputeDomain(ObjPtr<mirror::ClassLoader> class_loader,const DexFile * dex_file)109   static Domain ComputeDomain(ObjPtr<mirror::ClassLoader> class_loader, const DexFile* dex_file) {
110     if (dex_file == nullptr) {
111       return ComputeDomain(/* is_trusted= */ class_loader.IsNull());
112     }
113 
114     return dex_file->GetHiddenapiDomain();
115   }
116 
ComputeDomain(ObjPtr<mirror::Class> klass,const DexFile * dex_file)117   static Domain ComputeDomain(ObjPtr<mirror::Class> klass, const DexFile* dex_file)
118       REQUIRES_SHARED(Locks::mutator_lock_) {
119     // Check other aspects of the context.
120     Domain domain = ComputeDomain(klass->GetClassLoader(), dex_file);
121 
122     if (domain == Domain::kApplication &&
123         klass->ShouldSkipHiddenApiChecks() &&
124         Runtime::Current()->IsJavaDebuggable()) {
125       // Class is known, it is marked trusted and we are in debuggable mode.
126       domain = ComputeDomain(/* is_trusted= */ true);
127     }
128 
129     return domain;
130   }
131 
132   // Pointer to declaring class of the caller/callee (null if not provided).
133   // This is not safe across GC but we're only using this class for passing
134   // information about the caller to the access check logic and never retain
135   // the AccessContext instance beyond that.
136   const ObjPtr<mirror::Class> klass_;
137 
138   // DexFile of the caller/callee (null if not provided).
139   const DexFile* const dex_file_;
140 
141   // Computed domain of the caller/callee.
142   const Domain domain_;
143 };
144 
145 class ScopedHiddenApiEnforcementPolicySetting {
146  public:
ScopedHiddenApiEnforcementPolicySetting(EnforcementPolicy new_policy)147   explicit ScopedHiddenApiEnforcementPolicySetting(EnforcementPolicy new_policy)
148       : initial_policy_(Runtime::Current()->GetHiddenApiEnforcementPolicy()) {
149     Runtime::Current()->SetHiddenApiEnforcementPolicy(new_policy);
150   }
151 
~ScopedHiddenApiEnforcementPolicySetting()152   ~ScopedHiddenApiEnforcementPolicySetting() {
153     Runtime::Current()->SetHiddenApiEnforcementPolicy(initial_policy_);
154   }
155 
156  private:
157   const EnforcementPolicy initial_policy_;
158   DISALLOW_COPY_AND_ASSIGN(ScopedHiddenApiEnforcementPolicySetting);
159 };
160 
161 void InitializeCorePlatformApiPrivateFields() REQUIRES(!Locks::mutator_lock_);
162 
163 // Implementation details. DO NOT ACCESS DIRECTLY.
164 namespace detail {
165 
166 // Class to encapsulate the signature of a member (ArtField or ArtMethod). This
167 // is used as a helper when matching prefixes, and when logging the signature.
168 class MemberSignature {
169  private:
170   enum MemberType {
171     kField,
172     kMethod,
173   };
174 
175   std::string class_name_;
176   std::string member_name_;
177   std::string type_signature_;
178   std::string tmp_;
179   MemberType type_;
180 
181   inline std::vector<const char*> GetSignatureParts() const;
182 
183  public:
184   explicit MemberSignature(ArtField* field) REQUIRES_SHARED(Locks::mutator_lock_);
185   explicit MemberSignature(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_);
186   explicit MemberSignature(const ClassAccessor::Field& field);
187   explicit MemberSignature(const ClassAccessor::Method& method);
188 
189   void Dump(std::ostream& os) const;
190 
191   bool Equals(const MemberSignature& other);
192   bool MemberNameAndTypeMatch(const MemberSignature& other);
193 
194   // Performs prefix match on this member. Since the full member signature is
195   // composed of several parts, we match each part in turn (rather than
196   // building the entire thing in memory and performing a simple prefix match)
197   bool DoesPrefixMatch(const std::string& prefix) const;
198 
199   bool DoesPrefixMatchAny(const std::vector<std::string>& exemptions);
200 
201   void WarnAboutAccess(AccessMethod access_method, ApiList list, bool access_denied);
202 
203   void LogAccessToEventLog(uint32_t sampled_value, AccessMethod access_method, bool access_denied);
204 
205   // Calls back into managed code to notify VMRuntime.nonSdkApiUsageConsumer that
206   // |member| was accessed. This is usually called when an API is unsupported,
207   // conditionally or unconditionally blocked. Given that the callback can execute arbitrary
208   // code, a call to this method can result in thread suspension.
209   void NotifyHiddenApiListener(AccessMethod access_method);
210 };
211 
212 // Locates hiddenapi flags for `field` in the corresponding dex file.
213 // NB: This is an O(N) operation, linear with the number of members in the class def.
214 template<typename T>
215 uint32_t GetDexFlags(T* member) REQUIRES_SHARED(Locks::mutator_lock_);
216 
217 // Handler of detected core platform API violations. Returns true if access to
218 // `member` should be denied.
219 template<typename T>
220 bool HandleCorePlatformApiViolation(T* member,
221                                     const AccessContext& caller_context,
222                                     AccessMethod access_method,
223                                     EnforcementPolicy policy)
224     REQUIRES_SHARED(Locks::mutator_lock_);
225 
226 template<typename T>
227 bool ShouldDenyAccessToMemberImpl(T* member, ApiList api_list, AccessMethod access_method)
228     REQUIRES_SHARED(Locks::mutator_lock_);
229 
GetInterfaceMemberIfProxy(ArtField * field)230 inline ArtField* GetInterfaceMemberIfProxy(ArtField* field) { return field; }
231 
GetInterfaceMemberIfProxy(ArtMethod * method)232 inline ArtMethod* GetInterfaceMemberIfProxy(ArtMethod* method)
233     REQUIRES_SHARED(Locks::mutator_lock_) {
234   return method->GetInterfaceMethodIfProxy(kRuntimePointerSize);
235 }
236 
237 // Returns access flags for the runtime representation of a class member (ArtField/ArtMember).
CreateRuntimeFlags_Impl(uint32_t dex_flags)238 ALWAYS_INLINE inline uint32_t CreateRuntimeFlags_Impl(uint32_t dex_flags) {
239   uint32_t runtime_flags = 0u;
240 
241   ApiList api_list(dex_flags);
242   DCHECK(api_list.IsValid());
243 
244   if (api_list.Contains(ApiList::Sdk())) {
245     runtime_flags |= kAccPublicApi;
246   } else {
247     // Only add domain-specific flags for non-public API members.
248     // This simplifies hardcoded values for intrinsics.
249     if (api_list.Contains(ApiList::CorePlatformApi())) {
250       runtime_flags |= kAccCorePlatformApi;
251     }
252   }
253 
254   DCHECK_EQ(runtime_flags & kAccHiddenapiBits, runtime_flags)
255       << "Runtime flags not in reserved access flags bits";
256   return runtime_flags;
257 }
258 
259 }  // namespace detail
260 
261 // Returns access flags for the runtime representation of a class member (ArtField/ArtMember).
CreateRuntimeFlags(const ClassAccessor::BaseItem & member)262 ALWAYS_INLINE inline uint32_t CreateRuntimeFlags(const ClassAccessor::BaseItem& member) {
263   return detail::CreateRuntimeFlags_Impl(member.GetHiddenapiFlags());
264 }
265 
266 // Returns access flags for the runtime representation of a class member (ArtField/ArtMember).
267 template<typename T>
CreateRuntimeFlags(T * member)268 ALWAYS_INLINE inline uint32_t CreateRuntimeFlags(T* member) REQUIRES_SHARED(Locks::mutator_lock_) {
269   return detail::CreateRuntimeFlags_Impl(detail::GetDexFlags(member));
270 }
271 
272 // Extracts hiddenapi runtime flags from access flags of ArtField.
GetRuntimeFlags(ArtField * field)273 ALWAYS_INLINE inline uint32_t GetRuntimeFlags(ArtField* field)
274     REQUIRES_SHARED(Locks::mutator_lock_) {
275   return field->GetAccessFlags() & kAccHiddenapiBits;
276 }
277 
278 // Extracts hiddenapi runtime flags from access flags of ArtMethod.
279 // Uses hardcoded values for intrinsics.
GetRuntimeFlags(ArtMethod * method)280 ALWAYS_INLINE inline uint32_t GetRuntimeFlags(ArtMethod* method)
281     REQUIRES_SHARED(Locks::mutator_lock_) {
282   if (UNLIKELY(method->IsIntrinsic())) {
283     switch (static_cast<Intrinsics>(method->GetIntrinsic())) {
284       case Intrinsics::kSystemArrayCopyChar:
285       case Intrinsics::kStringGetCharsNoCheck:
286       case Intrinsics::kReferenceGetReferent:
287       case Intrinsics::kReferenceRefersTo:
288       case Intrinsics::kMemoryPeekByte:
289       case Intrinsics::kMemoryPokeByte:
290       case Intrinsics::kCRC32Update:
291       case Intrinsics::kCRC32UpdateBytes:
292       case Intrinsics::kCRC32UpdateByteBuffer:
293       case Intrinsics::kStringNewStringFromBytes:
294       case Intrinsics::kStringNewStringFromChars:
295       case Intrinsics::kStringNewStringFromString:
296       case Intrinsics::kMemoryPeekIntNative:
297       case Intrinsics::kMemoryPeekLongNative:
298       case Intrinsics::kMemoryPeekShortNative:
299       case Intrinsics::kMemoryPokeIntNative:
300       case Intrinsics::kMemoryPokeLongNative:
301       case Intrinsics::kMemoryPokeShortNative:
302       case Intrinsics::kUnsafeCASInt:
303       case Intrinsics::kUnsafeCASLong:
304       case Intrinsics::kUnsafeCASObject:
305       case Intrinsics::kUnsafeGetAndAddInt:
306       case Intrinsics::kUnsafeGetAndAddLong:
307       case Intrinsics::kUnsafeGetAndSetInt:
308       case Intrinsics::kUnsafeGetAndSetLong:
309       case Intrinsics::kUnsafeGetAndSetObject:
310       case Intrinsics::kUnsafeGetLongVolatile:
311       case Intrinsics::kUnsafeGetObjectVolatile:
312       case Intrinsics::kUnsafeGetVolatile:
313       case Intrinsics::kUnsafePutLongOrdered:
314       case Intrinsics::kUnsafePutLongVolatile:
315       case Intrinsics::kUnsafePutObjectOrdered:
316       case Intrinsics::kUnsafePutObjectVolatile:
317       case Intrinsics::kUnsafePutOrdered:
318       case Intrinsics::kUnsafePutVolatile:
319       case Intrinsics::kUnsafeLoadFence:
320       case Intrinsics::kUnsafeStoreFence:
321       case Intrinsics::kUnsafeFullFence:
322       case Intrinsics::kVarHandleFullFence:
323       case Intrinsics::kVarHandleAcquireFence:
324       case Intrinsics::kVarHandleReleaseFence:
325       case Intrinsics::kVarHandleLoadLoadFence:
326       case Intrinsics::kVarHandleStoreStoreFence:
327       case Intrinsics::kVarHandleCompareAndExchange:
328       case Intrinsics::kVarHandleCompareAndExchangeAcquire:
329       case Intrinsics::kVarHandleCompareAndExchangeRelease:
330       case Intrinsics::kVarHandleCompareAndSet:
331       case Intrinsics::kVarHandleGet:
332       case Intrinsics::kVarHandleGetAcquire:
333       case Intrinsics::kVarHandleGetAndAdd:
334       case Intrinsics::kVarHandleGetAndAddAcquire:
335       case Intrinsics::kVarHandleGetAndAddRelease:
336       case Intrinsics::kVarHandleGetAndBitwiseAnd:
337       case Intrinsics::kVarHandleGetAndBitwiseAndAcquire:
338       case Intrinsics::kVarHandleGetAndBitwiseAndRelease:
339       case Intrinsics::kVarHandleGetAndBitwiseOr:
340       case Intrinsics::kVarHandleGetAndBitwiseOrAcquire:
341       case Intrinsics::kVarHandleGetAndBitwiseOrRelease:
342       case Intrinsics::kVarHandleGetAndBitwiseXor:
343       case Intrinsics::kVarHandleGetAndBitwiseXorAcquire:
344       case Intrinsics::kVarHandleGetAndBitwiseXorRelease:
345       case Intrinsics::kVarHandleGetAndSet:
346       case Intrinsics::kVarHandleGetAndSetAcquire:
347       case Intrinsics::kVarHandleGetAndSetRelease:
348       case Intrinsics::kVarHandleGetOpaque:
349       case Intrinsics::kVarHandleGetVolatile:
350       case Intrinsics::kVarHandleSet:
351       case Intrinsics::kVarHandleSetOpaque:
352       case Intrinsics::kVarHandleSetRelease:
353       case Intrinsics::kVarHandleSetVolatile:
354       case Intrinsics::kVarHandleWeakCompareAndSet:
355       case Intrinsics::kVarHandleWeakCompareAndSetAcquire:
356       case Intrinsics::kVarHandleWeakCompareAndSetPlain:
357       case Intrinsics::kVarHandleWeakCompareAndSetRelease:
358         return 0u;
359       case Intrinsics::kFP16Ceil:
360       case Intrinsics::kFP16Floor:
361       case Intrinsics::kFP16Greater:
362       case Intrinsics::kFP16GreaterEquals:
363       case Intrinsics::kFP16Less:
364       case Intrinsics::kFP16LessEquals:
365       case Intrinsics::kFP16ToFloat:
366       case Intrinsics::kFP16ToHalf:
367       case Intrinsics::kFP16Rint:
368       case Intrinsics::kUnsafeGet:
369       case Intrinsics::kUnsafeGetLong:
370       case Intrinsics::kUnsafeGetObject:
371       case Intrinsics::kUnsafePutLong:
372       case Intrinsics::kUnsafePut:
373       case Intrinsics::kUnsafePutObject:
374         return kAccCorePlatformApi;
375       default:
376         // Remaining intrinsics are public API. We DCHECK that in SetIntrinsic().
377         return kAccPublicApi;
378     }
379   } else {
380     return method->GetAccessFlags() & kAccHiddenapiBits;
381   }
382 }
383 
384 // Called by class linker when a new dex file has been registered. Assigns
385 // the AccessContext domain to the newly-registered dex file based on its
386 // location and class loader.
387 void InitializeDexFileDomain(const DexFile& dex_file, ObjPtr<mirror::ClassLoader> class_loader);
388 
389 // Returns true if access to `member` should be denied in the given context.
390 // The decision is based on whether the caller is in a trusted context or not.
391 // Because determining the access context can be expensive, a lambda function
392 // "fn_get_access_context" is lazily invoked after other criteria have been
393 // considered.
394 // This function might print warnings into the log if the member is hidden.
395 template<typename T>
ShouldDenyAccessToMember(T * member,const std::function<AccessContext ()> & fn_get_access_context,AccessMethod access_method)396 inline bool ShouldDenyAccessToMember(T* member,
397                                      const std::function<AccessContext()>& fn_get_access_context,
398                                      AccessMethod access_method)
399     REQUIRES_SHARED(Locks::mutator_lock_) {
400   DCHECK(member != nullptr);
401 
402   // First check if we have an explicit sdk checker installed that should be used to
403   // verify access. If so, make the decision based on it.
404   //
405   // This is used during off-device AOT compilation which may want to generate verification
406   // metadata only for a specific list of public SDKs. Note that the check here is made
407   // based on descriptor equality and it's aim to further restrict a symbol that would
408   // otherwise be resolved.
409   //
410   // The check only applies to boot classpaths dex files.
411   Runtime* runtime = Runtime::Current();
412   if (UNLIKELY(runtime->IsAotCompiler())) {
413     if (member->GetDeclaringClass()->GetClassLoader() == nullptr &&
414         runtime->GetClassLinker()->DenyAccessBasedOnPublicSdk(member)) {
415       return true;
416     }
417   }
418 
419   // Get the runtime flags encoded in member's access flags.
420   // Note: this works for proxy methods because they inherit access flags from their
421   // respective interface methods.
422   const uint32_t runtime_flags = GetRuntimeFlags(member);
423 
424   // Exit early if member is public API. This flag is also set for non-boot class
425   // path fields/methods.
426   if ((runtime_flags & kAccPublicApi) != 0) {
427     return false;
428   }
429 
430   // Determine which domain the caller and callee belong to.
431   // This can be *very* expensive. This is why ShouldDenyAccessToMember
432   // should not be called on every individual access.
433   const AccessContext caller_context = fn_get_access_context();
434   const AccessContext callee_context(member->GetDeclaringClass());
435 
436   // Non-boot classpath callers should have exited early.
437   DCHECK(!callee_context.IsApplicationDomain());
438 
439   // Check if the caller is always allowed to access members in the callee context.
440   if (caller_context.CanAlwaysAccess(callee_context)) {
441     return false;
442   }
443 
444   // Check if this is platform accessing core platform. We may warn if `member` is
445   // not part of core platform API.
446   switch (caller_context.GetDomain()) {
447     case Domain::kApplication: {
448       DCHECK(!callee_context.IsApplicationDomain());
449 
450       // Exit early if access checks are completely disabled.
451       EnforcementPolicy policy = runtime->GetHiddenApiEnforcementPolicy();
452       if (policy == EnforcementPolicy::kDisabled) {
453         return false;
454       }
455 
456       // If this is a proxy method, look at the interface method instead.
457       member = detail::GetInterfaceMemberIfProxy(member);
458 
459       // Decode hidden API access flags from the dex file.
460       // This is an O(N) operation scaling with the number of fields/methods
461       // in the class. Only do this on slow path and only do it once.
462       ApiList api_list(detail::GetDexFlags(member));
463       DCHECK(api_list.IsValid());
464 
465       // Member is hidden and caller is not exempted. Enter slow path.
466       return detail::ShouldDenyAccessToMemberImpl(member, api_list, access_method);
467     }
468 
469     case Domain::kPlatform: {
470       DCHECK(callee_context.GetDomain() == Domain::kCorePlatform);
471 
472       // Member is part of core platform API. Accessing it is allowed.
473       if ((runtime_flags & kAccCorePlatformApi) != 0) {
474         return false;
475       }
476 
477       // Allow access if access checks are disabled.
478       EnforcementPolicy policy = Runtime::Current()->GetCorePlatformApiEnforcementPolicy();
479       if (policy == EnforcementPolicy::kDisabled) {
480         return false;
481       }
482 
483       // If this is a proxy method, look at the interface method instead.
484       member = detail::GetInterfaceMemberIfProxy(member);
485 
486       // Access checks are not disabled, report the violation.
487       // This may also add kAccCorePlatformApi to the access flags of `member`
488       // so as to not warn again on next access.
489       return detail::HandleCorePlatformApiViolation(member,
490                                                     caller_context,
491                                                     access_method,
492                                                     policy);
493     }
494 
495     case Domain::kCorePlatform: {
496       LOG(FATAL) << "CorePlatform domain should be allowed to access all domains";
497       UNREACHABLE();
498     }
499   }
500 }
501 
502 // Helper method for callers where access context can be determined beforehand.
503 // Wraps AccessContext in a lambda and passes it to the real ShouldDenyAccessToMember.
504 template<typename T>
ShouldDenyAccessToMember(T * member,const AccessContext & access_context,AccessMethod access_method)505 inline bool ShouldDenyAccessToMember(T* member,
506                                      const AccessContext& access_context,
507                                      AccessMethod access_method)
508     REQUIRES_SHARED(Locks::mutator_lock_) {
509   return ShouldDenyAccessToMember(member, [&]() { return access_context; }, access_method);
510 }
511 
512 }  // namespace hiddenapi
513 }  // namespace art
514 
515 #endif  // ART_RUNTIME_HIDDEN_API_H_
516