Print more information about hidden API accesses
This patch changes when we print hidden API access warnings and the
message that is printed:
(a) prints message even if reflection is denied
(b) prints if the access was due to reflection or JNI
Bug: 64382372
Test: manual
Change-Id: I1e59982516c12580a207fd294aa8aab851b1ad46
diff --git a/runtime/hidden_api.h b/runtime/hidden_api.h
index 05e68e6..d7e5e18 100644
--- a/runtime/hidden_api.h
+++ b/runtime/hidden_api.h
@@ -31,6 +31,23 @@
kDeny
};
+enum AccessMethod {
+ kReflection,
+ kJNI
+};
+
+inline std::ostream& operator<<(std::ostream& os, AccessMethod value) {
+ switch (value) {
+ case kReflection:
+ os << "reflection";
+ break;
+ case kJNI:
+ os << "JNI";
+ break;
+ }
+ return os;
+}
+
inline Action GetMemberAction(uint32_t access_flags) {
switch (HiddenApiAccessFlags::DecodeFromRuntime(access_flags)) {
case HiddenApiAccessFlags::kWhitelist:
@@ -45,19 +62,25 @@
}
// Issue a warning about field access.
-inline void WarnAboutMemberAccess(ArtField* field) REQUIRES_SHARED(Locks::mutator_lock_) {
+inline void WarnAboutMemberAccess(ArtField* field, AccessMethod access_method)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
std::string tmp;
LOG(WARNING) << "Accessing hidden field "
<< field->GetDeclaringClass()->GetDescriptor(&tmp) << "->"
- << field->GetName() << ":" << field->GetTypeDescriptor();
+ << field->GetName() << ":" << field->GetTypeDescriptor()
+ << " (" << HiddenApiAccessFlags::DecodeFromRuntime(field->GetAccessFlags())
+ << ", " << access_method << ")";
}
// Issue a warning about method access.
-inline void WarnAboutMemberAccess(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) {
+inline void WarnAboutMemberAccess(ArtMethod* method, AccessMethod access_method)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
std::string tmp;
LOG(WARNING) << "Accessing hidden method "
<< method->GetDeclaringClass()->GetDescriptor(&tmp) << "->"
- << method->GetName() << method->GetSignature().ToString();
+ << method->GetName() << method->GetSignature().ToString()
+ << " (" << HiddenApiAccessFlags::DecodeFromRuntime(method->GetAccessFlags())
+ << ", " << access_method << ")";
}
// Returns true if access to `member` should be denied to the caller of the
@@ -69,7 +92,8 @@
template<typename T>
inline bool ShouldBlockAccessToMember(T* member,
Thread* self,
- std::function<bool(Thread*)> fn_caller_in_boot)
+ std::function<bool(Thread*)> fn_caller_in_boot,
+ AccessMethod access_method)
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(member != nullptr);
Runtime* runtime = Runtime::Current();
@@ -92,25 +116,33 @@
return false;
}
- // Member is hidden and we are not in the boot class path. Act accordingly.
+ // Member is hidden and we are not in the boot class path.
+
+ // Print a log message with information about this class member access.
+ // We do this regardless of whether we block the access or not.
+ WarnAboutMemberAccess(member, access_method);
+
+ // Block access if on blacklist.
if (action == kDeny) {
return true;
- } else {
- DCHECK(action == kAllowButWarn || action == kAllowButWarnAndToast);
-
- // Allow access to this member but print a warning. Depending on a runtime
- // flag, we might move the member into whitelist and skip the warning the
- // next time the member is used.
- if (runtime->ShouldDedupeHiddenApiWarnings()) {
- member->SetAccessFlags(HiddenApiAccessFlags::EncodeForRuntime(
- member->GetAccessFlags(), HiddenApiAccessFlags::kWhitelist));
- }
- WarnAboutMemberAccess(member);
- if (action == kAllowButWarnAndToast || runtime->ShouldAlwaysSetHiddenApiWarningFlag()) {
- Runtime::Current()->SetPendingHiddenApiWarning(true);
- }
- return false;
}
+
+ // Allow access to this member but print a warning.
+ DCHECK(action == kAllowButWarn || action == kAllowButWarnAndToast);
+
+ // Depending on a runtime flag, we might move the member into whitelist and
+ // skip the warning the next time the member is accessed.
+ if (runtime->ShouldDedupeHiddenApiWarnings()) {
+ member->SetAccessFlags(HiddenApiAccessFlags::EncodeForRuntime(
+ member->GetAccessFlags(), HiddenApiAccessFlags::kWhitelist));
+ }
+
+ // If this action requires a UI warning, set the appropriate flag.
+ if (action == kAllowButWarnAndToast || runtime->ShouldAlwaysSetHiddenApiWarningFlag()) {
+ Runtime::Current()->SetPendingHiddenApiWarning(true);
+ }
+
+ return false;
}
// Returns true if access to member with `access_flags` should be denied to `caller`.
diff --git a/runtime/hidden_api_access_flags.h b/runtime/hidden_api_access_flags.h
index c328f96..6a88c12 100644
--- a/runtime/hidden_api_access_flags.h
+++ b/runtime/hidden_api_access_flags.h
@@ -146,6 +146,24 @@
};
};
+inline std::ostream& operator<<(std::ostream& os, HiddenApiAccessFlags::ApiList value) {
+ switch (value) {
+ case HiddenApiAccessFlags::kWhitelist:
+ os << "whitelist";
+ break;
+ case HiddenApiAccessFlags::kLightGreylist:
+ os << "light greylist";
+ break;
+ case HiddenApiAccessFlags::kDarkGreylist:
+ os << "dark greylist";
+ break;
+ case HiddenApiAccessFlags::kBlacklist:
+ os << "blacklist";
+ break;
+ }
+ return os;
+}
+
} // namespace art
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index 666fb98..cd4d954 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -90,7 +90,8 @@
template<typename T>
ALWAYS_INLINE static bool ShouldBlockAccessToMember(T* member, Thread* self)
REQUIRES_SHARED(Locks::mutator_lock_) {
- return hiddenapi::ShouldBlockAccessToMember(member, self, IsCallerInBootClassPath);
+ return hiddenapi::ShouldBlockAccessToMember(
+ member, self, IsCallerInBootClassPath, hiddenapi::kJNI);
}
// Helpers to call instrumentation functions for fields. These take jobjects so we don't need to set
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index 2091a27..4597f68 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -97,7 +97,8 @@
template<typename T>
ALWAYS_INLINE static bool ShouldBlockAccessToMember(T* member, Thread* self)
REQUIRES_SHARED(Locks::mutator_lock_) {
- return hiddenapi::ShouldBlockAccessToMember(member, self, IsCallerInBootClassPath);
+ return hiddenapi::ShouldBlockAccessToMember(
+ member, self, IsCallerInBootClassPath, hiddenapi::kReflection);
}
// Returns true if a class member should be discoverable with reflection given