blob: 61888833588bcb38bc931f8009754274fc472537 [file] [log] [blame]
Andreas Gampe25a9abe2016-06-24 14:55:38 -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>
19#include <sstream>
20
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 Gampe338a1d22016-06-24 21:05:23 -070027#include "oat.h"
28#include "oat_file.h"
Andreas Gampe25a9abe2016-06-24 14:55:38 -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
157 std::string command_line(Join(argv, ' '));
158
159 // We need to fix up the '&' being used for "do not check classpath."
160 size_t ampersand = command_line.find(" &");
161 CHECK_NE(ampersand, std::string::npos);
162 command_line = command_line.replace(ampersand, 2, " \\&");
163
164 command_line += " 2>&1";
165
166 // We need dex2oat to actually log things.
167 setenv("ANDROID_LOG_TAGS", "*:d", 1);
168
169 FILE* pipe = popen(command_line.c_str(), "r");
170
171 setenv("ANDROID_LOG_TAGS", "*:e", 1);
172
173 if (pipe == nullptr) {
174 success_ = false;
175 } else {
176 char buffer[128];
177
178 while (fgets(buffer, 128, pipe) != nullptr) {
179 output_ += buffer;
180 }
181
182 int result = pclose(pipe);
183 success_ = result == 0;
184 }
185 return success_;
186 }
187
188 std::string output_ = "";
189 std::string error_msg_ = "";
190 bool success_ = false;
191};
192
193class Dex2oatSwapTest : public Dex2oatTest {
194 protected:
195 void RunTest(bool use_fd, bool expect_use, const std::vector<std::string>& extra_args = {}) {
196 std::string dex_location = GetScratchDir() + "/Dex2OatSwapTest.jar";
197 std::string odex_location = GetOdexDir() + "/Dex2OatSwapTest.odex";
198
199 Copy(GetDexSrc1(), dex_location);
200
201 std::vector<std::string> copy(extra_args);
202
203 std::unique_ptr<ScratchFile> sf;
204 if (use_fd) {
205 sf.reset(new ScratchFile());
206 copy.push_back(StringPrintf("--swap-fd=%d", sf->GetFd()));
207 } else {
208 std::string swap_location = GetOdexDir() + "/Dex2OatSwapTest.odex.swap";
209 copy.push_back("--swap-file=" + swap_location);
210 }
211 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed, copy);
212
213 CheckValidity();
214 ASSERT_TRUE(success_);
215 CheckResult(expect_use);
216 }
217
218 void CheckResult(bool expect_use) {
219 if (kIsTargetBuild) {
220 CheckTargetResult(expect_use);
221 } else {
222 CheckHostResult(expect_use);
223 }
224 }
225
226 void CheckTargetResult(bool expect_use ATTRIBUTE_UNUSED) {
227 // TODO: Ignore for now, as we won't capture any output (it goes to the logcat). We may do
228 // something for variants with file descriptor where we can control the lifetime of
229 // the swap file and thus take a look at it.
230 }
231
232 void CheckHostResult(bool expect_use) {
233 if (!kIsTargetBuild) {
234 if (expect_use) {
235 EXPECT_NE(output_.find("Large app, accepted running with swap."), std::string::npos)
236 << output_;
237 } else {
238 EXPECT_EQ(output_.find("Large app, accepted running with swap."), std::string::npos)
239 << output_;
240 }
241 }
242 }
243
244 // Check whether the dex2oat run was really successful.
245 void CheckValidity() {
246 if (kIsTargetBuild) {
247 CheckTargetValidity();
248 } else {
249 CheckHostValidity();
250 }
251 }
252
253 void CheckTargetValidity() {
254 // TODO: Ignore for now, as we won't capture any output (it goes to the logcat). We may do
255 // something for variants with file descriptor where we can control the lifetime of
256 // the swap file and thus take a look at it.
257 }
258
259 // On the host, we can get the dex2oat output. Here, look for "dex2oat took."
260 void CheckHostValidity() {
261 EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_;
262 }
263};
264
265TEST_F(Dex2oatSwapTest, DoNotUseSwapDefaultSingleSmall) {
266 RunTest(false /* use_fd */, false /* expect_use */);
267 RunTest(true /* use_fd */, false /* expect_use */);
268}
269
270TEST_F(Dex2oatSwapTest, DoNotUseSwapSingle) {
271 RunTest(false /* use_fd */, false /* expect_use */, { "--swap-dex-size-threshold=0" });
272 RunTest(true /* use_fd */, false /* expect_use */, { "--swap-dex-size-threshold=0" });
273}
274
275TEST_F(Dex2oatSwapTest, DoNotUseSwapSmall) {
276 RunTest(false /* use_fd */, false /* expect_use */, { "--swap-dex-count-threshold=0" });
277 RunTest(true /* use_fd */, false /* expect_use */, { "--swap-dex-count-threshold=0" });
278}
279
280TEST_F(Dex2oatSwapTest, DoUseSwapSingleSmall) {
281 RunTest(false /* use_fd */,
282 true /* expect_use */,
283 { "--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0" });
284 RunTest(true /* use_fd */,
285 true /* expect_use */,
286 { "--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0" });
287}
288
Andreas Gampe338a1d22016-06-24 21:05:23 -0700289class Dex2oatVeryLargeTest : public Dex2oatTest {
290 protected:
291 void CheckFilter(CompilerFilter::Filter input ATTRIBUTE_UNUSED,
292 CompilerFilter::Filter result ATTRIBUTE_UNUSED) OVERRIDE {
293 // Ignore, we'll do our own checks.
294 }
295
296 void RunTest(CompilerFilter::Filter filter,
297 bool expect_large,
298 const std::vector<std::string>& extra_args = {}) {
299 std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
300 std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
301
302 Copy(GetDexSrc1(), dex_location);
303
304 std::vector<std::string> copy(extra_args);
305
306 GenerateOdexForTest(dex_location, odex_location, filter, copy);
307
308 CheckValidity();
309 ASSERT_TRUE(success_);
310 CheckResult(dex_location, odex_location, filter, expect_large);
311 }
312
313 void CheckResult(const std::string& dex_location,
314 const std::string& odex_location,
315 CompilerFilter::Filter filter,
316 bool expect_large) {
317 // Host/target independent checks.
318 std::string error_msg;
319 std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
320 odex_location.c_str(),
321 nullptr,
322 nullptr,
323 false,
324 /*low_4gb*/false,
325 dex_location.c_str(),
326 &error_msg));
327 ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
328 if (expect_large) {
329 // Note: we cannot check the following:
330 // EXPECT_TRUE(CompilerFilter::IsAsGoodAs(CompilerFilter::kVerifyAtRuntime,
331 // odex_file->GetCompilerFilter()));
332 // The reason is that the filter override currently happens when the dex files are
333 // loaded in dex2oat, which is after the oat file has been started. Thus, the header
334 // store cannot be changed, and the original filter is set in stone.
335
336 for (const OatDexFile* oat_dex_file : odex_file->GetOatDexFiles()) {
337 std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&error_msg);
338 ASSERT_TRUE(dex_file != nullptr);
339 uint32_t class_def_count = dex_file->NumClassDefs();
340 ASSERT_LT(class_def_count, std::numeric_limits<uint16_t>::max());
341 for (uint16_t class_def_index = 0; class_def_index < class_def_count; ++class_def_index) {
342 OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index);
343 EXPECT_EQ(oat_class.GetType(), OatClassType::kOatClassNoneCompiled);
344 }
345 }
346
347 // If the input filter was "below," it should have been used.
348 if (!CompilerFilter::IsAsGoodAs(CompilerFilter::kVerifyAtRuntime, filter)) {
349 EXPECT_EQ(odex_file->GetCompilerFilter(), filter);
350 }
351 } else {
352 EXPECT_EQ(odex_file->GetCompilerFilter(), filter);
353 }
354
355 // Host/target dependent checks.
356 if (kIsTargetBuild) {
357 CheckTargetResult(expect_large);
358 } else {
359 CheckHostResult(expect_large);
360 }
361 }
362
363 void CheckTargetResult(bool expect_large ATTRIBUTE_UNUSED) {
364 // TODO: Ignore for now. May do something for fd things.
365 }
366
367 void CheckHostResult(bool expect_large) {
368 if (!kIsTargetBuild) {
369 if (expect_large) {
370 EXPECT_NE(output_.find("Very large app, downgrading to verify-at-runtime."),
371 std::string::npos)
372 << output_;
373 } else {
374 EXPECT_EQ(output_.find("Very large app, downgrading to verify-at-runtime."),
375 std::string::npos)
376 << output_;
377 }
378 }
379 }
380
381 // Check whether the dex2oat run was really successful.
382 void CheckValidity() {
383 if (kIsTargetBuild) {
384 CheckTargetValidity();
385 } else {
386 CheckHostValidity();
387 }
388 }
389
390 void CheckTargetValidity() {
391 // TODO: Ignore for now.
392 }
393
394 // On the host, we can get the dex2oat output. Here, look for "dex2oat took."
395 void CheckHostValidity() {
396 EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_;
397 }
398};
399
400TEST_F(Dex2oatVeryLargeTest, DontUseVeryLarge) {
401 RunTest(CompilerFilter::kVerifyNone, false);
402 RunTest(CompilerFilter::kVerifyAtRuntime, false);
403 RunTest(CompilerFilter::kInterpretOnly, false);
404 RunTest(CompilerFilter::kSpeed, false);
405
406 RunTest(CompilerFilter::kVerifyNone, false, { "--very-large-app-threshold=1000000" });
407 RunTest(CompilerFilter::kVerifyAtRuntime, false, { "--very-large-app-threshold=1000000" });
408 RunTest(CompilerFilter::kInterpretOnly, false, { "--very-large-app-threshold=1000000" });
409 RunTest(CompilerFilter::kSpeed, false, { "--very-large-app-threshold=1000000" });
410}
411
412TEST_F(Dex2oatVeryLargeTest, UseVeryLarge) {
413 RunTest(CompilerFilter::kVerifyNone, false, { "--very-large-app-threshold=100" });
414 RunTest(CompilerFilter::kVerifyAtRuntime, false, { "--very-large-app-threshold=100" });
415 RunTest(CompilerFilter::kInterpretOnly, true, { "--very-large-app-threshold=100" });
416 RunTest(CompilerFilter::kSpeed, true, { "--very-large-app-threshold=100" });
417}
418
Andreas Gampe25a9abe2016-06-24 14:55:38 -0700419} // namespace art