ART学习系列:Android 10 的Class的GetMethod 过程分析
之前我们分析了Android9 的调用过程,并且尝试着一种方式,可以访问隐藏Api,但是最近发现当APP的target api为 29的时候,该方法失效了,所以猜测,Android 10 的GetMethod 方法过程发生变化, 那么一起分析一下。
从Class.java 层的GetMethod 与Android 9 上的并无区别。
我们从Native 层的方法开始分析。
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());
}
我们发现getDeclaredMethodInternal 的方法内部大部分相同,但是ShouldDenyAccessToMember 这个方法名字与Android9时的方法
发生了变化。 这个勾起我的兴趣。
ALWAYS_INLINE static bool ShouldDenyAccessToMember(T* member, Thread* self)
REQUIRES_SHARED(Locks::mutator_lock_) {
return hiddenapi::ShouldDenyAccessToMember(member,
GetHiddenapiAccessContextFunction(self),
hiddenapi::AccessMethod::kReflection);
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();
// 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();
}
}
}
看到这个过程,首先是GetRuntimeFlags(member) 返回了该方法的access flag 的状态,是否是public等。
接着看caller 的域是属于Application 还是platform的。
// Check if the caller is always allowed to access members in the callee context.
if (caller_context.CanAlwaysAccess(callee_context)) {
return false;
}
// Returns true if this domain is always allowed to access the domain of `callee`.
bool CanAlwaysAccess(const AccessContext& callee) const {
return IsDomainMoreTrustedThan(domain_, callee.domain_);
}
// List of domains supported by the hidden API access checks. Domain with a lower
// ordinal is considered more "trusted", i.e. always allowed to access members of
// domains with a greater ordinal. Access checks are performed when code tries to
// access a method/field from a more trusted domain than itself.
enum class Domain {
kCorePlatform = 0,
kPlatform,
kApplication,
};
inline bool IsDomainMoreTrustedThan(Domain domainA, Domain domainB) {
return static_cast<uint32_t>(domainA) <= static_cast<uint32_t>(domainB);
}
从这个过程来看
在这个系统版本时,Android给分了三个域,coreplatform, platform, application, 权限级别又高至低。
所以得看从那个域调用到那个域里去, 高权限的可以直接访问低权限的。
接下来就是,根据每个域里里的判断条件来抉择。
首先看Application 这个域,第一步判断是否 disable 访问access。
第二部,根据访问Member到ShouldDenyAccessToMemberImpl 方法进行判断。
433 template<typename T>
434 bool ShouldDenyAccessToMemberImpl(T* member, ApiList api_list, AccessMethod access_method) {
435 DCHECK(member != nullptr);
436 Runtime* runtime = Runtime::Current();
437
438 EnforcementPolicy policy = runtime->GetHiddenApiEnforcementPolicy();
439 DCHECK(policy != EnforcementPolicy::kDisabled)
440 << "Should never enter this function when access checks are completely disabled";
441
442 const bool deny_access =
443 (policy == EnforcementPolicy::kEnabled) &&
444 IsSdkVersionSetAndMoreThan(runtime->GetTargetSdkVersion(),
445 api_list.GetMaxAllowedSdkVersion());
446
447 MemberSignature member_signature(member);
448
449 // Check for an exemption first. Exempted APIs are treated as white list.
450 if (member_signature.IsExempted(runtime->GetHiddenApiExemptions())) {
451 // Avoid re-examining the exemption list next time.
452 // Note this results in no warning for the member, which seems like what one would expect.
453 // Exemptions effectively adds new members to the whitelist.
454 MaybeUpdateAccessFlags(runtime, member, kAccPublicApi);
455 return false;
456 }
457
458 if (access_method != AccessMethod::kNone) {
459 // Print a log message with information about this class member access.
460 // We do this if we're about to deny access, or the app is debuggable.
461 if (kLogAllAccesses || deny_access || runtime->IsJavaDebuggable()) {
462 member_signature.WarnAboutAccess(access_method, api_list, deny_access);
463 }
464
465 // If there is a StrictMode listener, notify it about this violation.
466 member_signature.NotifyHiddenApiListener(access_method);
467
468 // If event log sampling is enabled, report this violation.
469 if (kIsTargetBuild && !kIsTargetLinux) {
470 uint32_t eventLogSampleRate = runtime->GetHiddenApiEventLogSampleRate();
471 // Assert that RAND_MAX is big enough, to ensure sampling below works as expected.
472 static_assert(RAND_MAX >= 0xffff, "RAND_MAX too small");
473 if (eventLogSampleRate != 0) {
474 const uint32_t sampled_value = static_cast<uint32_t>(std::rand()) & 0xffff;
475 if (sampled_value < eventLogSampleRate) {
476 member_signature.LogAccessToEventLog(sampled_value, access_method, deny_access);
477 }
478 }
479 }
480
481 // If this access was not denied, move the member into whitelist and skip
482 // the warning the next time the member is accessed.
483 if (!deny_access) {
484 MaybeUpdateAccessFlags(runtime, member, kAccPublicApi);
485 }
486 }
487
488 return deny_access;
489 }
我们看到了这个函数IsSdkVersionSetAndMoreThan
inline bool IsSdkVersionSetAndMoreThan(uint32_t lhs, SdkVersion rhs) {
return lhs != static_cast<uint32_t>(SdkVersion::kUnset) && lhs > static_cast<uint32_t>(rhs);
}
IsSdkVersionSetAndMoreThan(runtime->GetTargetSdkVersion(), api_list.GetMaxAllowedSdkVersion());
此时这个函数的参数有当前应用的tagertSdkVersion 和 api限制列表的的最大允许sdk版本。
也就是如果targetsdkversion如果小于最大允许sdk版本,那么总的deny_access 的值就会变为false,就不会进行下面的check。
接下来,与Android9的版本里的判断一样,有一个GetHiddenApiExemptions的排除Api的判断。
结束这个函数分析。
返回到 ShouldDenyAccessToMemberImpl 函数, 我们看case platform 有一段代码。runtime_flags 有一个CorePlatformApi 的字段。
// Member is part of core platform API. Accessing it is allowed.
if ((runtime_flags & kAccCorePlatformApi) != 0) {
return false;
}
也就是Api的分级增加了一个CorePlatformApi的字段。
接着我们去检查VMRuntime.java的SetHiddenApiExemptions 方法。
@libcore.api.CorePlatformApipublic native void setHiddenApiExemptions(String[] signaturePrefixes);
我们看到该方法上面加上了CorePlatformApi 的flag。
但是上面的分析过程,我们想尝试从域的访问权限,看看能不能进入到core api的域里。