Add a --whitelist and --only-report-sdk-uses to veridex.

In order to list SDK uses.

bug: 112978171
Test: manual
Change-Id: Ic2b36d6e8a3e07d3ec7001ed24888bd390219a85
diff --git a/Android.mk b/Android.mk
index 7852be5..0c20973 100644
--- a/Android.mk
+++ b/Android.mk
@@ -427,7 +427,7 @@
 define build-art-hiddenapi
 $(shell if [ ! -d frameworks/base ]; then \
   mkdir -p ${TARGET_OUT_COMMON_INTERMEDIATES}/PACKAGING; \
-	touch ${TARGET_OUT_COMMON_INTERMEDIATES}/PACKAGING/hiddenapi-{blacklist,dark-greylist,light-greylist}.txt; \
+	touch ${TARGET_OUT_COMMON_INTERMEDIATES}/PACKAGING/hiddenapi-{whitelist,blacklist,dark-greylist,light-greylist}.txt; \
   fi;)
 endef
 
diff --git a/libdexfile/dex/hidden_api_access_flags.h b/libdexfile/dex/hidden_api_access_flags.h
index 1aaeabd..369615d 100644
--- a/libdexfile/dex/hidden_api_access_flags.h
+++ b/libdexfile/dex/hidden_api_access_flags.h
@@ -62,6 +62,7 @@
     kLightGreylist,
     kDarkGreylist,
     kBlacklist,
+    kNoList,
   };
 
   static ALWAYS_INLINE ApiList DecodeFromDex(uint32_t dex_access_flags) {
@@ -159,6 +160,9 @@
     case HiddenApiAccessFlags::kBlacklist:
       os << "blacklist";
       break;
+    case HiddenApiAccessFlags::kNoList:
+      os << "no list";
+      break;
   }
   return os;
 }
diff --git a/tools/veridex/Android.mk b/tools/veridex/Android.mk
index 2faa577..99ced7b 100644
--- a/tools/veridex/Android.mk
+++ b/tools/veridex/Android.mk
@@ -31,6 +31,7 @@
 	$(transform-classes.jar-to-dex)
 
 app_compat_lists := \
+  $(INTERNAL_PLATFORM_HIDDENAPI_WHITELIST) \
   $(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST) \
   $(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST) \
   $(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST)
diff --git a/tools/veridex/appcompat.sh b/tools/veridex/appcompat.sh
index e7b735d..9a24d82 100755
--- a/tools/veridex/appcompat.sh
+++ b/tools/veridex/appcompat.sh
@@ -22,6 +22,7 @@
 SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
 
 if [[ -e ${SCRIPT_DIR}/veridex && \
+      -e ${SCRIPT_DIR}/hiddenapi-whitelist.txt && \
       -e ${SCRIPT_DIR}/hiddenapi-blacklist.txt && \
       -e ${SCRIPT_DIR}/hiddenapi-light-greylist.txt && \
       -e ${SCRIPT_DIR}/hiddenapi-dark-greylist.txt && \
@@ -29,6 +30,7 @@
       -e ${SCRIPT_DIR}/system-stubs.zip ]]; then
   exec ${SCRIPT_DIR}/veridex \
     --core-stubs=${SCRIPT_DIR}/system-stubs.zip:${SCRIPT_DIR}/org.apache.http.legacy-stubs.zip \
+    --whitelist=${SCRIPT_DIR}/hiddenapi-whitelist.txt \
     --blacklist=${SCRIPT_DIR}/hiddenapi-blacklist.txt \
     --light-greylist=${SCRIPT_DIR}/hiddenapi-light-greylist.txt \
     --dark-greylist=${SCRIPT_DIR}/hiddenapi-dark-greylist.txt \
@@ -62,6 +64,7 @@
 
 ${ANDROID_HOST_OUT}/bin/veridex \
     --core-stubs=${PACKAGING}/core_dex_intermediates/classes.dex:${PACKAGING}/oahl_dex_intermediates/classes.dex \
+    --whitelist=${PACKAGING}/hiddenapi-whitelist.txt \
     --blacklist=${PACKAGING}/hiddenapi-blacklist.txt \
     --light-greylist=${PACKAGING}/hiddenapi-light-greylist.txt \
     --dark-greylist=${PACKAGING}/hiddenapi-dark-greylist.txt \
diff --git a/tools/veridex/hidden_api.h b/tools/veridex/hidden_api.h
index b1c8559..68485bd 100644
--- a/tools/veridex/hidden_api.h
+++ b/tools/veridex/hidden_api.h
@@ -33,10 +33,14 @@
  */
 class HiddenApi {
  public:
-  HiddenApi(const char* blacklist, const char* dark_greylist, const char* light_greylist) {
+  HiddenApi(const char* whitelist,
+            const char* blacklist,
+            const char* dark_greylist,
+            const char* light_greylist) {
     FillList(light_greylist, light_greylist_);
     FillList(dark_greylist, dark_greylist_);
     FillList(blacklist, blacklist_);
+    FillList(whitelist, whitelist_);
   }
 
   HiddenApiAccessFlags::ApiList GetApiList(const std::string& name) const {
@@ -46,13 +50,15 @@
       return HiddenApiAccessFlags::kDarkGreylist;
     } else if (IsInList(name, light_greylist_)) {
       return HiddenApiAccessFlags::kLightGreylist;
-    } else {
+    } else if (IsInList(name, whitelist_)) {
       return HiddenApiAccessFlags::kWhitelist;
+    } else {
+      return HiddenApiAccessFlags::kNoList;
     }
   }
 
-  bool IsInRestrictionList(const std::string& name) const {
-    return GetApiList(name) != HiddenApiAccessFlags::kWhitelist;
+  bool IsInAnyList(const std::string& name) const {
+    return GetApiList(name) != HiddenApiAccessFlags::kNoList;
   }
 
   static std::string GetApiMethodName(const DexFile& dex_file, uint32_t method_index);
@@ -76,6 +82,7 @@
 
   static void FillList(const char* filename, std::set<std::string>& entries);
 
+  std::set<std::string> whitelist_;
   std::set<std::string> blacklist_;
   std::set<std::string> light_greylist_;
   std::set<std::string> dark_greylist_;
@@ -85,7 +92,7 @@
   uint32_t count = 0;
   uint32_t reflection_count = 0;
   uint32_t linking_count = 0;
-  uint32_t api_counts[4] = { 0, 0, 0, 0 };
+  uint32_t api_counts[5] = { 0, 0, 0, 0, 0 };
 };
 
 }  // namespace art
diff --git a/tools/veridex/hidden_api_finder.cc b/tools/veridex/hidden_api_finder.cc
index d81f133..9e2f936 100644
--- a/tools/veridex/hidden_api_finder.cc
+++ b/tools/veridex/hidden_api_finder.cc
@@ -35,7 +35,7 @@
   // Note: we always query whether a method is in a list, as the app
   // might define blacklisted APIs (which won't be used at runtime).
   std::string name = HiddenApi::GetApiMethodName(resolver->GetDexFile(), method_id);
-  if (hidden_api_.IsInRestrictionList(name)) {
+  if (hidden_api_.IsInAnyList(name)) {
     method_locations_[name].push_back(ref);
   }
 }
@@ -46,7 +46,7 @@
   // Note: we always query whether a field is in a list, as the app
   // might define blacklisted APIs (which won't be used at runtime).
   std::string name = HiddenApi::GetApiFieldName(resolver->GetDexFile(), field_id);
-  if (hidden_api_.IsInRestrictionList(name)) {
+  if (hidden_api_.IsInAnyList(name)) {
     field_locations_[name].push_back(ref);
   }
 }
@@ -57,7 +57,7 @@
   // types can lead to being used through reflection.
   for (uint32_t i = 0; i < dex_file.NumTypeIds(); ++i) {
     std::string name(dex_file.StringByTypeIdx(dex::TypeIndex(i)));
-    if (hidden_api_.IsInRestrictionList(name)) {
+    if (hidden_api_.IsInAnyList(name)) {
       classes_.insert(name);
     }
   }
@@ -81,9 +81,9 @@
               // private methods and fields in them.
               // We don't add class names to the `strings_` set as we know method/field names
               // don't have '.' or '/'. All hidden API class names have a '/'.
-              if (hidden_api_.IsInRestrictionList(str)) {
+              if (hidden_api_.IsInAnyList(str)) {
                 classes_.insert(str);
-              } else if (hidden_api_.IsInRestrictionList(name)) {
+              } else if (hidden_api_.IsInAnyList(name)) {
                 // Could be something passed to JNI.
                 classes_.insert(name);
               } else {
@@ -210,7 +210,7 @@
         std::string full_name = cls + "->" + name;
         HiddenApiAccessFlags::ApiList api_list = hidden_api_.GetApiList(full_name);
         stats->api_counts[api_list]++;
-        if (api_list != HiddenApiAccessFlags::kWhitelist) {
+        if (api_list != HiddenApiAccessFlags::kNoList) {
           stats->reflection_count++;
           os << "#" << ++stats->count << ": Reflection " << api_list << " " << full_name
              << " potential use(s):";
diff --git a/tools/veridex/precise_hidden_api_finder.cc b/tools/veridex/precise_hidden_api_finder.cc
index 445221e..08ac6d7 100644
--- a/tools/veridex/precise_hidden_api_finder.cc
+++ b/tools/veridex/precise_hidden_api_finder.cc
@@ -92,7 +92,7 @@
       std::string name(info.name.ToString());
       std::string full_name = cls + "->" + name;
       HiddenApiAccessFlags::ApiList api_list = hidden_api_.GetApiList(full_name);
-      if (api_list != HiddenApiAccessFlags::kWhitelist) {
+      if (api_list != HiddenApiAccessFlags::kNoList) {
         named_uses[full_name].push_back(ref);
       }
     }
diff --git a/tools/veridex/veridex.cc b/tools/veridex/veridex.cc
index 1d3a4fb..cf1167f 100644
--- a/tools/veridex/veridex.cc
+++ b/tools/veridex/veridex.cc
@@ -68,11 +68,13 @@
 struct VeridexOptions {
   const char* dex_file = nullptr;
   const char* core_stubs = nullptr;
+  const char* whitelist = nullptr;
   const char* blacklist = nullptr;
   const char* light_greylist = nullptr;
   const char* dark_greylist = nullptr;
   bool precise = true;
   int target_sdk_version = 28; /* P */
+  bool only_report_sdk_uses = false;
 };
 
 static const char* Substr(const char* str, int index) {
@@ -90,17 +92,21 @@
 
   static const char* kDexFileOption = "--dex-file=";
   static const char* kStubsOption = "--core-stubs=";
+  static const char* kWhitelistOption = "--whitelist=";
   static const char* kBlacklistOption = "--blacklist=";
   static const char* kDarkGreylistOption = "--dark-greylist=";
   static const char* kLightGreylistOption = "--light-greylist=";
   static const char* kImprecise = "--imprecise";
   static const char* kTargetSdkVersion = "--target-sdk-version=";
+  static const char* kOnlyReportSdkUses = "--only-report-sdk-uses";
 
   for (int i = 0; i < argc; ++i) {
     if (StartsWith(argv[i], kDexFileOption)) {
       options->dex_file = Substr(argv[i], strlen(kDexFileOption));
     } else if (StartsWith(argv[i], kStubsOption)) {
       options->core_stubs = Substr(argv[i], strlen(kStubsOption));
+    } else if (StartsWith(argv[i], kWhitelistOption)) {
+      options->whitelist = Substr(argv[i], strlen(kWhitelistOption));
     } else if (StartsWith(argv[i], kBlacklistOption)) {
       options->blacklist = Substr(argv[i], strlen(kBlacklistOption));
     } else if (StartsWith(argv[i], kDarkGreylistOption)) {
@@ -111,6 +117,8 @@
       options->precise = false;
     } else if (StartsWith(argv[i], kTargetSdkVersion)) {
       options->target_sdk_version = atoi(Substr(argv[i], strlen(kTargetSdkVersion)));
+    } else if (strcmp(argv[i], kOnlyReportSdkUses) == 0) {
+      options->only_report_sdk_uses = true;
     }
   }
 }
@@ -215,8 +223,17 @@
     std::vector<std::unique_ptr<VeridexResolver>> app_resolvers;
     Resolve(app_dex_files, resolver_map, type_map, &app_resolvers);
 
+    if (options.only_report_sdk_uses) {
+      // If we only need to report SDK uses, clear out any of the other lists so that
+      // the analysis don't report them.
+      options.blacklist = nullptr;
+      options.dark_greylist = nullptr;
+      options.light_greylist = nullptr;
+    }
+
     // Find and log uses of hidden APIs.
-    HiddenApi hidden_api(options.blacklist, options.dark_greylist, options.light_greylist);
+    HiddenApi hidden_api(
+        options.whitelist, options.blacklist, options.dark_greylist, options.light_greylist);
     HiddenApiStats stats;
 
     HiddenApiFinder api_finder(hidden_api);
@@ -229,7 +246,7 @@
       precise_api_finder.Dump(std::cout, &stats);
     }
 
-    DumpSummaryStats(std::cout, stats);
+    DumpSummaryStats(std::cout, stats, options);
 
     if (options.precise) {
       std::cout << "To run an analysis that can give more reflection accesses, " << std::endl
@@ -240,17 +257,23 @@
   }
 
  private:
-  static void DumpSummaryStats(std::ostream& os, const HiddenApiStats& stats) {
+  static void DumpSummaryStats(std::ostream& os,
+                               const HiddenApiStats& stats,
+                               const VeridexOptions& options) {
     static const char* kPrefix = "       ";
-    os << stats.count << " hidden API(s) used: "
-       << stats.linking_count << " linked against, "
-       << stats.reflection_count << " through reflection" << std::endl;
-    os << kPrefix << stats.api_counts[HiddenApiAccessFlags::kBlacklist]
-       << " in blacklist" << std::endl;
-    os << kPrefix << stats.api_counts[HiddenApiAccessFlags::kDarkGreylist]
-       << " in dark greylist" << std::endl;
-    os << kPrefix << stats.api_counts[HiddenApiAccessFlags::kLightGreylist]
-       << " in light greylist" << std::endl;
+    if (options.only_report_sdk_uses) {
+      os << stats.api_counts[HiddenApiAccessFlags::kWhitelist] << " SDK API uses." << std::endl;
+    } else {
+      os << stats.count << " hidden API(s) used: "
+         << stats.linking_count << " linked against, "
+         << stats.reflection_count << " through reflection" << std::endl;
+      os << kPrefix << stats.api_counts[HiddenApiAccessFlags::kBlacklist]
+         << " in blacklist" << std::endl;
+      os << kPrefix << stats.api_counts[HiddenApiAccessFlags::kDarkGreylist]
+         << " in dark greylist" << std::endl;
+      os << kPrefix << stats.api_counts[HiddenApiAccessFlags::kLightGreylist]
+         << " in light greylist" << std::endl;
+    }
   }
 
   static bool Load(const std::string& filename,