blob: de3aed9d05bf7cf3aa189a5f3d047de5bf8100ad [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>
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"
27#include "utils.h"
28
29#include <sys/wait.h>
30#include <unistd.h>
31
32namespace art {
33
34class Dex2oatTest : public Dex2oatEnvironmentTest {
35 public:
36 virtual void TearDown() OVERRIDE {
37 Dex2oatEnvironmentTest::TearDown();
38
39 output_ = "";
40 error_msg_ = "";
41 success_ = false;
42 }
43
44 protected:
45 void GenerateOdexForTest(const std::string& dex_location,
46 const std::string& odex_location,
47 CompilerFilter::Filter filter,
48 const std::vector<std::string>& extra_args = {},
49 bool expect_success = true) {
50 std::vector<std::string> args;
51 args.push_back("--dex-file=" + dex_location);
52 args.push_back("--oat-file=" + odex_location);
53 args.push_back("--compiler-filter=" + CompilerFilter::NameOfFilter(filter));
54 args.push_back("--runtime-arg");
55 args.push_back("-Xnorelocate");
56
57 args.insert(args.end(), extra_args.begin(), extra_args.end());
58
59 std::string error_msg;
60 bool success = Dex2Oat(args, &error_msg);
61
62 if (expect_success) {
63 ASSERT_TRUE(success) << error_msg;
64
65 // Verify the odex file was generated as expected.
66 std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
67 odex_location.c_str(),
68 nullptr,
69 nullptr,
70 false,
71 /*low_4gb*/false,
72 dex_location.c_str(),
73 &error_msg));
74 ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
75
76 CheckFilter(filter, odex_file->GetCompilerFilter());
77 } else {
78 ASSERT_FALSE(success) << output_;
79
80 error_msg_ = error_msg;
81
82 // Verify there's no loadable odex file.
83 std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
84 odex_location.c_str(),
85 nullptr,
86 nullptr,
87 false,
88 /*low_4gb*/false,
89 dex_location.c_str(),
90 &error_msg));
91 ASSERT_TRUE(odex_file.get() == nullptr);
92 }
93 }
94
95 // Check the input compiler filter against the generated oat file's filter. Mayb be overridden
96 // in subclasses when equality is not expected.
97 virtual void CheckFilter(CompilerFilter::Filter expected, CompilerFilter::Filter actual) {
98 EXPECT_EQ(expected, actual);
99 }
100
101 bool Dex2Oat(const std::vector<std::string>& dex2oat_args, std::string* error_msg) {
102 Runtime* runtime = Runtime::Current();
103
104 const std::vector<gc::space::ImageSpace*>& image_spaces =
105 runtime->GetHeap()->GetBootImageSpaces();
106 if (image_spaces.empty()) {
107 *error_msg = "No image location found for Dex2Oat.";
108 return false;
109 }
110 std::string image_location = image_spaces[0]->GetImageLocation();
111
112 std::vector<std::string> argv;
113 argv.push_back(runtime->GetCompilerExecutable());
114 argv.push_back("--runtime-arg");
115 argv.push_back("-classpath");
116 argv.push_back("--runtime-arg");
117 std::string class_path = runtime->GetClassPathString();
118 if (class_path == "") {
119 class_path = OatFile::kSpecialSharedLibrary;
120 }
121 argv.push_back(class_path);
122 if (runtime->IsDebuggable()) {
123 argv.push_back("--debuggable");
124 }
125 runtime->AddCurrentRuntimeFeaturesAsDex2OatArguments(&argv);
126
127 if (!runtime->IsVerificationEnabled()) {
128 argv.push_back("--compiler-filter=verify-none");
129 }
130
131 if (runtime->MustRelocateIfPossible()) {
132 argv.push_back("--runtime-arg");
133 argv.push_back("-Xrelocate");
134 } else {
135 argv.push_back("--runtime-arg");
136 argv.push_back("-Xnorelocate");
137 }
138
139 if (!kIsTargetBuild) {
140 argv.push_back("--host");
141 }
142
143 argv.push_back("--boot-image=" + image_location);
144
145 std::vector<std::string> compiler_options = runtime->GetCompilerOptions();
146 argv.insert(argv.end(), compiler_options.begin(), compiler_options.end());
147
148 argv.insert(argv.end(), dex2oat_args.begin(), dex2oat_args.end());
149
150 // We must set --android-root.
151 const char* android_root = getenv("ANDROID_ROOT");
152 CHECK(android_root != nullptr);
153 argv.push_back("--android-root=" + std::string(android_root));
154
155 std::string command_line(Join(argv, ' '));
156
157 // We need to fix up the '&' being used for "do not check classpath."
158 size_t ampersand = command_line.find(" &");
159 CHECK_NE(ampersand, std::string::npos);
160 command_line = command_line.replace(ampersand, 2, " \\&");
161
162 command_line += " 2>&1";
163
164 // We need dex2oat to actually log things.
165 setenv("ANDROID_LOG_TAGS", "*:d", 1);
166
167 FILE* pipe = popen(command_line.c_str(), "r");
168
169 setenv("ANDROID_LOG_TAGS", "*:e", 1);
170
171 if (pipe == nullptr) {
172 success_ = false;
173 } else {
174 char buffer[128];
175
176 while (fgets(buffer, 128, pipe) != nullptr) {
177 output_ += buffer;
178 }
179
180 int result = pclose(pipe);
181 success_ = result == 0;
182 }
183 return success_;
184 }
185
186 std::string output_ = "";
187 std::string error_msg_ = "";
188 bool success_ = false;
189};
190
191class Dex2oatSwapTest : public Dex2oatTest {
192 protected:
193 void RunTest(bool use_fd, bool expect_use, const std::vector<std::string>& extra_args = {}) {
194 std::string dex_location = GetScratchDir() + "/Dex2OatSwapTest.jar";
195 std::string odex_location = GetOdexDir() + "/Dex2OatSwapTest.odex";
196
197 Copy(GetDexSrc1(), dex_location);
198
199 std::vector<std::string> copy(extra_args);
200
201 std::unique_ptr<ScratchFile> sf;
202 if (use_fd) {
203 sf.reset(new ScratchFile());
204 copy.push_back(StringPrintf("--swap-fd=%d", sf->GetFd()));
205 } else {
206 std::string swap_location = GetOdexDir() + "/Dex2OatSwapTest.odex.swap";
207 copy.push_back("--swap-file=" + swap_location);
208 }
209 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed, copy);
210
211 CheckValidity();
212 ASSERT_TRUE(success_);
213 CheckResult(expect_use);
214 }
215
216 void CheckResult(bool expect_use) {
217 if (kIsTargetBuild) {
218 CheckTargetResult(expect_use);
219 } else {
220 CheckHostResult(expect_use);
221 }
222 }
223
224 void CheckTargetResult(bool expect_use ATTRIBUTE_UNUSED) {
225 // TODO: Ignore for now, as we won't capture any output (it goes to the logcat). We may do
226 // something for variants with file descriptor where we can control the lifetime of
227 // the swap file and thus take a look at it.
228 }
229
230 void CheckHostResult(bool expect_use) {
231 if (!kIsTargetBuild) {
232 if (expect_use) {
233 EXPECT_NE(output_.find("Large app, accepted running with swap."), std::string::npos)
234 << output_;
235 } else {
236 EXPECT_EQ(output_.find("Large app, accepted running with swap."), std::string::npos)
237 << output_;
238 }
239 }
240 }
241
242 // Check whether the dex2oat run was really successful.
243 void CheckValidity() {
244 if (kIsTargetBuild) {
245 CheckTargetValidity();
246 } else {
247 CheckHostValidity();
248 }
249 }
250
251 void CheckTargetValidity() {
252 // TODO: Ignore for now, as we won't capture any output (it goes to the logcat). We may do
253 // something for variants with file descriptor where we can control the lifetime of
254 // the swap file and thus take a look at it.
255 }
256
257 // On the host, we can get the dex2oat output. Here, look for "dex2oat took."
258 void CheckHostValidity() {
259 EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_;
260 }
261};
262
263TEST_F(Dex2oatSwapTest, DoNotUseSwapDefaultSingleSmall) {
264 RunTest(false /* use_fd */, false /* expect_use */);
265 RunTest(true /* use_fd */, false /* expect_use */);
266}
267
268TEST_F(Dex2oatSwapTest, DoNotUseSwapSingle) {
269 RunTest(false /* use_fd */, false /* expect_use */, { "--swap-dex-size-threshold=0" });
270 RunTest(true /* use_fd */, false /* expect_use */, { "--swap-dex-size-threshold=0" });
271}
272
273TEST_F(Dex2oatSwapTest, DoNotUseSwapSmall) {
274 RunTest(false /* use_fd */, false /* expect_use */, { "--swap-dex-count-threshold=0" });
275 RunTest(true /* use_fd */, false /* expect_use */, { "--swap-dex-count-threshold=0" });
276}
277
278TEST_F(Dex2oatSwapTest, DoUseSwapSingleSmall) {
279 RunTest(false /* use_fd */,
280 true /* expect_use */,
281 { "--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0" });
282 RunTest(true /* use_fd */,
283 true /* expect_use */,
284 { "--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0" });
285}
286
287} // namespace art