Treat hidden API exemptions as whitelist.

This was a request from android-api-council, effectively to treat
exempted APIs as equivalent to public APIs. The reasoning for this is
that if the support library uses such APIs, we don't want to confuse
developers with a warning in the log.

To avoid examing the exemptions list on all light greylist API accesses,
also change the light greylist warn behavior to only print a warning in
the log if the app is debuggable. This means:
- less log spam from light greylist usages
- debuggable apps still get info about light greylist usage

Bug: 64382372
Test: m
Test: Boot device
Test: $ adb shell settings put global hidden_api_blacklist_exemptions \
Test:     "\"Landroid/app/Activity;->mWindow:,Landroid/app/Activity;->mCalled:\""
Test: Verified with test app & adb logcat
Merged-In: Ibada61b591517f7e72c7101aea04ff0ad4beb0ee
Change-Id: Ibada61b591517f7e72c7101aea04ff0ad4beb0ee
(cherry picked from commit c8ce5f520d2ba84ff8f393f78ba953ae6d467ca8)
diff --git a/runtime/hidden_api.cc b/runtime/hidden_api.cc
index fa47e3a..02b4f53 100644
--- a/runtime/hidden_api.cc
+++ b/runtime/hidden_api.cc
@@ -125,25 +125,29 @@
 
   Runtime* runtime = Runtime::Current();
 
-  if (action == kDeny) {
-    // If we were about to deny, check for an exemption first.
-    // Exempted APIs are treated as light grey list.
+  // Check for an exemption first. Exempted APIs are treated as white list.
+  // We only do this if we're about to deny, or if the app is debuggable. This is because:
+  // - we only print a warning for light greylist violations for debuggable apps
+  // - for non-debuggable apps, there is no distinction between light grey & whitelisted APIs.
+  // - we want to avoid the overhead of checking for exemptions for light greylisted APIs whenever
+  //   possible.
+  if (action == kDeny || runtime->IsJavaDebuggable()) {
     if (member_signature.IsExempted(runtime->GetHiddenApiExemptions())) {
-      action = kAllowButWarn;
+      action = kAllow;
       // Avoid re-examining the exemption list next time.
-      // Note this results in the warning below showing "light greylist", which
-      // seems like what one would expect. Exemptions effectively add new members to
-      // the light greylist.
+      // Note this results in no warning for the member, which seems like what one would expect.
+      // Exemptions effectively adds new members to the whitelist.
       member->SetAccessFlags(HiddenApiAccessFlags::EncodeForRuntime(
-              member->GetAccessFlags(), HiddenApiAccessFlags::kLightGreylist));
+              member->GetAccessFlags(), HiddenApiAccessFlags::kWhitelist));
+      return kAllow;
     }
-  }
 
-  if (access_method != kNone) {
-    // Print a log message with information about this class member access.
-    // We do this regardless of whether we block the access or not.
-    member_signature.WarnAboutAccess(access_method,
-        HiddenApiAccessFlags::DecodeFromRuntime(member->GetAccessFlags()));
+    if (access_method != kNone) {
+      // Print a log message with information about this class member access.
+      // We do this if we're about to block access, or the app is debuggable.
+      member_signature.WarnAboutAccess(access_method,
+          HiddenApiAccessFlags::DecodeFromRuntime(member->GetAccessFlags()));
+    }
   }
 
   if (action == kDeny) {
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 56d95e0..67813a7 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -1006,7 +1006,8 @@
   // Whether access checks on hidden API should be performed.
   hiddenapi::EnforcementPolicy hidden_api_policy_;
 
-  // List of signature prefixes of methods that have been removed from the blacklist
+  // List of signature prefixes of methods that have been removed from the blacklist, and treated
+  // as if whitelisted.
   std::vector<std::string> hidden_api_exemptions_;
 
   // Whether the application has used an API which is not restricted but we