summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/hidden_api.h69
-rw-r--r--runtime/native/dalvik_system_ZygoteHooks.cc49
-rw-r--r--runtime/native/java_lang_Class.cc4
-rw-r--r--runtime/runtime.cc13
-rw-r--r--runtime/runtime.h14
-rw-r--r--runtime/well_known_classes.cc9
-rw-r--r--test/674-hiddenapi/hiddenapi.cc3
7 files changed, 107 insertions, 54 deletions
diff --git a/runtime/hidden_api.h b/runtime/hidden_api.h
index f2ea2fdaaa..321d55d9b7 100644
--- a/runtime/hidden_api.h
+++ b/runtime/hidden_api.h
@@ -27,6 +27,23 @@
namespace art {
namespace hiddenapi {
+// 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,
+ kAllLists = 1, // ban anything but whitelist
+ kDarkGreyAndBlackList = 2, // ban dark grey & blacklist
+ kBlacklistOnly = 3, // ban blacklist violations only
+ kMax = kBlacklistOnly,
+};
+
+inline EnforcementPolicy EnforcementPolicyFromInt(int api_policy_int) {
+ DCHECK_GE(api_policy_int, 0);
+ DCHECK_LE(api_policy_int, static_cast<int>(EnforcementPolicy::kMax));
+ return static_cast<EnforcementPolicy>(api_policy_int);
+}
+
enum Action {
kAllow,
kAllowButWarn,
@@ -59,16 +76,38 @@ inline std::ostream& operator<<(std::ostream& os, AccessMethod value) {
return os;
}
+static constexpr bool EnumsEqual(EnforcementPolicy policy, HiddenApiAccessFlags::ApiList apiList) {
+ return static_cast<int>(policy) == static_cast<int>(apiList);
+}
+
inline Action GetMemberAction(uint32_t access_flags) {
- switch (HiddenApiAccessFlags::DecodeFromRuntime(access_flags)) {
- case HiddenApiAccessFlags::kWhitelist:
- return kAllow;
- case HiddenApiAccessFlags::kLightGreylist:
- return kAllowButWarn;
- case HiddenApiAccessFlags::kDarkGreylist:
- return kAllowButWarnAndToast;
- case HiddenApiAccessFlags::kBlacklist:
- return kDeny;
+ 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;
+ }
+ // The logic below relies on equality of values in the enums EnforcementPolicy and
+ // HiddenApiAccessFlags::ApiList, and their ordering. Assert that this is as expected.
+ static_assert(
+ EnumsEqual(EnforcementPolicy::kAllLists, HiddenApiAccessFlags::kLightGreylist) &&
+ EnumsEqual(EnforcementPolicy::kDarkGreyAndBlackList, HiddenApiAccessFlags::kDarkGreylist) &&
+ EnumsEqual(EnforcementPolicy::kBlacklistOnly, HiddenApiAccessFlags::kBlacklist),
+ "Mismatch between EnforcementPolicy and ApiList enums");
+ static_assert(
+ EnforcementPolicy::kAllLists < EnforcementPolicy::kDarkGreyAndBlackList &&
+ EnforcementPolicy::kDarkGreyAndBlackList < EnforcementPolicy::kBlacklistOnly,
+ "EnforcementPolicy values ordering not correct");
+ if (static_cast<int>(policy) > static_cast<int>(api_list)) {
+ return api_list == HiddenApiAccessFlags::kDarkGreylist
+ ? kAllowButWarnAndToast
+ : kAllowButWarn;
+ } else {
+ return kDeny;
}
}
@@ -107,12 +146,6 @@ inline bool ShouldBlockAccessToMember(T* member,
AccessMethod access_method)
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(member != nullptr);
- Runtime* runtime = Runtime::Current();
-
- if (!runtime->AreHiddenApiChecksEnabled()) {
- // Exit early. Nothing to enforce.
- return false;
- }
Action action = GetMemberAction(member->GetAccessFlags());
if (action == kAllow) {
@@ -133,14 +166,16 @@ inline bool ShouldBlockAccessToMember(T* member,
// We do this regardless of whether we block the access or not.
WarnAboutMemberAccess(member, access_method);
- // Block access if on blacklist.
if (action == kDeny) {
+ // Block access
return true;
}
// Allow access to this member but print a warning.
DCHECK(action == kAllowButWarn || action == kAllowButWarnAndToast);
+ Runtime* runtime = Runtime::Current();
+
// 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()) {
@@ -150,7 +185,7 @@ inline bool ShouldBlockAccessToMember(T* member,
// If this action requires a UI warning, set the appropriate flag.
if (action == kAllowButWarnAndToast || runtime->ShouldAlwaysSetHiddenApiWarningFlag()) {
- Runtime::Current()->SetPendingHiddenApiWarning(true);
+ runtime->SetPendingHiddenApiWarning(true);
}
return false;
diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc
index 89135698e3..cbc2aeb41f 100644
--- a/runtime/native/dalvik_system_ZygoteHooks.cc
+++ b/runtime/native/dalvik_system_ZygoteHooks.cc
@@ -162,19 +162,24 @@ static void CollectNonDebuggableClasses() REQUIRES(!Locks::mutator_lock_) {
// Must match values in com.android.internal.os.Zygote.
enum {
- DEBUG_ENABLE_JDWP = 1,
- DEBUG_ENABLE_CHECKJNI = 1 << 1,
- DEBUG_ENABLE_ASSERT = 1 << 2,
- DEBUG_ENABLE_SAFEMODE = 1 << 3,
- DEBUG_ENABLE_JNI_LOGGING = 1 << 4,
- DEBUG_GENERATE_DEBUG_INFO = 1 << 5,
- DEBUG_ALWAYS_JIT = 1 << 6,
- DEBUG_NATIVE_DEBUGGABLE = 1 << 7,
- DEBUG_JAVA_DEBUGGABLE = 1 << 8,
- DISABLE_VERIFIER = 1 << 9,
- ONLY_USE_SYSTEM_OAT_FILES = 1 << 10,
- ENABLE_HIDDEN_API_CHECKS = 1 << 11,
- DEBUG_GENERATE_MINI_DEBUG_INFO = 1 << 12,
+ DEBUG_ENABLE_JDWP = 1,
+ DEBUG_ENABLE_CHECKJNI = 1 << 1,
+ DEBUG_ENABLE_ASSERT = 1 << 2,
+ DEBUG_ENABLE_SAFEMODE = 1 << 3,
+ DEBUG_ENABLE_JNI_LOGGING = 1 << 4,
+ DEBUG_GENERATE_DEBUG_INFO = 1 << 5,
+ DEBUG_ALWAYS_JIT = 1 << 6,
+ DEBUG_NATIVE_DEBUGGABLE = 1 << 7,
+ DEBUG_JAVA_DEBUGGABLE = 1 << 8,
+ DISABLE_VERIFIER = 1 << 9,
+ ONLY_USE_SYSTEM_OAT_FILES = 1 << 10,
+ DEBUG_GENERATE_MINI_DEBUG_INFO = 1 << 11,
+ HIDDEN_API_ENFORCEMENT_POLICY_MASK = (1 << 12)
+ | (1 << 13),
+
+ // bits to shift (flags & HIDDEN_API_ENFORCEMENT_POLICY_MASK) by to get a value
+ // corresponding to hiddenapi::EnforcementPolicy
+ API_ENFORCEMENT_POLICY_SHIFT = CTZ(HIDDEN_API_ENFORCEMENT_POLICY_MASK),
};
static uint32_t EnableDebugFeatures(uint32_t runtime_flags) {
@@ -285,7 +290,8 @@ static void ZygoteHooks_nativePostForkChild(JNIEnv* env,
// Our system thread ID, etc, has changed so reset Thread state.
thread->InitAfterFork();
runtime_flags = EnableDebugFeatures(runtime_flags);
- bool do_hidden_api_checks = false;
+ hiddenapi::EnforcementPolicy api_enforcement_policy = hiddenapi::EnforcementPolicy::kNoChecks;
+ bool dedupe_hidden_api_warnings = true;
if ((runtime_flags & DISABLE_VERIFIER) != 0) {
Runtime::Current()->DisableVerifier();
@@ -297,10 +303,9 @@ static void ZygoteHooks_nativePostForkChild(JNIEnv* env,
runtime_flags &= ~ONLY_USE_SYSTEM_OAT_FILES;
}
- if ((runtime_flags & ENABLE_HIDDEN_API_CHECKS) != 0) {
- do_hidden_api_checks = true;
- runtime_flags &= ~ENABLE_HIDDEN_API_CHECKS;
- }
+ api_enforcement_policy = hiddenapi::EnforcementPolicyFromInt(
+ (runtime_flags & HIDDEN_API_ENFORCEMENT_POLICY_MASK) >> API_ENFORCEMENT_POLICY_SHIFT);
+ runtime_flags &= ~HIDDEN_API_ENFORCEMENT_POLICY_MASK;
if (runtime_flags != 0) {
LOG(ERROR) << StringPrintf("Unknown bits set in runtime_flags: %#x", runtime_flags);
@@ -351,11 +356,13 @@ static void ZygoteHooks_nativePostForkChild(JNIEnv* env,
}
}
+ bool do_hidden_api_checks = api_enforcement_policy != hiddenapi::EnforcementPolicy::kNoChecks;
DCHECK(!(is_system_server && do_hidden_api_checks))
- << "SystemServer should be forked with ENABLE_HIDDEN_API_CHECKS";
+ << "SystemServer should be forked with EnforcementPolicy::kDisable";
DCHECK(!(is_zygote && do_hidden_api_checks))
- << "Child zygote processes should be forked with ENABLE_HIDDEN_API_CHECKS";
- Runtime::Current()->SetHiddenApiChecksEnabled(do_hidden_api_checks);
+ << "Child zygote processes should be forked with EnforcementPolicy::kDisable";
+ Runtime::Current()->SetHiddenApiEnforcementPolicy(api_enforcement_policy);
+ Runtime::Current()->SetDedupeHiddenApiWarnings(dedupe_hidden_api_warnings);
// Clear the hidden API warning flag, in case it was set.
Runtime::Current()->SetPendingHiddenApiWarning(false);
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index 25d50376de..fc61c9597e 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -89,8 +89,8 @@ static bool IsCallerInBootClassPath(Thread* self) REQUIRES_SHARED(Locks::mutator
// access hidden APIs. This can be *very* expensive. Never call this in a loop.
ALWAYS_INLINE static bool ShouldEnforceHiddenApi(Thread* self)
REQUIRES_SHARED(Locks::mutator_lock_) {
- return Runtime::Current()->AreHiddenApiChecksEnabled() &&
- !IsCallerInBootClassPath(self);
+ hiddenapi::EnforcementPolicy policy = Runtime::Current()->GetHiddenApiEnforcementPolicy();
+ return policy != hiddenapi::EnforcementPolicy::kNoChecks && !IsCallerInBootClassPath(self);
}
// Returns true if the first non-ClassClass caller up the stack should not be
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 7d9d3426fc..53982ae833 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -267,7 +267,7 @@ Runtime::Runtime()
oat_file_manager_(nullptr),
is_low_memory_mode_(false),
safe_mode_(false),
- do_hidden_api_checks_(false),
+ hidden_api_policy_(hiddenapi::EnforcementPolicy::kNoChecks),
pending_hidden_api_warning_(false),
dedupe_hidden_api_warnings_(true),
always_set_hidden_api_warning_flag_(false),
@@ -1196,9 +1196,14 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) {
// by default and we only enable them if:
// (a) runtime was started with a flag that enables the checks, or
// (b) Zygote forked a new process that is not exempt (see ZygoteHooks).
- do_hidden_api_checks_ = runtime_options.Exists(Opt::HiddenApiChecks);
- DCHECK(!is_zygote_ || !do_hidden_api_checks_)
- << "Zygote should not be started with hidden API checks";
+ bool do_hidden_api_checks = runtime_options.Exists(Opt::HiddenApiChecks);
+ DCHECK(!is_zygote_ || !do_hidden_api_checks);
+ // TODO pass the actual enforcement policy in, rather than just a single bit.
+ // As is, we're encoding some logic here about which specific policy to use, which would be better
+ // controlled by the framework.
+ hidden_api_policy_ = do_hidden_api_checks
+ ? hiddenapi::EnforcementPolicy::kBlacklistOnly
+ : hiddenapi::EnforcementPolicy::kNoChecks;
no_sig_chain_ = runtime_options.Exists(Opt::NoSigChain);
force_native_bridge_ = runtime_options.Exists(Opt::ForceNativeBridge);
diff --git a/runtime/runtime.h b/runtime/runtime.h
index c7f650ea3f..dba31b2939 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -49,6 +49,10 @@ class AbstractSystemWeakHolder;
class Heap;
} // namespace gc
+namespace hiddenapi {
+enum class EnforcementPolicy;
+} // namespace hiddenapi
+
namespace jit {
class Jit;
class JitOptions;
@@ -520,12 +524,12 @@ class Runtime {
bool IsVerificationEnabled() const;
bool IsVerificationSoftFail() const;
- void SetHiddenApiChecksEnabled(bool value) {
- do_hidden_api_checks_ = value;
+ void SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy policy) {
+ hidden_api_policy_ = policy;
}
- bool AreHiddenApiChecksEnabled() const {
- return do_hidden_api_checks_;
+ hiddenapi::EnforcementPolicy GetHiddenApiEnforcementPolicy() const {
+ return hidden_api_policy_;
}
void SetPendingHiddenApiWarning(bool value) {
@@ -990,7 +994,7 @@ class Runtime {
bool safe_mode_;
// Whether access checks on hidden API should be performed.
- bool do_hidden_api_checks_;
+ hiddenapi::EnforcementPolicy hidden_api_policy_;
// Whether the application has used an API which is not restricted but we
// should issue a warning about it.
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index 67ea64be74..bf36ccf0fa 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -24,6 +24,7 @@
#include <android-base/stringprintf.h>
#include "entrypoints/quick/quick_entrypoints_enum.h"
+#include "hidden_api.h"
#include "jni_internal.h"
#include "mirror/class.h"
#include "mirror/throwable.h"
@@ -287,17 +288,17 @@ class ScopedHiddenApiExemption {
public:
explicit ScopedHiddenApiExemption(Runtime* runtime)
: runtime_(runtime),
- initially_enabled_(runtime_->AreHiddenApiChecksEnabled()) {
- runtime_->SetHiddenApiChecksEnabled(false);
+ initial_policy_(runtime_->GetHiddenApiEnforcementPolicy()) {
+ runtime_->SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kNoChecks);
}
~ScopedHiddenApiExemption() {
- runtime_->SetHiddenApiChecksEnabled(initially_enabled_);
+ runtime_->SetHiddenApiEnforcementPolicy(initial_policy_);
}
private:
Runtime* runtime_;
- const bool initially_enabled_;
+ const hiddenapi::EnforcementPolicy initial_policy_;
DISALLOW_COPY_AND_ASSIGN(ScopedHiddenApiExemption);
};
diff --git a/test/674-hiddenapi/hiddenapi.cc b/test/674-hiddenapi/hiddenapi.cc
index effa37ade4..04c3fbf03a 100644
--- a/test/674-hiddenapi/hiddenapi.cc
+++ b/test/674-hiddenapi/hiddenapi.cc
@@ -16,6 +16,7 @@
#include "class_linker.h"
#include "dex/art_dex_file_loader.h"
+#include "hidden_api.h"
#include "jni.h"
#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
@@ -27,7 +28,7 @@ namespace Test674HiddenApi {
extern "C" JNIEXPORT void JNICALL Java_Main_init(JNIEnv*, jclass) {
Runtime* runtime = Runtime::Current();
- runtime->SetHiddenApiChecksEnabled(true);
+ runtime->SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kBlacklistOnly);
runtime->SetDedupeHiddenApiWarnings(false);
runtime->AlwaysSetHiddenApiWarningFlag();
}