summaryrefslogtreecommitdiff
path: root/runtime/hidden_api.h
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/hidden_api.h')
-rw-r--r--runtime/hidden_api.h107
1 files changed, 79 insertions, 28 deletions
diff --git a/runtime/hidden_api.h b/runtime/hidden_api.h
index ffdeacbfff..8e21fd3b8f 100644
--- a/runtime/hidden_api.h
+++ b/runtime/hidden_api.h
@@ -33,7 +33,7 @@ namespace hiddenapi {
// frameworks/base/core/java/android/content/pm/ApplicationInfo.java
enum class EnforcementPolicy {
kNoChecks = 0,
- kAllLists = 1, // ban anything but whitelist
+ kJustWarn = 1, // keep checks enabled, but allow everything (enables logging)
kDarkGreyAndBlackList = 2, // ban dark grey & blacklist
kBlacklistOnly = 3, // ban blacklist violations only
kMax = kBlacklistOnly,
@@ -53,22 +53,37 @@ enum Action {
};
enum AccessMethod {
+ kNone, // internal test that does not correspond to an actual access by app
kReflection,
kJNI,
kLinking,
};
-inline Action GetActionFromAccessFlags(uint32_t access_flags) {
+// Do not change the values of items in this enum, as they are written to the
+// event log for offline analysis. Any changes will interfere with that analysis.
+enum AccessContextFlags {
+ // Accessed member is a field if this bit is set, else a method
+ kMemberIsField = 1 << 0,
+ // Indicates if access was denied to the member, instead of just printing a warning.
+ kAccessDenied = 1 << 1,
+};
+
+inline Action GetActionFromAccessFlags(HiddenApiAccessFlags::ApiList api_list) {
+ if (api_list == HiddenApiAccessFlags::kWhitelist) {
+ return kAllow;
+ }
+
EnforcementPolicy policy = Runtime::Current()->GetHiddenApiEnforcementPolicy();
if (policy == EnforcementPolicy::kNoChecks) {
// Exit early. Nothing to enforce.
return kAllow;
}
- HiddenApiAccessFlags::ApiList api_list = HiddenApiAccessFlags::DecodeFromRuntime(access_flags);
- if (api_list == HiddenApiAccessFlags::kWhitelist) {
- return kAllow;
+ // 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)) {
@@ -87,9 +102,18 @@ namespace detail {
// is used as a helper when matching prefixes, and when logging the signature.
class MemberSignature {
private:
- std::string member_type_;
- std::vector<std::string> signature_parts_;
+ enum MemberType {
+ kField,
+ kMethod,
+ };
+
+ std::string class_name_;
+ std::string member_name_;
+ std::string type_signature_;
std::string tmp_;
+ MemberType type_;
+
+ inline std::vector<const char*> GetSignatureParts() const;
public:
explicit MemberSignature(ArtField* field) REQUIRES_SHARED(Locks::mutator_lock_);
@@ -105,45 +129,72 @@ class MemberSignature {
bool IsExempted(const std::vector<std::string>& exemptions);
void WarnAboutAccess(AccessMethod access_method, HiddenApiAccessFlags::ApiList list);
+
+ void LogAccessToEventLog(AccessMethod access_method, Action action_taken);
};
template<typename T>
-Action GetMemberActionImpl(T* member, Action action, AccessMethod access_method)
+Action GetMemberActionImpl(T* member,
+ HiddenApiAccessFlags::ApiList api_list,
+ Action action,
+ AccessMethod access_method)
REQUIRES_SHARED(Locks::mutator_lock_);
// 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
-inline bool IsCallerInPlatformDex(ObjPtr<mirror::ClassLoader> caller_class_loader,
- ObjPtr<mirror::DexCache> caller_dex_cache)
+inline bool IsCallerTrusted(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.
return true;
- } else if (caller_dex_cache.IsNull()) {
- return false;
- } else {
+ }
+
+ if (!caller_dex_cache.IsNull()) {
const DexFile* caller_dex_file = caller_dex_cache->GetDexFile();
- return caller_dex_file != nullptr && caller_dex_file->IsPlatformDexFile();
+ if (caller_dex_file != nullptr && caller_dex_file->IsPlatformDexFile()) {
+ // Caller is in a platform dex file.
+ return true;
+ }
}
+
+ if (!caller.IsNull() &&
+ caller->ShouldSkipHiddenApiChecks() &&
+ Runtime::Current()->IsJavaDebuggable()) {
+ // We are in debuggable mode and this caller has been marked trusted.
+ return true;
+ }
+
+ return false;
}
} // namespace detail
// 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 in the
-// platform or not. Because different users of this function determine this
-// in a different way, `fn_caller_in_platform(self)` is called and should
-// return true if the caller is located in the platform.
+// 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>
inline Action GetMemberAction(T* member,
Thread* self,
- std::function<bool(Thread*)> fn_caller_in_platform,
+ std::function<bool(Thread*)> fn_caller_is_trusted,
AccessMethod access_method)
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(member != nullptr);
- Action action = GetActionFromAccessFlags(member->GetAccessFlags());
+ // 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).
+ HiddenApiAccessFlags::ApiList api_list = member->GetHiddenApiAccessFlags();
+
+ Action action = GetActionFromAccessFlags(member->GetHiddenApiAccessFlags());
if (action == kAllow) {
// Nothing to do.
return action;
@@ -151,19 +202,18 @@ inline Action GetMemberAction(T* member,
// 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_in_platform(self)) {
- // Caller in the platform. Exit.
+ if (fn_caller_is_trusted(self)) {
+ // Caller is trusted. Exit.
return kAllow;
}
// Member is hidden and caller is not in the platform.
- return detail::GetMemberActionImpl(member, action, access_method);
+ return detail::GetMemberActionImpl(member, api_list, action, access_method);
}
-inline bool IsCallerInPlatformDex(ObjPtr<mirror::Class> caller)
- REQUIRES_SHARED(Locks::mutator_lock_) {
+inline bool IsCallerTrusted(ObjPtr<mirror::Class> caller) REQUIRES_SHARED(Locks::mutator_lock_) {
return !caller.IsNull() &&
- detail::IsCallerInPlatformDex(caller->GetClassLoader(), caller->GetDexCache());
+ detail::IsCallerTrusted(caller, caller->GetClassLoader(), caller->GetDexCache());
}
// Returns true if access to `member` should be denied to a caller loaded with
@@ -175,10 +225,11 @@ inline Action GetMemberAction(T* member,
ObjPtr<mirror::DexCache> caller_dex_cache,
AccessMethod access_method)
REQUIRES_SHARED(Locks::mutator_lock_) {
- bool caller_in_platform = detail::IsCallerInPlatformDex(caller_class_loader, caller_dex_cache);
+ bool is_caller_trusted =
+ detail::IsCallerTrusted(/* caller */ nullptr, caller_class_loader, caller_dex_cache);
return GetMemberAction(member,
/* thread */ nullptr,
- [caller_in_platform] (Thread*) { return caller_in_platform; },
+ [is_caller_trusted] (Thread*) { return is_caller_trusted; },
access_method);
}