1 /*
2  * Copyright (C) 2017 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 "dex2oat_options.h"
18 
19 #include <memory>
20 
21 #include "cmdline_parser.h"
22 #include "driver/compiler_options_map-inl.h"
23 
24 namespace art {
25 
26 template<>
27 struct CmdlineType<InstructionSet> : CmdlineTypeParser<InstructionSet> {
Parseart::CmdlineType28   Result Parse(const std::string& option) {
29     InstructionSet set = GetInstructionSetFromString(option.c_str());
30     if (set == InstructionSet::kNone) {
31       return Result::Failure(std::string("Not a valid instruction set: '") + option + "'");
32     }
33     return Result::Success(set);
34   }
35 
Nameart::CmdlineType36   static const char* Name() { return "InstructionSet"; }
DescribeTypeart::CmdlineType37   static const char* DescribeType() { return "arm|arm64|x86|x86_64|none"; }
38 };
39 
40 #define COMPILER_OPTIONS_MAP_TYPE Dex2oatArgumentMap
41 #define COMPILER_OPTIONS_MAP_KEY_TYPE Dex2oatArgumentMapKey
42 #include "driver/compiler_options_map-storage.h"
43 
44 // Specify storage for the Dex2oatOptions keys.
45 
46 #define DEX2OAT_OPTIONS_KEY(Type, Name, ...) \
47   const Dex2oatArgumentMap::Key<Type> Dex2oatArgumentMap::Name {__VA_ARGS__};
48 #include "dex2oat_options.def"
49 
50 #pragma GCC diagnostic push
51 #pragma GCC diagnostic ignored "-Wframe-larger-than="
52 
53 using M = Dex2oatArgumentMap;
54 using Parser = CmdlineParser<Dex2oatArgumentMap, Dex2oatArgumentMap::Key>;
55 using Builder = Parser::Builder;
56 
AddInputMappings(Builder & builder)57 static void AddInputMappings(Builder& builder) {
58   builder.
59       Define("--dex-file=_")
60           .WithType<std::vector<std::string>>().AppendValues()
61           .WithHelp("Specifies a .dex, .jar, or .apk file to compile.\n"
62                     "Eg: --dex-file=/system/framework/core.jar")
63           .WithMetavar("<dex-file>")
64           .IntoKey(M::DexFiles)
65       .Define("--dex-location=_")
66           .WithType<std::vector<std::string>>().AppendValues()
67           .WithMetavar("<dex-location>")
68           .WithHelp("specifies an alternative dex location to encode in the oat file for the\n"
69                     "corresponding --dex-file argument. The first --dex-location corresponds to\n"
70                     "the first --dex-file, the second to the second and so on.\n"
71                     "Eg: --dex-file=/home/build/out/system/framework/core.jar\n"
72                     "    --dex-location=/system/framework/core.jar")
73           .IntoKey(M::DexLocations)
74       .Define("--zip-fd=_")
75           .WithType<int>()
76           .WithHelp("specifies a file descriptor of a zip file containing a classes.dex file to\n"
77                     "compile. Eg: --zip-fd=5")
78           .IntoKey(M::ZipFd)
79       .Define("--zip-location=_")
80           .WithType<std::string>()
81           .WithHelp("Specifies a symbolic name for the file corresponding to the FD given by\n"
82                     "--zip-fd.")
83           .IntoKey(M::ZipLocation)
84       .Define("--boot-image=_")
85           .WithType<std::string>()
86           .WithHelp("provide the image file for the boot class path.\n"
87                     "Do not include the arch as part of the name, it is added automatically.\n"
88                     "Example: --boot-image=/system/framework/boot.art\n"
89                     "         (specifies /system/framework/<arch>/boot.art as the image file)\n"
90                     "Example: --boot-image=boot.art:boot-framework.art\n"
91                     "         (specifies <bcp-path1>/<arch>/boot.art as the image file and\n"
92                     "         <bcp-path2>/<arch>/boot-framework.art as the image extension file\n"
93                     "         with paths taken from corresponding boot class path components)\n"
94                     "Example: --boot-image=/apex/com.android.art/boot.art:/system/framework/*:*\n"
95                     "         (specifies /apex/com.android.art/<arch>/boot.art as the image\n"
96                     "         file and search for extensions in /framework/system and boot\n"
97                     "         class path components' paths)\n"
98                     "Default: $ANDROID_ROOT/system/framework/boot.art")
99           .IntoKey(M::BootImage);
100 }
101 
AddGeneratedArtifactMappings(Builder & builder)102 static void AddGeneratedArtifactMappings(Builder& builder) {
103   builder.
104       Define("--input-vdex-fd=_")
105           .WithType<int>()
106           .WithHelp("specifies the vdex input source via a file descriptor.")
107           .IntoKey(M::InputVdexFd)
108       .Define("--input-vdex=_")
109           .WithType<std::string>()
110           .WithHelp("specifies the vdex input source via a filename.")
111           .IntoKey(M::InputVdex)
112       .Define("--output-vdex-fd=_")
113           .WithHelp("specifies the vdex output destination via a file descriptor.")
114           .WithType<int>()
115           .IntoKey(M::OutputVdexFd)
116       .Define("--output-vdex=_")
117           .WithType<std::string>()
118           .WithHelp("specifies the vdex output destination via a filename.")
119           .IntoKey(M::OutputVdex)
120       .Define("--dm-fd=_")
121           .WithType<int>()
122           .WithHelp("specifies the dm output destination via a file descriptor.")
123           .IntoKey(M::DmFd)
124       .Define("--dm-file=_")
125           .WithType<std::string>()
126           .WithHelp("specifies the dm output destination via a filename.")
127           .IntoKey(M::DmFile)
128       .Define("--oat-file=_")
129           .WithType<std::string>()
130           .WithHelp(" Specifies an oat output destination via a filename.\n"
131                     "Eg: --oat-file=/system/framework/boot.oat")
132           .IntoKey(M::OatFile)
133       .Define("--oat-symbols=_")
134           .WithType<std::string>()
135           .WithHelp("Specifies a symbolized oat output destination.\n"
136                     "Eg: --oat-symbols=symbols/system/framework/boot.oat")
137           .IntoKey(M::OatSymbols)
138       .Define("--strip")
139           .WithHelp("remove all debugging sections at the end (but keep mini-debug-info).\n"
140                     "This is equivalent to the \"strip\" command as build post-processing step.\n"
141                     "It is intended to be used with --oat-symbols and it happens after it.\n"
142                     "Eg: --oat-symbols=/symbols/system/framework/boot.oat")
143           .IntoKey(M::Strip)
144       .Define("--oat-fd=_")
145           .WithType<int>()
146           .WithHelp("Specifies the oat output destination via a file descriptor. Eg: --oat-fd=5")
147           .IntoKey(M::OatFd)
148       .Define("--oat-location=_")
149           .WithType<std::string>()
150           .WithHelp("specifies a symbolic name for the file corresponding to the file descriptor\n"
151                     "specified by --oat-fd.\n"
152                     "Eg: --oat-location=/data/dalvik-cache/system@app@Calculator.apk.oat")
153           .IntoKey(M::OatLocation);
154 }
155 
AddImageMappings(Builder & builder)156 static void AddImageMappings(Builder& builder) {
157   builder.
158       Define("--image=_")
159           .WithType<std::string>()
160           .WithHelp("specifies an output image filename. Eg: --image=/system/framework/boot.art")
161           .IntoKey(M::ImageFilename)
162       .Define("--image-fd=_")
163           .WithType<int>()
164           .WithHelp("specifies an output image file descriptor. Cannot be used with --image.\n"
165                     "Eg: --image-fd=7")
166           .IntoKey(M::ImageFd)
167       .Define("--base=_")
168           .WithType<std::string>()
169           .WithHelp("Specifies the base address when creating a boot image. Eg: --base=0x50000000")
170           .WithMetavar("{hex address}")
171           .IntoKey(M::Base)
172       .Define("--app-image-file=_")
173           .WithType<std::string>()
174           .WithHelp("Specify a file name for app image. Only used if a profile is passed in.")
175           .IntoKey(M::AppImageFile)
176       .Define("--app-image-fd=_")
177           .WithType<int>()
178           .WithHelp("Specify a file descriptor for app image. Only used if a profile is passed in.")
179           .IntoKey(M::AppImageFileFd)
180       .Define({"--multi-image", "--single-image"})
181           .WithValues({true, false})
182           .WithHelp("Specifies if separate oat and image files should be generated for each dex\n"
183                     "file. --multi-image is default for boot image and --single-image for app\n"
184                     "images.")
185           .IntoKey(M::MultiImage)
186       .Define("--dirty-image-objects=_")
187           .WithType<std::string>()
188           .WithHelp("list of known dirty objects in the image. The image writer will group them"
189                     " together")
190           .IntoKey(M::DirtyImageObjects)
191       .Define("--updatable-bcp-packages-file=_")
192           .WithType<std::string>()
193           .WithHelp("file with a list of updatable boot class path packages. Classes in these\n"
194                     "packages and sub-packages shall not be resolved during app compilation to\n"
195                     "avoid AOT assumptions being invalidated after applying updates to these\n"
196                     "components."
197           )
198           .IntoKey(M::UpdatableBcpPackagesFile)
199       .Define("--image-format=_")
200           .WithType<ImageHeader::StorageMode>()
201           .WithValueMap({{"lz4", ImageHeader::kStorageModeLZ4},
202                          {"lz4hc", ImageHeader::kStorageModeLZ4HC},
203                          {"uncompressed", ImageHeader::kStorageModeUncompressed}})
204           .WithHelp("Which format to store the image Defaults to uncompressed. Eg:"
205                     " --image-format=lz4")
206           .IntoKey(M::ImageFormat);
207 }
208 
AddSwapMappings(Builder & builder)209 static void AddSwapMappings(Builder& builder) {
210   builder.
211       Define("--swap-file=_")
212           .WithType<std::string>()
213           .WithHelp("Specify a file to use for swap. Eg: --swap-file=/data/tmp/swap.001")
214           .IntoKey(M::SwapFile)
215       .Define("--swap-fd=_")
216           .WithType<int>()
217           .WithHelp("Specify a file to use for swap by file-descriptor. Eg: --swap-fd=3")
218           .IntoKey(M::SwapFileFd)
219       .Define("--swap-dex-size-threshold=_")
220           .WithType<unsigned int>()
221           .WithHelp("specifies the minimum total dex file size in bytes to allow the use of swap.")
222           .IntoKey(M::SwapDexSizeThreshold)
223       .Define("--swap-dex-count-threshold=_")
224           .WithType<unsigned int>()
225           .WithHelp("specifies the minimum number of dex file to allow the use of swap.")
226           .IntoKey(M::SwapDexCountThreshold);
227 }
228 
AddCompilerMappings(Builder & builder)229 static void AddCompilerMappings(Builder& builder) {
230   builder.
231       Define("--run-passes=_")
232           .WithType<std::string>()
233           .IntoKey(M::Passes)
234       .Define("--profile-file=_")
235           .WithType<std::string>()
236           .WithHelp("Specify profiler output file to use for compilation using a filename.")
237           .IntoKey(M::Profile)
238       .Define("--profile-file-fd=_")
239           .WithType<int>()
240           .WithHelp("Specify profiler output file to use for compilation using a file-descriptor.")
241           .IntoKey(M::ProfileFd)
242       .Define("--no-inline-from=_")
243           .WithType<std::string>()
244           .IntoKey(M::NoInlineFrom);
245 }
246 
AddTargetMappings(Builder & builder)247 static void AddTargetMappings(Builder& builder) {
248   builder.
249       Define("--instruction-set=_")
250           .WithType<InstructionSet>()
251           .WithHelp("Compile for a particular instruction set.")
252           .IntoKey(M::TargetInstructionSet)
253       .Define("--instruction-set-variant=_")
254           .WithType<std::string>()
255           .WithHelp("Specify instruction set features using variant name.\n"
256                     "Eg: --instruction-set-variant=silvermont")
257           .WithMetavar("{Variant Name}")
258           .IntoKey(M::TargetInstructionSetVariant)
259       .Define("--instruction-set-features=_")
260           .WithType<std::string>()
261           .WithHelp("Specify instruction set features.\n"
262                     "On target the value 'runtime' can be used to detect features at run time.\n"
263                     "If target does not support run-time detection the value 'runtime'\n"
264                     "has the same effect as the value 'default'.\n"
265                     "Note: the value 'runtime' has no effect if it is used on host.\n"
266                     "Example: --instruction-set-features=div\n"
267                     "Default: default")
268           .IntoKey(M::TargetInstructionSetFeatures);
269 }
270 
CreateDex2oatArgumentParser()271 Parser CreateDex2oatArgumentParser() {
272   std::unique_ptr<Builder> parser_builder = std::make_unique<Builder>();
273 
274   AddInputMappings(*parser_builder);
275   AddGeneratedArtifactMappings(*parser_builder);
276   AddImageMappings(*parser_builder);
277   AddSwapMappings(*parser_builder);
278   AddCompilerMappings(*parser_builder);
279   AddTargetMappings(*parser_builder);
280 
281   parser_builder->
282       Define({"--watch-dog", "--no-watch-dog"})
283           .WithHelp("Enable or disable the watchdog timer.")
284           .WithValues({true, false})
285           .IntoKey(M::Watchdog)
286       .Define("--watchdog-timeout=_")
287           .WithType<int>()
288           .WithHelp("Set the watchdog timeout value in seconds.")
289           .IntoKey(M::WatchdogTimeout)
290       .Define("-j_")
291           .WithType<unsigned int>()
292           .WithHelp("specifies the number of threads used for compilation. Default is the number\n"
293                     "of detected hardware threads available on the host system.")
294           .IntoKey(M::Threads)
295       .Define("--cpu-set=_")
296           .WithType<std::vector<int32_t>>()
297           .WithHelp("sets the cpu affinitiy to the given <set>. The <set> is a comma separated\n"
298                     "list of cpus. Eg: --cpu-set=0,1,2,3")
299           .WithMetavar("<set>")
300           .IntoKey(M::CpuSet)
301       .Define("--android-root=_")
302           .WithType<std::string>()
303           .WithHelp("Used to locate libraries for portable linking.\n"
304                     "Eg: --android-root=out/host/linux-x86\n"
305                     "Default: $ANDROID_ROOT")
306           .IntoKey(M::AndroidRoot)
307       .Define("--compiler-backend=_")
308           .WithType<Compiler::Kind>()
309           .WithValueMap({{"Quick", Compiler::Kind::kQuick},
310                          {"Optimizing", Compiler::Kind::kOptimizing}})
311           .WithHelp("Select a compiler backend set. Default: optimizing")
312           .IntoKey(M::Backend)
313       .Define("--host")
314           .WithHelp("Run in host mode")
315           .IntoKey(M::Host)
316       .Define("--avoid-storing-invocation")
317           .WithHelp("Avoid storing the invocation args in the key-value store. Used to test\n"
318                     "determinism with different args.")
319           .IntoKey(M::AvoidStoringInvocation)
320       .Define("--very-large-app-threshold=_")
321           .WithType<unsigned int>()
322           .WithHelp("Specifies the minimum total dex file size in bytes to consider the input\n"
323                     "\"very large\" and reduce compilation done.")
324           .IntoKey(M::VeryLargeAppThreshold)
325       .Define("--force-determinism")
326           .WithHelp("Force the compiler to emit a deterministic output")
327           .IntoKey(M::ForceDeterminism)
328       .Define("--check-linkage-conditions")
329           .IntoKey(M::CheckLinkageConditions)
330       .Define("--crash-on-linkage-violation")
331           .IntoKey(M::CrashOnLinkageViolation)
332       .Define("--copy-dex-files=_")
333           .WithType<linker::CopyOption>()
334           .WithValueMap({{"true", linker::CopyOption::kOnlyIfCompressed},
335                          {"false", linker::CopyOption::kNever},
336                          {"always", linker::CopyOption::kAlways}})
337           .WithHelp("enable|disable copying the dex files into the output vdex.")
338           .IntoKey(M::CopyDexFiles)
339       .Define("--force-allow-oj-inlines")
340           .WithHelp("Disables automatic no-inline for core-oj on host. Has no effect on target."
341                     " FOR TESTING USE ONLY! DO NOT DISTRIBUTE BINARIES BUILT WITH THIS OPTION!")
342           .IntoKey(M::ForceAllowOjInlines)
343       .Define("--write-invocation-to=_")
344           .WithHelp("Write the invocation commandline to the given file for later use. Used to\n"
345                     "test determinism with different args.")
346           .WithType<std::string>()
347           .IntoKey(M::InvocationFile)
348       .Define("--classpath-dir=_")
349           .WithType<std::string>()
350           .WithHelp("Directory used to resolve relative class paths.")
351           .IntoKey(M::ClasspathDir)
352       .Define("--class-loader-context=_")
353           .WithType<std::string>()
354           .WithHelp("a string specifying the intended runtime loading context for the compiled\n"
355                     "dex files.")
356           .IntoKey(M::ClassLoaderContext)
357       .Define("--class-loader-context-fds=_")
358           .WithType<std::string>()
359           .WithHelp("a colon-separated list of file descriptors for dex files in\n"
360                     "--class-loader-context. Their order must be the same as dex files in a\n"
361                     "flattened class loader context")
362           .IntoKey(M::ClassLoaderContextFds)
363       .Define("--stored-class-loader-context=_")
364           .WithType<std::string>()
365           .WithHelp("a string specifying the intended runtime loading context that is stored\n"
366                     "in the oat file. Overrides --class-loader-context. Note that this ignores\n"
367                     "the classpath_dir arg.\n"
368                     "\n"
369                     "It describes how the class loader chain should be built in order to ensure\n"
370                     "classes are resolved during dex2aot as they would be resolved at runtime.\n"
371                     "This spec will be encoded in the oat file. If at runtime the dex file is\n"
372                     "loaded in a different context, the oat file will be rejected.\n"
373                     "\n"
374                     "The chain is interpreted in the natural 'parent order', meaning that class\n"
375                     "loader 'i+1' will be the parent of class loader 'i'.\n"
376                     "The compilation sources will be appended to the classpath of the first class\n"
377                     "loader.\n"
378                     "\n"
379                     "E.g. if the context is 'PCL[lib1.dex];DLC[lib2.dex]' and \n"
380                     "--dex-file=src.dex then dex2oat will setup a PathClassLoader with classpath \n"
381                     "'lib1.dex:src.dex' and set its parent to a DelegateLastClassLoader with \n"
382                     "classpath 'lib2.dex'.\n"
383                     "\n"
384                     "Note that the compiler will be tolerant if the source dex files specified\n"
385                     "with --dex-file are found in the classpath. The source dex files will be\n"
386                     "removed from any class loader's classpath possibly resulting in empty\n"
387                     "class loaders.\n"
388                     "\n"
389                     "Example: --class-loader-context=PCL[lib1.dex:lib2.dex];DLC[lib3.dex]")
390           .IntoKey(M::StoredClassLoaderContext)
391       .Define("--compact-dex-level=_")
392           .WithType<CompactDexLevel>()
393           .WithValueMap({{"none", CompactDexLevel::kCompactDexLevelNone},
394                          {"fast", CompactDexLevel::kCompactDexLevelFast}})
395           .WithHelp("None avoids generating compact dex, fast generates compact dex with low\n"
396                     "compile time. If speed-profile is specified as the compiler filter and the\n"
397                     "profile is not empty, the default compact dex level is always used.")
398           .IntoKey(M::CompactDexLevel)
399       .Define("--runtime-arg _")
400           .WithType<std::vector<std::string>>().AppendValues()
401           .WithMetavar("{dalvikvm-arg}")
402           .WithHelp("used to specify various arguments for the runtime, such as initial heap\n"
403                     "size, maximum heap size, and verbose output. Use a separate --runtime-arg\n"
404                     "switch for each argument.\n"
405                     "Example: --runtime-arg -Xms256m")
406           .IntoKey(M::RuntimeOptions)
407       .Define("--compilation-reason=_")
408           .WithType<std::string>()
409           .WithHelp("optional metadata specifying the reason for compiling the apk. If specified,\n"
410                     "the string will be embedded verbatim in the key value store of the oat file.\n"
411                     "Example: --compilation-reason=install")
412           .IntoKey(M::CompilationReason)
413       .Define("--compile-individually")
414           .WithHelp("Compiles dex files individually, unloading classes in between compiling each"
415                     " file.")
416           .IntoKey(M::CompileIndividually)
417       .Define("--public-sdk=_")
418           .WithType<std::string>()
419           .IntoKey(M::PublicSdk)
420       .Define("--apex-versions=_")
421           .WithType<std::string>()
422           .WithHelp("Versions of apexes in the boot classpath, separated by '/'")
423           .IntoKey(M::ApexVersions);
424 
425   AddCompilerOptionsArgumentParserOptions<Dex2oatArgumentMap>(*parser_builder);
426 
427   parser_builder->IgnoreUnrecognized(false);
428 
429   return parser_builder->Build();
430 }
431 
Parse(int argc,const char ** argv,std::string * error_msg)432 std::unique_ptr<Dex2oatArgumentMap> Dex2oatArgumentMap::Parse(int argc,
433                                                               const char** argv,
434                                                               std::string* error_msg) {
435   Parser parser = CreateDex2oatArgumentParser();
436   CmdlineResult parse_result = parser.Parse(argv, argc);
437   if (!parse_result.IsSuccess()) {
438     *error_msg = parse_result.GetMessage();
439     return nullptr;
440   }
441 
442   return std::make_unique<Dex2oatArgumentMap>(parser.ReleaseArgumentsMap());
443 }
444 
445 #pragma GCC diagnostic pop
446 }  // namespace art
447