• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
CommandLine()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 
FdIsValid(int fd)73 static bool FdIsValid(int fd) {
74   return fd != kInvalidFd;
75 }
76 
UsageErrorV(const char * fmt,va_list ap)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 
UsageError(const char * fmt,...)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 
Usage(const char * fmt,...)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 
Abort(const char * msg)187 NO_RETURN static void Abort(const char* msg) {
188   LOG(ERROR) << msg;
189   exit(1);
190 }
191 
192 template <typename T>
ParseUintOption(const char * raw_option,std::string_view option_prefix,T * out)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:
ProfMan()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 
~ProfMan()237   ~ProfMan() {
238     LogCompletionTime();
239   }
240 
ParseArgs(int argc,char ** argv)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 {
ProfileFilterKeyart::ProfMan::ProfileFilterKey338     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 
operator ==art::ProfMan::ProfileFilterKey343     bool operator==(const ProfileFilterKey& other) const {
344       return checksum_ == other.checksum_ && dex_location_ == other.dex_location_;
345     }
operator <art::ProfMan::ProfileFilterKey346     bool operator<(const ProfileFilterKey& other) const {
347       return checksum_ == other.checksum_
348           ?  dex_location_ < other.dex_location_
349           : checksum_ < other.checksum_;
350     }
351   };
352 
ProcessProfiles()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 
GetProfileFilterKeyFromApks(std::set<ProfileFilterKey> * profile_filter_keys)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 
OpenApkFilesFromLocations(std::vector<std::unique_ptr<const DexFile>> * dex_files)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 
OpenApkFilesFromLocations(const std::function<void (std::unique_ptr<const DexFile> &&)> & process_fn)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.
ComputeDexLocationsFromApkFds()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 
LoadProfile(const std::string & filename,int fd)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 
DumpOneProfile(const std::string & banner,const std::string & filename,int fd,const std::vector<std::unique_ptr<const DexFile>> * dex_files,std::string * dump)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 
DumpProfileInfo()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 
ShouldOnlyDumpProfile()627   bool ShouldOnlyDumpProfile() {
628     return dump_only_;
629   }
630 
GetClassNamesAndMethods(int fd,std::vector<std::unique_ptr<const DexFile>> * dex_files,std::set<std::string> * out_lines)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 
GetClassNamesAndMethods(const std::string & profile_file,std::vector<std::unique_ptr<const DexFile>> * dex_files,std::set<std::string> * out_lines)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 
DumpClassesAndMethods()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 
ShouldOnlyDumpClassesAndMethods()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>
ReadCommentedInputFromFile(const char * input_filename,std::function<std::string (const char *)> * process)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>
ReadCommentedInputStream(std::istream & in_stream,std::function<std::string (const char *)> * process)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.
FindClass(const std::vector<std::unique_ptr<const DexFile>> & dex_files,const std::string & klass_descriptor,TypeReference * class_ref)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.
FindMethodIndex(const TypeReference & class_ref,const std::string & method_spec)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.
HasSingleInvoke(const TypeReference & class_ref,uint16_t method_index,uint32_t * dex_pc)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.
ProcessLine(const std::vector<std::unique_ptr<const DexFile>> & dex_files,const std::string & line,ProfileCompilationInfo * profile)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 
OpenReferenceProfile() const1068   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
CreateProfile()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 
ShouldCreateBootProfile() const1139   bool ShouldCreateBootProfile() const {
1140     return generate_boot_image_profile_;
1141   }
1142 
CreateBootProfile()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 
ShouldCreateProfile()1188   bool ShouldCreateProfile() {
1189     return !create_profile_from_file_.empty();
1190   }
1191 
GenerateTestProfile()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 
ShouldGenerateTestProfile()1242   bool ShouldGenerateTestProfile() {
1243     return !test_profile_.empty();
1244   }
1245 
ShouldCopyAndUpdateProfileKey() const1246   bool ShouldCopyAndUpdateProfileKey() const {
1247     return copy_and_update_profile_key_;
1248   }
1249 
CopyAndUpdateProfileKey()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:
ParseFdForCollection(const char * raw_option,std::string_view option_prefix,std::vector<int> * fds)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 
CloseAllFds(const std::vector<int> & fds,const char * descriptor)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 
LogCompletionTime()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.
profman(int argc,char ** argv)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 
main(int argc,char ** argv)1377 int main(int argc, char **argv) {
1378   return art::profman(argc, argv);
1379 }
1380