Add profman option to generate a random profile based on dex files.

Extends --generate-test-profile to make a randomized profile based on a
set of dex files. Will randomly incorporate classes and methods from all
the dex files given. Can be given a random seed for reproducibility.

Bug: 36107940
Test: mm test-art-host-gtest-profile_assistant_test
Change-Id: Ib0e54bde5317439516a39afa41c3c9980834fa54
diff --git a/profman/profman.cc b/profman/profman.cc
index dac95b8..5504695 100644
--- a/profman/profman.cc
+++ b/profman/profman.cc
@@ -117,6 +117,8 @@
   UsageError("      number of methods that should be generated. Defaults to 5.");
   UsageError("  --generate-test-profile-class-ratio=<number>: the percentage from the maximum");
   UsageError("      number of classes that should be generated. Defaults to 5.");
+  UsageError("  --generate-test-profile-seed=<number>: seed for random number generator used when");
+  UsageError("      generating random test profiles. Defaults to using NanoTime.");
   UsageError("");
   UsageError("  --create-profile-from=<filename>: creates a profile from a list of classes.");
   UsageError("");
@@ -156,6 +158,7 @@
       test_profile_num_dex_(kDefaultTestProfileNumDex),
       test_profile_method_ratio_(kDefaultTestProfileMethodRatio),
       test_profile_class_ratio_(kDefaultTestProfileClassRatio),
+      test_profile_seed_(NanoTime()),
       start_ns_(NanoTime()) {}
 
   ~ProfMan() {
@@ -221,6 +224,8 @@
                         "--generate-test-profile-class-ratio",
                         &test_profile_class_ratio_,
                         Usage);
+      } else if (option.starts_with("--generate-test-profile-seed=")) {
+        ParseUintOption(option, "--generate-test-profile-seed", &test_profile_seed_, Usage);
       } else {
         Usage("Unknown argument '%s'", option.data());
       }
@@ -798,17 +803,39 @@
     if (test_profile_class_ratio_ > 100) {
       Usage("Invalid ratio for --generate-test-profile-class-ratio");
     }
+    // If given APK files or DEX locations, check that they're ok.
+    if (!apk_files_.empty() || !apks_fd_.empty() || !dex_locations_.empty()) {
+      if (apk_files_.empty() && apks_fd_.empty()) {
+        Usage("APK files must be specified when passing DEX locations to --generate-test-profile");
+      }
+      if (dex_locations_.empty()) {
+        Usage("DEX locations must be specified when passing APK files to --generate-test-profile");
+      }
+    }
     // ShouldGenerateTestProfile confirms !test_profile_.empty().
     int profile_test_fd = open(test_profile_.c_str(), O_CREAT | O_TRUNC | O_WRONLY, 0644);
     if (profile_test_fd < 0) {
       LOG(ERROR) << "Cannot open " << test_profile_ << strerror(errno);
       return -1;
     }
-
-    bool result = ProfileCompilationInfo::GenerateTestProfile(profile_test_fd,
-                                                              test_profile_num_dex_,
-                                                              test_profile_method_ratio_,
-                                                              test_profile_class_ratio_);
+    bool result;
+    if (apk_files_.empty() && apks_fd_.empty() && dex_locations_.empty()) {
+      result = ProfileCompilationInfo::GenerateTestProfile(profile_test_fd,
+                                                           test_profile_num_dex_,
+                                                           test_profile_method_ratio_,
+                                                           test_profile_class_ratio_,
+                                                           test_profile_seed_);
+    } else {
+      // Initialize MemMap for ZipArchive::OpenFromFd.
+      MemMap::Init();
+      // Open the dex files to look up classes and methods.
+      std::vector<std::unique_ptr<const DexFile>> dex_files;
+      OpenApkFilesFromLocations(&dex_files);
+      // Create a random profile file based on the set of dex files.
+      result = ProfileCompilationInfo::GenerateTestProfile(profile_test_fd,
+                                                           dex_files,
+                                                           test_profile_seed_);
+    }
     close(profile_test_fd);  // ignore close result.
     return result ? 0 : -1;
   }
@@ -857,6 +884,7 @@
   uint16_t test_profile_num_dex_;
   uint16_t test_profile_method_ratio_;
   uint16_t test_profile_class_ratio_;
+  uint32_t test_profile_seed_;
   uint64_t start_ns_;
 };