// Hidden API access method // This must be kept in sync with VMRuntime.HiddenApiUsageLogger.ACCESS_METHOD_* // for the access methods that are logged. enumclass AccessMethod { // Internal checks that don't log access warnings or failures. They may be // used for checks that don't correspond to an actual access by the running // app. They may also be used for a check that, if denied, will be followed by // zero or more kCheck or kCheckWithPolicy checks and eventually an // AccessMethod that is something else. That last check will then log and // apply the policy (if it is denied too). // // kCheck returns whether the access would be allowed by hiddenapi or not, // regardless of the current EnforcementPolicy in the runtime. // kCheckWithPolicy does apply the policy and hence may only return a denial // if it's kEnabled.
kCheck = 0,
kCheckWithPolicy = 4,
// Checks that log access warnings and failures, depending on the current // EnforcementPolicy in the runtime.
kReflection = 1,
kJNI = 2,
kLinking = 3,
};
// Represents the API domain of a caller/callee. class AccessContext { public: // Initialize to either the fully-trusted or fully-untrusted domain. explicit AccessContext(bool is_trusted)
: klass_(nullptr),
dex_file_(nullptr),
native_caller_addr_(nullptr),
domain_(ComputeDomain(is_trusted)) {}
// Initialize from class loader and dex file (via dex cache).
AccessContext(ObjPtr<mirror::ClassLoader> class_loader, ObjPtr<mirror::DexCache> dex_cache)
REQUIRES_SHARED(Locks::mutator_lock_)
: klass_(nullptr),
dex_file_(GetDexFileFromDexCache(dex_cache)),
native_caller_addr_(nullptr),
domain_(ComputeDomain(class_loader, dex_file_)) {}
// Initialize from class loader and dex file (only used by tests).
AccessContext(ObjPtr<mirror::ClassLoader> class_loader, const DexFile* dex_file)
: klass_(nullptr),
dex_file_(dex_file),
native_caller_addr_(nullptr),
domain_(ComputeDomain(class_loader, dex_file_)) {}
// Returns true if this domain is always allowed to access the domain of `callee`. bool CanAlwaysAccess(const AccessContext& callee) const { return IsDomainAtLeastAsTrustedAs(domain_, callee.domain_);
}
// Returns an AccessContext based on the return address to a native (non-OAT) // caller. If the DSO (dynamic shared object) of the caller can't be // determined then returns a fully-untrusted context for which // GetNativeCallerAddr returns nullptr. static AccessContext FromNativeCaller(void* native_caller_addr);
static Domain ComputeDomain(ObjPtr<mirror::Class> klass, const DexFile* dex_file)
REQUIRES_SHARED(Locks::mutator_lock_) { // Check other aspects of the context.
Domain domain = ComputeDomain(klass->GetClassLoader(), dex_file);
if (domain == Domain::kApplication &&
klass->ShouldSkipHiddenApiChecks() &&
Runtime::Current()->IsJavaDebuggableAtInit()) { // Class is known, it is marked trusted and we are in debuggable mode.
domain = ComputeDomain(/* is_trusted= */ true);
}
return domain;
}
// Pointer to declaring class of the caller/callee (null if not provided). // This is not safe across GC but we're only using this class for passing // information about the caller to the access check logic and never retain // the AccessContext instance beyond that. const ObjPtr<mirror::Class> klass_;
// DexFile of the caller/callee (null if not provided). const DexFile* const dex_file_;
// The return address for a native (non-OAT) caller. void* native_caller_addr_;
// Computed domain of the caller/callee. const Domain domain_;
};
// TODO(b/377676642): Replace this with an inline android_get_device_api_level() // >= 37 check once the flag is fully ramped. bool EnableHiddenapiPlatformEnforcement();
// Walks the stack, finds the caller of this reflective call and returns // a hiddenapi AccessContext formed from its declaring class.
AccessContext GetReflectionCallerAccessContext(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_);
// Implementation details. DO NOT ACCESS DIRECTLY. namespace detail {
// Class to encapsulate the signature of a member (ArtField or ArtMethod). This // is used as a helper when matching prefixes, and when logging the signature. class MemberSignature { private: enum MemberType {
kField,
kMethod,
};
// Performs prefix match on this member. Since the full member signature is // composed of several parts, we match each part in turn (rather than // building the entire thing in memory and performing a simple prefix match) bool DoesPrefixMatch(const std::string& prefix) const;
// Calls back into managed code to notify VMRuntime.nonSdkApiUsageConsumer that // |member| was accessed. This is usually called when an API is unsupported, // conditionally or unconditionally blocked. Given that the callback can execute arbitrary // code, a call to this method can result in thread suspension. void NotifyHiddenApiListener(AccessMethod access_method);
};
// Locates hiddenapi flags for `member` in the corresponding dex file. // NB: This is an O(N) operation, linear with the number of members in the class def. template<typename T>
uint32_t GetDexFlags(T* member) REQUIRES_SHARED(Locks::mutator_lock_);
// Handler of detected core platform API violations. Returns true if access to // `member` should be denied. template <typename T> bool HandleCorePlatformApiViolation(T* member,
ApiList api_list,
uint32_t runtime_flags, const AccessContext& caller_context, const AccessContext& callee_context,
AccessMethod access_method,
EnforcementPolicy policy) REQUIRES_SHARED(Locks::mutator_lock_);
// Returns access flags for the runtime representation of a class member (ArtField/ArtMember).
ALWAYS_INLINE inline uint32_t CreateRuntimeFlags_Impl(uint32_t dex_flags) {
uint32_t runtime_flags = 0u;
if (api_list.Contains(ApiList::Sdk())) {
runtime_flags |= kAccPublicApi;
} else { // Only add domain-specific flags for non-public API members. // This simplifies hardcoded values for intrinsics. if (api_list.Contains(ApiList::CorePlatformApi())) {
runtime_flags |= kAccCorePlatformApi;
}
}
DCHECK_EQ(runtime_flags & kAccHiddenapiBits, runtime_flags)
<< "Runtime flags not in reserved access flags bits"; return runtime_flags;
}
} // namespace detail
// Returns access flags for the runtime representation of a class member (ArtField/ArtMember).
ALWAYS_INLINE inline uint32_t CreateRuntimeFlags(const ClassAccessor::BaseItem& member) { return detail::CreateRuntimeFlags_Impl(member.GetHiddenapiFlags());
}
// Returns access flags for the runtime representation of a class member (ArtField/ArtMember). template<typename T>
ALWAYS_INLINE inline uint32_t CreateRuntimeFlags(T* member) REQUIRES_SHARED(Locks::mutator_lock_) { return detail::CreateRuntimeFlags_Impl(detail::GetDexFlags(member));
}
// Extracts hiddenapi runtime flags from access flags of ArtMethod. // Uses hardcoded values for intrinsics.
ALWAYS_INLINE inline uint32_t GetRuntimeFlags(ArtMethod* method)
REQUIRES_SHARED(Locks::mutator_lock_) { if (UNLIKELY(method->IsIntrinsic())) { switch (method->GetIntrinsic()) { case Intrinsics::kSystemArrayCopyChar: case Intrinsics::kSystemArrayCopyByte: case Intrinsics::kSystemArrayCopyInt: case Intrinsics::kStringGetCharsNoCheck: case Intrinsics::kReferenceGetReferent: case Intrinsics::kMemoryPeekByte: case Intrinsics::kMemoryPokeByte: case Intrinsics::kCRC32Update: case Intrinsics::kCRC32UpdateBytes: case Intrinsics::kCRC32UpdateByteBuffer: case Intrinsics::kStringNewStringFromBytes: case Intrinsics::kStringNewStringFromChars: case Intrinsics::kStringNewStringFromString: case Intrinsics::kMemoryPeekIntNative: case Intrinsics::kMemoryPeekLongNative: case Intrinsics::kMemoryPeekShortNative: case Intrinsics::kMemoryPokeIntNative: case Intrinsics::kMemoryPokeLongNative: case Intrinsics::kMemoryPokeShortNative: case Intrinsics::kUnsafeCASInt: case Intrinsics::kUnsafeCASLong: case Intrinsics::kUnsafeCASObject: case Intrinsics::kUnsafeGetAndAddInt: case Intrinsics::kUnsafeGetAndAddLong: case Intrinsics::kUnsafeGetAndSetInt: case Intrinsics::kUnsafeGetAndSetLong: case Intrinsics::kUnsafeGetAndSetObject: case Intrinsics::kUnsafeGetLongVolatile: case Intrinsics::kUnsafeGetObjectVolatile: case Intrinsics::kUnsafeGetVolatile: case Intrinsics::kUnsafePutLongOrdered: case Intrinsics::kUnsafePutLongVolatile: case Intrinsics::kUnsafePutObjectVolatile: case Intrinsics::kUnsafePutOrderedInt: case Intrinsics::kUnsafePutOrderedObject: case Intrinsics::kUnsafePutVolatile: case Intrinsics::kUnsafeLoadFence: case Intrinsics::kUnsafeStoreFence: case Intrinsics::kUnsafeFullFence: case Intrinsics::kJdkUnsafeArrayBaseOffset: case Intrinsics::kJdkUnsafeCompareAndSetInt: case Intrinsics::kJdkUnsafeCompareAndSetLong: case Intrinsics::kJdkUnsafeCompareAndSetReference: case Intrinsics::kJdkUnsafeGetAndAddInt: case Intrinsics::kJdkUnsafeGetAndAddLong: case Intrinsics::kJdkUnsafeGetAndSetInt: case Intrinsics::kJdkUnsafeGetAndSetLong: case Intrinsics::kJdkUnsafeGetAndSetReference: case Intrinsics::kJdkUnsafeGetLongVolatile: case Intrinsics::kJdkUnsafeGetLongAcquire: case Intrinsics::kJdkUnsafeGetReferenceVolatile: case Intrinsics::kJdkUnsafeGetReferenceAcquire: case Intrinsics::kJdkUnsafeGetVolatile: case Intrinsics::kJdkUnsafeGetAcquire: case Intrinsics::kJdkUnsafePutLongVolatile: case Intrinsics::kJdkUnsafePutLongRelease: case Intrinsics::kJdkUnsafePutReferenceVolatile: case Intrinsics::kJdkUnsafePutReferenceRelease: case Intrinsics::kJdkUnsafePutVolatile: case Intrinsics::kJdkUnsafePutRelease: case Intrinsics::kJdkUnsafeLoadFence: case Intrinsics::kJdkUnsafeStoreFence: case Intrinsics::kJdkUnsafeFullFence: case Intrinsics::kJdkUnsafeGet: case Intrinsics::kJdkUnsafeGetAbsolute: case Intrinsics::kJdkUnsafeGetLong: case Intrinsics::kJdkUnsafeGetByte: case Intrinsics::kJdkUnsafeGetReference: case Intrinsics::kJdkUnsafePutLong: case Intrinsics::kJdkUnsafePut: case Intrinsics::kJdkUnsafePutAbsolute: case Intrinsics::kJdkUnsafePutReference: case Intrinsics::kJdkUnsafePutByte: return0u; case Intrinsics::kFP16Ceil: case Intrinsics::kFP16Compare: case Intrinsics::kFP16Floor: case Intrinsics::kFP16Greater: case Intrinsics::kFP16GreaterEquals: case Intrinsics::kFP16Less: case Intrinsics::kFP16LessEquals: case Intrinsics::kFP16Min: case Intrinsics::kFP16Max: case Intrinsics::kFP16ToFloat: case Intrinsics::kFP16ToHalf: case Intrinsics::kFP16Rint: case Intrinsics::kUnsafeArrayBaseOffset: case Intrinsics::kUnsafeGet: case Intrinsics::kUnsafeGetAbsolute: case Intrinsics::kUnsafeGetLong: case Intrinsics::kUnsafeGetByte: case Intrinsics::kUnsafeGetObject: case Intrinsics::kUnsafePutLong: case Intrinsics::kUnsafePut: case Intrinsics::kUnsafePutAbsolute: case Intrinsics::kUnsafePutObject: case Intrinsics::kUnsafePutByte: return kAccCorePlatformApi; default: // Remaining intrinsics are public API. We DCHECK that in SetIntrinsic(). return kAccPublicApi;
}
} else { return method->GetAccessFlags() & kAccHiddenapiBits;
}
}
// Called by class linker when a new dex file has been registered. Assigns // the AccessContext domain to the newly-registered dex file based on its // location and class loader. void InitializeDexFileDomain(const DexFile& dex_file, ObjPtr<mirror::ClassLoader> class_loader);
// Returns true if access to `member` should be denied in the given context. // The decision is based on whether the caller is in a trusted context or not. // Because determining the access context can be expensive, a lambda function // "fn_get_access_context" is lazily invoked after other criteria have been // considered. // This function might print warnings into the log if the member is hidden. template<typename T> bool ShouldDenyAccessToMember(T* member, const std::function<AccessContext()>& fn_get_access_context,
AccessMethod access_method)
REQUIRES_SHARED(Locks::mutator_lock_);
// Helper method for callers where access context can be determined beforehand. // Wraps AccessContext in a lambda and passes it to the real ShouldDenyAccessToMember. template<typename T> inlinebool ShouldDenyAccessToMember(T* member, const AccessContext& access_context,
AccessMethod access_method)
REQUIRES_SHARED(Locks::mutator_lock_) {
access_context.GetClass().AssertValid(); return ShouldDenyAccessToMember(member, [&]() { return access_context; }, access_method);
}
} // namespace hiddenapi
} // namespace art
#endif// ART_RUNTIME_HIDDEN_API_H_
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.14 Sekunden
(vorverarbeitet am 2026-06-29)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.