xref: /aosp_15_r20/art/cmdline/cmdline.h (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2014 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #ifndef ART_CMDLINE_CMDLINE_H_
18*795d594fSAndroid Build Coastguard Worker #define ART_CMDLINE_CMDLINE_H_
19*795d594fSAndroid Build Coastguard Worker 
20*795d594fSAndroid Build Coastguard Worker #include <stdio.h>
21*795d594fSAndroid Build Coastguard Worker #include <stdlib.h>
22*795d594fSAndroid Build Coastguard Worker 
23*795d594fSAndroid Build Coastguard Worker #include <fstream>
24*795d594fSAndroid Build Coastguard Worker #include <iostream>
25*795d594fSAndroid Build Coastguard Worker #include <memory>
26*795d594fSAndroid Build Coastguard Worker #include <string>
27*795d594fSAndroid Build Coastguard Worker #include <string_view>
28*795d594fSAndroid Build Coastguard Worker #include <vector>
29*795d594fSAndroid Build Coastguard Worker 
30*795d594fSAndroid Build Coastguard Worker #include "android-base/stringprintf.h"
31*795d594fSAndroid Build Coastguard Worker #include "android-base/strings.h"
32*795d594fSAndroid Build Coastguard Worker #include "base/file_utils.h"
33*795d594fSAndroid Build Coastguard Worker #include "base/logging.h"
34*795d594fSAndroid Build Coastguard Worker #include "base/mutex.h"
35*795d594fSAndroid Build Coastguard Worker #include "base/utils.h"
36*795d594fSAndroid Build Coastguard Worker #include "noop_compiler_callbacks.h"
37*795d594fSAndroid Build Coastguard Worker #include "oat/oat_file_assistant_context.h"
38*795d594fSAndroid Build Coastguard Worker #include "runtime.h"
39*795d594fSAndroid Build Coastguard Worker 
40*795d594fSAndroid Build Coastguard Worker #if !defined(NDEBUG)
41*795d594fSAndroid Build Coastguard Worker #define DBG_LOG LOG(INFO)
42*795d594fSAndroid Build Coastguard Worker #else
43*795d594fSAndroid Build Coastguard Worker #define DBG_LOG LOG(DEBUG)
44*795d594fSAndroid Build Coastguard Worker #endif
45*795d594fSAndroid Build Coastguard Worker 
46*795d594fSAndroid Build Coastguard Worker namespace art {
47*795d594fSAndroid Build Coastguard Worker 
StartRuntime(const std::vector<std::string> & boot_image_locations,InstructionSet instruction_set,const std::vector<const char * > & runtime_args)48*795d594fSAndroid Build Coastguard Worker static Runtime* StartRuntime(const std::vector<std::string>& boot_image_locations,
49*795d594fSAndroid Build Coastguard Worker                              InstructionSet instruction_set,
50*795d594fSAndroid Build Coastguard Worker                              const std::vector<const char*>& runtime_args) {
51*795d594fSAndroid Build Coastguard Worker   RuntimeOptions options;
52*795d594fSAndroid Build Coastguard Worker 
53*795d594fSAndroid Build Coastguard Worker   // We are more like a compiler than a run-time. We don't want to execute code.
54*795d594fSAndroid Build Coastguard Worker   {
55*795d594fSAndroid Build Coastguard Worker     static NoopCompilerCallbacks callbacks;
56*795d594fSAndroid Build Coastguard Worker     options.push_back(std::make_pair("compilercallbacks", &callbacks));
57*795d594fSAndroid Build Coastguard Worker   }
58*795d594fSAndroid Build Coastguard Worker 
59*795d594fSAndroid Build Coastguard Worker   // Boot image location.
60*795d594fSAndroid Build Coastguard Worker   {
61*795d594fSAndroid Build Coastguard Worker     std::string boot_image_option = "-Ximage:";
62*795d594fSAndroid Build Coastguard Worker     if (!boot_image_locations.empty()) {
63*795d594fSAndroid Build Coastguard Worker       boot_image_option += android::base::Join(boot_image_locations, ':');
64*795d594fSAndroid Build Coastguard Worker     } else {
65*795d594fSAndroid Build Coastguard Worker       boot_image_option += GetJitZygoteBootImageLocation();
66*795d594fSAndroid Build Coastguard Worker     }
67*795d594fSAndroid Build Coastguard Worker     options.push_back(std::make_pair(boot_image_option, nullptr));
68*795d594fSAndroid Build Coastguard Worker   }
69*795d594fSAndroid Build Coastguard Worker 
70*795d594fSAndroid Build Coastguard Worker   // Instruction set.
71*795d594fSAndroid Build Coastguard Worker   options.push_back(
72*795d594fSAndroid Build Coastguard Worker       std::make_pair("imageinstructionset",
73*795d594fSAndroid Build Coastguard Worker                      reinterpret_cast<const void*>(GetInstructionSetString(instruction_set))));
74*795d594fSAndroid Build Coastguard Worker 
75*795d594fSAndroid Build Coastguard Worker   // Explicit runtime args.
76*795d594fSAndroid Build Coastguard Worker   for (const char* runtime_arg : runtime_args) {
77*795d594fSAndroid Build Coastguard Worker     options.push_back(std::make_pair(runtime_arg, nullptr));
78*795d594fSAndroid Build Coastguard Worker   }
79*795d594fSAndroid Build Coastguard Worker 
80*795d594fSAndroid Build Coastguard Worker   // None of the command line tools need sig chain. If this changes we'll need
81*795d594fSAndroid Build Coastguard Worker   // to upgrade this option to a proper parameter.
82*795d594fSAndroid Build Coastguard Worker   options.push_back(std::make_pair("-Xno-sig-chain", nullptr));
83*795d594fSAndroid Build Coastguard Worker   if (!Runtime::Create(options, false)) {
84*795d594fSAndroid Build Coastguard Worker     fprintf(stderr, "Failed to create runtime\n");
85*795d594fSAndroid Build Coastguard Worker     return nullptr;
86*795d594fSAndroid Build Coastguard Worker   }
87*795d594fSAndroid Build Coastguard Worker 
88*795d594fSAndroid Build Coastguard Worker   // Runtime::Create acquired the mutator_lock_ that is normally given away when we Runtime::Start,
89*795d594fSAndroid Build Coastguard Worker   // give it away now and then switch to a more manageable ScopedObjectAccess.
90*795d594fSAndroid Build Coastguard Worker   Thread::Current()->TransitionFromRunnableToSuspended(ThreadState::kNative);
91*795d594fSAndroid Build Coastguard Worker 
92*795d594fSAndroid Build Coastguard Worker   return Runtime::Current();
93*795d594fSAndroid Build Coastguard Worker }
94*795d594fSAndroid Build Coastguard Worker 
95*795d594fSAndroid Build Coastguard Worker struct CmdlineArgs {
96*795d594fSAndroid Build Coastguard Worker   enum ParseStatus {
97*795d594fSAndroid Build Coastguard Worker     kParseOk,               // Parse successful. Do not set the error message.
98*795d594fSAndroid Build Coastguard Worker     kParseUnknownArgument,  // Unknown argument. Do not set the error message.
99*795d594fSAndroid Build Coastguard Worker     kParseError,            // Parse ok, but failed elsewhere. Print the set error message.
100*795d594fSAndroid Build Coastguard Worker   };
101*795d594fSAndroid Build Coastguard Worker 
ParseCmdlineArgs102*795d594fSAndroid Build Coastguard Worker   bool Parse(int argc, char** argv) {
103*795d594fSAndroid Build Coastguard Worker     // Skip over argv[0].
104*795d594fSAndroid Build Coastguard Worker     argv++;
105*795d594fSAndroid Build Coastguard Worker     argc--;
106*795d594fSAndroid Build Coastguard Worker 
107*795d594fSAndroid Build Coastguard Worker     if (argc == 0) {
108*795d594fSAndroid Build Coastguard Worker       fprintf(stderr, "No arguments specified\n");
109*795d594fSAndroid Build Coastguard Worker       PrintUsage();
110*795d594fSAndroid Build Coastguard Worker       return false;
111*795d594fSAndroid Build Coastguard Worker     }
112*795d594fSAndroid Build Coastguard Worker 
113*795d594fSAndroid Build Coastguard Worker     std::string error_msg;
114*795d594fSAndroid Build Coastguard Worker     for (int i = 0; i < argc; i++) {
115*795d594fSAndroid Build Coastguard Worker       const char* const raw_option = argv[i];
116*795d594fSAndroid Build Coastguard Worker       const std::string_view option(raw_option);
117*795d594fSAndroid Build Coastguard Worker       if (option.starts_with("--boot-image=")) {
118*795d594fSAndroid Build Coastguard Worker         Split(raw_option + strlen("--boot-image="), ':', &boot_image_locations_);
119*795d594fSAndroid Build Coastguard Worker       } else if (option.starts_with("--instruction-set=")) {
120*795d594fSAndroid Build Coastguard Worker         const char* const instruction_set_str = raw_option + strlen("--instruction-set=");
121*795d594fSAndroid Build Coastguard Worker         instruction_set_ = GetInstructionSetFromString(instruction_set_str);
122*795d594fSAndroid Build Coastguard Worker         if (instruction_set_ == InstructionSet::kNone) {
123*795d594fSAndroid Build Coastguard Worker           fprintf(stderr, "Unsupported instruction set %s\n", instruction_set_str);
124*795d594fSAndroid Build Coastguard Worker           PrintUsage();
125*795d594fSAndroid Build Coastguard Worker           return false;
126*795d594fSAndroid Build Coastguard Worker         }
127*795d594fSAndroid Build Coastguard Worker       } else if (option == "--runtime-arg") {
128*795d594fSAndroid Build Coastguard Worker         if (i + 1 == argc) {
129*795d594fSAndroid Build Coastguard Worker           fprintf(stderr, "Missing argument for --runtime-arg\n");
130*795d594fSAndroid Build Coastguard Worker           PrintUsage();
131*795d594fSAndroid Build Coastguard Worker           return false;
132*795d594fSAndroid Build Coastguard Worker         }
133*795d594fSAndroid Build Coastguard Worker         ++i;
134*795d594fSAndroid Build Coastguard Worker         runtime_args_.push_back(argv[i]);
135*795d594fSAndroid Build Coastguard Worker       } else if (option.starts_with("--output=")) {
136*795d594fSAndroid Build Coastguard Worker         output_name_ = std::string(option.substr(strlen("--output=")));
137*795d594fSAndroid Build Coastguard Worker         const char* filename = output_name_.c_str();
138*795d594fSAndroid Build Coastguard Worker         out_.reset(new std::ofstream(filename));
139*795d594fSAndroid Build Coastguard Worker         if (!out_->good()) {
140*795d594fSAndroid Build Coastguard Worker           fprintf(stderr, "Failed to open output filename %s\n", filename);
141*795d594fSAndroid Build Coastguard Worker           PrintUsage();
142*795d594fSAndroid Build Coastguard Worker           return false;
143*795d594fSAndroid Build Coastguard Worker         }
144*795d594fSAndroid Build Coastguard Worker         os_ = out_.get();
145*795d594fSAndroid Build Coastguard Worker       } else {
146*795d594fSAndroid Build Coastguard Worker         ParseStatus parse_status = ParseCustom(raw_option, option.length(), &error_msg);
147*795d594fSAndroid Build Coastguard Worker 
148*795d594fSAndroid Build Coastguard Worker         if (parse_status == kParseUnknownArgument) {
149*795d594fSAndroid Build Coastguard Worker           fprintf(stderr, "Unknown argument %s\n", option.data());
150*795d594fSAndroid Build Coastguard Worker         }
151*795d594fSAndroid Build Coastguard Worker 
152*795d594fSAndroid Build Coastguard Worker         if (parse_status != kParseOk) {
153*795d594fSAndroid Build Coastguard Worker           fprintf(stderr, "%s\n", error_msg.c_str());
154*795d594fSAndroid Build Coastguard Worker           PrintUsage();
155*795d594fSAndroid Build Coastguard Worker           return false;
156*795d594fSAndroid Build Coastguard Worker         }
157*795d594fSAndroid Build Coastguard Worker       }
158*795d594fSAndroid Build Coastguard Worker     }
159*795d594fSAndroid Build Coastguard Worker 
160*795d594fSAndroid Build Coastguard Worker     if (instruction_set_ == InstructionSet::kNone) {
161*795d594fSAndroid Build Coastguard Worker       LOG(WARNING) << "No instruction set given, assuming " << GetInstructionSetString(kRuntimeISA);
162*795d594fSAndroid Build Coastguard Worker       instruction_set_ = kRuntimeISA;
163*795d594fSAndroid Build Coastguard Worker     }
164*795d594fSAndroid Build Coastguard Worker 
165*795d594fSAndroid Build Coastguard Worker     DBG_LOG << "will call parse checks";
166*795d594fSAndroid Build Coastguard Worker 
167*795d594fSAndroid Build Coastguard Worker     {
168*795d594fSAndroid Build Coastguard Worker       ParseStatus checks_status = ParseChecks(&error_msg);
169*795d594fSAndroid Build Coastguard Worker       if (checks_status != kParseOk) {
170*795d594fSAndroid Build Coastguard Worker           fprintf(stderr, "%s\n", error_msg.c_str());
171*795d594fSAndroid Build Coastguard Worker           PrintUsage();
172*795d594fSAndroid Build Coastguard Worker           return false;
173*795d594fSAndroid Build Coastguard Worker       }
174*795d594fSAndroid Build Coastguard Worker     }
175*795d594fSAndroid Build Coastguard Worker 
176*795d594fSAndroid Build Coastguard Worker     return true;
177*795d594fSAndroid Build Coastguard Worker   }
178*795d594fSAndroid Build Coastguard Worker 
GetUsageCmdlineArgs179*795d594fSAndroid Build Coastguard Worker   virtual std::string GetUsage() const {
180*795d594fSAndroid Build Coastguard Worker     std::string usage;
181*795d594fSAndroid Build Coastguard Worker 
182*795d594fSAndroid Build Coastguard Worker     usage +=  // Required.
183*795d594fSAndroid Build Coastguard Worker         "  --boot-image=<file.art>: provide the image location for the boot class path.\n"
184*795d594fSAndroid Build Coastguard Worker         "      Do not include the arch as part of the name, it is added automatically.\n"
185*795d594fSAndroid Build Coastguard Worker         "      Example: --boot-image=/system/framework/boot.art\n"
186*795d594fSAndroid Build Coastguard Worker         "               (specifies /system/framework/<arch>/boot.art as the image file)\n"
187*795d594fSAndroid Build Coastguard Worker         "\n";
188*795d594fSAndroid Build Coastguard Worker     usage += android::base::StringPrintf(  // Optional.
189*795d594fSAndroid Build Coastguard Worker         "  --instruction-set=(arm|arm64|x86|x86_64): for locating the image\n"
190*795d594fSAndroid Build Coastguard Worker         "      file based on the image location set.\n"
191*795d594fSAndroid Build Coastguard Worker         "      Example: --instruction-set=x86\n"
192*795d594fSAndroid Build Coastguard Worker         "      Default: %s\n"
193*795d594fSAndroid Build Coastguard Worker         "\n",
194*795d594fSAndroid Build Coastguard Worker         GetInstructionSetString(kRuntimeISA));
195*795d594fSAndroid Build Coastguard Worker     usage +=
196*795d594fSAndroid Build Coastguard Worker         "  --runtime-arg <argument> used to specify various arguments for the runtime\n"
197*795d594fSAndroid Build Coastguard Worker         "      such as initial heap size, maximum heap size, and verbose output.\n"
198*795d594fSAndroid Build Coastguard Worker         "      Use a separate --runtime-arg switch for each argument.\n"
199*795d594fSAndroid Build Coastguard Worker         "      Example: --runtime-arg -Xms256m\n"
200*795d594fSAndroid Build Coastguard Worker         "\n";
201*795d594fSAndroid Build Coastguard Worker     usage +=  // Optional.
202*795d594fSAndroid Build Coastguard Worker         "  --output=<file> may be used to send the output to a file.\n"
203*795d594fSAndroid Build Coastguard Worker         "      Example: --output=/tmp/oatdump.txt\n"
204*795d594fSAndroid Build Coastguard Worker         "\n";
205*795d594fSAndroid Build Coastguard Worker 
206*795d594fSAndroid Build Coastguard Worker     return usage;
207*795d594fSAndroid Build Coastguard Worker   }
208*795d594fSAndroid Build Coastguard Worker 
209*795d594fSAndroid Build Coastguard Worker   // Specified by --runtime-arg -Xbootclasspath or default.
210*795d594fSAndroid Build Coastguard Worker   std::vector<std::string> boot_class_path_;
211*795d594fSAndroid Build Coastguard Worker   // Specified by --runtime-arg -Xbootclasspath-locations or default.
212*795d594fSAndroid Build Coastguard Worker   std::vector<std::string> boot_class_path_locations_;
213*795d594fSAndroid Build Coastguard Worker   // True if `boot_class_path_` is the default one.
214*795d594fSAndroid Build Coastguard Worker   bool is_default_boot_class_path_ = false;
215*795d594fSAndroid Build Coastguard Worker   // Specified by --boot-image or inferred.
216*795d594fSAndroid Build Coastguard Worker   std::vector<std::string> boot_image_locations_;
217*795d594fSAndroid Build Coastguard Worker   // Specified by --instruction-set.
218*795d594fSAndroid Build Coastguard Worker   InstructionSet instruction_set_ = InstructionSet::kNone;
219*795d594fSAndroid Build Coastguard Worker   // Runtime arguments specified by --runtime-arg.
220*795d594fSAndroid Build Coastguard Worker   std::vector<const char*> runtime_args_;
221*795d594fSAndroid Build Coastguard Worker   // Specified by --output.
222*795d594fSAndroid Build Coastguard Worker   std::ostream* os_ = &std::cout;
223*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<std::ofstream> out_;  // If something besides cout is used
224*795d594fSAndroid Build Coastguard Worker   std::string output_name_;
225*795d594fSAndroid Build Coastguard Worker 
~CmdlineArgsCmdlineArgs226*795d594fSAndroid Build Coastguard Worker   virtual ~CmdlineArgs() {}
227*795d594fSAndroid Build Coastguard Worker 
228*795d594fSAndroid Build Coastguard Worker   // Checks for --boot-image location.
ParseCheckBootImageCmdlineArgs229*795d594fSAndroid Build Coastguard Worker   bool ParseCheckBootImage(std::string* error_msg) {
230*795d594fSAndroid Build Coastguard Worker     if (boot_image_locations_.empty()) {
231*795d594fSAndroid Build Coastguard Worker       LOG(WARNING) << "--boot-image not specified. Starting runtime in imageless mode";
232*795d594fSAndroid Build Coastguard Worker       return true;
233*795d594fSAndroid Build Coastguard Worker     }
234*795d594fSAndroid Build Coastguard Worker 
235*795d594fSAndroid Build Coastguard Worker     const std::string& boot_image_location = boot_image_locations_[0];
236*795d594fSAndroid Build Coastguard Worker     size_t file_name_idx = boot_image_location.rfind('/');
237*795d594fSAndroid Build Coastguard Worker     if (file_name_idx == std::string::npos) {  // Prevent a InsertIsaDirectory check failure.
238*795d594fSAndroid Build Coastguard Worker       *error_msg = "Boot image location must have a / in it";
239*795d594fSAndroid Build Coastguard Worker       return false;
240*795d594fSAndroid Build Coastguard Worker     }
241*795d594fSAndroid Build Coastguard Worker 
242*795d594fSAndroid Build Coastguard Worker     // Don't let image locations with the 'arch' in it through, since it's not a location.
243*795d594fSAndroid Build Coastguard Worker     // This prevents a common error "Could not create an image space..." when initing the Runtime.
244*795d594fSAndroid Build Coastguard Worker     if (file_name_idx > 0) {
245*795d594fSAndroid Build Coastguard Worker       size_t ancestor_dirs_idx = boot_image_location.rfind('/', file_name_idx - 1);
246*795d594fSAndroid Build Coastguard Worker 
247*795d594fSAndroid Build Coastguard Worker       std::string parent_dir_name;
248*795d594fSAndroid Build Coastguard Worker       if (ancestor_dirs_idx != std::string::npos) {
249*795d594fSAndroid Build Coastguard Worker           parent_dir_name = boot_image_location.substr(/*pos=*/ancestor_dirs_idx + 1,
250*795d594fSAndroid Build Coastguard Worker                                                        /*n=*/file_name_idx - ancestor_dirs_idx - 1);
251*795d594fSAndroid Build Coastguard Worker       } else {
252*795d594fSAndroid Build Coastguard Worker           parent_dir_name = boot_image_location.substr(/*pos=*/0,
253*795d594fSAndroid Build Coastguard Worker                                                        /*n=*/file_name_idx);
254*795d594fSAndroid Build Coastguard Worker       }
255*795d594fSAndroid Build Coastguard Worker 
256*795d594fSAndroid Build Coastguard Worker       DBG_LOG << "boot_image_location parent_dir_name was " << parent_dir_name;
257*795d594fSAndroid Build Coastguard Worker 
258*795d594fSAndroid Build Coastguard Worker       if (GetInstructionSetFromString(parent_dir_name.c_str()) != InstructionSet::kNone) {
259*795d594fSAndroid Build Coastguard Worker           *error_msg = "Do not specify the architecture as part of the boot image location";
260*795d594fSAndroid Build Coastguard Worker           return false;
261*795d594fSAndroid Build Coastguard Worker       }
262*795d594fSAndroid Build Coastguard Worker     }
263*795d594fSAndroid Build Coastguard Worker 
264*795d594fSAndroid Build Coastguard Worker     return true;
265*795d594fSAndroid Build Coastguard Worker   }
266*795d594fSAndroid Build Coastguard Worker 
PrintUsageCmdlineArgs267*795d594fSAndroid Build Coastguard Worker   void PrintUsage() { fprintf(stderr, "%s", GetUsage().c_str()); }
268*795d594fSAndroid Build Coastguard Worker 
GetOatFileAssistantContextCmdlineArgs269*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<OatFileAssistantContext> GetOatFileAssistantContext(std::string* error_msg) {
270*795d594fSAndroid Build Coastguard Worker     if (boot_class_path_.empty()) {
271*795d594fSAndroid Build Coastguard Worker       *error_msg = "Boot classpath is empty";
272*795d594fSAndroid Build Coastguard Worker       return nullptr;
273*795d594fSAndroid Build Coastguard Worker     }
274*795d594fSAndroid Build Coastguard Worker 
275*795d594fSAndroid Build Coastguard Worker     CHECK(!boot_class_path_locations_.empty());
276*795d594fSAndroid Build Coastguard Worker 
277*795d594fSAndroid Build Coastguard Worker     return std::make_unique<OatFileAssistantContext>(
278*795d594fSAndroid Build Coastguard Worker         std::make_unique<OatFileAssistantContext::RuntimeOptions>(
279*795d594fSAndroid Build Coastguard Worker             OatFileAssistantContext::RuntimeOptions{
280*795d594fSAndroid Build Coastguard Worker                 .image_locations = boot_image_locations_,
281*795d594fSAndroid Build Coastguard Worker                 .boot_class_path = boot_class_path_,
282*795d594fSAndroid Build Coastguard Worker                 .boot_class_path_locations = boot_class_path_locations_,
283*795d594fSAndroid Build Coastguard Worker             }));
284*795d594fSAndroid Build Coastguard Worker   }
285*795d594fSAndroid Build Coastguard Worker 
286*795d594fSAndroid Build Coastguard Worker  protected:
ParseCustomCmdlineArgs287*795d594fSAndroid Build Coastguard Worker   virtual ParseStatus ParseCustom([[maybe_unused]] const char* raw_option,
288*795d594fSAndroid Build Coastguard Worker                                   [[maybe_unused]] size_t raw_option_length,
289*795d594fSAndroid Build Coastguard Worker                                   [[maybe_unused]] std::string* error_msg) {
290*795d594fSAndroid Build Coastguard Worker     return kParseUnknownArgument;
291*795d594fSAndroid Build Coastguard Worker   }
292*795d594fSAndroid Build Coastguard Worker 
ParseChecksCmdlineArgs293*795d594fSAndroid Build Coastguard Worker   virtual ParseStatus ParseChecks([[maybe_unused]] std::string* error_msg) {
294*795d594fSAndroid Build Coastguard Worker     ParseBootclasspath();
295*795d594fSAndroid Build Coastguard Worker     if (boot_image_locations_.empty()) {
296*795d594fSAndroid Build Coastguard Worker       InferBootImage();
297*795d594fSAndroid Build Coastguard Worker     }
298*795d594fSAndroid Build Coastguard Worker     return kParseOk;
299*795d594fSAndroid Build Coastguard Worker   }
300*795d594fSAndroid Build Coastguard Worker 
301*795d594fSAndroid Build Coastguard Worker  private:
ParseBootclasspathCmdlineArgs302*795d594fSAndroid Build Coastguard Worker   void ParseBootclasspath() {
303*795d594fSAndroid Build Coastguard Worker     std::optional<std::string_view> bcp_str = std::nullopt;
304*795d594fSAndroid Build Coastguard Worker     std::optional<std::string_view> bcp_location_str = std::nullopt;
305*795d594fSAndroid Build Coastguard Worker     for (std::string_view arg : runtime_args_) {
306*795d594fSAndroid Build Coastguard Worker       if (arg.starts_with("-Xbootclasspath:")) {
307*795d594fSAndroid Build Coastguard Worker           bcp_str = arg.substr(strlen("-Xbootclasspath:"));
308*795d594fSAndroid Build Coastguard Worker       }
309*795d594fSAndroid Build Coastguard Worker       if (arg.starts_with("-Xbootclasspath-locations:")) {
310*795d594fSAndroid Build Coastguard Worker           bcp_location_str = arg.substr(strlen("-Xbootclasspath-locations:"));
311*795d594fSAndroid Build Coastguard Worker       }
312*795d594fSAndroid Build Coastguard Worker     }
313*795d594fSAndroid Build Coastguard Worker 
314*795d594fSAndroid Build Coastguard Worker     if (bcp_str.has_value() && bcp_location_str.has_value()) {
315*795d594fSAndroid Build Coastguard Worker       Split(*bcp_str, ':', &boot_class_path_);
316*795d594fSAndroid Build Coastguard Worker       Split(*bcp_location_str, ':', &boot_class_path_locations_);
317*795d594fSAndroid Build Coastguard Worker     } else if (bcp_str.has_value()) {
318*795d594fSAndroid Build Coastguard Worker       Split(*bcp_str, ':', &boot_class_path_);
319*795d594fSAndroid Build Coastguard Worker       boot_class_path_locations_ = boot_class_path_;
320*795d594fSAndroid Build Coastguard Worker     } else {
321*795d594fSAndroid Build Coastguard Worker       // Try the default.
322*795d594fSAndroid Build Coastguard Worker       const char* env_value = getenv("BOOTCLASSPATH");
323*795d594fSAndroid Build Coastguard Worker       if (env_value != nullptr && strlen(env_value) > 0) {
324*795d594fSAndroid Build Coastguard Worker           Split(env_value, ':', &boot_class_path_);
325*795d594fSAndroid Build Coastguard Worker           boot_class_path_locations_ = boot_class_path_;
326*795d594fSAndroid Build Coastguard Worker           is_default_boot_class_path_ = true;
327*795d594fSAndroid Build Coastguard Worker       }
328*795d594fSAndroid Build Coastguard Worker     }
329*795d594fSAndroid Build Coastguard Worker   }
330*795d594fSAndroid Build Coastguard Worker 
331*795d594fSAndroid Build Coastguard Worker   // Infers the boot image on a best-effort basis.
332*795d594fSAndroid Build Coastguard Worker   // The inference logic aligns with installd/artd + dex2oat.
InferBootImageCmdlineArgs333*795d594fSAndroid Build Coastguard Worker   void InferBootImage() {
334*795d594fSAndroid Build Coastguard Worker     // The boot image inference only makes sense on device.
335*795d594fSAndroid Build Coastguard Worker     if (!kIsTargetAndroid) {
336*795d594fSAndroid Build Coastguard Worker       return;
337*795d594fSAndroid Build Coastguard Worker     }
338*795d594fSAndroid Build Coastguard Worker 
339*795d594fSAndroid Build Coastguard Worker     // The inferred boot image can only be used with the default bootclasspath.
340*795d594fSAndroid Build Coastguard Worker     if (boot_class_path_.empty() || !is_default_boot_class_path_) {
341*795d594fSAndroid Build Coastguard Worker       return;
342*795d594fSAndroid Build Coastguard Worker     }
343*795d594fSAndroid Build Coastguard Worker 
344*795d594fSAndroid Build Coastguard Worker     std::string error_msg;
345*795d594fSAndroid Build Coastguard Worker     std::string boot_image = GetBootImageLocationForDefaultBcpRespectingSysProps(&error_msg);
346*795d594fSAndroid Build Coastguard Worker     if (boot_image.empty()) {
347*795d594fSAndroid Build Coastguard Worker       LOG(WARNING) << "Failed to infer boot image: " << error_msg;
348*795d594fSAndroid Build Coastguard Worker       return;
349*795d594fSAndroid Build Coastguard Worker     }
350*795d594fSAndroid Build Coastguard Worker 
351*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << "Inferred boot image: " << boot_image;
352*795d594fSAndroid Build Coastguard Worker     Split(boot_image, ':', &boot_image_locations_);
353*795d594fSAndroid Build Coastguard Worker 
354*795d594fSAndroid Build Coastguard Worker     // Verify the inferred boot image.
355*795d594fSAndroid Build Coastguard Worker     std::unique_ptr<OatFileAssistantContext> ofa_context = GetOatFileAssistantContext(&error_msg);
356*795d594fSAndroid Build Coastguard Worker     CHECK_NE(ofa_context, nullptr);
357*795d594fSAndroid Build Coastguard Worker     size_t verified_boot_image_count = ofa_context->GetBootImageInfoList(instruction_set_).size();
358*795d594fSAndroid Build Coastguard Worker     if (verified_boot_image_count != boot_image_locations_.size()) {
359*795d594fSAndroid Build Coastguard Worker       LOG(WARNING) << "Failed to verify inferred boot image";
360*795d594fSAndroid Build Coastguard Worker       boot_image_locations_.resize(verified_boot_image_count);
361*795d594fSAndroid Build Coastguard Worker     }
362*795d594fSAndroid Build Coastguard Worker   }
363*795d594fSAndroid Build Coastguard Worker };
364*795d594fSAndroid Build Coastguard Worker 
365*795d594fSAndroid Build Coastguard Worker template <typename Args = CmdlineArgs>
366*795d594fSAndroid Build Coastguard Worker struct CmdlineMain {
MainCmdlineMain367*795d594fSAndroid Build Coastguard Worker   int Main(int argc, char** argv) {
368*795d594fSAndroid Build Coastguard Worker     Locks::Init();
369*795d594fSAndroid Build Coastguard Worker     InitLogging(argv, Runtime::Abort);
370*795d594fSAndroid Build Coastguard Worker     std::unique_ptr<Args> args = std::unique_ptr<Args>(CreateArguments());
371*795d594fSAndroid Build Coastguard Worker     args_ = args.get();
372*795d594fSAndroid Build Coastguard Worker 
373*795d594fSAndroid Build Coastguard Worker     DBG_LOG << "Try to parse";
374*795d594fSAndroid Build Coastguard Worker 
375*795d594fSAndroid Build Coastguard Worker     if (args_ == nullptr || !args_->Parse(argc, argv)) {
376*795d594fSAndroid Build Coastguard Worker       return EXIT_FAILURE;
377*795d594fSAndroid Build Coastguard Worker     }
378*795d594fSAndroid Build Coastguard Worker 
379*795d594fSAndroid Build Coastguard Worker     bool needs_runtime = NeedsRuntime();
380*795d594fSAndroid Build Coastguard Worker     std::unique_ptr<Runtime> runtime;
381*795d594fSAndroid Build Coastguard Worker 
382*795d594fSAndroid Build Coastguard Worker 
383*795d594fSAndroid Build Coastguard Worker     if (needs_runtime) {
384*795d594fSAndroid Build Coastguard Worker       std::string error_msg;
385*795d594fSAndroid Build Coastguard Worker       if (!args_->ParseCheckBootImage(&error_msg)) {
386*795d594fSAndroid Build Coastguard Worker         fprintf(stderr, "%s\n", error_msg.c_str());
387*795d594fSAndroid Build Coastguard Worker         args_->PrintUsage();
388*795d594fSAndroid Build Coastguard Worker         return EXIT_FAILURE;
389*795d594fSAndroid Build Coastguard Worker       }
390*795d594fSAndroid Build Coastguard Worker       runtime.reset(CreateRuntime(args.get()));
391*795d594fSAndroid Build Coastguard Worker       if (runtime == nullptr) {
392*795d594fSAndroid Build Coastguard Worker         return EXIT_FAILURE;
393*795d594fSAndroid Build Coastguard Worker       }
394*795d594fSAndroid Build Coastguard Worker       if (!ExecuteWithRuntime(runtime.get())) {
395*795d594fSAndroid Build Coastguard Worker         return EXIT_FAILURE;
396*795d594fSAndroid Build Coastguard Worker       }
397*795d594fSAndroid Build Coastguard Worker     } else {
398*795d594fSAndroid Build Coastguard Worker       if (!ExecuteWithoutRuntime()) {
399*795d594fSAndroid Build Coastguard Worker         return EXIT_FAILURE;
400*795d594fSAndroid Build Coastguard Worker       }
401*795d594fSAndroid Build Coastguard Worker     }
402*795d594fSAndroid Build Coastguard Worker 
403*795d594fSAndroid Build Coastguard Worker     if (!ExecuteCommon()) {
404*795d594fSAndroid Build Coastguard Worker       return EXIT_FAILURE;
405*795d594fSAndroid Build Coastguard Worker     }
406*795d594fSAndroid Build Coastguard Worker 
407*795d594fSAndroid Build Coastguard Worker     return EXIT_SUCCESS;
408*795d594fSAndroid Build Coastguard Worker   }
409*795d594fSAndroid Build Coastguard Worker 
410*795d594fSAndroid Build Coastguard Worker   // Override this function to create your own arguments.
411*795d594fSAndroid Build Coastguard Worker   // Usually will want to return a subtype of CmdlineArgs.
CreateArgumentsCmdlineMain412*795d594fSAndroid Build Coastguard Worker   virtual Args* CreateArguments() {
413*795d594fSAndroid Build Coastguard Worker     return new Args();
414*795d594fSAndroid Build Coastguard Worker   }
415*795d594fSAndroid Build Coastguard Worker 
416*795d594fSAndroid Build Coastguard Worker   // Override this function to do something else with the runtime.
ExecuteWithRuntimeCmdlineMain417*795d594fSAndroid Build Coastguard Worker   virtual bool ExecuteWithRuntime(Runtime* runtime) {
418*795d594fSAndroid Build Coastguard Worker     CHECK(runtime != nullptr);
419*795d594fSAndroid Build Coastguard Worker     // Do nothing
420*795d594fSAndroid Build Coastguard Worker     return true;
421*795d594fSAndroid Build Coastguard Worker   }
422*795d594fSAndroid Build Coastguard Worker 
423*795d594fSAndroid Build Coastguard Worker   // Does the code execution need a runtime? Sometimes it doesn't.
NeedsRuntimeCmdlineMain424*795d594fSAndroid Build Coastguard Worker   virtual bool NeedsRuntime() {
425*795d594fSAndroid Build Coastguard Worker     return true;
426*795d594fSAndroid Build Coastguard Worker   }
427*795d594fSAndroid Build Coastguard Worker 
428*795d594fSAndroid Build Coastguard Worker   // Do execution without having created a runtime.
ExecuteWithoutRuntimeCmdlineMain429*795d594fSAndroid Build Coastguard Worker   virtual bool ExecuteWithoutRuntime() {
430*795d594fSAndroid Build Coastguard Worker     return true;
431*795d594fSAndroid Build Coastguard Worker   }
432*795d594fSAndroid Build Coastguard Worker 
433*795d594fSAndroid Build Coastguard Worker   // Continue execution after ExecuteWith[out]Runtime
ExecuteCommonCmdlineMain434*795d594fSAndroid Build Coastguard Worker   virtual bool ExecuteCommon() {
435*795d594fSAndroid Build Coastguard Worker     return true;
436*795d594fSAndroid Build Coastguard Worker   }
437*795d594fSAndroid Build Coastguard Worker 
~CmdlineMainCmdlineMain438*795d594fSAndroid Build Coastguard Worker   virtual ~CmdlineMain() {}
439*795d594fSAndroid Build Coastguard Worker 
440*795d594fSAndroid Build Coastguard Worker  protected:
441*795d594fSAndroid Build Coastguard Worker   Args* args_ = nullptr;
442*795d594fSAndroid Build Coastguard Worker 
443*795d594fSAndroid Build Coastguard Worker  private:
CreateRuntimeCmdlineMain444*795d594fSAndroid Build Coastguard Worker   Runtime* CreateRuntime(CmdlineArgs* args) {
445*795d594fSAndroid Build Coastguard Worker     CHECK(args != nullptr);
446*795d594fSAndroid Build Coastguard Worker 
447*795d594fSAndroid Build Coastguard Worker     return StartRuntime(args->boot_image_locations_, args->instruction_set_, args_->runtime_args_);
448*795d594fSAndroid Build Coastguard Worker   }
449*795d594fSAndroid Build Coastguard Worker };
450*795d594fSAndroid Build Coastguard Worker }  // namespace art
451*795d594fSAndroid Build Coastguard Worker 
452*795d594fSAndroid Build Coastguard Worker #endif  // ART_CMDLINE_CMDLINE_H_
453