blob: 93351e9f285e996effc27eb74c6930d41ed5bc77 [file] [log] [blame]
Andreas Gampee1459ae2016-06-29 09:36:30 -07001/*
2 * Copyright (C) 2016 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#include <vector>
Andreas Gampeec743ff2016-07-23 05:17:18 +000019#include <sstream>
Andreas Gampee1459ae2016-06-29 09:36:30 -070020
21#include "common_runtime_test.h"
22
23#include "base/logging.h"
24#include "base/macros.h"
25#include "base/stringprintf.h"
26#include "dex2oat_environment_test.h"
Andreas Gampe67f02822016-06-24 21:05:23 -070027#include "oat.h"
28#include "oat_file.h"
Andreas Gampee1459ae2016-06-29 09:36:30 -070029#include "utils.h"
30
31#include <sys/wait.h>
32#include <unistd.h>
33
34namespace art {
35
36class Dex2oatTest : public Dex2oatEnvironmentTest {
37 public:
38 virtual void TearDown() OVERRIDE {
39 Dex2oatEnvironmentTest::TearDown();
40
41 output_ = "";
42 error_msg_ = "";
43 success_ = false;
44 }
45
46 protected:
47 void GenerateOdexForTest(const std::string& dex_location,
48 const std::string& odex_location,
49 CompilerFilter::Filter filter,
50 const std::vector<std::string>& extra_args = {},
51 bool expect_success = true) {
52 std::vector<std::string> args;
53 args.push_back("--dex-file=" + dex_location);
54 args.push_back("--oat-file=" + odex_location);
55 args.push_back("--compiler-filter=" + CompilerFilter::NameOfFilter(filter));
56 args.push_back("--runtime-arg");
57 args.push_back("-Xnorelocate");
58
59 args.insert(args.end(), extra_args.begin(), extra_args.end());
60
61 std::string error_msg;
62 bool success = Dex2Oat(args, &error_msg);
63
64 if (expect_success) {
65 ASSERT_TRUE(success) << error_msg;
66
67 // Verify the odex file was generated as expected.
68 std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
69 odex_location.c_str(),
70 nullptr,
71 nullptr,
72 false,
73 /*low_4gb*/false,
74 dex_location.c_str(),
75 &error_msg));
76 ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
77
78 CheckFilter(filter, odex_file->GetCompilerFilter());
79 } else {
80 ASSERT_FALSE(success) << output_;
81
82 error_msg_ = error_msg;
83
84 // Verify there's no loadable odex file.
85 std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
86 odex_location.c_str(),
87 nullptr,
88 nullptr,
89 false,
90 /*low_4gb*/false,
91 dex_location.c_str(),
92 &error_msg));
93 ASSERT_TRUE(odex_file.get() == nullptr);
94 }
95 }
96
97 // Check the input compiler filter against the generated oat file's filter. Mayb be overridden
98 // in subclasses when equality is not expected.
99 virtual void CheckFilter(CompilerFilter::Filter expected, CompilerFilter::Filter actual) {
100 EXPECT_EQ(expected, actual);
101 }
102
103 bool Dex2Oat(const std::vector<std::string>& dex2oat_args, std::string* error_msg) {
104 Runtime* runtime = Runtime::Current();
105
106 const std::vector<gc::space::ImageSpace*>& image_spaces =
107 runtime->GetHeap()->GetBootImageSpaces();
108 if (image_spaces.empty()) {
109 *error_msg = "No image location found for Dex2Oat.";
110 return false;
111 }
112 std::string image_location = image_spaces[0]->GetImageLocation();
113
114 std::vector<std::string> argv;
115 argv.push_back(runtime->GetCompilerExecutable());
116 argv.push_back("--runtime-arg");
117 argv.push_back("-classpath");
118 argv.push_back("--runtime-arg");
119 std::string class_path = runtime->GetClassPathString();
120 if (class_path == "") {
121 class_path = OatFile::kSpecialSharedLibrary;
122 }
123 argv.push_back(class_path);
124 if (runtime->IsDebuggable()) {
125 argv.push_back("--debuggable");
126 }
127 runtime->AddCurrentRuntimeFeaturesAsDex2OatArguments(&argv);
128
129 if (!runtime->IsVerificationEnabled()) {
130 argv.push_back("--compiler-filter=verify-none");
131 }
132
133 if (runtime->MustRelocateIfPossible()) {
134 argv.push_back("--runtime-arg");
135 argv.push_back("-Xrelocate");
136 } else {
137 argv.push_back("--runtime-arg");
138 argv.push_back("-Xnorelocate");
139 }
140
141 if (!kIsTargetBuild) {
142 argv.push_back("--host");
143 }
144
145 argv.push_back("--boot-image=" + image_location);
146
147 std::vector<std::string> compiler_options = runtime->GetCompilerOptions();
148 argv.insert(argv.end(), compiler_options.begin(), compiler_options.end());
149
150 argv.insert(argv.end(), dex2oat_args.begin(), dex2oat_args.end());
151
152 // We must set --android-root.
153 const char* android_root = getenv("ANDROID_ROOT");
154 CHECK(android_root != nullptr);
155 argv.push_back("--android-root=" + std::string(android_root));
156
Nicolas Geoffray56fe0f02016-06-30 15:07:46 +0100157 int link[2];
Andreas Gampee1459ae2016-06-29 09:36:30 -0700158
Nicolas Geoffray56fe0f02016-06-30 15:07:46 +0100159 if (pipe(link) == -1) {
160 return false;
161 }
Andreas Gampee1459ae2016-06-29 09:36:30 -0700162
Nicolas Geoffray56fe0f02016-06-30 15:07:46 +0100163 pid_t pid = fork();
164 if (pid == -1) {
165 return false;
166 }
Andreas Gampee1459ae2016-06-29 09:36:30 -0700167
Nicolas Geoffray56fe0f02016-06-30 15:07:46 +0100168 if (pid == 0) {
169 // We need dex2oat to actually log things.
170 setenv("ANDROID_LOG_TAGS", "*:d", 1);
171 dup2(link[1], STDERR_FILENO);
172 close(link[0]);
173 close(link[1]);
174 std::vector<const char*> c_args;
175 for (const std::string& str : argv) {
176 c_args.push_back(str.c_str());
Andreas Gampee1459ae2016-06-29 09:36:30 -0700177 }
Nicolas Geoffray56fe0f02016-06-30 15:07:46 +0100178 c_args.push_back(nullptr);
179 execv(c_args[0], const_cast<char* const*>(c_args.data()));
180 exit(1);
181 } else {
182 close(link[1]);
183 char buffer[128];
184 memset(buffer, 0, 128);
185 ssize_t bytes_read = 0;
Andreas Gampee1459ae2016-06-29 09:36:30 -0700186
Nicolas Geoffray56fe0f02016-06-30 15:07:46 +0100187 while (TEMP_FAILURE_RETRY(bytes_read = read(link[0], buffer, 128)) > 0) {
188 output_ += std::string(buffer, bytes_read);
189 }
190 close(link[0]);
191 int status = 0;
192 if (waitpid(pid, &status, 0) != -1) {
193 success_ = (status == 0);
194 }
Andreas Gampee1459ae2016-06-29 09:36:30 -0700195 }
196 return success_;
197 }
198
199 std::string output_ = "";
200 std::string error_msg_ = "";
201 bool success_ = false;
202};
203
204class Dex2oatSwapTest : public Dex2oatTest {
205 protected:
206 void RunTest(bool use_fd, bool expect_use, const std::vector<std::string>& extra_args = {}) {
207 std::string dex_location = GetScratchDir() + "/Dex2OatSwapTest.jar";
208 std::string odex_location = GetOdexDir() + "/Dex2OatSwapTest.odex";
209
Andreas Gampeec743ff2016-07-23 05:17:18 +0000210 Copy(GetDexSrc1(), dex_location);
Andreas Gampee1459ae2016-06-29 09:36:30 -0700211
212 std::vector<std::string> copy(extra_args);
213
214 std::unique_ptr<ScratchFile> sf;
215 if (use_fd) {
216 sf.reset(new ScratchFile());
217 copy.push_back(StringPrintf("--swap-fd=%d", sf->GetFd()));
218 } else {
219 std::string swap_location = GetOdexDir() + "/Dex2OatSwapTest.odex.swap";
220 copy.push_back("--swap-file=" + swap_location);
221 }
222 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed, copy);
223
224 CheckValidity();
225 ASSERT_TRUE(success_);
226 CheckResult(expect_use);
227 }
228
Andreas Gampeec743ff2016-07-23 05:17:18 +0000229 void CheckResult(bool expect_use) {
Andreas Gampee1459ae2016-06-29 09:36:30 -0700230 if (kIsTargetBuild) {
231 CheckTargetResult(expect_use);
232 } else {
233 CheckHostResult(expect_use);
234 }
235 }
236
Andreas Gampeec743ff2016-07-23 05:17:18 +0000237 void CheckTargetResult(bool expect_use ATTRIBUTE_UNUSED) {
Andreas Gampee1459ae2016-06-29 09:36:30 -0700238 // TODO: Ignore for now, as we won't capture any output (it goes to the logcat). We may do
239 // something for variants with file descriptor where we can control the lifetime of
240 // the swap file and thus take a look at it.
241 }
242
Andreas Gampeec743ff2016-07-23 05:17:18 +0000243 void CheckHostResult(bool expect_use) {
Andreas Gampee1459ae2016-06-29 09:36:30 -0700244 if (!kIsTargetBuild) {
245 if (expect_use) {
246 EXPECT_NE(output_.find("Large app, accepted running with swap."), std::string::npos)
247 << output_;
248 } else {
249 EXPECT_EQ(output_.find("Large app, accepted running with swap."), std::string::npos)
250 << output_;
251 }
252 }
253 }
254
255 // Check whether the dex2oat run was really successful.
Andreas Gampeec743ff2016-07-23 05:17:18 +0000256 void CheckValidity() {
Andreas Gampee1459ae2016-06-29 09:36:30 -0700257 if (kIsTargetBuild) {
258 CheckTargetValidity();
259 } else {
260 CheckHostValidity();
261 }
262 }
263
Andreas Gampeec743ff2016-07-23 05:17:18 +0000264 void CheckTargetValidity() {
Andreas Gampee1459ae2016-06-29 09:36:30 -0700265 // TODO: Ignore for now, as we won't capture any output (it goes to the logcat). We may do
266 // something for variants with file descriptor where we can control the lifetime of
267 // the swap file and thus take a look at it.
268 }
269
270 // On the host, we can get the dex2oat output. Here, look for "dex2oat took."
Andreas Gampeec743ff2016-07-23 05:17:18 +0000271 void CheckHostValidity() {
Andreas Gampee1459ae2016-06-29 09:36:30 -0700272 EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_;
273 }
274};
275
276TEST_F(Dex2oatSwapTest, DoNotUseSwapDefaultSingleSmall) {
277 RunTest(false /* use_fd */, false /* expect_use */);
278 RunTest(true /* use_fd */, false /* expect_use */);
279}
280
281TEST_F(Dex2oatSwapTest, DoNotUseSwapSingle) {
282 RunTest(false /* use_fd */, false /* expect_use */, { "--swap-dex-size-threshold=0" });
283 RunTest(true /* use_fd */, false /* expect_use */, { "--swap-dex-size-threshold=0" });
284}
285
286TEST_F(Dex2oatSwapTest, DoNotUseSwapSmall) {
287 RunTest(false /* use_fd */, false /* expect_use */, { "--swap-dex-count-threshold=0" });
288 RunTest(true /* use_fd */, false /* expect_use */, { "--swap-dex-count-threshold=0" });
289}
290
291TEST_F(Dex2oatSwapTest, DoUseSwapSingleSmall) {
292 RunTest(false /* use_fd */,
293 true /* expect_use */,
294 { "--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0" });
295 RunTest(true /* use_fd */,
296 true /* expect_use */,
297 { "--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0" });
298}
299
Andreas Gampe67f02822016-06-24 21:05:23 -0700300class Dex2oatVeryLargeTest : public Dex2oatTest {
301 protected:
302 void CheckFilter(CompilerFilter::Filter input ATTRIBUTE_UNUSED,
303 CompilerFilter::Filter result ATTRIBUTE_UNUSED) OVERRIDE {
304 // Ignore, we'll do our own checks.
305 }
306
307 void RunTest(CompilerFilter::Filter filter,
308 bool expect_large,
309 const std::vector<std::string>& extra_args = {}) {
310 std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
311 std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
312
313 Copy(GetDexSrc1(), dex_location);
314
315 std::vector<std::string> copy(extra_args);
316
317 GenerateOdexForTest(dex_location, odex_location, filter, copy);
318
319 CheckValidity();
320 ASSERT_TRUE(success_);
321 CheckResult(dex_location, odex_location, filter, expect_large);
322 }
323
324 void CheckResult(const std::string& dex_location,
325 const std::string& odex_location,
326 CompilerFilter::Filter filter,
327 bool expect_large) {
328 // Host/target independent checks.
329 std::string error_msg;
330 std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
331 odex_location.c_str(),
332 nullptr,
333 nullptr,
334 false,
335 /*low_4gb*/false,
336 dex_location.c_str(),
337 &error_msg));
338 ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
339 if (expect_large) {
340 // Note: we cannot check the following:
341 // EXPECT_TRUE(CompilerFilter::IsAsGoodAs(CompilerFilter::kVerifyAtRuntime,
342 // odex_file->GetCompilerFilter()));
343 // The reason is that the filter override currently happens when the dex files are
344 // loaded in dex2oat, which is after the oat file has been started. Thus, the header
345 // store cannot be changed, and the original filter is set in stone.
346
347 for (const OatDexFile* oat_dex_file : odex_file->GetOatDexFiles()) {
348 std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&error_msg);
349 ASSERT_TRUE(dex_file != nullptr);
350 uint32_t class_def_count = dex_file->NumClassDefs();
351 ASSERT_LT(class_def_count, std::numeric_limits<uint16_t>::max());
352 for (uint16_t class_def_index = 0; class_def_index < class_def_count; ++class_def_index) {
353 OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index);
354 EXPECT_EQ(oat_class.GetType(), OatClassType::kOatClassNoneCompiled);
355 }
356 }
357
358 // If the input filter was "below," it should have been used.
359 if (!CompilerFilter::IsAsGoodAs(CompilerFilter::kVerifyAtRuntime, filter)) {
360 EXPECT_EQ(odex_file->GetCompilerFilter(), filter);
361 }
362 } else {
363 EXPECT_EQ(odex_file->GetCompilerFilter(), filter);
364 }
365
366 // Host/target dependent checks.
367 if (kIsTargetBuild) {
368 CheckTargetResult(expect_large);
369 } else {
370 CheckHostResult(expect_large);
371 }
372 }
373
374 void CheckTargetResult(bool expect_large ATTRIBUTE_UNUSED) {
375 // TODO: Ignore for now. May do something for fd things.
376 }
377
378 void CheckHostResult(bool expect_large) {
379 if (!kIsTargetBuild) {
380 if (expect_large) {
381 EXPECT_NE(output_.find("Very large app, downgrading to verify-at-runtime."),
382 std::string::npos)
383 << output_;
384 } else {
385 EXPECT_EQ(output_.find("Very large app, downgrading to verify-at-runtime."),
386 std::string::npos)
387 << output_;
388 }
389 }
390 }
391
392 // Check whether the dex2oat run was really successful.
393 void CheckValidity() {
394 if (kIsTargetBuild) {
395 CheckTargetValidity();
396 } else {
397 CheckHostValidity();
398 }
399 }
400
401 void CheckTargetValidity() {
402 // TODO: Ignore for now.
403 }
404
405 // On the host, we can get the dex2oat output. Here, look for "dex2oat took."
406 void CheckHostValidity() {
407 EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_;
408 }
409};
410
411TEST_F(Dex2oatVeryLargeTest, DontUseVeryLarge) {
412 RunTest(CompilerFilter::kVerifyNone, false);
413 RunTest(CompilerFilter::kVerifyAtRuntime, false);
414 RunTest(CompilerFilter::kInterpretOnly, false);
415 RunTest(CompilerFilter::kSpeed, false);
416
417 RunTest(CompilerFilter::kVerifyNone, false, { "--very-large-app-threshold=1000000" });
418 RunTest(CompilerFilter::kVerifyAtRuntime, false, { "--very-large-app-threshold=1000000" });
419 RunTest(CompilerFilter::kInterpretOnly, false, { "--very-large-app-threshold=1000000" });
420 RunTest(CompilerFilter::kSpeed, false, { "--very-large-app-threshold=1000000" });
421}
422
423TEST_F(Dex2oatVeryLargeTest, UseVeryLarge) {
424 RunTest(CompilerFilter::kVerifyNone, false, { "--very-large-app-threshold=100" });
425 RunTest(CompilerFilter::kVerifyAtRuntime, false, { "--very-large-app-threshold=100" });
426 RunTest(CompilerFilter::kInterpretOnly, true, { "--very-large-app-threshold=100" });
427 RunTest(CompilerFilter::kSpeed, true, { "--very-large-app-threshold=100" });
428}
429
Andreas Gampee1459ae2016-06-29 09:36:30 -0700430} // namespace art