1 /*
2  * Copyright (C) 2011 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 "parsed_options.h"
18 
19 #include <memory>
20 #include <sstream>
21 
22 #include <android-base/logging.h>
23 #include <android-base/strings.h>
24 
25 #include "base/file_utils.h"
26 #include "base/flags.h"
27 #include "base/indenter.h"
28 #include "base/macros.h"
29 #include "base/utils.h"
30 #include "debugger.h"
31 #include "gc/heap.h"
32 #include "jni_id_type.h"
33 #include "monitor.h"
34 #include "runtime.h"
35 #include "ti/agent.h"
36 #include "trace.h"
37 
38 #include "cmdline_parser.h"
39 #include "runtime_options.h"
40 
41 namespace art {
42 
43 using MemoryKiB = Memory<1024>;
44 
ParsedOptions()45 ParsedOptions::ParsedOptions()
46   : hook_is_sensitive_thread_(nullptr),
47     hook_vfprintf_(vfprintf),
48     hook_exit_(exit),
49     hook_abort_(nullptr) {                          // We don't call abort(3) by default; see
50                                                     // Runtime::Abort
51 }
52 
Parse(const RuntimeOptions & options,bool ignore_unrecognized,RuntimeArgumentMap * runtime_options)53 bool ParsedOptions::Parse(const RuntimeOptions& options,
54                           bool ignore_unrecognized,
55                           RuntimeArgumentMap* runtime_options) {
56   CHECK(runtime_options != nullptr);
57 
58   ParsedOptions parser;
59   return parser.DoParse(options, ignore_unrecognized, runtime_options);
60 }
61 
62 using RuntimeParser = CmdlineParser<RuntimeArgumentMap, RuntimeArgumentMap::Key>;
63 using HiddenapiPolicyValueMap =
64     std::initializer_list<std::pair<const char*, hiddenapi::EnforcementPolicy>>;
65 
66 // Yes, the stack frame is huge. But we get called super early on (and just once)
67 // to pass the command line arguments, so we'll probably be ok.
68 // Ideas to avoid suppressing this diagnostic are welcome!
69 #pragma GCC diagnostic push
70 #pragma GCC diagnostic ignored "-Wframe-larger-than="
71 
MakeParser(bool ignore_unrecognized)72 std::unique_ptr<RuntimeParser> ParsedOptions::MakeParser(bool ignore_unrecognized) {
73   using M = RuntimeArgumentMap;
74 
75   std::unique_ptr<RuntimeParser::Builder> parser_builder =
76       std::make_unique<RuntimeParser::Builder>();
77 
78   HiddenapiPolicyValueMap hiddenapi_policy_valuemap =
79       {{"disabled",  hiddenapi::EnforcementPolicy::kDisabled},
80        {"just-warn", hiddenapi::EnforcementPolicy::kJustWarn},
81        {"enabled",   hiddenapi::EnforcementPolicy::kEnabled}};
82   DCHECK_EQ(hiddenapi_policy_valuemap.size(),
83             static_cast<size_t>(hiddenapi::EnforcementPolicy::kMax) + 1);
84 
85   parser_builder->
86        SetCategory("standard")
87       .Define({"-classpath _", "-cp _"})
88           .WithHelp("The classpath, separated by ':'")
89           .WithType<std::string>()
90           .IntoKey(M::ClassPath)
91       .Define("-D_")
92           .WithType<std::vector<std::string>>().AppendValues()
93           .IntoKey(M::PropertiesList)
94       .Define("-verbose:_")
95           .WithHelp("Switches for advanced logging. Multiple categories can be enabled separated by ','. Eg: -verbose:class,deopt")
96           .WithType<LogVerbosity>()
97           .IntoKey(M::Verbose)
98       .Define({"-help", "-h"})
99           .WithHelp("Print this help text.")
100           .IntoKey(M::Help)
101       .Define("-showversion")
102           .IntoKey(M::ShowVersion)
103       // TODO Re-enable -agentlib: once I have a good way to transform the values.
104       // .Define("-agentlib:_")
105       //     .WithType<std::vector<ti::Agent>>().AppendValues()
106       //     .IntoKey(M::AgentLib)
107       .Define("-agentpath:_")
108           .WithHelp("Load native agents.")
109           .WithType<std::list<ti::AgentSpec>>().AppendValues()
110           .IntoKey(M::AgentPath)
111       .SetCategory("extended")
112       .Define("-Xbootclasspath:_")
113           .WithType<ParseStringList<':'>>()  // std::vector<std::string>, split by :
114           .IntoKey(M::BootClassPath)
115       .Define("-Xcheck:jni")
116           .IntoKey(M::CheckJni)
117       .Define("-Xms_")
118           .WithType<MemoryKiB>()
119           .IntoKey(M::MemoryInitialSize)
120       .Define("-Xmx_")
121           .WithType<MemoryKiB>()
122           .IntoKey(M::MemoryMaximumSize)
123       .Define("-Xss_")
124           .WithType<Memory<1>>()
125           .IntoKey(M::StackSize)
126       .Define("-Xint")
127           .WithValue(true)
128           .IntoKey(M::Interpret)
129       .SetCategory("Dalvik")
130       .Define("-Xzygote")
131           .WithHelp("Start as zygote")
132           .IntoKey(M::Zygote)
133       .Define("-Xjnitrace:_")
134           .WithType<std::string>()
135           .IntoKey(M::JniTrace)
136       .Define("-Xgc:_")
137           .WithType<XGcOption>()
138           .IntoKey(M::GcOption)
139       .Define("-XX:HeapGrowthLimit=_")
140           .WithType<MemoryKiB>()
141           .IntoKey(M::HeapGrowthLimit)
142       .Define("-XX:HeapMinFree=_")
143           .WithType<MemoryKiB>()
144           .IntoKey(M::HeapMinFree)
145       .Define("-XX:HeapMaxFree=_")
146           .WithType<MemoryKiB>()
147           .IntoKey(M::HeapMaxFree)
148       .Define("-XX:NonMovingSpaceCapacity=_")
149           .WithType<MemoryKiB>()
150           .IntoKey(M::NonMovingSpaceCapacity)
151       .Define("-XX:HeapTargetUtilization=_")
152           .WithType<double>().WithRange(0.1, 0.9)
153           .IntoKey(M::HeapTargetUtilization)
154       .Define("-XX:ForegroundHeapGrowthMultiplier=_")
155           .WithType<double>().WithRange(0.1, 5.0)
156           .IntoKey(M::ForegroundHeapGrowthMultiplier)
157       .Define("-XX:LowMemoryMode")
158           .IntoKey(M::LowMemoryMode)
159       .Define("-Xprofile:_")
160           .WithType<TraceClockSource>()
161           .WithValueMap({{"threadcpuclock", TraceClockSource::kThreadCpu},
162                          {"wallclock",      TraceClockSource::kWall},
163                          {"dualclock",      TraceClockSource::kDual}})
164           .IntoKey(M::ProfileClock)
165       .Define("-Xjitthreshold:_")
166           .WithType<unsigned int>()
167           .IntoKey(M::JITCompileThreshold)
168       .SetCategory("ART")
169       .Define("-Ximage:_")
170           .WithType<std::string>()
171           .IntoKey(M::Image)
172       .Define("-Xprimaryzygote")
173           .IntoKey(M::PrimaryZygote)
174       .Define("-Xbootclasspath-locations:_")
175           .WithType<ParseStringList<':'>>()  // std::vector<std::string>, split by :
176           .IntoKey(M::BootClassPathLocations)
177       .Define("-Xjniopts:forcecopy")
178           .IntoKey(M::JniOptsForceCopy)
179       .Define("-XjdwpProvider:_")
180           .WithType<JdwpProvider>()
181           .IntoKey(M::JdwpProvider)
182       .Define("-XjdwpOptions:_")
183           .WithMetavar("OPTION[,OPTION...]")
184           .WithHelp("JDWP options. Eg suspend=n,server=y.")
185           .WithType<std::string>()
186           .IntoKey(M::JdwpOptions)
187       .Define("-XX:StopForNativeAllocs=_")
188           .WithType<MemoryKiB>()
189           .IntoKey(M::StopForNativeAllocs)
190       .Define("-XX:ParallelGCThreads=_")
191           .WithType<unsigned int>()
192           .IntoKey(M::ParallelGCThreads)
193       .Define("-XX:ConcGCThreads=_")
194           .WithType<unsigned int>()
195           .IntoKey(M::ConcGCThreads)
196       .Define("-XX:FinalizerTimeoutMs=_")
197           .WithType<unsigned int>()
198           .IntoKey(M::FinalizerTimeoutMs)
199       .Define("-XX:MaxSpinsBeforeThinLockInflation=_")
200           .WithType<unsigned int>()
201           .IntoKey(M::MaxSpinsBeforeThinLockInflation)
202       .Define("-XX:LongPauseLogThreshold=_")  // in ms
203           .WithType<MillisecondsToNanoseconds>()  // store as ns
204           .IntoKey(M::LongPauseLogThreshold)
205       .Define("-XX:LongGCLogThreshold=_")  // in ms
206           .WithType<MillisecondsToNanoseconds>()  // store as ns
207           .IntoKey(M::LongGCLogThreshold)
208       .Define("-XX:DumpGCPerformanceOnShutdown")
209           .IntoKey(M::DumpGCPerformanceOnShutdown)
210       .Define("-XX:DumpRegionInfoBeforeGC")
211           .IntoKey(M::DumpRegionInfoBeforeGC)
212       .Define("-XX:DumpRegionInfoAfterGC")
213           .IntoKey(M::DumpRegionInfoAfterGC)
214       .Define("-XX:DumpJITInfoOnShutdown")
215           .IntoKey(M::DumpJITInfoOnShutdown)
216       .Define("-XX:IgnoreMaxFootprint")
217           .IntoKey(M::IgnoreMaxFootprint)
218       .Define("-XX:AlwaysLogExplicitGcs:_")
219           .WithHelp("Allows one to control the logging of explicit GCs. Defaults to 'true'")
220           .WithType<bool>()
221           .WithValueMap({{"false", false}, {"true", true}})
222           .IntoKey(M::AlwaysLogExplicitGcs)
223       .Define("-XX:UseTLAB")
224           .WithValue(true)
225           .IntoKey(M::UseTLAB)
226       .Define({"-XX:EnableHSpaceCompactForOOM", "-XX:DisableHSpaceCompactForOOM"})
227           .WithValues({true, false})
228           .IntoKey(M::EnableHSpaceCompactForOOM)
229       .Define("-XX:DumpNativeStackOnSigQuit:_")
230           .WithType<bool>()
231           .WithValueMap({{"false", false}, {"true", true}})
232           .IntoKey(M::DumpNativeStackOnSigQuit)
233       .Define("-XX:MadviseRandomAccess:_")
234           .WithType<bool>()
235           .WithValueMap({{"false", false}, {"true", true}})
236           .IntoKey(M::MadviseRandomAccess)
237       .Define("-XMadviseWillNeedVdexFileSize:_")
238           .WithType<unsigned int>()
239           .IntoKey(M::MadviseWillNeedVdexFileSize)
240       .Define("-XMadviseWillNeedOdexFileSize:_")
241           .WithType<unsigned int>()
242           .IntoKey(M::MadviseWillNeedOdexFileSize)
243       .Define("-XMadviseWillNeedArtFileSize:_")
244           .WithType<unsigned int>()
245           .IntoKey(M::MadviseWillNeedArtFileSize)
246       .Define("-Xusejit:_")
247           .WithType<bool>()
248           .WithValueMap({{"false", false}, {"true", true}})
249           .IntoKey(M::UseJitCompilation)
250       .Define("-Xuseprofiledjit:_")
251           .WithType<bool>()
252           .WithValueMap({{"false", false}, {"true", true}})
253           .IntoKey(M::UseProfiledJitCompilation)
254       .Define("-Xjitinitialsize:_")
255           .WithType<MemoryKiB>()
256           .IntoKey(M::JITCodeCacheInitialCapacity)
257       .Define("-Xjitmaxsize:_")
258           .WithType<MemoryKiB>()
259           .IntoKey(M::JITCodeCacheMaxCapacity)
260       .Define("-Xjitwarmupthreshold:_")
261           .WithType<unsigned int>()
262           .IntoKey(M::JITWarmupThreshold)
263       .Define("-Xjitosrthreshold:_")
264           .WithType<unsigned int>()
265           .IntoKey(M::JITOsrThreshold)
266       .Define("-Xjitprithreadweight:_")
267           .WithType<unsigned int>()
268           .IntoKey(M::JITPriorityThreadWeight)
269       .Define("-Xjittransitionweight:_")
270           .WithType<unsigned int>()
271           .IntoKey(M::JITInvokeTransitionWeight)
272       .Define("-Xjitpthreadpriority:_")
273           .WithType<int>()
274           .IntoKey(M::JITPoolThreadPthreadPriority)
275       .Define("-Xjitzygotepthreadpriority:_")
276           .WithType<int>()
277           .IntoKey(M::JITZygotePoolThreadPthreadPriority)
278       .Define("-Xjitsaveprofilinginfo")
279           .WithType<ProfileSaverOptions>()
280           .AppendValues()
281           .IntoKey(M::ProfileSaverOpts)
282       // .Define("-Xps-_")  // profile saver options -Xps-<key>:<value>
283       //     .WithType<ProfileSaverOptions>()
284       //     .AppendValues()
285       //     .IntoKey(M::ProfileSaverOpts)  // NOTE: Appends into same key as -Xjitsaveprofilinginfo
286       // profile saver options -Xps-<key>:<value> but are split-out for better help messages.
287       // The order of these is important. We want the wildcard one to be the
288       // only one actually matched so it needs to be first.
289       // TODO This should be redone.
290       .Define({"-Xps-_",
291                "-Xps-min-save-period-ms:_",
292                "-Xps-min-first-save-ms:_",
293                "-Xps-save-resolved-classes-delayed-ms:_",
294                "-Xps-hot-startup-method-samples:_",
295                "-Xps-min-methods-to-save:_",
296                "-Xps-min-classes-to-save:_",
297                "-Xps-min-notification-before-wake:_",
298                "-Xps-max-notification-before-wake:_",
299                "-Xps-profile-path:_"})
300           .WithHelp("profile-saver options -Xps-<key>:<value>")
301           .WithType<ProfileSaverOptions>()
302           .AppendValues()
303           .IntoKey(M::ProfileSaverOpts)  // NOTE: Appends into same key as -Xjitsaveprofilinginfo
304       .Define("-XX:HspaceCompactForOOMMinIntervalMs=_")  // in ms
305           .WithType<MillisecondsToNanoseconds>()  // store as ns
306           .IntoKey(M::HSpaceCompactForOOMMinIntervalsMs)
307       .Define({"-Xrelocate", "-Xnorelocate"})
308           .WithValues({true, false})
309           .IntoKey(M::Relocate)
310       .Define({"-Ximage-dex2oat", "-Xnoimage-dex2oat"})
311           .WithValues({true, false})
312           .IntoKey(M::ImageDex2Oat)
313       .Define("-XX:LargeObjectSpace=_")
314           .WithType<gc::space::LargeObjectSpaceType>()
315           .WithValueMap({{"disabled", gc::space::LargeObjectSpaceType::kDisabled},
316                          {"freelist", gc::space::LargeObjectSpaceType::kFreeList},
317                          {"map",      gc::space::LargeObjectSpaceType::kMap}})
318           .IntoKey(M::LargeObjectSpace)
319       .Define("-XX:LargeObjectThreshold=_")
320           .WithType<Memory<1>>()
321           .IntoKey(M::LargeObjectThreshold)
322       .Define("-XX:BackgroundGC=_")
323           .WithType<BackgroundGcOption>()
324           .IntoKey(M::BackgroundGc)
325       .Define("-XX:+DisableExplicitGC")
326           .IntoKey(M::DisableExplicitGC)
327       .Define("-Xlockprofthreshold:_")
328           .WithType<unsigned int>()
329           .IntoKey(M::LockProfThreshold)
330       .Define("-Xstackdumplockprofthreshold:_")
331           .WithType<unsigned int>()
332           .IntoKey(M::StackDumpLockProfThreshold)
333       .Define("-Xmethod-trace")
334           .IntoKey(M::MethodTrace)
335       .Define("-Xmethod-trace-file:_")
336           .WithType<std::string>()
337           .IntoKey(M::MethodTraceFile)
338       .Define("-Xmethod-trace-file-size:_")
339           .WithType<unsigned int>()
340           .IntoKey(M::MethodTraceFileSize)
341       .Define("-Xmethod-trace-stream")
342           .IntoKey(M::MethodTraceStreaming)
343       .Define("-Xcompiler:_")
344           .WithType<std::string>()
345           .IntoKey(M::Compiler)
346       .Define("-Xcompiler-option _")
347           .WithType<std::vector<std::string>>()
348           .AppendValues()
349           .IntoKey(M::CompilerOptions)
350       .Define("-Ximage-compiler-option _")
351           .WithType<std::vector<std::string>>()
352           .AppendValues()
353           .IntoKey(M::ImageCompilerOptions)
354       .Define("-Xverify:_")
355           .WithType<verifier::VerifyMode>()
356           .WithValueMap({{"none",     verifier::VerifyMode::kNone},
357                          {"remote",   verifier::VerifyMode::kEnable},
358                          {"all",      verifier::VerifyMode::kEnable},
359                          {"softfail", verifier::VerifyMode::kSoftFail}})
360           .IntoKey(M::Verify)
361       .Define("-XX:NativeBridge=_")
362           .WithType<std::string>()
363           .IntoKey(M::NativeBridge)
364       .Define("-Xzygote-max-boot-retry=_")
365           .WithType<unsigned int>()
366           .IntoKey(M::ZygoteMaxFailedBoots)
367       .Define("-Xno-sig-chain")
368           .IntoKey(M::NoSigChain)
369       .Define("--cpu-abilist=_")
370           .WithType<std::string>()
371           .IntoKey(M::CpuAbiList)
372       .Define("-Xfingerprint:_")
373           .WithType<std::string>()
374           .IntoKey(M::Fingerprint)
375       .Define("-Xexperimental:_")
376           .WithType<ExperimentalFlags>()
377           .AppendValues()
378           .IntoKey(M::Experimental)
379       .Define("-Xforce-nb-testing")
380           .IntoKey(M::ForceNativeBridge)
381       .Define("-Xplugin:_")
382           .WithHelp("Load and initialize the specified art-plugin.")
383           .WithType<std::vector<Plugin>>().AppendValues()
384           .IntoKey(M::Plugins)
385       .Define("-XX:ThreadSuspendTimeout=_")  // in ms
386           .WithType<MillisecondsToNanoseconds>()  // store as ns
387           .IntoKey(M::ThreadSuspendTimeout)
388       .Define("-XX:MonitorTimeoutEnable=_")
389           .WithType<bool>()
390           .WithValueMap({{"false", false}, {"true", true}})
391           .IntoKey(M::MonitorTimeoutEnable)
392       .Define("-XX:MonitorTimeout=_")  // in ms
393           .WithType<int>()
394           .IntoKey(M::MonitorTimeout)
395       .Define("-XX:GlobalRefAllocStackTraceLimit=_")  // Number of free slots to enable tracing.
396           .WithType<unsigned int>()
397           .IntoKey(M::GlobalRefAllocStackTraceLimit)
398       .Define("-XX:SlowDebug=_")
399           .WithType<bool>()
400           .WithValueMap({{"false", false}, {"true", true}})
401           .IntoKey(M::SlowDebug)
402       .Define("-Xtarget-sdk-version:_")
403           .WithType<unsigned int>()
404           .IntoKey(M::TargetSdkVersion)
405       .Define("-Xhidden-api-policy:_")
406           .WithType<hiddenapi::EnforcementPolicy>()
407           .WithValueMap(hiddenapi_policy_valuemap)
408           .IntoKey(M::HiddenApiPolicy)
409       .Define("-Xcore-platform-api-policy:_")
410           .WithType<hiddenapi::EnforcementPolicy>()
411           .WithValueMap(hiddenapi_policy_valuemap)
412           .IntoKey(M::CorePlatformApiPolicy)
413       .Define("-Xuse-stderr-logger")
414           .IntoKey(M::UseStderrLogger)
415       .Define("-Xonly-use-system-oat-files")
416           .IntoKey(M::OnlyUseTrustedOatFiles)
417       .Define("-Xdeny-art-apex-data-files")
418           .IntoKey(M::DenyArtApexDataFiles)
419       .Define("-Xverifier-logging-threshold=_")
420           .WithType<unsigned int>()
421           .IntoKey(M::VerifierLoggingThreshold)
422       .Define("-XX:FastClassNotFoundException=_")
423           .WithType<bool>()
424           .WithValueMap({{"false", false}, {"true", true}})
425           .IntoKey(M::FastClassNotFoundException)
426       .Define("-Xopaque-jni-ids:_")
427           .WithHelp("Control the representation of jmethodID and jfieldID values")
428           .WithType<JniIdType>()
429           .WithValueMap({{"true", JniIdType::kIndices},
430                          {"false", JniIdType::kPointer},
431                          {"swapable", JniIdType::kSwapablePointer},
432                          {"pointer", JniIdType::kPointer},
433                          {"indices", JniIdType::kIndices},
434                          {"default", JniIdType::kDefault}})
435           .IntoKey(M::OpaqueJniIds)
436       .Define("-Xauto-promote-opaque-jni-ids:_")
437           .WithType<bool>()
438           .WithValueMap({{"true", true}, {"false", false}})
439           .IntoKey(M::AutoPromoteOpaqueJniIds)
440       .Define("-XX:VerifierMissingKThrowFatal=_")
441           .WithType<bool>()
442           .WithValueMap({{"false", false}, {"true", true}})
443           .IntoKey(M::VerifierMissingKThrowFatal)
444       .Define("-XX:ForceJavaZygoteForkLoop=_")
445           .WithType<bool>()
446           .WithValueMap({{"false", false}, {"true", true}})
447           .IntoKey(M::ForceJavaZygoteForkLoop)
448       .Define("-XX:PerfettoHprof=_")
449           .WithType<bool>()
450           .WithValueMap({{"false", false}, {"true", true}})
451           .IntoKey(M::PerfettoHprof)
452       .Define("-XX:PerfettoJavaHeapStackProf=_")
453           .WithType<bool>()
454           .WithValueMap({{"false", false}, {"true", true}})
455           .IntoKey(M::PerfettoJavaHeapStackProf);
456 
457       FlagBase::AddFlagsToCmdlineParser(parser_builder.get());
458 
459       parser_builder->Ignore({
460           "-ea", "-da", "-enableassertions", "-disableassertions", "--runtime-arg", "-esa",
461           "-dsa", "-enablesystemassertions", "-disablesystemassertions", "-Xrs", "-Xint:_",
462           "-Xdexopt:_", "-Xnoquithandler", "-Xjnigreflimit:_", "-Xgenregmap", "-Xnogenregmap",
463           "-Xverifyopt:_", "-Xcheckdexsum", "-Xincludeselectedop", "-Xjitop:_",
464           "-Xincludeselectedmethod",
465           "-Xjitblocking", "-Xjitmethod:_", "-Xjitclass:_", "-Xjitoffset:_",
466           "-Xjitconfig:_", "-Xjitcheckcg", "-Xjitverbose", "-Xjitprofile",
467           "-Xjitdisableopt", "-Xjitsuspendpoll", "-XX:mainThreadStackSize=_"})
468       .IgnoreUnrecognized(ignore_unrecognized)
469       .OrderCategories({"standard", "extended", "Dalvik", "ART"});
470 
471   // TODO: Move Usage information into this DSL.
472 
473   return std::make_unique<RuntimeParser>(parser_builder->Build());
474 }
475 
476 #pragma GCC diagnostic pop
477 
478 // Remove all the special options that have something in the void* part of the option.
479 // If runtime_options is not null, put the options in there.
480 // As a side-effect, populate the hooks from options.
ProcessSpecialOptions(const RuntimeOptions & options,RuntimeArgumentMap * runtime_options,std::vector<std::string> * out_options)481 bool ParsedOptions::ProcessSpecialOptions(const RuntimeOptions& options,
482                                           RuntimeArgumentMap* runtime_options,
483                                           std::vector<std::string>* out_options) {
484   using M = RuntimeArgumentMap;
485 
486   // TODO: Move the below loop into JNI
487   // Handle special options that set up hooks
488   for (size_t i = 0; i < options.size(); ++i) {
489     const std::string option(options[i].first);
490       // TODO: support -Djava.class.path
491     if (option == "bootclasspath") {
492       auto boot_class_path = static_cast<std::vector<std::unique_ptr<const DexFile>>*>(
493           const_cast<void*>(options[i].second));
494 
495       if (runtime_options != nullptr) {
496         runtime_options->Set(M::BootClassPathDexList, boot_class_path);
497       }
498     } else if (option == "compilercallbacks") {
499       CompilerCallbacks* compiler_callbacks =
500           reinterpret_cast<CompilerCallbacks*>(const_cast<void*>(options[i].second));
501       if (runtime_options != nullptr) {
502         runtime_options->Set(M::CompilerCallbacksPtr, compiler_callbacks);
503       }
504     } else if (option == "imageinstructionset") {
505       const char* isa_str = reinterpret_cast<const char*>(options[i].second);
506       auto&& image_isa = GetInstructionSetFromString(isa_str);
507       if (image_isa == InstructionSet::kNone) {
508         Usage("%s is not a valid instruction set.", isa_str);
509         return false;
510       }
511       if (runtime_options != nullptr) {
512         runtime_options->Set(M::ImageInstructionSet, image_isa);
513       }
514     } else if (option == "sensitiveThread") {
515       const void* hook = options[i].second;
516       bool (*hook_is_sensitive_thread)() = reinterpret_cast<bool (*)()>(const_cast<void*>(hook));
517 
518       if (runtime_options != nullptr) {
519         runtime_options->Set(M::HookIsSensitiveThread, hook_is_sensitive_thread);
520       }
521     } else if (option == "vfprintf") {
522       const void* hook = options[i].second;
523       if (hook == nullptr) {
524         Usage("vfprintf argument was nullptr");
525         return false;
526       }
527       int (*hook_vfprintf)(FILE *, const char*, va_list) =
528           reinterpret_cast<int (*)(FILE *, const char*, va_list)>(const_cast<void*>(hook));
529 
530       if (runtime_options != nullptr) {
531         runtime_options->Set(M::HookVfprintf, hook_vfprintf);
532       }
533       hook_vfprintf_ = hook_vfprintf;
534     } else if (option == "exit") {
535       const void* hook = options[i].second;
536       if (hook == nullptr) {
537         Usage("exit argument was nullptr");
538         return false;
539       }
540       void(*hook_exit)(jint) = reinterpret_cast<void(*)(jint)>(const_cast<void*>(hook));
541       if (runtime_options != nullptr) {
542         runtime_options->Set(M::HookExit, hook_exit);
543       }
544       hook_exit_ = hook_exit;
545     } else if (option == "abort") {
546       const void* hook = options[i].second;
547       if (hook == nullptr) {
548         Usage("abort was nullptr\n");
549         return false;
550       }
551       void(*hook_abort)() = reinterpret_cast<void(*)()>(const_cast<void*>(hook));
552       if (runtime_options != nullptr) {
553         runtime_options->Set(M::HookAbort, hook_abort);
554       }
555       hook_abort_ = hook_abort;
556     } else {
557       // It is a regular option, that doesn't have a known 'second' value.
558       // Push it on to the regular options which will be parsed by our parser.
559       if (out_options != nullptr) {
560         out_options->push_back(option);
561       }
562     }
563   }
564 
565   return true;
566 }
567 
568 // Intended for local changes only.
MaybeOverrideVerbosity()569 static void MaybeOverrideVerbosity() {
570   //  gLogVerbosity.class_linker = true;  // TODO: don't check this in!
571   //  gLogVerbosity.collector = true;  // TODO: don't check this in!
572   //  gLogVerbosity.compiler = true;  // TODO: don't check this in!
573   //  gLogVerbosity.deopt = true;  // TODO: don't check this in!
574   //  gLogVerbosity.gc = true;  // TODO: don't check this in!
575   //  gLogVerbosity.heap = true;  // TODO: don't check this in!
576   //  gLogVerbosity.image = true;  // TODO: don't check this in!
577   //  gLogVerbosity.interpreter = true;  // TODO: don't check this in!
578   //  gLogVerbosity.jdwp = true;  // TODO: don't check this in!
579   //  gLogVerbosity.jit = true;  // TODO: don't check this in!
580   //  gLogVerbosity.jni = true;  // TODO: don't check this in!
581   //  gLogVerbosity.monitor = true;  // TODO: don't check this in!
582   //  gLogVerbosity.oat = true;  // TODO: don't check this in!
583   //  gLogVerbosity.profiler = true;  // TODO: don't check this in!
584   //  gLogVerbosity.signals = true;  // TODO: don't check this in!
585   //  gLogVerbosity.simulator = true; // TODO: don't check this in!
586   //  gLogVerbosity.startup = true;  // TODO: don't check this in!
587   //  gLogVerbosity.third_party_jni = true;  // TODO: don't check this in!
588   //  gLogVerbosity.threads = true;  // TODO: don't check this in!
589   //  gLogVerbosity.verifier = true;  // TODO: don't check this in!
590 }
591 
DoParse(const RuntimeOptions & options,bool ignore_unrecognized,RuntimeArgumentMap * runtime_options)592 bool ParsedOptions::DoParse(const RuntimeOptions& options,
593                             bool ignore_unrecognized,
594                             RuntimeArgumentMap* runtime_options) {
595   for (size_t i = 0; i < options.size(); ++i) {
596     if (true && options[0].first == "-Xzygote") {
597       LOG(INFO) << "option[" << i << "]=" << options[i].first;
598     }
599   }
600 
601   auto parser = MakeParser(ignore_unrecognized);
602 
603   // Convert to a simple string list (without the magic pointer options)
604   std::vector<std::string> argv_list;
605   if (!ProcessSpecialOptions(options, nullptr, &argv_list)) {
606     return false;
607   }
608 
609   CmdlineResult parse_result = parser->Parse(argv_list);
610 
611   // Handle parse errors by displaying the usage and potentially exiting.
612   if (parse_result.IsError()) {
613     if (parse_result.GetStatus() == CmdlineResult::kUsage) {
614       UsageMessage(stdout, "%s\n", parse_result.GetMessage().c_str());
615       Exit(0);
616     } else if (parse_result.GetStatus() == CmdlineResult::kUnknown && !ignore_unrecognized) {
617       Usage("%s\n", parse_result.GetMessage().c_str());
618       return false;
619     } else {
620       Usage("%s\n", parse_result.GetMessage().c_str());
621       Exit(0);
622     }
623 
624     UNREACHABLE();
625   }
626 
627   using M = RuntimeArgumentMap;
628   RuntimeArgumentMap args = parser->ReleaseArgumentsMap();
629 
630   // -help, -showversion, etc.
631   if (args.Exists(M::Help)) {
632     Usage(nullptr);
633     return false;
634   } else if (args.Exists(M::ShowVersion)) {
635     UsageMessage(stdout,
636                  "ART version %s %s\n",
637                  Runtime::GetVersion(),
638                  GetInstructionSetString(kRuntimeISA));
639     Exit(0);
640   } else if (args.Exists(M::BootClassPath)) {
641     LOG(INFO) << "setting boot class path to " << args.Get(M::BootClassPath)->Join();
642   }
643 
644   if (args.GetOrDefault(M::Interpret)) {
645     if (args.Exists(M::UseJitCompilation) && *args.Get(M::UseJitCompilation)) {
646       Usage("-Xusejit:true and -Xint cannot be specified together\n");
647       Exit(0);
648     }
649     args.Set(M::UseJitCompilation, false);
650   }
651 
652   // Set a default boot class path if we didn't get an explicit one via command line.
653   const char* env_bcp = getenv("BOOTCLASSPATH");
654   if (env_bcp != nullptr) {
655     args.SetIfMissing(M::BootClassPath, ParseStringList<':'>::Split(env_bcp));
656   }
657 
658   // Set a default class path if we didn't get an explicit one via command line.
659   if (getenv("CLASSPATH") != nullptr) {
660     args.SetIfMissing(M::ClassPath, std::string(getenv("CLASSPATH")));
661   }
662 
663   // Default to number of processors minus one since the main GC thread also does work.
664   args.SetIfMissing(M::ParallelGCThreads, gc::Heap::kDefaultEnableParallelGC ?
665       static_cast<unsigned int>(sysconf(_SC_NPROCESSORS_CONF) - 1u) : 0u);
666 
667   // -verbose:
668   {
669     LogVerbosity *log_verbosity = args.Get(M::Verbose);
670     if (log_verbosity != nullptr) {
671       gLogVerbosity = *log_verbosity;
672     }
673   }
674 
675   MaybeOverrideVerbosity();
676 
677   SetRuntimeDebugFlagsEnabled(args.GetOrDefault(M::SlowDebug));
678 
679   // -Xprofile:
680   Trace::SetDefaultClockSource(args.GetOrDefault(M::ProfileClock));
681 
682   if (!ProcessSpecialOptions(options, &args, nullptr)) {
683       return false;
684   }
685 
686   {
687     // If not set, background collector type defaults to homogeneous compaction.
688     // If not low memory mode, semispace otherwise.
689 
690     gc::CollectorType background_collector_type_;
691     gc::CollectorType collector_type_ = (XGcOption{}).collector_type_;
692     bool low_memory_mode_ = args.Exists(M::LowMemoryMode);
693 
694     background_collector_type_ = args.GetOrDefault(M::BackgroundGc);
695     {
696       XGcOption* xgc = args.Get(M::GcOption);
697       if (xgc != nullptr && xgc->collector_type_ != gc::kCollectorTypeNone) {
698         collector_type_ = xgc->collector_type_;
699       }
700     }
701 
702     if (background_collector_type_ == gc::kCollectorTypeNone) {
703       background_collector_type_ = low_memory_mode_ ?
704           gc::kCollectorTypeSS : gc::kCollectorTypeHomogeneousSpaceCompact;
705     }
706 
707     args.Set(M::BackgroundGc, BackgroundGcOption { background_collector_type_ });
708   }
709 
710   const ParseStringList<':'>* boot_class_path_locations = args.Get(M::BootClassPathLocations);
711   if (boot_class_path_locations != nullptr && boot_class_path_locations->Size() != 0u) {
712     const ParseStringList<':'>* boot_class_path = args.Get(M::BootClassPath);
713     if (boot_class_path == nullptr ||
714         boot_class_path_locations->Size() != boot_class_path->Size()) {
715       Usage("The number of boot class path files does not match"
716           " the number of boot class path locations given\n"
717           "  boot class path files     (%zu): %s\n"
718           "  boot class path locations (%zu): %s\n",
719           (boot_class_path != nullptr) ? boot_class_path->Size() : 0u,
720           (boot_class_path != nullptr) ? boot_class_path->Join().c_str() : "<nil>",
721           boot_class_path_locations->Size(),
722           boot_class_path_locations->Join().c_str());
723       return false;
724     }
725   }
726 
727   if (!args.Exists(M::CompilerCallbacksPtr) && !args.Exists(M::Image)) {
728     const bool deny_art_apex_data_files = args.Exists(M::DenyArtApexDataFiles);
729     std::string image =
730         GetDefaultBootImageLocation(GetAndroidRoot(), deny_art_apex_data_files);
731     args.Set(M::Image, image);
732   }
733 
734   // 0 means no growth limit, and growth limit should be always <= heap size
735   if (args.GetOrDefault(M::HeapGrowthLimit) <= 0u ||
736       args.GetOrDefault(M::HeapGrowthLimit) > args.GetOrDefault(M::MemoryMaximumSize)) {
737     args.Set(M::HeapGrowthLimit, args.GetOrDefault(M::MemoryMaximumSize));
738   }
739 
740   *runtime_options = std::move(args);
741   return true;
742 }
743 
Exit(int status)744 void ParsedOptions::Exit(int status) {
745   hook_exit_(status);
746 }
747 
Abort()748 void ParsedOptions::Abort() {
749   hook_abort_();
750 }
751 
UsageMessageV(FILE * stream,const char * fmt,va_list ap)752 void ParsedOptions::UsageMessageV(FILE* stream, const char* fmt, va_list ap) {
753   hook_vfprintf_(stream, fmt, ap);
754 }
755 
UsageMessage(FILE * stream,const char * fmt,...)756 void ParsedOptions::UsageMessage(FILE* stream, const char* fmt, ...) {
757   va_list ap;
758   va_start(ap, fmt);
759   UsageMessageV(stream, fmt, ap);
760   va_end(ap);
761 }
762 
Usage(const char * fmt,...)763 void ParsedOptions::Usage(const char* fmt, ...) {
764   bool error = (fmt != nullptr);
765   FILE* stream = error ? stderr : stdout;
766 
767   if (fmt != nullptr) {
768     va_list ap;
769     va_start(ap, fmt);
770     UsageMessageV(stream, fmt, ap);
771     va_end(ap);
772   }
773 
774   const char* program = "dalvikvm";
775   UsageMessage(stream, "%s: [options] class [argument ...]\n", program);
776   UsageMessage(stream, "\n");
777 
778   std::stringstream oss;
779   VariableIndentationOutputStream vios(&oss);
780   auto parser = MakeParser(false);
781   parser->DumpHelp(vios);
782   UsageMessage(stream, oss.str().c_str());
783   Exit((error) ? 1 : 0);
784 }
785 
786 }  // namespace art
787