• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 /** A commandline tool to generate a primary boot image for testing. */
18 
19 #include <sys/stat.h>
20 #include <sysexits.h>
21 
22 #include <algorithm>
23 #include <cstdlib>
24 #include <string>
25 #include <vector>
26 
27 #include "android-base/stringprintf.h"
28 #include "android-base/strings.h"
29 #include "arch/instruction_set.h"
30 #include "base/file_utils.h"
31 #include "base/globals.h"
32 #include "base/os.h"
33 #include "base/testing.h"
34 
35 namespace art {
36 
37 namespace {
38 
39 using ::android::base::Join;
40 using ::android::base::StringPrintf;
41 using ::art::testing::GetLibCoreDexFileNames;
42 
GetCompilerExecutable()43 std::string GetCompilerExecutable() {
44   std::string compiler_executable = GetArtBinDir() + "/dex2oat";
45   if (kIsDebugBuild) {
46     compiler_executable += 'd';
47   }
48   compiler_executable += Is64BitInstructionSet(kRuntimeISA) ? "64" : "32";
49   return compiler_executable;
50 }
51 
52 // Joins a list of commandline args into a single string, where each part is quoted with double
53 // quotes. Note that this is a naive implementation that does NOT escape existing double quotes,
54 // which is fine since we don't have existing double quotes in the args in this particular use case
55 // and this code is never used in production.
BuildCommand(const std::vector<std::string> & args)56 std::string BuildCommand(const std::vector<std::string>& args) {
57   std::string command = "";
58   for (const std::string& arg : args) {
59     if (!command.empty()) {
60       command += " ";
61     }
62     command += '"' + arg + '"';
63   }
64   return command;
65 }
66 
GenerateBootImage(const std::string & dir,const std::string & compiler_filter)67 int GenerateBootImage(const std::string& dir, const std::string& compiler_filter) {
68   std::string isa = GetInstructionSetString(kRuntimeISA);
69 
70   std::vector<std::string> args;
71   args.push_back(GetCompilerExecutable());
72 
73   std::vector<std::string> dex_files = GetLibCoreDexFileNames(/*core_only=*/true);
74   args.push_back("--runtime-arg");
75   args.push_back("-Xbootclasspath:" + Join(dex_files, ":"));
76   for (const std::string& file : dex_files) {
77     args.push_back("--dex-file=" + file);
78   }
79 
80   args.push_back("--instruction-set=" + isa);
81   args.push_back(StringPrintf("--base=0x%08x", ART_BASE_ADDRESS));
82   args.push_back("--compiler-filter=" + compiler_filter);
83   args.push_back(StringPrintf("--profile-file=%s/etc/boot-image.prof", GetArtRoot().c_str()));
84   args.push_back("--avoid-storing-invocation");
85   args.push_back("--generate-debug-info");
86   args.push_back("--generate-build-id");
87   args.push_back("--image-format=lz4hc");
88   args.push_back("--strip");
89   args.push_back("--android-root=out/empty");
90 
91   std::string path = StringPrintf("%s/%s", dir.c_str(), isa.c_str());
92   if (!OS::DirectoryExists(path.c_str())) {
93     CHECK_EQ(mkdir(path.c_str(), S_IRWXU), 0);
94   }
95   args.push_back(StringPrintf("--image=%s/boot.art", path.c_str()));
96   args.push_back(StringPrintf("--oat-file=%s/boot.oat", path.c_str()));
97 
98   int exit_code = system(BuildCommand(args).c_str());
99   if (exit_code != 0) {
100     LOG(ERROR) << "dex2oat invocation failed. Exit code: " << exit_code;
101   }
102   return exit_code;
103 }
104 
105 }  // namespace
106 }  // namespace art
107 
main(int argc,char ** argv)108 int main(int argc, char** argv) {
109   android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));
110 
111   std::string dir = "";
112   // Set the compiler filter to `verify` by default to make test preparation
113   // faster.
114   std::string compiler_filter = "verify";
115   for (int i = 1; i < argc; i++) {
116     std::string_view arg{argv[i]};
117     if (android::base::ConsumePrefix(&arg, "--output-dir=")) {
118       dir = arg;
119     } else if (android::base::ConsumePrefix(&arg, "--compiler-filter=")) {
120       compiler_filter = arg;
121     } else {
122       LOG(ERROR) << android::base::StringPrintf("Unrecognized argument: '%s'", argv[i]);
123       exit(EX_USAGE);
124     }
125   }
126 
127   if (dir.empty()) {
128     LOG(ERROR) << "--output-dir must be specified";
129     exit(EX_USAGE);
130   }
131 
132   return art::GenerateBootImage(dir, compiler_filter);
133 }
134