Android P 非SDK接口限制分析

涉及的源码路径

  1. libcore/ojluni/src/main/java/java/lang/Class.java
  2. art/runtime/native/java_lang_Class.cc
  3. art/runtime/hidden_api.h
  4. art/runtime/runtime.h
  5. art/libdexfile/dex/hidden_api_access_flags.h
  6. art/runtime/hidden_api.cc
  7. art/runtime/art_method-inl.h

Google为了限制APP调用非公开的SDK接口,在android P开始添加了相关的限制.详情

本文从源码上分析其实现,先上一张大图.

hidden_API framework

1. java 端调用

反射调用代码:

  1. Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
  2. Method currentActivityThreadMethod = activityThreadClass.getDeclaredMethod("currentActivityThread");

代码是通过getDeclaredMethod调用开始的,接下来代码就从这开始. Class.java

  1. public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
  2. throws NoSuchMethodException, SecurityException {
  3. return getMethod(name, parameterTypes, false); // 进入该函数
  4. }
  1. private Method getMethod(String name, Class<?>[] parameterTypes, boolean recursivePublicMethods)
  2. throws NoSuchMethodException {
  3. if (name == null) {
  4. throw new NullPointerException("name == null");
  5. }
  6. if (parameterTypes == null) {
  7. parameterTypes = EmptyArray.CLASS;
  8. }
  9. for (Class<?> c : parameterTypes) {
  10. if (c == null) {
  11. throw new NoSuchMethodException("parameter type is null");
  12. }
  13. }
  14. // recursivePublicMethods的值传入的是false,所以走getDeclaredMethodInternal
  15. Method result = recursivePublicMethods ? getPublicMethodRecursive(name, parameterTypes)
  16. : getDeclaredMethodInternal(name, parameterTypes);
  17. // Fail if we didn't find the method or it was expected to be public.
  18. if (result == null ||
  19. (recursivePublicMethods && !Modifier.isPublic(result.getAccessFlags()))) {
  20. throw new NoSuchMethodException(name + " " + Arrays.toString(parameterTypes));
  21. }
  22. return result;
  23. }

这里的java方法是一个native方法

  1. /**
  2. * Returns the method if it is defined by this class; {@code null} otherwise. This may return a
  3. * non-public member.
  4. *
  5. * @param name the method name
  6. * @param args the method's parameter types
  7. */
  8. @FastNative
  9. private native Method getDeclaredMethodInternal(String name, Class<?>[] args);

通过JNI跳转到接C++方法

2. C++ 端的实现

2.1 Class_getDeclaredMethodInternal

java_lang_Class.cc

  1. static jobject Class_getDeclaredMethodInternal(JNIEnv* env, jobject javaThis,
  2. jstring name, jobjectArray args) {
  3. ScopedFastNativeObjectAccess soa(env);
  4. StackHandleScope<1> hs(soa.Self());
  5. DCHECK_EQ(Runtime::Current()->GetClassLinker()->GetImagePointerSize(), kRuntimePointerSize);
  6. DCHECK(!Runtime::Current()->IsActiveTransaction());
  7. Handle<mirror::Method> result = hs.NewHandle(
  8. mirror::Class::GetDeclaredMethodInternal<kRuntimePointerSize, false>(
  9. soa.Self(),
  10. DecodeClass(soa, javaThis),
  11. soa.Decode<mirror::String>(name),
  12. soa.Decode<mirror::ObjectArray<mirror::Class>>(args)));
  13. //检测该方法是否允许访问【小节2.4】
  14. if (result == nullptr || ShouldBlockAccessToMember(result->GetArtMethod(), soa.Self())) {
  15. return nullptr;
  16. }
  17. return soa.AddLocalReference<jobject>(result.Get());
  18. }

2.2 ShouldBlockAccessToMember

  1. // Returns true if the first non-ClassClass caller up the stack should not be
  2. // allowed access to `member`.
  3. template<typename T>
  4. ALWAYS_INLINE static bool ShouldBlockAccessToMember(T* member, Thread* self)
  5. REQUIRES_SHARED(Locks::mutator_lock_) {
  6. hiddenapi::Action action = hiddenapi::GetMemberAction( // 获取的action的类型是重点
  7. member, self, IsCallerTrusted, hiddenapi::kReflection); // kReflection : 反射方式调用
  8. if (action != hiddenapi::kAllow) {
  9. hiddenapi::NotifyHiddenApiListener(member); // 当不是kAllow时,则需要警告或者弹窗,则通过此方法通知
  10. }
  11. return action == hiddenapi::kDeny; // 返回true则被限制,也就是当action是kAllow/kAllowButWarn/kAllowButWarnAndToast返回false,都是允许accessmember的
  12. }

hidden_api.h

  1. enum Action {
  2. kAllow, // 允许
  3. kAllowButWarn, // 允许+警告
  4. kAllowButWarnAndToast, // 允许+警告+弹窗
  5. kDeny // 阻止
  6. };
  7. // 调用方式
  8. enum AccessMethod {
  9. kNone, // internal test that does not correspond to an actual access by app
  10. kReflection, //反射
  11. kJNI, //JNI
  12. kLinking, //动态链接
  13. };

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

  1. // Returns true if access to `member` should be denied to the caller of the
  2. // reflective query. The decision is based on whether the caller is trusted or
  3. // not. Because different users of this function determine this in a different
  4. // way, `fn_caller_is_trusted(self)` is called and should return true if the
  5. // caller is allowed to access the platform.
  6. // This function might print warnings into the log if the member is hidden.
  7. template<typename T>
  8. //Action就是允许,警告,弹窗,阻止
  9. inline Action GetMemberAction(T* member,
  10. Thread* self,
  11. std::function<bool(Thread*)> fn_caller_is_trusted,
  12. AccessMethod access_method)
  13. REQUIRES_SHARED(Locks::mutator_lock_) {
  14. DCHECK(member != nullptr);
  15. // Decode hidden API access flags.
  16. // NB Multiple threads might try to access (and overwrite) these simultaneously,
  17. // causing a race. We only do that if access has not been denied, so the race
  18. // cannot change Java semantics. We should, however, decode the access flags
  19. // once and use it throughout this function, otherwise we may get inconsistent
  20. // results, e.g. print whitelist warnings (b/78327881).
  21. // inline HiddenApiAccessFlags::ApiList ArtMethod::GetHiddenApiAccessFlags()
  22. HiddenApiAccessFlags::ApiList api_list = member->GetHiddenApiAccessFlags(); // 获取方法的可访问标示符,返回在哪个名单里面 art_method-inl.h
  23. // HiddenApiAccessFlags 定义在 hidden_api_access_flags.h 白名单 浅灰名单 深灰名单 黑名单
  24. Action action = GetActionFromAccessFlags(member->GetHiddenApiAccessFlags()); // 1.依据名单类型,获取action类型->允许,警告,弹窗,阻止
  25. if (action == kAllow) {
  26. // Nothing to do.
  27. return action;
  28. }
  29. // Member is hidden. Invoke `fn_caller_in_platform` and find the origin of the access.
  30. // This can be *very* expensive. Save it for last.
  31. if (fn_caller_is_trusted(self)) { // 2. 通过函数指针调用到IsCallerTrusted函数
  32. // Caller is trusted. Exit.
  33. return kAllow;
  34. }
  35. // Member is hidden and caller is not in the platform.
  36. return detail::GetMemberActionImpl(member, api_list, action, access_method); //3.access_method是kReflection表示是反射调用
  37. }

此方法里有三处要分析:

  • GetActionFromAccessFlags(member->GetHiddenApiAccessFlags())
  • fn_caller_is_trusted(self)
  • detail::GetMemberActionImpl

分析上面三个方法之前,先来看看上面的代码用到的

  1. class HiddenApiAccessFlags {
  2. public:
  3. enum ApiList {
  4. kWhitelist = 0, // 白名单
  5. kLightGreylist, // 浅灰名单
  6. kDarkGreylist, // 深灰名单
  7. kBlacklist, // 黑名单
  8. };

2.3.1 GetHiddenApiAccessFlags

先看GetActionFromAccessFlags(member->GetHiddenApiAccessFlags()),要先分析member->GetHiddenApiAccessFlags.

art_method-inl.h

  1. inline HiddenApiAccessFlags::ApiList ArtMethod::GetHiddenApiAccessFlags()
  2. REQUIRES_SHARED(Locks::mutator_lock_) {
  3. if (UNLIKELY(IsIntrinsic())) {
  4. switch (static_cast<Intrinsics>(GetIntrinsic())) {
  5. case Intrinsics::kSystemArrayCopyChar:
  6. case Intrinsics::kStringGetCharsNoCheck:
  7. case Intrinsics::kReferenceGetReferent:
  8. // These intrinsics are on the light greylist and will fail a DCHECK in
  9. // SetIntrinsic() if their flags change on the respective dex methods.
  10. // Note that the DCHECK currently won't fail if the dex methods are
  11. // whitelisted, e.g. in the core image (b/77733081). As a result, we
  12. // might print warnings but we won't change the semantics.
  13. return HiddenApiAccessFlags::kLightGreylist;
  14. case Intrinsics::kVarHandleFullFence:
  15. case Intrinsics::kVarHandleAcquireFence:
  16. case Intrinsics::kVarHandleReleaseFence:
  17. case Intrinsics::kVarHandleLoadLoadFence:
  18. case Intrinsics::kVarHandleStoreStoreFence:
  19. case Intrinsics::kVarHandleCompareAndExchange:
  20. case Intrinsics::kVarHandleCompareAndExchangeAcquire:
  21. case Intrinsics::kVarHandleCompareAndExchangeRelease:
  22. case Intrinsics::kVarHandleCompareAndSet:
  23. case Intrinsics::kVarHandleGet:
  24. case Intrinsics::kVarHandleGetAcquire:
  25. case Intrinsics::kVarHandleGetAndAdd:
  26. case Intrinsics::kVarHandleGetAndAddAcquire:
  27. case Intrinsics::kVarHandleGetAndAddRelease:
  28. case Intrinsics::kVarHandleGetAndBitwiseAnd:
  29. case Intrinsics::kVarHandleGetAndBitwiseAndAcquire:
  30. case Intrinsics::kVarHandleGetAndBitwiseAndRelease:
  31. case Intrinsics::kVarHandleGetAndBitwiseOr:
  32. case Intrinsics::kVarHandleGetAndBitwiseOrAcquire:
  33. case Intrinsics::kVarHandleGetAndBitwiseOrRelease:
  34. case Intrinsics::kVarHandleGetAndBitwiseXor:
  35. case Intrinsics::kVarHandleGetAndBitwiseXorAcquire:
  36. case Intrinsics::kVarHandleGetAndBitwiseXorRelease:
  37. case Intrinsics::kVarHandleGetAndSet:
  38. case Intrinsics::kVarHandleGetAndSetAcquire:
  39. case Intrinsics::kVarHandleGetAndSetRelease:
  40. case Intrinsics::kVarHandleGetOpaque:
  41. case Intrinsics::kVarHandleGetVolatile:
  42. case Intrinsics::kVarHandleSet:
  43. case Intrinsics::kVarHandleSetOpaque:
  44. case Intrinsics::kVarHandleSetRelease:
  45. case Intrinsics::kVarHandleSetVolatile:
  46. case Intrinsics::kVarHandleWeakCompareAndSet:
  47. case Intrinsics::kVarHandleWeakCompareAndSetAcquire:
  48. case Intrinsics::kVarHandleWeakCompareAndSetPlain:
  49. case Intrinsics::kVarHandleWeakCompareAndSetRelease:
  50. // These intrinsics are on the blacklist and will fail a DCHECK in
  51. // SetIntrinsic() if their flags change on the respective dex methods.
  52. // Note that the DCHECK currently won't fail if the dex methods are
  53. // whitelisted, e.g. in the core image (b/77733081). Given that they are
  54. // exclusively VarHandle intrinsics, they should not be used outside
  55. // tests that do not enable hidden API checks.
  56. return HiddenApiAccessFlags::kBlacklist;
  57. default:
  58. // Remaining intrinsics are public API. We DCHECK that in SetIntrinsic().
  59. return HiddenApiAccessFlags::kWhitelist;
  60. }
  61. } else {
  62. return HiddenApiAccessFlags::DecodeFromRuntime(GetAccessFlags());
  63. }
  64. }

2.3.2 GetActionFromAccessFlags

GetHiddenApiAccessFlags()获取相应的flag,接着看GetActionFromAccessFlags:

  1. inline Action GetActionFromAccessFlags(HiddenApiAccessFlags::ApiList api_list) {
  2. // api_list就是 kWhitelist/kLightGreylist/kDarkGreylist/kBlacklist
  3. if (api_list == HiddenApiAccessFlags::kWhitelist) {// 白名单直接返回
  4. return kAllow;
  5. }
  6. EnforcementPolicy policy = Runtime::Current()->GetHiddenApiEnforcementPolicy(); // 1 EnforcementPolicy
  7. if (policy == EnforcementPolicy::kNoChecks) {
  8. // Exit early. Nothing to enforce.
  9. return kAllow;
  10. }
  11. // if policy is "just warn", always warn. We returned above for whitelist APIs.
  12. if (policy == EnforcementPolicy::kJustWarn) {
  13. return kAllowButWarn;
  14. }
  15. DCHECK(policy >= EnforcementPolicy::kDarkGreyAndBlackList);
  16. // The logic below relies on equality of values in the enums EnforcementPolicy and
  17. // HiddenApiAccessFlags::ApiList, and their ordering. Assertions are in hidden_api.cc.
  18. if (static_cast<int>(policy) > static_cast<int>(api_list)) {
  19. return api_list == HiddenApiAccessFlags::kDarkGreylist
  20. ? kAllowButWarnAndToast
  21. : kAllowButWarn;
  22. } else {
  23. return kDeny;
  24. }
  25. }
  1. // Hidden API enforcement policy
  2. // This must be kept in sync with ApplicationInfo.ApiEnforcementPolicy in
  3. // frameworks/base/core/java/android/content/pm/ApplicationInfo.java
  4. enum class EnforcementPolicy {
  5. kNoChecks = 0,
  6. kJustWarn = 1, // keep checks enabled, but allow everything (enables logging)
  7. kDarkGreyAndBlackList = 2, // ban dark grey & blacklist
  8. kBlacklistOnly = 3, // ban blacklist violations only
  9. kMax = kBlacklistOnly,
  10. };
  • kNoChecks:允许调用所有API,不做任何检测
  • kJustWarn:允许调用所有API,但是对于私有API的调用会打印警告log
  • kDarkGreyAndBlackList:会阻止调用dark grey或black list中的API
  • kBlacklistOnly:会阻止调用black list中的API

ApiList,Action,EnforcementPolicy这三者的关系,Google其实是通过EnforcementPolicy的配置,将ApiList转成Action。 ApiList,Action,EnforcementPolicy关系表

  1. void SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy policy) {
  2. hidden_api_policy_ = policy;
  3. }
  4. hiddenapi::EnforcementPolicy GetHiddenApiEnforcementPolicy() const {
  5. return hidden_api_policy_;
  6. }

2.3.2 IsCallerTrusted

fn_caller_is_trusted 其实是通过函数指针调用到IsCallerTrusted函数

  1. // Returns true if the first caller outside of the Class class or java.lang.invoke package
  2. // is in a platform DEX file.
  3. static bool IsCallerTrusted(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) {
  4. // Walk the stack and find the first frame not from java.lang.Class and not from java.lang.invoke.
  5. // This is very expensive. Save this till the last.
  6. struct FirstExternalCallerVisitor : public StackVisitor {
  7. explicit FirstExternalCallerVisitor(Thread* thread)
  8. : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
  9. caller(nullptr) {
  10. }
  11. bool VisitFrame() REQUIRES_SHARED(Locks::mutator_lock_) {
  12. ArtMethod *m = GetMethod();
  13. if (m == nullptr) {
  14. // Attached native thread. Assume this is *not* boot class path.
  15. caller = nullptr;
  16. return false;
  17. } else if (m->IsRuntimeMethod()) {
  18. // Internal runtime method, continue walking the stack.
  19. return true;
  20. }
  21. ObjPtr<mirror::Class> declaring_class = m->GetDeclaringClass();
  22. if (declaring_class->IsBootStrapClassLoaded()) {
  23. if (declaring_class->IsClassClass()) {
  24. return true;
  25. }
  26. // Check classes in the java.lang.invoke package. At the time of writing, the
  27. // classes of interest are MethodHandles and MethodHandles.Lookup, but this
  28. // is subject to change so conservatively cover the entire package.
  29. // NB Static initializers within java.lang.invoke are permitted and do not
  30. // need further stack inspection.
  31. ObjPtr<mirror::Class> lookup_class = mirror::MethodHandlesLookup::StaticClass();
  32. if ((declaring_class == lookup_class || declaring_class->IsInSamePackage(lookup_class))
  33. && !m->IsClassInitializer()) {
  34. return true;
  35. }
  36. }
  37. caller = m;
  38. return false;
  39. }
  40. ArtMethod* caller;
  41. };
  42. FirstExternalCallerVisitor visitor(self);
  43. visitor.WalkStack();
  44. return visitor.caller != nullptr &&
  45. hiddenapi::IsCallerTrusted(visitor.caller->GetDeclaringClass()); // 调用到hidden_api.h 里的IsCallerTrusted函数
  46. }

hiddenapi::IsCallerTrusted ,是调用到了

hidden_api.h

  1. // Returns true if the caller is either loaded by the boot strap class loader or comes from
  2. // a dex file located in ${ANDROID_ROOT}/framework/.
  3. ALWAYS_INLINE
  4. inline bool IsCallerTrusted(ObjPtr<mirror::Class> caller,
  5. ObjPtr<mirror::ClassLoader> caller_class_loader,
  6. ObjPtr<mirror::DexCache> caller_dex_cache)
  7. REQUIRES_SHARED(Locks::mutator_lock_) {
  8. if (caller_class_loader.IsNull()) {
  9. // Boot class loader. Boot classloader
  10. return true;
  11. }
  12. if (!caller_dex_cache.IsNull()) {
  13. const DexFile* caller_dex_file = caller_dex_cache->GetDexFile();
  14. if (caller_dex_file != nullptr && caller_dex_file->IsPlatformDexFile()) {
  15. // Caller is in a platform dex file. caller是平台dex文件
  16. return true;
  17. }
  18. }
  19. if (!caller.IsNull() &&
  20. caller->ShouldSkipHiddenApiChecks() &&
  21. Runtime::Current()->IsJavaDebuggable()) {
  22. // We are in debuggable mode and this caller has been marked trusted. 处于debuggable调试模式且caller已被标记可信任
  23. return true;
  24. }
  25. return false; // 除了以上三种情况都是false
  26. }

所以IsCallerTrusted就是在将信任的caller排除在外.

2.3.3 GetMemberActionImpl

hidden_api.cc

  1. template<typename T>
  2. Action GetMemberActionImpl(T* member,
  3. HiddenApiAccessFlags::ApiList api_list,
  4. Action action,
  5. AccessMethod access_method) {
  6. DCHECK_NE(action, kAllow);
  7. // Get the signature, we need it later.
  8. MemberSignature member_signature(member); // 获取签名
  9. Runtime* runtime = Runtime::Current();
  10. // Check for an exemption first. Exempted APIs are treated as white list.
  11. // We only do this if we're about to deny, or if the app is debuggable. This is because:
  12. // - we only print a warning for light greylist violations for debuggable apps
  13. // - for non-debuggable apps, there is no distinction between light grey & whitelisted APIs.
  14. // - we want to avoid the overhead of checking for exemptions for light greylisted APIs whenever
  15. // possible.
  16. const bool shouldWarn = kLogAllAccesses || runtime->IsJavaDebuggable();
  17. if (shouldWarn || action == kDeny) {
  18. if (member_signature.IsExempte(runtime->GetHiddenApiExemptions())) { // 判断是否可以豁免
  19. action = kAllow;
  20. // Avoid re-examining the exemption list next time.
  21. // Note this results in no warning for the member, which seems like what one would expect.
  22. // Exemptions effectively adds new members to the whitelist.
  23. MaybeWhitelistMember(runtime, member);
  24. return kAllow;
  25. }
  26. if (access_method != kNone) {
  27. // Print a log message with information about this class member access.
  28. // We do this if we're about to block access, or the app is debuggable.
  29. member_signature.WarnAboutAccess(access_method, api_list); // 判断是否通知警告
  30. }
  31. }
  32. if (kIsTargetBuild) {
  33. uint32_t eventLogSampleRate = runtime->GetHiddenApiEventLogSampleRate();
  34. // Assert that RAND_MAX is big enough, to ensure sampling below works as expected.
  35. static_assert(RAND_MAX >= 0xffff, "RAND_MAX too small");
  36. if (eventLogSampleRate != 0 &&
  37. (static_cast<uint32_t>(std::rand()) & 0xffff) < eventLogSampleRate) {
  38. member_signature.LogAccessToEventLog(access_method, action); // 输出EventLog
  39. }
  40. }
  41. if (action == kDeny) {
  42. // Block access
  43. return action;
  44. }
  45. // Allow access to this member but print a warning.
  46. DCHECK(action == kAllowButWarn || action == kAllowButWarnAndToast);
  47. if (access_method != kNone) {
  48. // Depending on a runtime flag, we might move the member into whitelist and
  49. // skip the warning the next time the member is accessed.
  50. MaybeWhitelistMember(runtime, member);
  51. // If this action requires a UI warning, set the appropriate flag.
  52. if (shouldWarn &&
  53. (action == kAllowButWarnAndToast || runtime->ShouldAlwaysSetHiddenApiWarningFlag())) {
  54. runtime->SetPendingHiddenApiWarning(true);
  55. }
  56. }
  57. return action;
  58. }

WarnAboutAccess 用来输出log

hidden_api.cc

  1. void MemberSignature::WarnAboutAccess(AccessMethod access_method,
  2. HiddenApiAccessFlags::ApiList list) {
  3. LOG(WARNING) << "Accessing hidden " << (type_ == kField ? "field " : "method ")
  4. << Dumpable<MemberSignature>(*this) << " (" << list << ", " << access_method << ")";

在代码介绍过程中有白名单,灰名单等,在源码中的目录如下

  1. out/target/common/obj/PACKAGING/hiddenapi-light-greylist.txt
  2. out/target/common/obj/PACKAGING/hiddenapi-dark-greylist.txt
  3. out/target/common/obj/PACKAGING/hiddenapi-blacklist.txt
  4. frameworks/base/config/hiddenapi-force-blacklist.txt
  5. frameworks/base/config/hiddenapi-light-greylist.txt
  6. frameworks/base/config/hiddenapi-private-dex.txt
  7. frameworks/base/config/hiddenapi-public-dex.txt
  8. frameworks/base/config/hiddenapi-removed-dex.txt
  9. frameworks/base/config/hiddenapi-vendor-list.txt
  10. out/target/product/product_name/system/etc/sysconfig/hiddenapi-package-whitelist.xml
  11. frameworks/base/data/etc/hiddenapi-package-whitelist.xml

参考资料