Home | History | Annotate | Download | only in profman
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <errno.h>
     18 #include <stdio.h>
     19 #include <stdlib.h>
     20 #include <sys/file.h>
     21 #include <sys/param.h>
     22 #include <unistd.h>
     23 
     24 #include <fstream>
     25 #include <iostream>
     26 #include <set>
     27 #include <string>
     28 #include <string_view>
     29 #include <unordered_set>
     30 #include <vector>
     31 
     32 #include "android-base/stringprintf.h"
     33 #include "android-base/strings.h"
     34 
     35 #include "base/dumpable.h"
     36 #include "base/logging.h"  // For InitLogging.
     37 #include "base/mem_map.h"
     38 #include "base/scoped_flock.h"
     39 #include "base/stl_util.h"
     40 #include "base/string_view_cpp20.h"
     41 #include "base/time_utils.h"
     42 #include "base/unix_file/fd_file.h"
     43 #include "base/utils.h"
     44 #include "base/zip_archive.h"
     45 #include "boot_image_profile.h"
     46 #include "dex/art_dex_file_loader.h"
     47 #include "dex/bytecode_utils.h"
     48 #include "dex/class_accessor-inl.h"
     49 #include "dex/code_item_accessors-inl.h"
     50 #include "dex/dex_file.h"
     51 #include "dex/dex_file_loader.h"
     52 #include "dex/dex_file_types.h"
     53 #include "dex/type_reference.h"
     54 #include "profile/profile_compilation_info.h"
     55 #include "profile_assistant.h"
     56 
     57 namespace art {
     58 
     59 static int original_argc;
     60 static char** original_argv;
     61 
     62 static std::string CommandLine() {
     63   std::vector<std::string> command;
     64   command.reserve(original_argc);
     65   for (int i = 0; i < original_argc; ++i) {
     66     command.push_back(original_argv[i]);
     67   }
     68   return android::base::Join(command, ' ');
     69 }
     70 
     71 static constexpr int kInvalidFd = -1;
     72 
     73 static bool FdIsValid(int fd) {
     74   return fd != kInvalidFd;
     75 }
     76 
     77 static void UsageErrorV(const char* fmt, va_list ap) {
     78   std::string error;
     79   android::base::StringAppendV(&error, fmt, ap);
     80   LOG(ERROR) << error;
     81 }
     82 
     83 static void UsageError(const char* fmt, ...) {
     84   va_list ap;
     85   va_start(ap, fmt);
     86   UsageErrorV(fmt, ap);
     87   va_end(ap);
     88 }
     89 
     90 NO_RETURN static void Usage(const char *fmt, ...) {
     91   va_list ap;
     92   va_start(ap, fmt);
     93   UsageErrorV(fmt, ap);
     94   va_end(ap);
     95 
     96   UsageError("Command: %s", CommandLine().c_str());
     97   UsageError("Usage: profman [options]...");
     98   UsageError("");
     99   UsageError("  --dump-only: dumps the content of the specified profile files");
    100   UsageError("      to standard output (default) in a human readable form.");
    101   UsageError("");
    102   UsageError("  --dump-output-to-fd=<number>: redirects --dump-only output to a file descriptor.");
    103   UsageError("");
    104   UsageError("  --dump-classes-and-methods: dumps a sorted list of classes and methods that are");
    105   UsageError("      in the specified profile file to standard output (default) in a human");
    106   UsageError("      readable form. The output is valid input for --create-profile-from");
    107   UsageError("");
    108   UsageError("  --profile-file=<filename>: specify profiler output file to use for compilation.");
    109   UsageError("      Can be specified multiple time, in which case the data from the different");
    110   UsageError("      profiles will be aggregated.");
    111   UsageError("");
    112   UsageError("  --profile-file-fd=<number>: same as --profile-file but accepts a file descriptor.");
    113   UsageError("      Cannot be used together with --profile-file.");
    114   UsageError("");
    115   UsageError("  --reference-profile-file=<filename>: specify a reference profile.");
    116   UsageError("      The data in this file will be compared with the data obtained by merging");
    117   UsageError("      all the files specified with --profile-file or --profile-file-fd.");
    118   UsageError("      If the exit code is EXIT_COMPILE then all --profile-file will be merged into");
    119   UsageError("      --reference-profile-file. ");
    120   UsageError("");
    121   UsageError("  --reference-profile-file-fd=<number>: same as --reference-profile-file but");
    122   UsageError("      accepts a file descriptor. Cannot be used together with");
    123   UsageError("      --reference-profile-file.");
    124   UsageError("");
    125   UsageError("  --generate-test-profile=<filename>: generates a random profile file for testing.");
    126   UsageError("  --generate-test-profile-num-dex=<number>: number of dex files that should be");
    127   UsageError("      included in the generated profile. Defaults to 20.");
    128   UsageError("  --generate-test-profile-method-percentage=<number>: the percentage from the maximum");
    129   UsageError("      number of methods that should be generated. Defaults to 5.");
    130   UsageError("  --generate-test-profile-class-percentage=<number>: the percentage from the maximum");
    131   UsageError("      number of classes that should be generated. Defaults to 5.");
    132   UsageError("  --generate-test-profile-seed=<number>: seed for random number generator used when");
    133   UsageError("      generating random test profiles. Defaults to using NanoTime.");
    134   UsageError("");
    135   UsageError("  --create-profile-from=<filename>: creates a profile from a list of classes and");
    136   UsageError("      methods.");
    137   UsageError("");
    138   UsageError("  --dex-location=<string>: location string to use with corresponding");
    139   UsageError("      apk-fd to find dex files");
    140   UsageError("");
    141   UsageError("  --apk-fd=<number>: file descriptor containing an open APK to");
    142   UsageError("      search for dex files");
    143   UsageError("  --apk-=<filename>: an APK to search for dex files");
    144   UsageError("  --skip-apk-verification: do not attempt to verify APKs");
    145   UsageError("");
    146   UsageError("  --generate-boot-image-profile: Generate a boot image profile based on input");
    147   UsageError("      profiles. Requires passing in dex files to inspect properties of classes.");
    148   UsageError("  --boot-image-class-threshold=<value>: specify minimum number of class occurrences");
    149   UsageError("      to include a class in the boot image profile. Default is 10.");
    150   UsageError("  --boot-image-clean-class-threshold=<value>: specify minimum number of clean class");
    151   UsageError("      occurrences to include a class in the boot image profile. A clean class is a");
    152   UsageError("      class that doesn't have any static fields or native methods and is likely to");
    153   UsageError("      remain clean in the image. Default is 3.");
    154   UsageError("  --boot-image-sampled-method-threshold=<value>: minimum number of profiles a");
    155   UsageError("      non-hot method needs to be in order to be hot in the output profile. The");
    156   UsageError("      default is max int.");
    157   UsageError("  --copy-and-update-profile-key: if present, profman will copy the profile from");
    158   UsageError("      the file passed with --profile-fd(file) to the profile passed with");
    159   UsageError("      --reference-profile-fd(file) and update at the same time the profile-key");
    160   UsageError("      of entries corresponding to the apks passed with --apk(-fd).");
    161   UsageError("  --store-aggregation-counters: if present, profman will compute and store");
    162   UsageError("      the aggregation counters of classes and methods in the output profile.");
    163   UsageError("      In this case the profile will have a different version.");
    164   UsageError("");
    165 
    166   exit(EXIT_FAILURE);
    167 }
    168 
    169 // Note: make sure you update the Usage if you change these values.
    170 static constexpr uint16_t kDefaultTestProfileNumDex = 20;
    171 static constexpr uint16_t kDefaultTestProfileMethodPercentage = 5;
    172 static constexpr uint16_t kDefaultTestProfileClassPercentage = 5;
    173 
    174 // Separators used when parsing human friendly representation of profiles.
    175 static const std::string kMethodSep = "->";  // NOLINT [runtime/string] [4]
    176 static const std::string kMissingTypesMarker = "missing_types";  // NOLINT [runtime/string] [4]
    177 static const std::string kInvalidClassDescriptor = "invalid_class";  // NOLINT [runtime/string] [4]
    178 static const std::string kInvalidMethod = "invalid_method";  // NOLINT [runtime/string] [4]
    179 static const std::string kClassAllMethods = "*";  // NOLINT [runtime/string] [4]
    180 static constexpr char kProfileParsingInlineChacheSep = '+';
    181 static constexpr char kProfileParsingTypeSep = ',';
    182 static constexpr char kProfileParsingFirstCharInSignature = '(';
    183 static constexpr char kMethodFlagStringHot = 'H';
    184 static constexpr char kMethodFlagStringStartup = 'S';
    185 static constexpr char kMethodFlagStringPostStartup = 'P';
    186 
    187 NO_RETURN static void Abort(const char* msg) {
    188   LOG(ERROR) << msg;
    189   exit(1);
    190 }
    191 
    192 template <typename T>
    193 static void ParseUintOption(const char* raw_option,
    194                             std::string_view option_prefix,
    195                             T* out) {
    196   DCHECK(EndsWith(option_prefix, "="));
    197   DCHECK(StartsWith(raw_option, option_prefix)) << raw_option << " " << option_prefix;
    198   const char* value_string = raw_option + option_prefix.size();
    199   int64_t parsed_integer_value = 0;
    200   if (!android::base::ParseInt(value_string, &parsed_integer_value)) {
    201     std::string option_name(option_prefix.substr(option_prefix.size() - 1u));
    202     Usage("Failed to parse %s '%s' as an integer", option_name.c_str(), value_string);
    203   }
    204   if (parsed_integer_value < 0) {
    205     std::string option_name(option_prefix.substr(option_prefix.size() - 1u));
    206     Usage("%s passed a negative value %" PRId64, option_name.c_str(), parsed_integer_value);
    207   }
    208   if (static_cast<uint64_t>(parsed_integer_value) >
    209       static_cast<std::make_unsigned_t<T>>(std::numeric_limits<T>::max())) {
    210     std::string option_name(option_prefix.substr(option_prefix.size() - 1u));
    211     Usage("%s passed a value %" PRIu64 " above max (%" PRIu64 ")",
    212           option_name.c_str(),
    213           static_cast<uint64_t>(parsed_integer_value),
    214           static_cast<uint64_t>(std::numeric_limits<T>::max()));
    215   }
    216   *out = dchecked_integral_cast<T>(parsed_integer_value);
    217 }
    218 
    219 // TODO(calin): This class has grown too much from its initial design. Split the functionality
    220 // into smaller, more contained pieces.
    221 class ProfMan final {
    222  public:
    223   ProfMan() :
    224       reference_profile_file_fd_(kInvalidFd),
    225       dump_only_(false),
    226       dump_classes_and_methods_(false),
    227       generate_boot_image_profile_(false),
    228       dump_output_to_fd_(kInvalidFd),
    229       test_profile_num_dex_(kDefaultTestProfileNumDex),
    230       test_profile_method_percerntage_(kDefaultTestProfileMethodPercentage),
    231       test_profile_class_percentage_(kDefaultTestProfileClassPercentage),
    232       test_profile_seed_(NanoTime()),
    233       start_ns_(NanoTime()),
    234       copy_and_update_profile_key_(false),
    235       store_aggregation_counters_(false) {}
    236 
    237   ~ProfMan() {
    238     LogCompletionTime();
    239   }
    240 
    241   void ParseArgs(int argc, char **argv) {
    242     original_argc = argc;
    243     original_argv = argv;
    244 
    245     MemMap::Init();
    246     InitLogging(argv, Abort);
    247 
    248     // Skip over the command name.
    249     argv++;
    250     argc--;
    251 
    252     if (argc == 0) {
    253       Usage("No arguments specified");
    254     }
    255 
    256     for (int i = 0; i < argc; ++i) {
    257       const char* raw_option = argv[i];
    258       const std::string_view option(raw_option);
    259       const bool log_options = false;
    260       if (log_options) {
    261         LOG(INFO) << "profman: option[" << i << "]=" << argv[i];
    262       }
    263       if (option == "--dump-only") {
    264         dump_only_ = true;
    265       } else if (option == "--dump-classes-and-methods") {
    266         dump_classes_and_methods_ = true;
    267       } else if (StartsWith(option, "--create-profile-from=")) {
    268         create_profile_from_file_ = std::string(option.substr(strlen("--create-profile-from=")));
    269       } else if (StartsWith(option, "--dump-output-to-fd=")) {
    270         ParseUintOption(raw_option, "--dump-output-to-fd=", &dump_output_to_fd_);
    271       } else if (option == "--generate-boot-image-profile") {
    272         generate_boot_image_profile_ = true;
    273       } else if (StartsWith(option, "--boot-image-class-threshold=")) {
    274         ParseUintOption(raw_option,
    275                         "--boot-image-class-threshold=",
    276                         &boot_image_options_.image_class_theshold);
    277       } else if (StartsWith(option, "--boot-image-clean-class-threshold=")) {
    278         ParseUintOption(raw_option,
    279                         "--boot-image-clean-class-threshold=",
    280                         &boot_image_options_.image_class_clean_theshold);
    281       } else if (StartsWith(option, "--boot-image-sampled-method-threshold=")) {
    282         ParseUintOption(raw_option,
    283                         "--boot-image-sampled-method-threshold=",
    284                         &boot_image_options_.compiled_method_threshold);
    285       } else if (StartsWith(option, "--profile-file=")) {
    286         profile_files_.push_back(std::string(option.substr(strlen("--profile-file="))));
    287       } else if (StartsWith(option, "--profile-file-fd=")) {
    288         ParseFdForCollection(raw_option, "--profile-file-fd=", &profile_files_fd_);
    289       } else if (StartsWith(option, "--reference-profile-file=")) {
    290         reference_profile_file_ = std::string(option.substr(strlen("--reference-profile-file=")));
    291       } else if (StartsWith(option, "--reference-profile-file-fd=")) {
    292         ParseUintOption(raw_option, "--reference-profile-file-fd=", &reference_profile_file_fd_);
    293       } else if (StartsWith(option, "--dex-location=")) {
    294         dex_locations_.push_back(std::string(option.substr(strlen("--dex-location="))));
    295       } else if (StartsWith(option, "--apk-fd=")) {
    296         ParseFdForCollection(raw_option, "--apk-fd=", &apks_fd_);
    297       } else if (StartsWith(option, "--apk=")) {
    298         apk_files_.push_back(std::string(option.substr(strlen("--apk="))));
    299       } else if (StartsWith(option, "--generate-test-profile=")) {
    300         test_profile_ = std::string(option.substr(strlen("--generate-test-profile=")));
    301       } else if (StartsWith(option, "--generate-test-profile-num-dex=")) {
    302         ParseUintOption(raw_option,
    303                         "--generate-test-profile-num-dex=",
    304                         &test_profile_num_dex_);
    305       } else if (StartsWith(option, "--generate-test-profile-method-percentage=")) {
    306         ParseUintOption(raw_option,
    307                         "--generate-test-profile-method-percentage=",
    308                         &test_profile_method_percerntage_);
    309       } else if (StartsWith(option, "--generate-test-profile-class-percentage=")) {
    310         ParseUintOption(raw_option,
    311                         "--generate-test-profile-class-percentage=",
    312                         &test_profile_class_percentage_);
    313       } else if (StartsWith(option, "--generate-test-profile-seed=")) {
    314         ParseUintOption(raw_option, "--generate-test-profile-seed=", &test_profile_seed_);
    315       } else if (option == "--copy-and-update-profile-key") {
    316         copy_and_update_profile_key_ = true;
    317       } else if (option == "--store-aggregation-counters") {
    318         store_aggregation_counters_ = true;
    319       } else {
    320         Usage("Unknown argument '%s'", raw_option);
    321       }
    322     }
    323 
    324     // Validate global consistency between file/fd options.
    325     if (!profile_files_.empty() && !profile_files_fd_.empty()) {
    326       Usage("Profile files should not be specified with both --profile-file-fd and --profile-file");
    327     }
    328     if (!reference_profile_file_.empty() && FdIsValid(reference_profile_file_fd_)) {
    329       Usage("Reference profile should not be specified with both "
    330             "--reference-profile-file-fd and --reference-profile-file");
    331     }
    332     if (!apk_files_.empty() && !apks_fd_.empty()) {
    333       Usage("APK files should not be specified with both --apk-fd and --apk");
    334     }
    335   }
    336 
    337   struct ProfileFilterKey {
    338     ProfileFilterKey(const std::string& dex_location, uint32_t checksum)
    339         : dex_location_(dex_location), checksum_(checksum) {}
    340     const std::string dex_location_;
    341     uint32_t checksum_;
    342 
    343     bool operator==(const ProfileFilterKey& other) const {
    344       return checksum_ == other.checksum_ && dex_location_ == other.dex_location_;
    345     }
    346     bool operator<(const ProfileFilterKey& other) const {
    347       return checksum_ == other.checksum_
    348           ?  dex_location_ < other.dex_location_
    349           : checksum_ < other.checksum_;
    350     }
    351   };
    352 
    353   ProfileAssistant::ProcessingResult ProcessProfiles() {
    354     // Validate that at least one profile file was passed, as well as a reference profile.
    355     if (profile_files_.empty() && profile_files_fd_.empty()) {
    356       Usage("No profile files specified.");
    357     }
    358     if (reference_profile_file_.empty() && !FdIsValid(reference_profile_file_fd_)) {
    359       Usage("No reference profile file specified.");
    360     }
    361     if ((!profile_files_.empty() && FdIsValid(reference_profile_file_fd_)) ||
    362         (!profile_files_fd_.empty() && !FdIsValid(reference_profile_file_fd_))) {
    363       Usage("Options --profile-file-fd and --reference-profile-file-fd "
    364             "should only be used together");
    365     }
    366 
    367     // Check if we have any apks which we should use to filter the profile data.
    368     std::set<ProfileFilterKey> profile_filter_keys;
    369     if (!GetProfileFilterKeyFromApks(&profile_filter_keys)) {
    370       return ProfileAssistant::kErrorIO;
    371     }
    372 
    373     // Build the profile filter function. If the set of keys is empty it means we
    374     // don't have any apks; as such we do not filter anything.
    375     const ProfileCompilationInfo::ProfileLoadFilterFn& filter_fn =
    376         [profile_filter_keys](const std::string& dex_location, uint32_t checksum) {
    377             if (profile_filter_keys.empty()) {
    378               // No --apk was specified. Accept all dex files.
    379               return true;
    380             } else {
    381               bool res = profile_filter_keys.find(
    382                   ProfileFilterKey(dex_location, checksum)) != profile_filter_keys.end();
    383               return res;
    384             }
    385         };
    386 
    387     ProfileAssistant::ProcessingResult result;
    388 
    389     if (profile_files_.empty()) {
    390       // The file doesn't need to be flushed here (ProcessProfiles will do it)
    391       // so don't check the usage.
    392       File file(reference_profile_file_fd_, false);
    393       result = ProfileAssistant::ProcessProfiles(profile_files_fd_,
    394                                                  reference_profile_file_fd_,
    395                                                  filter_fn,
    396                                                  store_aggregation_counters_);
    397       CloseAllFds(profile_files_fd_, "profile_files_fd_");
    398     } else {
    399       result = ProfileAssistant::ProcessProfiles(profile_files_,
    400                                                  reference_profile_file_,
    401                                                  filter_fn,
    402                                                  store_aggregation_counters_);
    403     }
    404     return result;
    405   }
    406 
    407   bool GetProfileFilterKeyFromApks(std::set<ProfileFilterKey>* profile_filter_keys) {
    408     auto process_fn = [profile_filter_keys](std::unique_ptr<const DexFile>&& dex_file) {
    409       // Store the profile key of the location instead of the location itself.
    410       // This will make the matching in the profile filter method much easier.
    411       profile_filter_keys->emplace(ProfileCompilationInfo::GetProfileDexFileKey(
    412           dex_file->GetLocation()), dex_file->GetLocationChecksum());
    413     };
    414     return OpenApkFilesFromLocations(process_fn);
    415   }
    416 
    417   bool OpenApkFilesFromLocations(std::vector<std::unique_ptr<const DexFile>>* dex_files) {
    418     auto process_fn = [dex_files](std::unique_ptr<const DexFile>&& dex_file) {
    419       dex_files->emplace_back(std::move(dex_file));
    420     };
    421     return OpenApkFilesFromLocations(process_fn);
    422   }
    423 
    424   bool OpenApkFilesFromLocations(
    425       const std::function<void(std::unique_ptr<const DexFile>&&)>& process_fn) {
    426     bool use_apk_fd_list = !apks_fd_.empty();
    427     if (use_apk_fd_list) {
    428       // Get the APKs from the collection of FDs.
    429       if (dex_locations_.empty()) {
    430         // Try to compute the dex locations from the file paths of the descriptions.
    431         // This will make it easier to invoke profman with --apk-fd and without
    432         // being force to pass --dex-location when the location would be the apk path.
    433         if (!ComputeDexLocationsFromApkFds()) {
    434           return false;
    435         }
    436       } else {
    437         if (dex_locations_.size() != apks_fd_.size()) {
    438             Usage("The number of apk-fds must match the number of dex-locations.");
    439         }
    440       }
    441     } else if (!apk_files_.empty()) {
    442       if (dex_locations_.empty()) {
    443         // If no dex locations are specified use the apk names as locations.
    444         dex_locations_ = apk_files_;
    445       } else if (dex_locations_.size() != apk_files_.size()) {
    446           Usage("The number of apk-fds must match the number of dex-locations.");
    447       }
    448     } else {
    449       // No APKs were specified.
    450       CHECK(dex_locations_.empty());
    451       return true;
    452     }
    453     static constexpr bool kVerifyChecksum = true;
    454     for (size_t i = 0; i < dex_locations_.size(); ++i) {
    455       std::string error_msg;
    456       const ArtDexFileLoader dex_file_loader;
    457       std::vector<std::unique_ptr<const DexFile>> dex_files_for_location;
    458       // We do not need to verify the apk for processing profiles.
    459       if (use_apk_fd_list) {
    460         if (dex_file_loader.OpenZip(apks_fd_[i],
    461                                     dex_locations_[i],
    462                                     /* verify= */ false,
    463                                     kVerifyChecksum,
    464                                     &error_msg,
    465                                     &dex_files_for_location)) {
    466         } else {
    467           LOG(ERROR) << "OpenZip failed for '" << dex_locations_[i] << "' " << error_msg;
    468           return false;
    469         }
    470       } else {
    471         if (dex_file_loader.Open(apk_files_[i].c_str(),
    472                                  dex_locations_[i],
    473                                  /* verify= */ false,
    474                                  kVerifyChecksum,
    475                                  &error_msg,
    476                                  &dex_files_for_location)) {
    477         } else {
    478           LOG(ERROR) << "Open failed for '" << dex_locations_[i] << "' " << error_msg;
    479           return false;
    480         }
    481       }
    482       for (std::unique_ptr<const DexFile>& dex_file : dex_files_for_location) {
    483         process_fn(std::move(dex_file));
    484       }
    485     }
    486     return true;
    487   }
    488 
    489   // Get the dex locations from the apk fds.
    490   // The methods reads the links from /proc/self/fd/ to find the original apk paths
    491   // and puts them in the dex_locations_ vector.
    492   bool ComputeDexLocationsFromApkFds() {
    493 #ifdef _WIN32
    494     PLOG(ERROR) << "ComputeDexLocationsFromApkFds is unsupported on Windows.";
    495     return false;
    496 #else
    497     // We can't use a char array of PATH_MAX size without exceeding the frame size.
    498     // So we use a vector as the buffer for the path.
    499     std::vector<char> buffer(PATH_MAX, 0);
    500     for (size_t i = 0; i < apks_fd_.size(); ++i) {
    501       std::string fd_path = "/proc/self/fd/" + std::to_string(apks_fd_[i]);
    502       ssize_t len = readlink(fd_path.c_str(), buffer.data(), buffer.size() - 1);
    503       if (len == -1) {
    504         PLOG(ERROR) << "Could not open path from fd";
    505         return false;
    506       }
    507 
    508       buffer[len] = '\0';
    509       dex_locations_.push_back(buffer.data());
    510     }
    511     return true;
    512 #endif
    513   }
    514 
    515   std::unique_ptr<const ProfileCompilationInfo> LoadProfile(const std::string& filename, int fd) {
    516     if (!filename.empty()) {
    517 #ifdef _WIN32
    518       int flags = O_RDWR;
    519 #else
    520       int flags = O_RDWR | O_CLOEXEC;
    521 #endif
    522       fd = open(filename.c_str(), flags);
    523       if (fd < 0) {
    524         PLOG(ERROR) << "Cannot open " << filename;
    525         return nullptr;
    526       }
    527     }
    528     std::unique_ptr<ProfileCompilationInfo> info(new ProfileCompilationInfo);
    529     if (!info->Load(fd)) {
    530       LOG(ERROR) << "Cannot load profile info from fd=" << fd << "\n";
    531       return nullptr;
    532     }
    533     return info;
    534   }
    535 
    536   int DumpOneProfile(const std::string& banner,
    537                      const std::string& filename,
    538                      int fd,
    539                      const std::vector<std::unique_ptr<const DexFile>>* dex_files,
    540                      std::string* dump) {
    541     std::unique_ptr<const ProfileCompilationInfo> info(LoadProfile(filename, fd));
    542     if (info == nullptr) {
    543       LOG(ERROR) << "Cannot load profile info from filename=" << filename << " fd=" << fd;
    544       return -1;
    545     }
    546     *dump += banner + "\n" + info->DumpInfo(MakeNonOwningPointerVector(*dex_files)) + "\n";
    547     return 0;
    548   }
    549 
    550   int DumpProfileInfo() {
    551     // Validate that at least one profile file or reference was specified.
    552     if (profile_files_.empty() && profile_files_fd_.empty() &&
    553         reference_profile_file_.empty() && !FdIsValid(reference_profile_file_fd_)) {
    554       Usage("No profile files or reference profile specified.");
    555     }
    556     static const char* kEmptyString = "";
    557     static const char* kOrdinaryProfile = "=== profile ===";
    558     static const char* kReferenceProfile = "=== reference profile ===";
    559     static const char* kDexFiles = "=== Dex files  ===";
    560 
    561     std::vector<std::unique_ptr<const DexFile>> dex_files;
    562     OpenApkFilesFromLocations(&dex_files);
    563 
    564     std::string dump;
    565 
    566     // Dump checkfiles and corresponding checksums.
    567     dump += kDexFiles;
    568     dump += "\n";
    569     for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
    570       std::ostringstream oss;
    571       oss << dex_file->GetLocation()
    572           << " [checksum=" << std::hex << dex_file->GetLocationChecksum() << "]\n";
    573       dump += oss.str();
    574     }
    575 
    576     // Dump individual profile files.
    577     if (!profile_files_fd_.empty()) {
    578       for (int profile_file_fd : profile_files_fd_) {
    579         int ret = DumpOneProfile(kOrdinaryProfile,
    580                                  kEmptyString,
    581                                  profile_file_fd,
    582                                  &dex_files,
    583                                  &dump);
    584         if (ret != 0) {
    585           return ret;
    586         }
    587       }
    588     }
    589     for (const std::string& profile_file : profile_files_) {
    590       int ret = DumpOneProfile(kOrdinaryProfile, profile_file, kInvalidFd, &dex_files, &dump);
    591       if (ret != 0) {
    592         return ret;
    593       }
    594     }
    595     // Dump reference profile file.
    596     if (FdIsValid(reference_profile_file_fd_)) {
    597       int ret = DumpOneProfile(kReferenceProfile,
    598                                kEmptyString,
    599                                reference_profile_file_fd_,
    600                                &dex_files,
    601                                &dump);
    602       if (ret != 0) {
    603         return ret;
    604       }
    605     }
    606     if (!reference_profile_file_.empty()) {
    607       int ret = DumpOneProfile(kReferenceProfile,
    608                                reference_profile_file_,
    609                                kInvalidFd,
    610                                &dex_files,
    611                                &dump);
    612       if (ret != 0) {
    613         return ret;
    614       }
    615     }
    616     if (!FdIsValid(dump_output_to_fd_)) {
    617       std::cout << dump;
    618     } else {
    619       unix_file::FdFile out_fd(dump_output_to_fd_, /*check_usage=*/ false);
    620       if (!out_fd.WriteFully(dump.c_str(), dump.length())) {
    621         return -1;
    622       }
    623     }
    624     return 0;
    625   }
    626 
    627   bool ShouldOnlyDumpProfile() {
    628     return dump_only_;
    629   }
    630 
    631   bool GetClassNamesAndMethods(int fd,
    632                                std::vector<std::unique_ptr<const DexFile>>* dex_files,
    633                                std::set<std::string>* out_lines) {
    634     ProfileCompilationInfo profile_info;
    635     if (!profile_info.Load(fd)) {
    636       LOG(ERROR) << "Cannot load profile info";
    637       return false;
    638     }
    639     for (const std::unique_ptr<const DexFile>& dex_file : *dex_files) {
    640       std::set<dex::TypeIndex> class_types;
    641       std::set<uint16_t> hot_methods;
    642       std::set<uint16_t> startup_methods;
    643       std::set<uint16_t> post_startup_methods;
    644       std::set<uint16_t> combined_methods;
    645       if (profile_info.GetClassesAndMethods(*dex_file.get(),
    646                                             &class_types,
    647                                             &hot_methods,
    648                                             &startup_methods,
    649                                             &post_startup_methods)) {
    650         for (const dex::TypeIndex& type_index : class_types) {
    651           const dex::TypeId& type_id = dex_file->GetTypeId(type_index);
    652           out_lines->insert(std::string(dex_file->GetTypeDescriptor(type_id)));
    653         }
    654         combined_methods = hot_methods;
    655         combined_methods.insert(startup_methods.begin(), startup_methods.end());
    656         combined_methods.insert(post_startup_methods.begin(), post_startup_methods.end());
    657         for (uint16_t dex_method_idx : combined_methods) {
    658           const dex::MethodId& id = dex_file->GetMethodId(dex_method_idx);
    659           std::string signature_string(dex_file->GetMethodSignature(id).ToString());
    660           std::string type_string(dex_file->GetTypeDescriptor(dex_file->GetTypeId(id.class_idx_)));
    661           std::string method_name(dex_file->GetMethodName(id));
    662           std::string flags_string;
    663           if (hot_methods.find(dex_method_idx) != hot_methods.end()) {
    664             flags_string += kMethodFlagStringHot;
    665           }
    666           if (startup_methods.find(dex_method_idx) != startup_methods.end()) {
    667             flags_string += kMethodFlagStringStartup;
    668           }
    669           if (post_startup_methods.find(dex_method_idx) != post_startup_methods.end()) {
    670             flags_string += kMethodFlagStringPostStartup;
    671           }
    672           out_lines->insert(flags_string +
    673                             type_string +
    674                             kMethodSep +
    675                             method_name +
    676                             signature_string);
    677         }
    678       }
    679     }
    680     return true;
    681   }
    682 
    683   bool GetClassNamesAndMethods(const std::string& profile_file,
    684                                std::vector<std::unique_ptr<const DexFile>>* dex_files,
    685                                std::set<std::string>* out_lines) {
    686 #ifdef _WIN32
    687     int flags = O_RDONLY;
    688 #else
    689     int flags = O_RDONLY | O_CLOEXEC;
    690 #endif
    691     int fd = open(profile_file.c_str(), flags);
    692     if (!FdIsValid(fd)) {
    693       PLOG(ERROR) << "Cannot open " << profile_file;
    694       return false;
    695     }
    696     if (!GetClassNamesAndMethods(fd, dex_files, out_lines)) {
    697       return false;
    698     }
    699     if (close(fd) < 0) {
    700       PLOG(WARNING) << "Failed to close descriptor";
    701     }
    702     return true;
    703   }
    704 
    705   int DumpClassesAndMethods() {
    706     // Validate that at least one profile file or reference was specified.
    707     if (profile_files_.empty() && profile_files_fd_.empty() &&
    708         reference_profile_file_.empty() && !FdIsValid(reference_profile_file_fd_)) {
    709       Usage("No profile files or reference profile specified.");
    710     }
    711 
    712     // Open the dex files to get the names for classes.
    713     std::vector<std::unique_ptr<const DexFile>> dex_files;
    714     OpenApkFilesFromLocations(&dex_files);
    715     // Build a vector of class names from individual profile files.
    716     std::set<std::string> class_names;
    717     if (!profile_files_fd_.empty()) {
    718       for (int profile_file_fd : profile_files_fd_) {
    719         if (!GetClassNamesAndMethods(profile_file_fd, &dex_files, &class_names)) {
    720           return -1;
    721         }
    722       }
    723     }
    724     if (!profile_files_.empty()) {
    725       for (const std::string& profile_file : profile_files_) {
    726         if (!GetClassNamesAndMethods(profile_file, &dex_files, &class_names)) {
    727           return -1;
    728         }
    729       }
    730     }
    731     // Concatenate class names from reference profile file.
    732     if (FdIsValid(reference_profile_file_fd_)) {
    733       if (!GetClassNamesAndMethods(reference_profile_file_fd_, &dex_files, &class_names)) {
    734         return -1;
    735       }
    736     }
    737     if (!reference_profile_file_.empty()) {
    738       if (!GetClassNamesAndMethods(reference_profile_file_, &dex_files, &class_names)) {
    739         return -1;
    740       }
    741     }
    742     // Dump the class names.
    743     std::string dump;
    744     for (const std::string& class_name : class_names) {
    745       dump += class_name + std::string("\n");
    746     }
    747     if (!FdIsValid(dump_output_to_fd_)) {
    748       std::cout << dump;
    749     } else {
    750       unix_file::FdFile out_fd(dump_output_to_fd_, /*check_usage=*/ false);
    751       if (!out_fd.WriteFully(dump.c_str(), dump.length())) {
    752         return -1;
    753       }
    754     }
    755     return 0;
    756   }
    757 
    758   bool ShouldOnlyDumpClassesAndMethods() {
    759     return dump_classes_and_methods_;
    760   }
    761 
    762   // Read lines from the given file, dropping comments and empty lines. Post-process each line with
    763   // the given function.
    764   template <typename T>
    765   static T* ReadCommentedInputFromFile(
    766       const char* input_filename, std::function<std::string(const char*)>* process) {
    767     std::unique_ptr<std::ifstream> input_file(new std::ifstream(input_filename, std::ifstream::in));
    768     if (input_file.get() == nullptr) {
    769       LOG(ERROR) << "Failed to open input file " << input_filename;
    770       return nullptr;
    771     }
    772     std::unique_ptr<T> result(
    773         ReadCommentedInputStream<T>(*input_file, process));
    774     input_file->close();
    775     return result.release();
    776   }
    777 
    778   // Read lines from the given stream, dropping comments and empty lines. Post-process each line
    779   // with the given function.
    780   template <typename T>
    781   static T* ReadCommentedInputStream(
    782       std::istream& in_stream,
    783       std::function<std::string(const char*)>* process) {
    784     std::unique_ptr<T> output(new T());
    785     while (in_stream.good()) {
    786       std::string dot;
    787       std::getline(in_stream, dot);
    788       if (android::base::StartsWith(dot, "#") || dot.empty()) {
    789         continue;
    790       }
    791       if (process != nullptr) {
    792         std::string descriptor((*process)(dot.c_str()));
    793         output->insert(output->end(), descriptor);
    794       } else {
    795         output->insert(output->end(), dot);
    796       }
    797     }
    798     return output.release();
    799   }
    800 
    801   // Find class klass_descriptor in the given dex_files and store its reference
    802   // in the out parameter class_ref.
    803   // Return true if the definition of the class was found in any of the dex_files.
    804   bool FindClass(const std::vector<std::unique_ptr<const DexFile>>& dex_files,
    805                  const std::string& klass_descriptor,
    806                  /*out*/TypeReference* class_ref) {
    807     constexpr uint16_t kInvalidTypeIndex = std::numeric_limits<uint16_t>::max() - 1;
    808     for (const std::unique_ptr<const DexFile>& dex_file_ptr : dex_files) {
    809       const DexFile* dex_file = dex_file_ptr.get();
    810       if (klass_descriptor == kInvalidClassDescriptor) {
    811         if (kInvalidTypeIndex >= dex_file->NumTypeIds()) {
    812           // The dex file does not contain all possible type ids which leaves us room
    813           // to add an "invalid" type id.
    814           *class_ref = TypeReference(dex_file, dex::TypeIndex(kInvalidTypeIndex));
    815           return true;
    816         } else {
    817           // The dex file contains all possible type ids. We don't have any free type id
    818           // that we can use as invalid.
    819           continue;
    820         }
    821       }
    822 
    823       const dex::TypeId* type_id = dex_file->FindTypeId(klass_descriptor.c_str());
    824       if (type_id == nullptr) {
    825         continue;
    826       }
    827       dex::TypeIndex type_index = dex_file->GetIndexForTypeId(*type_id);
    828       if (dex_file->FindClassDef(type_index) == nullptr) {
    829         // Class is only referenced in the current dex file but not defined in it.
    830         continue;
    831       }
    832       *class_ref = TypeReference(dex_file, type_index);
    833       return true;
    834     }
    835     return false;
    836   }
    837 
    838   // Find the method specified by method_spec in the class class_ref.
    839   uint32_t FindMethodIndex(const TypeReference& class_ref,
    840                            const std::string& method_spec) {
    841     const DexFile* dex_file = class_ref.dex_file;
    842     if (method_spec == kInvalidMethod) {
    843       constexpr uint16_t kInvalidMethodIndex = std::numeric_limits<uint16_t>::max() - 1;
    844       return kInvalidMethodIndex >= dex_file->NumMethodIds()
    845              ? kInvalidMethodIndex
    846              : dex::kDexNoIndex;
    847     }
    848 
    849     std::vector<std::string> name_and_signature;
    850     Split(method_spec, kProfileParsingFirstCharInSignature, &name_and_signature);
    851     if (name_and_signature.size() != 2) {
    852       LOG(ERROR) << "Invalid method name and signature " << method_spec;
    853       return dex::kDexNoIndex;
    854     }
    855 
    856     const std::string& name = name_and_signature[0];
    857     const std::string& signature = kProfileParsingFirstCharInSignature + name_and_signature[1];
    858 
    859     const dex::StringId* name_id = dex_file->FindStringId(name.c_str());
    860     if (name_id == nullptr) {
    861       LOG(WARNING) << "Could not find name: "  << name;
    862       return dex::kDexNoIndex;
    863     }
    864     dex::TypeIndex return_type_idx;
    865     std::vector<dex::TypeIndex> param_type_idxs;
    866     if (!dex_file->CreateTypeList(signature, &return_type_idx, &param_type_idxs)) {
    867       LOG(WARNING) << "Could not create type list" << signature;
    868       return dex::kDexNoIndex;
    869     }
    870     const dex::ProtoId* proto_id = dex_file->FindProtoId(return_type_idx, param_type_idxs);
    871     if (proto_id == nullptr) {
    872       LOG(WARNING) << "Could not find proto_id: " << name;
    873       return dex::kDexNoIndex;
    874     }
    875     const dex::MethodId* method_id = dex_file->FindMethodId(
    876         dex_file->GetTypeId(class_ref.TypeIndex()), *name_id, *proto_id);
    877     if (method_id == nullptr) {
    878       LOG(WARNING) << "Could not find method_id: " << name;
    879       return dex::kDexNoIndex;
    880     }
    881 
    882     return dex_file->GetIndexForMethodId(*method_id);
    883   }
    884 
    885   // Given a method, return true if the method has a single INVOKE_VIRTUAL in its byte code.
    886   // Upon success it returns true and stores the method index and the invoke dex pc
    887   // in the output parameters.
    888   // The format of the method spec is "inlinePolymorphic(LSuper;)I+LSubA;,LSubB;,LSubC;".
    889   //
    890   // TODO(calin): support INVOKE_INTERFACE and the range variants.
    891   bool HasSingleInvoke(const TypeReference& class_ref,
    892                        uint16_t method_index,
    893                        /*out*/uint32_t* dex_pc) {
    894     const DexFile* dex_file = class_ref.dex_file;
    895     uint32_t offset = dex_file->FindCodeItemOffset(
    896         *dex_file->FindClassDef(class_ref.TypeIndex()),
    897         method_index);
    898     const dex::CodeItem* code_item = dex_file->GetCodeItem(offset);
    899 
    900     bool found_invoke = false;
    901     for (const DexInstructionPcPair& inst : CodeItemInstructionAccessor(*dex_file, code_item)) {
    902       if (inst->Opcode() == Instruction::INVOKE_VIRTUAL ||
    903           inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE) {
    904         if (found_invoke) {
    905           LOG(ERROR) << "Multiple invoke INVOKE_VIRTUAL found: "
    906                      << dex_file->PrettyMethod(method_index);
    907           return false;
    908         }
    909         found_invoke = true;
    910         *dex_pc = inst.DexPc();
    911       }
    912     }
    913     if (!found_invoke) {
    914       LOG(ERROR) << "Could not find any INVOKE_VIRTUAL: " << dex_file->PrettyMethod(method_index);
    915     }
    916     return found_invoke;
    917   }
    918 
    919   // Process a line defining a class or a method and its inline caches.
    920   // Upon success return true and add the class or the method info to profile.
    921   // The possible line formats are:
    922   // "LJustTheCass;".
    923   // "LTestInline;->inlinePolymorphic(LSuper;)I+LSubA;,LSubB;,LSubC;".
    924   // "LTestInline;->inlinePolymorphic(LSuper;)I+LSubA;,LSubB;,invalid_class".
    925   // "LTestInline;->inlineMissingTypes(LSuper;)I+missing_types".
    926   // "LTestInline;->inlineNoInlineCaches(LSuper;)I".
    927   // "LTestInline;->*".
    928   // "invalid_class".
    929   // "LTestInline;->invalid_method".
    930   // The method and classes are searched only in the given dex files.
    931   bool ProcessLine(const std::vector<std::unique_ptr<const DexFile>>& dex_files,
    932                    const std::string& line,
    933                    /*out*/ProfileCompilationInfo* profile) {
    934     std::string klass;
    935     std::string method_str;
    936     bool is_hot = false;
    937     bool is_startup = false;
    938     bool is_post_startup = false;
    939     const size_t method_sep_index = line.find(kMethodSep, 0);
    940     if (method_sep_index == std::string::npos) {
    941       klass = line.substr(0);
    942     } else {
    943       // The method prefix flags are only valid for method strings.
    944       size_t start_index = 0;
    945       while (start_index < line.size() && line[start_index] != 'L') {
    946         const char c = line[start_index];
    947         if (c == kMethodFlagStringHot) {
    948           is_hot = true;
    949         } else if (c == kMethodFlagStringStartup) {
    950           is_startup = true;
    951         } else if (c == kMethodFlagStringPostStartup) {
    952           is_post_startup = true;
    953         } else {
    954           LOG(WARNING) << "Invalid flag " << c;
    955           return false;
    956         }
    957         ++start_index;
    958       }
    959       klass = line.substr(start_index, method_sep_index - start_index);
    960       method_str = line.substr(method_sep_index + kMethodSep.size());
    961     }
    962 
    963     uint32_t flags = 0;
    964     if (is_hot) {
    965       flags |= ProfileCompilationInfo::MethodHotness::kFlagHot;
    966     }
    967     if (is_startup) {
    968       flags |= ProfileCompilationInfo::MethodHotness::kFlagStartup;
    969     }
    970     if (is_post_startup) {
    971       flags |= ProfileCompilationInfo::MethodHotness::kFlagPostStartup;
    972     }
    973 
    974     TypeReference class_ref(/* dex_file= */ nullptr, dex::TypeIndex());
    975     if (!FindClass(dex_files, klass, &class_ref)) {
    976       LOG(WARNING) << "Could not find class: " << klass;
    977       return false;
    978     }
    979 
    980     if (method_str.empty() || method_str == kClassAllMethods) {
    981       // Start by adding the class.
    982       std::set<DexCacheResolvedClasses> resolved_class_set;
    983       const DexFile* dex_file = class_ref.dex_file;
    984       const auto& dex_resolved_classes = resolved_class_set.emplace(
    985             dex_file->GetLocation(),
    986             DexFileLoader::GetBaseLocation(dex_file->GetLocation()),
    987             dex_file->GetLocationChecksum(),
    988             dex_file->NumMethodIds());
    989       dex_resolved_classes.first->AddClass(class_ref.TypeIndex());
    990       std::vector<ProfileMethodInfo> methods;
    991       if (method_str == kClassAllMethods) {
    992         ClassAccessor accessor(
    993             *dex_file,
    994             dex_file->GetIndexForClassDef(*dex_file->FindClassDef(class_ref.TypeIndex())));
    995         for (const ClassAccessor::Method& method : accessor.GetMethods()) {
    996           if (method.GetCodeItemOffset() != 0) {
    997             // Add all of the methods that have code to the profile.
    998             methods.push_back(ProfileMethodInfo(method.GetReference()));
    999           }
   1000         }
   1001       }
   1002       // TODO: Check return values?
   1003       profile->AddMethods(methods, static_cast<ProfileCompilationInfo::MethodHotness::Flag>(flags));
   1004       profile->AddClasses(resolved_class_set);
   1005       return true;
   1006     }
   1007 
   1008     // Process the method.
   1009     std::string method_spec;
   1010     std::vector<std::string> inline_cache_elems;
   1011 
   1012     // If none of the flags are set, default to hot.
   1013     is_hot = is_hot || (!is_hot && !is_startup && !is_post_startup);
   1014 
   1015     std::vector<std::string> method_elems;
   1016     bool is_missing_types = false;
   1017     Split(method_str, kProfileParsingInlineChacheSep, &method_elems);
   1018     if (method_elems.size() == 2) {
   1019       method_spec = method_elems[0];
   1020       is_missing_types = method_elems[1] == kMissingTypesMarker;
   1021       if (!is_missing_types) {
   1022         Split(method_elems[1], kProfileParsingTypeSep, &inline_cache_elems);
   1023       }
   1024     } else if (method_elems.size() == 1) {
   1025       method_spec = method_elems[0];
   1026     } else {
   1027       LOG(ERROR) << "Invalid method line: " << line;
   1028       return false;
   1029     }
   1030 
   1031     const uint32_t method_index = FindMethodIndex(class_ref, method_spec);
   1032     if (method_index == dex::kDexNoIndex) {
   1033       return false;
   1034     }
   1035 
   1036     std::vector<ProfileMethodInfo::ProfileInlineCache> inline_caches;
   1037     if (is_missing_types || !inline_cache_elems.empty()) {
   1038       uint32_t dex_pc;
   1039       if (!HasSingleInvoke(class_ref, method_index, &dex_pc)) {
   1040         return false;
   1041       }
   1042       std::vector<TypeReference> classes(inline_cache_elems.size(),
   1043                                          TypeReference(/* dex_file= */ nullptr, dex::TypeIndex()));
   1044       size_t class_it = 0;
   1045       for (const std::string& ic_class : inline_cache_elems) {
   1046         if (!FindClass(dex_files, ic_class, &(classes[class_it++]))) {
   1047           LOG(ERROR) << "Could not find class: " << ic_class;
   1048           return false;
   1049         }
   1050       }
   1051       inline_caches.emplace_back(dex_pc, is_missing_types, classes);
   1052     }
   1053     MethodReference ref(class_ref.dex_file, method_index);
   1054     if (is_hot) {
   1055       profile->AddMethod(ProfileMethodInfo(ref, inline_caches),
   1056           static_cast<ProfileCompilationInfo::MethodHotness::Flag>(flags));
   1057     }
   1058     if (flags != 0) {
   1059       if (!profile->AddMethodIndex(
   1060           static_cast<ProfileCompilationInfo::MethodHotness::Flag>(flags), ref)) {
   1061         return false;
   1062       }
   1063       DCHECK(profile->GetMethodHotness(ref).IsInProfile());
   1064     }
   1065     return true;
   1066   }
   1067 
   1068   int OpenReferenceProfile() const {
   1069     int fd = reference_profile_file_fd_;
   1070     if (!FdIsValid(fd)) {
   1071       CHECK(!reference_profile_file_.empty());
   1072 #ifdef _WIN32
   1073       int flags = O_CREAT | O_TRUNC | O_WRONLY;
   1074 #else
   1075       int flags = O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC;
   1076 #endif
   1077       fd = open(reference_profile_file_.c_str(), flags, 0644);
   1078       if (fd < 0) {
   1079         PLOG(ERROR) << "Cannot open " << reference_profile_file_;
   1080         return kInvalidFd;
   1081       }
   1082     }
   1083     return fd;
   1084   }
   1085 
   1086   // Creates a profile from a human friendly textual representation.
   1087   // The expected input format is:
   1088   //   # Classes
   1089   //   Ljava/lang/Comparable;
   1090   //   Ljava/lang/Math;
   1091   //   # Methods with inline caches
   1092   //   LTestInline;->inlinePolymorphic(LSuper;)I+LSubA;,LSubB;,LSubC;
   1093   //   LTestInline;->noInlineCache(LSuper;)I
   1094   int CreateProfile() {
   1095     // Validate parameters for this command.
   1096     if (apk_files_.empty() && apks_fd_.empty()) {
   1097       Usage("APK files must be specified");
   1098     }
   1099     if (dex_locations_.empty()) {
   1100       Usage("DEX locations must be specified");
   1101     }
   1102     if (reference_profile_file_.empty() && !FdIsValid(reference_profile_file_fd_)) {
   1103       Usage("Reference profile must be specified with --reference-profile-file or "
   1104             "--reference-profile-file-fd");
   1105     }
   1106     if (!profile_files_.empty() || !profile_files_fd_.empty()) {
   1107       Usage("Profile must be specified with --reference-profile-file or "
   1108             "--reference-profile-file-fd");
   1109     }
   1110     // Open the profile output file if needed.
   1111     int fd = OpenReferenceProfile();
   1112     if (!FdIsValid(fd)) {
   1113         return -1;
   1114     }
   1115     // Read the user-specified list of classes and methods.
   1116     std::unique_ptr<std::unordered_set<std::string>>
   1117         user_lines(ReadCommentedInputFromFile<std::unordered_set<std::string>>(
   1118             create_profile_from_file_.c_str(), nullptr));  // No post-processing.
   1119 
   1120     // Open the dex files to look up classes and methods.
   1121     std::vector<std::unique_ptr<const DexFile>> dex_files;
   1122     OpenApkFilesFromLocations(&dex_files);
   1123 
   1124     // Process the lines one by one and add the successful ones to the profile.
   1125     ProfileCompilationInfo info;
   1126 
   1127     for (const auto& line : *user_lines) {
   1128       ProcessLine(dex_files, line, &info);
   1129     }
   1130 
   1131     // Write the profile file.
   1132     CHECK(info.Save(fd));
   1133     if (close(fd) < 0) {
   1134       PLOG(WARNING) << "Failed to close descriptor";
   1135     }
   1136     return 0;
   1137   }
   1138 
   1139   bool ShouldCreateBootProfile() const {
   1140     return generate_boot_image_profile_;
   1141   }
   1142 
   1143   int CreateBootProfile() {
   1144     // Open the profile output file.
   1145     const int reference_fd = OpenReferenceProfile();
   1146     if (!FdIsValid(reference_fd)) {
   1147       PLOG(ERROR) << "Error opening reference profile";
   1148       return -1;
   1149     }
   1150     // Open the dex files.
   1151     std::vector<std::unique_ptr<const DexFile>> dex_files;
   1152     OpenApkFilesFromLocations(&dex_files);
   1153     if (dex_files.empty()) {
   1154       PLOG(ERROR) << "Expected dex files for creating boot profile";
   1155       return -2;
   1156     }
   1157     // Open the input profiles.
   1158     std::vector<std::unique_ptr<const ProfileCompilationInfo>> profiles;
   1159     if (!profile_files_fd_.empty()) {
   1160       for (int profile_file_fd : profile_files_fd_) {
   1161         std::unique_ptr<const ProfileCompilationInfo> profile(LoadProfile("", profile_file_fd));
   1162         if (profile == nullptr) {
   1163           return -3;
   1164         }
   1165         profiles.emplace_back(std::move(profile));
   1166       }
   1167     }
   1168     if (!profile_files_.empty()) {
   1169       for (const std::string& profile_file : profile_files_) {
   1170         std::unique_ptr<const ProfileCompilationInfo> profile(LoadProfile(profile_file, kInvalidFd));
   1171         if (profile == nullptr) {
   1172           return -4;
   1173         }
   1174         profiles.emplace_back(std::move(profile));
   1175       }
   1176     }
   1177     ProfileCompilationInfo out_profile;
   1178     GenerateBootImageProfile(dex_files,
   1179                              profiles,
   1180                              boot_image_options_,
   1181                              VLOG_IS_ON(profiler),
   1182                              &out_profile);
   1183     out_profile.Save(reference_fd);
   1184     close(reference_fd);
   1185     return 0;
   1186   }
   1187 
   1188   bool ShouldCreateProfile() {
   1189     return !create_profile_from_file_.empty();
   1190   }
   1191 
   1192   int GenerateTestProfile() {
   1193     // Validate parameters for this command.
   1194     if (test_profile_method_percerntage_ > 100) {
   1195       Usage("Invalid percentage for --generate-test-profile-method-percentage");
   1196     }
   1197     if (test_profile_class_percentage_ > 100) {
   1198       Usage("Invalid percentage for --generate-test-profile-class-percentage");
   1199     }
   1200     // If given APK files or DEX locations, check that they're ok.
   1201     if (!apk_files_.empty() || !apks_fd_.empty() || !dex_locations_.empty()) {
   1202       if (apk_files_.empty() && apks_fd_.empty()) {
   1203         Usage("APK files must be specified when passing DEX locations to --generate-test-profile");
   1204       }
   1205       if (dex_locations_.empty()) {
   1206         Usage("DEX locations must be specified when passing APK files to --generate-test-profile");
   1207       }
   1208     }
   1209     // ShouldGenerateTestProfile confirms !test_profile_.empty().
   1210 #ifdef _WIN32
   1211     int flags = O_CREAT | O_TRUNC | O_WRONLY;
   1212 #else
   1213     int flags = O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC;
   1214 #endif
   1215     int profile_test_fd = open(test_profile_.c_str(), flags, 0644);
   1216     if (profile_test_fd < 0) {
   1217       PLOG(ERROR) << "Cannot open " << test_profile_;
   1218       return -1;
   1219     }
   1220     bool result;
   1221     if (apk_files_.empty() && apks_fd_.empty() && dex_locations_.empty()) {
   1222       result = ProfileCompilationInfo::GenerateTestProfile(profile_test_fd,
   1223                                                            test_profile_num_dex_,
   1224                                                            test_profile_method_percerntage_,
   1225                                                            test_profile_class_percentage_,
   1226                                                            test_profile_seed_);
   1227     } else {
   1228       // Open the dex files to look up classes and methods.
   1229       std::vector<std::unique_ptr<const DexFile>> dex_files;
   1230       OpenApkFilesFromLocations(&dex_files);
   1231       // Create a random profile file based on the set of dex files.
   1232       result = ProfileCompilationInfo::GenerateTestProfile(profile_test_fd,
   1233                                                            dex_files,
   1234                                                            test_profile_method_percerntage_,
   1235                                                            test_profile_class_percentage_,
   1236                                                            test_profile_seed_);
   1237     }
   1238     close(profile_test_fd);  // ignore close result.
   1239     return result ? 0 : -1;
   1240   }
   1241 
   1242   bool ShouldGenerateTestProfile() {
   1243     return !test_profile_.empty();
   1244   }
   1245 
   1246   bool ShouldCopyAndUpdateProfileKey() const {
   1247     return copy_and_update_profile_key_;
   1248   }
   1249 
   1250   int32_t CopyAndUpdateProfileKey() {
   1251     // Validate that at least one profile file was passed, as well as a reference profile.
   1252     if (!(profile_files_.size() == 1 ^ profile_files_fd_.size() == 1)) {
   1253       Usage("Only one profile file should be specified.");
   1254     }
   1255     if (reference_profile_file_.empty() && !FdIsValid(reference_profile_file_fd_)) {
   1256       Usage("No reference profile file specified.");
   1257     }
   1258 
   1259     if (apk_files_.empty() && apks_fd_.empty()) {
   1260       Usage("No apk files specified");
   1261     }
   1262 
   1263     static constexpr int32_t kErrorFailedToUpdateProfile = -1;
   1264     static constexpr int32_t kErrorFailedToSaveProfile = -2;
   1265     static constexpr int32_t kErrorFailedToLoadProfile = -3;
   1266 
   1267     bool use_fds = profile_files_fd_.size() == 1;
   1268 
   1269     ProfileCompilationInfo profile;
   1270     // Do not clear if invalid. The input might be an archive.
   1271     bool load_ok = use_fds
   1272         ? profile.Load(profile_files_fd_[0])
   1273         : profile.Load(profile_files_[0], /*clear_if_invalid=*/ false);
   1274     if (load_ok) {
   1275       // Open the dex files to look up classes and methods.
   1276       std::vector<std::unique_ptr<const DexFile>> dex_files;
   1277       OpenApkFilesFromLocations(&dex_files);
   1278       if (!profile.UpdateProfileKeys(dex_files)) {
   1279         return kErrorFailedToUpdateProfile;
   1280       }
   1281       bool result = use_fds
   1282           ? profile.Save(reference_profile_file_fd_)
   1283           : profile.Save(reference_profile_file_, /*bytes_written=*/ nullptr);
   1284       return result ? 0 : kErrorFailedToSaveProfile;
   1285     } else {
   1286       return kErrorFailedToLoadProfile;
   1287     }
   1288   }
   1289 
   1290  private:
   1291   static void ParseFdForCollection(const char* raw_option,
   1292                                    std::string_view option_prefix,
   1293                                    std::vector<int>* fds) {
   1294     int fd;
   1295     ParseUintOption(raw_option, option_prefix, &fd);
   1296     fds->push_back(fd);
   1297   }
   1298 
   1299   static void CloseAllFds(const std::vector<int>& fds, const char* descriptor) {
   1300     for (size_t i = 0; i < fds.size(); i++) {
   1301       if (close(fds[i]) < 0) {
   1302         PLOG(WARNING) << "Failed to close descriptor for "
   1303             << descriptor << " at index " << i << ": " << fds[i];
   1304       }
   1305     }
   1306   }
   1307 
   1308   void LogCompletionTime() {
   1309     static constexpr uint64_t kLogThresholdTime = MsToNs(100);  // 100ms
   1310     uint64_t time_taken = NanoTime() - start_ns_;
   1311     if (time_taken > kLogThresholdTime) {
   1312       LOG(WARNING) << "profman took " << PrettyDuration(time_taken);
   1313     }
   1314   }
   1315 
   1316   std::vector<std::string> profile_files_;
   1317   std::vector<int> profile_files_fd_;
   1318   std::vector<std::string> dex_locations_;
   1319   std::vector<std::string> apk_files_;
   1320   std::vector<int> apks_fd_;
   1321   std::string reference_profile_file_;
   1322   int reference_profile_file_fd_;
   1323   bool dump_only_;
   1324   bool dump_classes_and_methods_;
   1325   bool generate_boot_image_profile_;
   1326   int dump_output_to_fd_;
   1327   BootImageOptions boot_image_options_;
   1328   std::string test_profile_;
   1329   std::string create_profile_from_file_;
   1330   uint16_t test_profile_num_dex_;
   1331   uint16_t test_profile_method_percerntage_;
   1332   uint16_t test_profile_class_percentage_;
   1333   uint32_t test_profile_seed_;
   1334   uint64_t start_ns_;
   1335   bool copy_and_update_profile_key_;
   1336   bool store_aggregation_counters_;
   1337 };
   1338 
   1339 // See ProfileAssistant::ProcessingResult for return codes.
   1340 static int profman(int argc, char** argv) {
   1341   ProfMan profman;
   1342 
   1343   // Parse arguments. Argument mistakes will lead to exit(EXIT_FAILURE) in UsageError.
   1344   profman.ParseArgs(argc, argv);
   1345 
   1346   // Initialize MemMap for ZipArchive::OpenFromFd.
   1347   MemMap::Init();
   1348 
   1349   if (profman.ShouldGenerateTestProfile()) {
   1350     return profman.GenerateTestProfile();
   1351   }
   1352   if (profman.ShouldOnlyDumpProfile()) {
   1353     return profman.DumpProfileInfo();
   1354   }
   1355   if (profman.ShouldOnlyDumpClassesAndMethods()) {
   1356     return profman.DumpClassesAndMethods();
   1357   }
   1358   if (profman.ShouldCreateProfile()) {
   1359     return profman.CreateProfile();
   1360   }
   1361 
   1362   if (profman.ShouldCreateBootProfile()) {
   1363     return profman.CreateBootProfile();
   1364   }
   1365 
   1366   if (profman.ShouldCopyAndUpdateProfileKey()) {
   1367     return profman.CopyAndUpdateProfileKey();
   1368   }
   1369 
   1370   // Process profile information and assess if we need to do a profile guided compilation.
   1371   // This operation involves I/O.
   1372   return profman.ProcessProfiles();
   1373 }
   1374 
   1375 }  // namespace art
   1376 
   1377 int main(int argc, char **argv) {
   1378   return art::profman(argc, argv);
   1379 }
   1380