blob: 9a2eb7f8ddff5b29975964b6cf1a46a5a0ca2430 [file] [log] [blame]
Calin Juravle36eb3132017-01-13 16:32:38 -08001/*
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 <string>
18
19#include "android-base/stringprintf.h"
20#include "android-base/strings.h"
21#include "compiler_filter.h"
22#include "dex_file.h"
23#include "noop_compiler_callbacks.h"
24#include "oat_file_assistant.h"
25#include "os.h"
26#include "runtime.h"
27#include "thread-inl.h"
28#include "utils.h"
29
30namespace art {
31
32// See OatFileAssistant docs for the meaning of the valid return codes.
33enum ReturnCodes {
34 kNoDexOptNeeded = 0,
35 kDex2OatFromScratch = 1,
36 kDex2OatForBootImageOat = 2,
37 kDex2OatForFilterOat = 3,
38 kDex2OatForRelocationOat = 4,
39 kDex2OatForBootImageOdex = 5,
40 kDex2OatForFilterOdex = 6,
41 kDex2OatForRelocationOdex = 7,
42
43 kErrorInvalidArguments = 101,
44 kErrorCannotCreateRuntime = 102,
45 kErrorUnknownDexOptNeeded = 103
46};
47
48static int original_argc;
49static char** original_argv;
50
51static std::string CommandLine() {
52 std::vector<std::string> command;
53 for (int i = 0; i < original_argc; ++i) {
54 command.push_back(original_argv[i]);
55 }
56 return android::base::Join(command, ' ');
57}
58
59static void UsageErrorV(const char* fmt, va_list ap) {
60 std::string error;
61 android::base::StringAppendV(&error, fmt, ap);
62 LOG(ERROR) << error;
63}
64
65static void UsageError(const char* fmt, ...) {
66 va_list ap;
67 va_start(ap, fmt);
68 UsageErrorV(fmt, ap);
69 va_end(ap);
70}
71
72NO_RETURN static void Usage(const char *fmt, ...) {
73 va_list ap;
74 va_start(ap, fmt);
75 UsageErrorV(fmt, ap);
76 va_end(ap);
77
78 UsageError("Command: %s", CommandLine().c_str());
79 UsageError(" Performs a dexopt analysis on the given dex file and returns whether or not");
80 UsageError(" the dex file needs to be dexopted.");
81 UsageError("Usage: dexoptanalyzer [options]...");
82 UsageError("");
83 UsageError(" --dex-file=<filename>: the dex file which should be analyzed.");
84 UsageError("");
85 UsageError(" --isa=<string>: the instruction set for which the analysis should be performed.");
86 UsageError("");
87 UsageError(" --compiler-filter=<string>: the target compiler filter to be used as reference");
88 UsageError(" when deciding if the dex file needs to be optimized.");
89 UsageError("");
90 UsageError(" --assume-profile-changed: assumes the profile information has changed");
91 UsageError(" when deciding if the dex file needs to be optimized.");
92 UsageError("");
93 UsageError(" --image=<filename>: optional, the image to be used to decide if the associated");
94 UsageError(" oat file is up to date. Defaults to $ANDROID_ROOT/framework/boot.art.");
95 UsageError(" Example: --image=/system/framework/boot.art");
96 UsageError("");
97 UsageError(" --android-data=<directory>: optional, the directory which should be used as");
98 UsageError(" android-data. By default ANDROID_DATA env variable is used.");
99 UsageError("");
100 UsageError("Return code:");
101 UsageError(" To make it easier to integrate with the internal tools this command will make");
102 UsageError(" available its result (dexoptNeeded) as the exit/return code. i.e. it will not");
103 UsageError(" return 0 for success and a non zero values for errors as the conventional");
104 UsageError(" commands. The following return codes are possible:");
105 UsageError(" kNoDexOptNeeded = 0");
106 UsageError(" kDex2OatFromScratch = 1");
107 UsageError(" kDex2OatForBootImageOat = 2");
108 UsageError(" kDex2OatForFilterOat = 3");
109 UsageError(" kDex2OatForRelocationOat = 4");
110 UsageError(" kDex2OatForBootImageOdex = 5");
111 UsageError(" kDex2OatForFilterOdex = 6");
112 UsageError(" kDex2OatForRelocationOdex = 7");
113
114 UsageError(" kErrorInvalidArguments = 101");
115 UsageError(" kErrorCannotCreateRuntime = 102");
116 UsageError(" kErrorUnknownDexOptNeeded = 103");
117 UsageError("");
118
119 exit(kErrorInvalidArguments);
120}
121
122class DexoptAnalyzer FINAL {
123 public:
124 DexoptAnalyzer() : assume_profile_changed_(false) {}
125
126 void ParseArgs(int argc, char **argv) {
127 original_argc = argc;
128 original_argv = argv;
129
130 InitLogging(argv, Runtime::Aborter);
131 // Skip over the command name.
132 argv++;
133 argc--;
134
135 if (argc == 0) {
136 Usage("No arguments specified");
137 }
138
139 for (int i = 0; i < argc; ++i) {
140 const StringPiece option(argv[i]);
141 if (option == "--assume-profile-changed") {
142 assume_profile_changed_ = true;
143 } else if (option.starts_with("--dex-file=")) {
144 dex_file_ = option.substr(strlen("--dex-file=")).ToString();
145 } else if (option.starts_with("--compiler-filter=")) {
146 std::string filter_str = option.substr(strlen("--compiler-filter=")).ToString();
147 if (!CompilerFilter::ParseCompilerFilter(filter_str.c_str(), &compiler_filter_)) {
148 Usage("Invalid compiler filter '%s'", option.data());
149 }
150 } else if (option.starts_with("--isa=")) {
151 std::string isa_str = option.substr(strlen("--isa=")).ToString();
152 isa_ = GetInstructionSetFromString(isa_str.c_str());
153 if (isa_ == kNone) {
154 Usage("Invalid isa '%s'", option.data());
155 }
156 } else if (option.starts_with("--image=")) {
157 image_ = option.substr(strlen("--image=")).ToString();
158 } else if (option.starts_with("--android-data=")) {
159 // Overwrite android-data if needed (oat file assistant relies on a valid directory to
160 // compute dalvik-cache folder). This is mostly used in tests.
161 std::string new_android_data = option.substr(strlen("--android-data=")).ToString();
162 setenv("ANDROID_DATA", new_android_data.c_str(), 1);
163 } else {
164 Usage("Unknown argument '%s'", option.data());
165 }
166 }
167
168 if (image_.empty()) {
169 // If we don't receive the image, try to use the default one.
170 // Tests may specify a different image (e.g. core image).
171 std::string error_msg;
172 image_ = GetDefaultBootImageLocation(&error_msg);
173
174 if (image_.empty()) {
175 LOG(ERROR) << error_msg;
176 Usage("--image unspecified and ANDROID_ROOT not set or image file does not exist.");
177 }
178 }
179 }
180
181 bool CreateRuntime() {
182 RuntimeOptions options;
183 // The image could be custom, so make sure we explicitly pass it.
184 std::string img = "-Ximage:" + image_;
185 options.push_back(std::make_pair(img.c_str(), nullptr));
186 // The instruction set of the image should match the instruction set we will test.
187 const void* isa_opt = reinterpret_cast<const void*>(GetInstructionSetString(isa_));
188 options.push_back(std::make_pair("imageinstructionset", isa_opt));
189 // Disable libsigchain. We don't don't need it to evaluate DexOptNeeded status.
190 options.push_back(std::make_pair("-Xno-sig-chain", nullptr));
191 // Pretend we are a compiler so that we can re-use the same infrastructure to load a different
192 // ISA image and minimize the amount of things that get started.
193 NoopCompilerCallbacks callbacks;
194 options.push_back(std::make_pair("compilercallbacks", &callbacks));
195 // Make sure we don't attempt to relocate. The tool should only retrieve the DexOptNeeded
196 // status and not attempt to relocate the boot image.
197 options.push_back(std::make_pair("-Xnorelocate", nullptr));
198
199 if (!Runtime::Create(options, false)) {
200 LOG(ERROR) << "Unable to initialize runtime";
201 return false;
202 }
203 // Runtime::Create acquired the mutator_lock_ that is normally given away when we
204 // Runtime::Start. Give it away now.
205 Thread::Current()->TransitionFromRunnableToSuspended(kNative);
206
207 return true;
208 }
209
210 int GetDexOptNeeded() {
211 // If the file does not exist there's nothing to do.
212 // This is a fast path to avoid creating the runtime (b/34385298).
213 if (!OS::FileExists(dex_file_.c_str())) {
214 return kNoDexOptNeeded;
215 }
216 if (!CreateRuntime()) {
217 return kErrorCannotCreateRuntime;
218 }
Andreas Gampe39f44b72017-04-26 22:00:04 -0700219 std::unique_ptr<Runtime> runtime(Runtime::Current());
220
Calin Juravle36eb3132017-01-13 16:32:38 -0800221 OatFileAssistant oat_file_assistant(dex_file_.c_str(), isa_, /*load_executable*/ false);
222 // Always treat elements of the bootclasspath as up-to-date.
223 // TODO(calin): this check should be in OatFileAssistant.
224 if (oat_file_assistant.IsInBootClassPath()) {
225 return kNoDexOptNeeded;
226 }
227 int dexoptNeeded = oat_file_assistant.GetDexOptNeeded(
228 compiler_filter_, assume_profile_changed_);
229
230 // Convert OatFileAssitant codes to dexoptanalyzer codes.
231 switch (dexoptNeeded) {
232 case OatFileAssistant::kNoDexOptNeeded: return kNoDexOptNeeded;
233 case OatFileAssistant::kDex2OatFromScratch: return kDex2OatFromScratch;
234 case OatFileAssistant::kDex2OatForBootImage: return kDex2OatForBootImageOat;
235 case OatFileAssistant::kDex2OatForFilter: return kDex2OatForFilterOat;
236 case OatFileAssistant::kDex2OatForRelocation: return kDex2OatForRelocationOat;
237
238 case -OatFileAssistant::kDex2OatForBootImage: return kDex2OatForBootImageOdex;
239 case -OatFileAssistant::kDex2OatForFilter: return kDex2OatForFilterOdex;
240 case -OatFileAssistant::kDex2OatForRelocation: return kDex2OatForRelocationOdex;
241 default:
242 LOG(ERROR) << "Unknown dexoptNeeded " << dexoptNeeded;
243 return kErrorUnknownDexOptNeeded;
244 }
245 }
246
247 private:
248 std::string dex_file_;
249 InstructionSet isa_;
250 CompilerFilter::Filter compiler_filter_;
251 bool assume_profile_changed_;
252 std::string image_;
253};
254
255static int dexoptAnalyze(int argc, char** argv) {
256 DexoptAnalyzer analyzer;
257
258 // Parse arguments. Argument mistakes will lead to exit(kErrorInvalidArguments) in UsageError.
259 analyzer.ParseArgs(argc, argv);
260 return analyzer.GetDexOptNeeded();
261}
262
263} // namespace art
264
265int main(int argc, char **argv) {
266 return art::dexoptAnalyze(argc, argv);
267}