private Method getMethod(String name, Class<?>[] parameterTypes, boolean recursivePublicMethods) throws NoSuchMethodException { if (name == null) { thrownew NullPointerException("name == null"); } if (parameterTypes == null) { parameterTypes = EmptyArray.CLASS; } for (Class<?> c : parameterTypes) { if (c == null) { thrownew NoSuchMethodException("parameter type is null"); } } // recursivePublicMethods的值传入的是false,所以走getDeclaredMethodInternal Method result = recursivePublicMethods ? getPublicMethodRecursive(name, parameterTypes) : getDeclaredMethodInternal(name, parameterTypes); // Fail if we didn't find the method or it was expected to be public. if (result == null || (recursivePublicMethods && !Modifier.isPublic(result.getAccessFlags()))) { thrownew NoSuchMethodException(name + " " + Arrays.toString(parameterTypes)); } return result; }
这里的java方法是一个native方法
/** * Returns the method if it is defined by this class; {@code null} otherwise. This may return a * non-public member. * * @param name the method name * @param args the method's parameter types */ @FastNative privatenative Method getDeclaredMethodInternal(String name, Class<?>[] args);
// Returns true if the first non-ClassClass caller up the stack should not be // allowed access to `member`. template<typename T> ALWAYS_INLINE staticboolShouldBlockAccessToMember(T* member, Thread* self) REQUIRES_SHARED(Locks::mutator_lock_){ hiddenapi::Action action = hiddenapi::GetMemberAction( // 获取的action的类型是重点 member, self, IsCallerTrusted, hiddenapi::kReflection); // kReflection : 反射方式调用 if (action != hiddenapi::kAllow) { hiddenapi::NotifyHiddenApiListener(member); // 当不是kAllow时,则需要警告或者弹窗,则通过此方法通知 }
// 调用方式 enum AccessMethod { kNone, // internal test that does not correspond to an actual access by app kReflection, //反射 kJNI, //JNI kLinking, //动态链接 };
Reflection反射过程:
Class_newInstance:对象实例化
Class_getDeclaredConstructorInternal:构造方法
Class_getDeclaredMethodInternal:获取方法
Class_getDeclaredField:获取字段
Class_getPublicFieldRecursive:获取字段
kJNI的JNI调用过程:
FindMethodID:查找方法
FindFieldID:查找字段
kLinking动态链接:
UnstartedClassNewInstance
UnstartedClassGetDeclaredConstructor
UnstartedClassGetDeclaredMethod
UnstartedClassGetDeclaredField
2.3 GetMemberAction
进入hiddenapi::GetMemberAction分析
hidden_api.h
// Returns true if access to `member` should be denied to the caller of the // reflective query. The decision is based on whether the caller is trusted or // not. Because different users of this function determine this in a different // way, `fn_caller_is_trusted(self)` is called and should return true if the // caller is allowed to access the platform. // This function might print warnings into the log if the member is hidden. template<typename T> //Action就是允许,警告,弹窗,阻止 inline Action GetMemberAction(T* member, Thread* self, std::function<bool(Thread*)> fn_caller_is_trusted, AccessMethod access_method) REQUIRES_SHARED(Locks::mutator_lock_) { DCHECK(member != nullptr);
// Decode hidden API access flags. // NB Multiple threads might try to access (and overwrite) these simultaneously, // causing a race. We only do that if access has not been denied, so the race // cannot change Java semantics. We should, however, decode the access flags // once and use it throughout this function, otherwise we may get inconsistent // results, e.g. print whitelist warnings (b/78327881).
Action action = GetActionFromAccessFlags(member->GetHiddenApiAccessFlags()); // 1.依据名单类型,获取action类型->允许,警告,弹窗,阻止 if (action == kAllow) { // Nothing to do. return action; }
// Member is hidden. Invoke `fn_caller_in_platform` and find the origin of the access. // This can be *very* expensive. Save it for last. if (fn_caller_is_trusted(self)) { // 2. 通过函数指针调用到IsCallerTrusted函数 // Caller is trusted. Exit. return kAllow; }
// Member is hidden and caller is not in the platform. return detail::GetMemberActionImpl(member, api_list, action, access_method); //3.access_method是kReflection表示是反射调用 }
inline HiddenApiAccessFlags::ApiList ArtMethod::GetHiddenApiAccessFlags() REQUIRES_SHARED(Locks::mutator_lock_) { if (UNLIKELY(IsIntrinsic())) { switch (static_cast<Intrinsics>(GetIntrinsic())) { case Intrinsics::kSystemArrayCopyChar: case Intrinsics::kStringGetCharsNoCheck: case Intrinsics::kReferenceGetReferent: // These intrinsics are on the light greylist and will fail a DCHECK in // SetIntrinsic() if their flags change on the respective dex methods. // Note that the DCHECK currently won't fail if the dex methods are // whitelisted, e.g. in the core image (b/77733081). As a result, we // might print warnings but we won't change the semantics. return HiddenApiAccessFlags::kLightGreylist; case Intrinsics::kVarHandleFullFence: case Intrinsics::kVarHandleAcquireFence: case Intrinsics::kVarHandleReleaseFence: case Intrinsics::kVarHandleLoadLoadFence: case Intrinsics::kVarHandleStoreStoreFence: case Intrinsics::kVarHandleCompareAndExchange: case Intrinsics::kVarHandleCompareAndExchangeAcquire: case Intrinsics::kVarHandleCompareAndExchangeRelease: case Intrinsics::kVarHandleCompareAndSet: case Intrinsics::kVarHandleGet: case Intrinsics::kVarHandleGetAcquire: case Intrinsics::kVarHandleGetAndAdd: case Intrinsics::kVarHandleGetAndAddAcquire: case Intrinsics::kVarHandleGetAndAddRelease: case Intrinsics::kVarHandleGetAndBitwiseAnd: case Intrinsics::kVarHandleGetAndBitwiseAndAcquire: case Intrinsics::kVarHandleGetAndBitwiseAndRelease: case Intrinsics::kVarHandleGetAndBitwiseOr: case Intrinsics::kVarHandleGetAndBitwiseOrAcquire: case Intrinsics::kVarHandleGetAndBitwiseOrRelease: case Intrinsics::kVarHandleGetAndBitwiseXor: case Intrinsics::kVarHandleGetAndBitwiseXorAcquire: case Intrinsics::kVarHandleGetAndBitwiseXorRelease: case Intrinsics::kVarHandleGetAndSet: case Intrinsics::kVarHandleGetAndSetAcquire: case Intrinsics::kVarHandleGetAndSetRelease: case Intrinsics::kVarHandleGetOpaque: case Intrinsics::kVarHandleGetVolatile: case Intrinsics::kVarHandleSet: case Intrinsics::kVarHandleSetOpaque: case Intrinsics::kVarHandleSetRelease: case Intrinsics::kVarHandleSetVolatile: case Intrinsics::kVarHandleWeakCompareAndSet: case Intrinsics::kVarHandleWeakCompareAndSetAcquire: case Intrinsics::kVarHandleWeakCompareAndSetPlain: case Intrinsics::kVarHandleWeakCompareAndSetRelease: // These intrinsics are on the blacklist and will fail a DCHECK in // SetIntrinsic() if their flags change on the respective dex methods. // Note that the DCHECK currently won't fail if the dex methods are // whitelisted, e.g. in the core image (b/77733081). Given that they are // exclusively VarHandle intrinsics, they should not be used outside // tests that do not enable hidden API checks. return HiddenApiAccessFlags::kBlacklist; default: // Remaining intrinsics are public API. We DCHECK that in SetIntrinsic(). return HiddenApiAccessFlags::kWhitelist; } } else { return HiddenApiAccessFlags::DecodeFromRuntime(GetAccessFlags()); } }
// if policy is "just warn", always warn. We returned above for whitelist APIs. if (policy == EnforcementPolicy::kJustWarn) { return kAllowButWarn; } DCHECK(policy >= EnforcementPolicy::kDarkGreyAndBlackList); // The logic below relies on equality of values in the enums EnforcementPolicy and // HiddenApiAccessFlags::ApiList, and their ordering. Assertions are in hidden_api.cc. if (static_cast<int>(policy) > static_cast<int>(api_list)) { return api_list == HiddenApiAccessFlags::kDarkGreylist ? kAllowButWarnAndToast : kAllowButWarn; } else { return kDeny; } }
// Hidden API enforcement policy // This must be kept in sync with ApplicationInfo.ApiEnforcementPolicy in // frameworks/base/core/java/android/content/pm/ApplicationInfo.java enum class EnforcementPolicy { kNoChecks = 0, kJustWarn = 1, // keep checks enabled, but allow everything (enables logging) kDarkGreyAndBlackList = 2, // ban dark grey & blacklist kBlacklistOnly = 3, // ban blacklist violations only kMax = kBlacklistOnly, };
// Returns true if the first caller outside of the Class class or java.lang.invoke package // is in a platform DEX file. static bool IsCallerTrusted(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) { // Walk the stack and find the first frame not from java.lang.Class and not from java.lang.invoke. // This is very expensive. Save this till the last. struct FirstExternalCallerVisitor : public StackVisitor { explicit FirstExternalCallerVisitor(Thread* thread) : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames), caller(nullptr) { }
bool VisitFrame() REQUIRES_SHARED(Locks::mutator_lock_) { ArtMethod *m = GetMethod(); if (m == nullptr) { // Attached native thread. Assume this is *not* boot class path. caller = nullptr; return false; } else if (m->IsRuntimeMethod()) { // Internal runtime method, continue walking the stack. return true; }
ObjPtr<mirror::Class> declaring_class = m->GetDeclaringClass(); if (declaring_class->IsBootStrapClassLoaded()) { if (declaring_class->IsClassClass()) { return true; } // Check classes in the java.lang.invoke package. At the time of writing, the // classes of interest are MethodHandles and MethodHandles.Lookup, but this // is subject to change so conservatively cover the entire package. // NB Static initializers within java.lang.invoke are permitted and do not // need further stack inspection. ObjPtr<mirror::Class> lookup_class = mirror::MethodHandlesLookup::StaticClass(); if ((declaring_class == lookup_class || declaring_class->IsInSamePackage(lookup_class)) && !m->IsClassInitializer()) { return true; } }
// Returns true if the caller is either loaded by the boot strap class loader or comes from // a dex file located in ${ANDROID_ROOT}/framework/. ALWAYS_INLINE inlineboolIsCallerTrusted(ObjPtr<mirror::Class> caller, ObjPtr<mirror::ClassLoader> caller_class_loader, ObjPtr<mirror::DexCache> caller_dex_cache) REQUIRES_SHARED(Locks::mutator_lock_){ if (caller_class_loader.IsNull()) { // Boot class loader. Boot classloader returntrue; }
if (!caller_dex_cache.IsNull()) { const DexFile* caller_dex_file = caller_dex_cache->GetDexFile(); if (caller_dex_file != nullptr && caller_dex_file->IsPlatformDexFile()) { // Caller is in a platform dex file. caller是平台dex文件 returntrue; } }
if (!caller.IsNull() && caller->ShouldSkipHiddenApiChecks() && Runtime::Current()->IsJavaDebuggable()) { // We are in debuggable mode and this caller has been marked trusted. 处于debuggable调试模式且caller已被标记可信任 returntrue; }
// Get the signature, we need it later. MemberSignature member_signature(member); // 获取签名
Runtime* runtime = Runtime::Current();
// Check for an exemption first. Exempted APIs are treated as white list. // We only do this if we're about to deny, or if the app is debuggable. This is because: // - we only print a warning for light greylist violations for debuggable apps // - for non-debuggable apps, there is no distinction between light grey & whitelisted APIs. // - we want to avoid the overhead of checking for exemptions for light greylisted APIs whenever // possible. constbool shouldWarn = kLogAllAccesses || runtime->IsJavaDebuggable(); if (shouldWarn || action == kDeny) { if (member_signature.IsExempte(runtime->GetHiddenApiExemptions())) { // 判断是否可以豁免 action = kAllow; // 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. MaybeWhitelistMember(runtime, member); return kAllow; }
if (access_method != kNone) { // Print a log message with information about this class member access. // We do this if we're about to block access, or the app is debuggable. member_signature.WarnAboutAccess(access_method, api_list); // 判断是否通知警告 } }
if (kIsTargetBuild) { 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 && (static_cast<uint32_t>(std::rand()) & 0xffff) < eventLogSampleRate) { member_signature.LogAccessToEventLog(access_method, action); // 输出EventLog } }
// Allow access to this member but print a warning. DCHECK(action == kAllowButWarn || action == kAllowButWarnAndToast);
if (access_method != kNone) { // Depending on a runtime flag, we might move the member into whitelist and // skip the warning the next time the member is accessed. MaybeWhitelistMember(runtime, member);
// If this action requires a UI warning, set the appropriate flag. if (shouldWarn && (action == kAllowButWarnAndToast || runtime->ShouldAlwaysSetHiddenApiWarningFlag())) { runtime->SetPendingHiddenApiWarning(true); } }