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