1 /*
2 * Copyright (C) 2012 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 "common_art_test.h"
18
19 #include <cstdio>
20 #include <dirent.h>
21 #include <dlfcn.h>
22 #include <fcntl.h>
23 #include <filesystem>
24 #include <ftw.h>
25 #include <libgen.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include "android-base/file.h"
29 #include "android-base/logging.h"
30 #include "nativehelper/scoped_local_ref.h"
31
32 #include "android-base/stringprintf.h"
33 #include "android-base/strings.h"
34 #include "android-base/unique_fd.h"
35
36 #include "art_field-inl.h"
37 #include "base/file_utils.h"
38 #include "base/logging.h"
39 #include "base/macros.h"
40 #include "base/mem_map.h"
41 #include "base/mutex.h"
42 #include "base/os.h"
43 #include "base/runtime_debug.h"
44 #include "base/stl_util.h"
45 #include "base/string_view_cpp20.h"
46 #include "base/unix_file/fd_file.h"
47 #include "dex/art_dex_file_loader.h"
48 #include "dex/dex_file-inl.h"
49 #include "dex/dex_file_loader.h"
50 #include "dex/primitive.h"
51 #include "gtest/gtest.h"
52
53 namespace art {
54
55 using android::base::StringPrintf;
56
ScratchDir(bool keep_files)57 ScratchDir::ScratchDir(bool keep_files) : keep_files_(keep_files) {
58 // ANDROID_DATA needs to be set
59 CHECK_NE(static_cast<char*>(nullptr), getenv("ANDROID_DATA")) <<
60 "Are you subclassing RuntimeTest?";
61 path_ = getenv("ANDROID_DATA");
62 path_ += "/tmp-XXXXXX";
63 bool ok = (mkdtemp(&path_[0]) != nullptr);
64 CHECK(ok) << strerror(errno) << " for " << path_;
65 path_ += "/";
66 }
67
~ScratchDir()68 ScratchDir::~ScratchDir() {
69 if (!keep_files_) {
70 // Recursively delete the directory and all its content.
71 nftw(path_.c_str(), [](const char* name, const struct stat*, int type, struct FTW *) {
72 if (type == FTW_F) {
73 unlink(name);
74 } else if (type == FTW_DP) {
75 rmdir(name);
76 }
77 return 0;
78 }, 256 /* max open file descriptors */, FTW_DEPTH);
79 }
80 }
81
ScratchFile()82 ScratchFile::ScratchFile() {
83 // ANDROID_DATA needs to be set
84 CHECK_NE(static_cast<char*>(nullptr), getenv("ANDROID_DATA")) <<
85 "Are you subclassing RuntimeTest?";
86 filename_ = getenv("ANDROID_DATA");
87 filename_ += "/TmpFile-XXXXXX";
88 int fd = mkstemp(&filename_[0]);
89 CHECK_NE(-1, fd) << strerror(errno) << " for " << filename_;
90 file_.reset(new File(fd, GetFilename(), true));
91 }
92
ScratchFile(const ScratchFile & other,const char * suffix)93 ScratchFile::ScratchFile(const ScratchFile& other, const char* suffix)
94 : ScratchFile(other.GetFilename() + suffix) {}
95
ScratchFile(const std::string & filename)96 ScratchFile::ScratchFile(const std::string& filename) : filename_(filename) {
97 int fd = open(filename_.c_str(), O_RDWR | O_CREAT | O_CLOEXEC, 0666);
98 CHECK_NE(-1, fd);
99 file_.reset(new File(fd, GetFilename(), true));
100 }
101
ScratchFile(File * file)102 ScratchFile::ScratchFile(File* file) {
103 CHECK(file != nullptr);
104 filename_ = file->GetPath();
105 file_.reset(file);
106 }
107
ScratchFile(ScratchFile && other)108 ScratchFile::ScratchFile(ScratchFile&& other) noexcept {
109 *this = std::move(other);
110 }
111
operator =(ScratchFile && other)112 ScratchFile& ScratchFile::operator=(ScratchFile&& other) noexcept {
113 if (GetFile() != other.GetFile()) {
114 std::swap(filename_, other.filename_);
115 std::swap(file_, other.file_);
116 }
117 return *this;
118 }
119
~ScratchFile()120 ScratchFile::~ScratchFile() {
121 Unlink();
122 }
123
GetFd() const124 int ScratchFile::GetFd() const {
125 return file_->Fd();
126 }
127
Close()128 void ScratchFile::Close() {
129 if (file_ != nullptr) {
130 if (file_->FlushCloseOrErase() != 0) {
131 PLOG(WARNING) << "Error closing scratch file.";
132 }
133 file_.reset();
134 }
135 }
136
Unlink()137 void ScratchFile::Unlink() {
138 if (!OS::FileExists(filename_.c_str())) {
139 return;
140 }
141 Close();
142 int unlink_result = unlink(filename_.c_str());
143 CHECK_EQ(0, unlink_result);
144 }
145
GetAndroidBuildTop()146 std::string CommonArtTestImpl::GetAndroidBuildTop() {
147 CHECK(IsHost());
148 std::string android_build_top;
149
150 // Look at how we were invoked to find the expected directory.
151 std::string argv;
152 if (android::base::ReadFileToString("/proc/self/cmdline", &argv)) {
153 // /proc/self/cmdline is the programs 'argv' with elements delimited by '\0'.
154 std::filesystem::path path(argv.substr(0, argv.find('\0')));
155 path = std::filesystem::absolute(path);
156 // Walk up until we find the one of the well-known directories.
157 for (; path.parent_path() != path; path = path.parent_path()) {
158 // We are running tests from out/host/linux-x86 on developer machine.
159 if (path.filename() == std::filesystem::path("linux-x86")) {
160 android_build_top = path.parent_path().parent_path().parent_path();
161 break;
162 }
163 // We are running tests from testcases (extracted from zip) on tradefed.
164 // The first path is for remote runs and the second path for local runs.
165 if (path.filename() == std::filesystem::path("testcases") ||
166 StartsWith(path.filename().string(), "host_testcases")) {
167 android_build_top = path.append("art_common");
168 break;
169 }
170 }
171 }
172 CHECK(!android_build_top.empty());
173
174 // Check that the expected directory matches the environment variable.
175 const char* android_build_top_from_env = getenv("ANDROID_BUILD_TOP");
176 android_build_top = std::filesystem::path(android_build_top).string();
177 CHECK(!android_build_top.empty());
178 if (android_build_top_from_env != nullptr) {
179 if (std::filesystem::weakly_canonical(android_build_top).string() !=
180 std::filesystem::weakly_canonical(android_build_top_from_env).string()) {
181 LOG(WARNING) << "Execution path (" << argv << ") not below ANDROID_BUILD_TOP ("
182 << android_build_top_from_env << ")! Using env-var.";
183 android_build_top = android_build_top_from_env;
184 }
185 } else {
186 setenv("ANDROID_BUILD_TOP", android_build_top.c_str(), /*overwrite=*/0);
187 }
188 if (android_build_top.back() != '/') {
189 android_build_top += '/';
190 }
191 return android_build_top;
192 }
193
GetAndroidHostOut()194 std::string CommonArtTestImpl::GetAndroidHostOut() {
195 CHECK(IsHost());
196
197 // Check that the expected directory matches the environment variable.
198 // ANDROID_HOST_OUT is set by envsetup or unset and is the full path to host binaries/libs
199 const char* android_host_out_from_env = getenv("ANDROID_HOST_OUT");
200 // OUT_DIR is a user-settable ENV_VAR that controls where soong puts build artifacts. It can
201 // either be relative to ANDROID_BUILD_TOP or a concrete path.
202 const char* android_out_dir = getenv("OUT_DIR");
203 // Take account of OUT_DIR setting.
204 if (android_out_dir == nullptr) {
205 android_out_dir = "out";
206 }
207 std::string android_host_out;
208 if (android_out_dir[0] == '/') {
209 android_host_out = (std::filesystem::path(android_out_dir) / "host" / "linux-x86").string();
210 } else {
211 android_host_out =
212 (std::filesystem::path(GetAndroidBuildTop()) / android_out_dir / "host" / "linux-x86")
213 .string();
214 }
215 std::filesystem::path expected(android_host_out);
216 if (android_host_out_from_env != nullptr) {
217 std::filesystem::path from_env(std::filesystem::weakly_canonical(android_host_out_from_env));
218 if (std::filesystem::weakly_canonical(expected).string() != from_env.string()) {
219 LOG(WARNING) << "Execution path (" << expected << ") not below ANDROID_HOST_OUT ("
220 << from_env << ")! Using env-var.";
221 expected = from_env;
222 }
223 } else {
224 setenv("ANDROID_HOST_OUT", android_host_out.c_str(), /*overwrite=*/0);
225 }
226 return expected.string();
227 }
228
SetUpAndroidRootEnvVars()229 void CommonArtTestImpl::SetUpAndroidRootEnvVars() {
230 if (IsHost()) {
231 std::string android_host_out = GetAndroidHostOut();
232
233 // Environment variable ANDROID_ROOT is set on the device, but not
234 // necessarily on the host.
235 const char* android_root_from_env = getenv("ANDROID_ROOT");
236 if (android_root_from_env == nullptr) {
237 // Use ANDROID_HOST_OUT for ANDROID_ROOT.
238 setenv("ANDROID_ROOT", android_host_out.c_str(), 1);
239 android_root_from_env = getenv("ANDROID_ROOT");
240 }
241
242 // Environment variable ANDROID_I18N_ROOT is set on the device, but not
243 // necessarily on the host. It needs to be set so that various libraries
244 // like libcore / icu4j / icu4c can find their data files.
245 const char* android_i18n_root_from_env = getenv("ANDROID_I18N_ROOT");
246 if (android_i18n_root_from_env == nullptr) {
247 // Use ${ANDROID_I18N_OUT}/com.android.i18n for ANDROID_I18N_ROOT.
248 std::string android_i18n_root = android_host_out.c_str();
249 android_i18n_root += "/com.android.i18n";
250 setenv("ANDROID_I18N_ROOT", android_i18n_root.c_str(), 1);
251 }
252
253 // Environment variable ANDROID_ART_ROOT is set on the device, but not
254 // necessarily on the host. It needs to be set so that various libraries
255 // like libcore / icu4j / icu4c can find their data files.
256 const char* android_art_root_from_env = getenv("ANDROID_ART_ROOT");
257 if (android_art_root_from_env == nullptr) {
258 // Use ${ANDROID_HOST_OUT}/com.android.art for ANDROID_ART_ROOT.
259 std::string android_art_root = android_host_out.c_str();
260 android_art_root += "/com.android.art";
261 setenv("ANDROID_ART_ROOT", android_art_root.c_str(), 1);
262 }
263
264 // Environment variable ANDROID_TZDATA_ROOT is set on the device, but not
265 // necessarily on the host. It needs to be set so that various libraries
266 // like libcore / icu4j / icu4c can find their data files.
267 const char* android_tzdata_root_from_env = getenv("ANDROID_TZDATA_ROOT");
268 if (android_tzdata_root_from_env == nullptr) {
269 // Use ${ANDROID_HOST_OUT}/com.android.tzdata for ANDROID_TZDATA_ROOT.
270 std::string android_tzdata_root = android_host_out.c_str();
271 android_tzdata_root += "/com.android.tzdata";
272 setenv("ANDROID_TZDATA_ROOT", android_tzdata_root.c_str(), 1);
273 }
274
275 setenv("LD_LIBRARY_PATH", ":", 0); // Required by java.lang.System.<clinit>.
276 }
277 }
278
SetUpAndroidDataDir(std::string & android_data)279 void CommonArtTestImpl::SetUpAndroidDataDir(std::string& android_data) {
280 if (IsHost()) {
281 const char* tmpdir = getenv("TMPDIR");
282 if (tmpdir != nullptr && tmpdir[0] != 0) {
283 android_data = tmpdir;
284 } else {
285 android_data = "/tmp";
286 }
287 } else {
288 // On target, we cannot use `/mnt/sdcard` because it is mounted `noexec`,
289 // nor `/data/dalvik-cache` as it is not accessible on `user` builds.
290 // Instead, use `/data/local/tmp`, which does not require any special
291 // permission.
292 android_data = "/data/local/tmp";
293 }
294 android_data += "/art-data-XXXXXX";
295 if (mkdtemp(&android_data[0]) == nullptr) {
296 PLOG(FATAL) << "mkdtemp(\"" << &android_data[0] << "\") failed";
297 }
298 setenv("ANDROID_DATA", android_data.c_str(), 1);
299 }
300
SetUp()301 void CommonArtTestImpl::SetUp() {
302 // Some tests clear these and when running with --no_isolate this can cause
303 // later tests to fail
304 Locks::Init();
305 MemMap::Init();
306 SetUpAndroidRootEnvVars();
307 SetUpAndroidDataDir(android_data_);
308
309 // Re-use the data temporary directory for /system_ext tests
310 android_system_ext_.append(android_data_.c_str());
311 android_system_ext_.append("/system_ext");
312 int mkdir_result = mkdir(android_system_ext_.c_str(), 0700);
313 ASSERT_EQ(mkdir_result, 0);
314 setenv("ANDROID_SYSTEM_EXT", android_system_ext_.c_str(), 1);
315
316 std::string system_ext_framework = android_system_ext_ + "/framework";
317 mkdir_result = mkdir(system_ext_framework.c_str(), 0700);
318 ASSERT_EQ(mkdir_result, 0);
319
320 dalvik_cache_.append(android_data_.c_str());
321 dalvik_cache_.append("/dalvik-cache");
322 mkdir_result = mkdir(dalvik_cache_.c_str(), 0700);
323 ASSERT_EQ(mkdir_result, 0);
324
325 if (kIsDebugBuild) {
326 static bool gSlowDebugTestFlag = false;
327 RegisterRuntimeDebugFlag(&gSlowDebugTestFlag);
328 SetRuntimeDebugFlagsEnabled(true);
329 CHECK(gSlowDebugTestFlag);
330 }
331 }
332
TearDownAndroidDataDir(const std::string & android_data,bool fail_on_error)333 void CommonArtTestImpl::TearDownAndroidDataDir(const std::string& android_data,
334 bool fail_on_error) {
335 if (fail_on_error) {
336 ASSERT_EQ(rmdir(android_data.c_str()), 0);
337 } else {
338 rmdir(android_data.c_str());
339 }
340 }
341
342 // Get prebuilt binary tool.
343 // The paths need to be updated when Android prebuilts update.
GetAndroidTool(const char * name,InstructionSet)344 std::string CommonArtTestImpl::GetAndroidTool(const char* name, InstructionSet) {
345 #ifndef ART_CLANG_PATH
346 UNUSED(name);
347 LOG(FATAL) << "There are no prebuilt tools available.";
348 UNREACHABLE();
349 #else
350 std::string path = GetAndroidBuildTop() + ART_CLANG_PATH + "/bin/";
351 CHECK(OS::DirectoryExists(path.c_str())) << path;
352 path += name;
353 CHECK(OS::FileExists(path.c_str())) << path;
354 return path;
355 #endif
356 }
357
GetCoreArtLocation()358 std::string CommonArtTestImpl::GetCoreArtLocation() {
359 return GetCoreFileLocation("art");
360 }
361
GetCoreOatLocation()362 std::string CommonArtTestImpl::GetCoreOatLocation() {
363 return GetCoreFileLocation("oat");
364 }
365
LoadExpectSingleDexFile(const char * location)366 std::unique_ptr<const DexFile> CommonArtTestImpl::LoadExpectSingleDexFile(const char* location) {
367 std::vector<std::unique_ptr<const DexFile>> dex_files;
368 std::string error_msg;
369 MemMap::Init();
370 static constexpr bool kVerifyChecksum = true;
371 const ArtDexFileLoader dex_file_loader;
372 std::string filename(IsHost() ? GetAndroidBuildTop() + location : location);
373 if (!dex_file_loader.Open(filename.c_str(),
374 std::string(location),
375 /* verify= */ true,
376 kVerifyChecksum,
377 &error_msg,
378 &dex_files)) {
379 LOG(FATAL) << "Could not open .dex file '" << filename << "': " << error_msg << "\n";
380 UNREACHABLE();
381 }
382 CHECK_EQ(1U, dex_files.size()) << "Expected only one dex file in " << filename;
383 return std::move(dex_files[0]);
384 }
385
ClearDirectory(const char * dirpath,bool recursive)386 void CommonArtTestImpl::ClearDirectory(const char* dirpath, bool recursive) {
387 ASSERT_TRUE(dirpath != nullptr);
388 DIR* dir = opendir(dirpath);
389 ASSERT_TRUE(dir != nullptr);
390 dirent* e;
391 struct stat s;
392 while ((e = readdir(dir)) != nullptr) {
393 if ((strcmp(e->d_name, ".") == 0) || (strcmp(e->d_name, "..") == 0)) {
394 continue;
395 }
396 std::string filename(dirpath);
397 filename.push_back('/');
398 filename.append(e->d_name);
399 int stat_result = lstat(filename.c_str(), &s);
400 ASSERT_EQ(0, stat_result) << "unable to stat " << filename;
401 if (S_ISDIR(s.st_mode)) {
402 if (recursive) {
403 ClearDirectory(filename.c_str());
404 int rmdir_result = rmdir(filename.c_str());
405 ASSERT_EQ(0, rmdir_result) << filename;
406 }
407 } else {
408 int unlink_result = unlink(filename.c_str());
409 ASSERT_EQ(0, unlink_result) << filename;
410 }
411 }
412 closedir(dir);
413 }
414
TearDown()415 void CommonArtTestImpl::TearDown() {
416 const char* android_data = getenv("ANDROID_DATA");
417 ASSERT_TRUE(android_data != nullptr);
418 ClearDirectory(dalvik_cache_.c_str());
419 int rmdir_cache_result = rmdir(dalvik_cache_.c_str());
420 ASSERT_EQ(0, rmdir_cache_result);
421 ClearDirectory(android_system_ext_.c_str(), true);
422 rmdir_cache_result = rmdir(android_system_ext_.c_str());
423 ASSERT_EQ(0, rmdir_cache_result);
424 TearDownAndroidDataDir(android_data_, true);
425 dalvik_cache_.clear();
426 android_system_ext_.clear();
427 }
428
GetDexFileName(const std::string & jar_prefix,bool host)429 static std::string GetDexFileName(const std::string& jar_prefix, bool host) {
430 std::string prefix(host ? GetAndroidRoot() : "");
431 const char* apexPath = (jar_prefix == "conscrypt") ? kAndroidConscryptApexDefaultPath
432 : (jar_prefix == "core-icu4j" ? kAndroidI18nApexDefaultPath
433 : kAndroidArtApexDefaultPath);
434 return StringPrintf("%s%s/javalib/%s.jar", prefix.c_str(), apexPath, jar_prefix.c_str());
435 }
436
GetLibCoreModuleNames() const437 std::vector<std::string> CommonArtTestImpl::GetLibCoreModuleNames() const {
438 // Note: This must start with the CORE_IMG_JARS in Android.common_path.mk
439 // because that's what we use for compiling the boot.art image.
440 // It may contain additional modules from TEST_CORE_JARS.
441 return {
442 // CORE_IMG_JARS modules.
443 "core-oj",
444 "core-libart",
445 "okhttp",
446 "bouncycastle",
447 "apache-xml",
448 // Additional modules.
449 "core-icu4j",
450 "conscrypt",
451 };
452 }
453
GetLibCoreDexFileNames(const std::vector<std::string> & modules) const454 std::vector<std::string> CommonArtTestImpl::GetLibCoreDexFileNames(
455 const std::vector<std::string>& modules) const {
456 std::vector<std::string> result;
457 result.reserve(modules.size());
458 for (const std::string& module : modules) {
459 result.push_back(GetDexFileName(module, IsHost()));
460 }
461 return result;
462 }
463
GetLibCoreDexFileNames() const464 std::vector<std::string> CommonArtTestImpl::GetLibCoreDexFileNames() const {
465 std::vector<std::string> modules = GetLibCoreModuleNames();
466 return GetLibCoreDexFileNames(modules);
467 }
468
GetLibCoreDexLocations(const std::vector<std::string> & modules) const469 std::vector<std::string> CommonArtTestImpl::GetLibCoreDexLocations(
470 const std::vector<std::string>& modules) const {
471 std::vector<std::string> result = GetLibCoreDexFileNames(modules);
472 if (IsHost()) {
473 // Strip the ANDROID_BUILD_TOP directory including the directory separator '/'.
474 std::string prefix = GetAndroidBuildTop();
475 for (std::string& location : result) {
476 CHECK_GT(location.size(), prefix.size());
477 CHECK_EQ(location.compare(0u, prefix.size(), prefix), 0)
478 << " prefix=" << prefix << " location=" << location;
479 location.erase(0u, prefix.size());
480 }
481 }
482 return result;
483 }
484
GetLibCoreDexLocations() const485 std::vector<std::string> CommonArtTestImpl::GetLibCoreDexLocations() const {
486 std::vector<std::string> modules = GetLibCoreModuleNames();
487 return GetLibCoreDexLocations(modules);
488 }
489
GetClassPathOption(const char * option,const std::vector<std::string> & class_path)490 std::string CommonArtTestImpl::GetClassPathOption(const char* option,
491 const std::vector<std::string>& class_path) {
492 return option + android::base::Join(class_path, ':');
493 }
494
495 // Check that for target builds we have ART_TARGET_NATIVETEST_DIR set.
496 #ifdef ART_TARGET
497 #ifndef ART_TARGET_NATIVETEST_DIR
498 #error "ART_TARGET_NATIVETEST_DIR not set."
499 #endif
500 // Wrap it as a string literal.
501 #define ART_TARGET_NATIVETEST_DIR_STRING STRINGIFY(ART_TARGET_NATIVETEST_DIR) "/"
502 #else
503 #define ART_TARGET_NATIVETEST_DIR_STRING ""
504 #endif
505
GetTestDexFileName(const char * name) const506 std::string CommonArtTestImpl::GetTestDexFileName(const char* name) const {
507 CHECK(name != nullptr);
508 // The needed jar files for gtest are located next to the gtest binary itself.
509 std::string cmdline;
510 bool result = android::base::ReadFileToString("/proc/self/cmdline", &cmdline);
511 CHECK(result);
512 UniqueCPtr<char[]> executable_path(realpath(cmdline.c_str(), nullptr));
513 CHECK(executable_path != nullptr);
514 std::string executable_dir = dirname(executable_path.get());
515 for (auto ext : {".jar", ".dex"}) {
516 std::string path = executable_dir + "/art-gtest-jars-" + name + ext;
517 if (OS::FileExists(path.c_str())) {
518 return path;
519 }
520 }
521 LOG(FATAL) << "Test file " << name << " not found";
522 UNREACHABLE();
523 }
524
OpenDexFiles(const char * filename)525 std::vector<std::unique_ptr<const DexFile>> CommonArtTestImpl::OpenDexFiles(const char* filename) {
526 static constexpr bool kVerify = true;
527 static constexpr bool kVerifyChecksum = true;
528 std::string error_msg;
529 const ArtDexFileLoader dex_file_loader;
530 std::vector<std::unique_ptr<const DexFile>> dex_files;
531 bool success = dex_file_loader.Open(filename,
532 filename,
533 kVerify,
534 kVerifyChecksum,
535 &error_msg,
536 &dex_files);
537 CHECK(success) << "Failed to open '" << filename << "': " << error_msg;
538 for (auto& dex_file : dex_files) {
539 CHECK_EQ(PROT_READ, dex_file->GetPermissions());
540 CHECK(dex_file->IsReadOnly());
541 }
542 return dex_files;
543 }
544
OpenDexFile(const char * filename)545 std::unique_ptr<const DexFile> CommonArtTestImpl::OpenDexFile(const char* filename) {
546 std::vector<std::unique_ptr<const DexFile>> dex_files(OpenDexFiles(filename));
547 CHECK_EQ(dex_files.size(), 1u) << "Expected only one dex file";
548 return std::move(dex_files[0]);
549 }
550
OpenTestDexFiles(const char * name)551 std::vector<std::unique_ptr<const DexFile>> CommonArtTestImpl::OpenTestDexFiles(
552 const char* name) {
553 return OpenDexFiles(GetTestDexFileName(name).c_str());
554 }
555
OpenTestDexFile(const char * name)556 std::unique_ptr<const DexFile> CommonArtTestImpl::OpenTestDexFile(const char* name) {
557 return OpenDexFile(GetTestDexFileName(name).c_str());
558 }
559
GetImageDirectory()560 std::string CommonArtTestImpl::GetImageDirectory() {
561 std::string path;
562 if (IsHost()) {
563 const char* host_dir = getenv("ANDROID_HOST_OUT");
564 CHECK(host_dir != nullptr);
565 path = std::string(host_dir) + "/apex/art_boot_images";
566 } else {
567 path = std::string(kAndroidArtApexDefaultPath);
568 }
569 return path + "/javalib";
570 }
571
GetCoreFileLocation(const char * suffix)572 std::string CommonArtTestImpl::GetCoreFileLocation(const char* suffix) {
573 CHECK(suffix != nullptr);
574 return GetImageDirectory() + "/boot." + suffix;
575 }
576
CreateClassPath(const std::vector<std::unique_ptr<const DexFile>> & dex_files)577 std::string CommonArtTestImpl::CreateClassPath(
578 const std::vector<std::unique_ptr<const DexFile>>& dex_files) {
579 CHECK(!dex_files.empty());
580 std::string classpath = dex_files[0]->GetLocation();
581 for (size_t i = 1; i < dex_files.size(); i++) {
582 classpath += ":" + dex_files[i]->GetLocation();
583 }
584 return classpath;
585 }
586
CreateClassPathWithChecksums(const std::vector<std::unique_ptr<const DexFile>> & dex_files)587 std::string CommonArtTestImpl::CreateClassPathWithChecksums(
588 const std::vector<std::unique_ptr<const DexFile>>& dex_files) {
589 CHECK(!dex_files.empty());
590 std::string classpath = dex_files[0]->GetLocation() + "*" +
591 std::to_string(dex_files[0]->GetLocationChecksum());
592 for (size_t i = 1; i < dex_files.size(); i++) {
593 classpath += ":" + dex_files[i]->GetLocation() + "*" +
594 std::to_string(dex_files[i]->GetLocationChecksum());
595 }
596 return classpath;
597 }
598
ForkAndExec(const std::vector<std::string> & argv,const PostForkFn & post_fork,const OutputHandlerFn & handler)599 CommonArtTestImpl::ForkAndExecResult CommonArtTestImpl::ForkAndExec(
600 const std::vector<std::string>& argv,
601 const PostForkFn& post_fork,
602 const OutputHandlerFn& handler) {
603 ForkAndExecResult result;
604 result.status_code = 0;
605 result.stage = ForkAndExecResult::kLink;
606
607 std::vector<const char*> c_args;
608 for (const std::string& str : argv) {
609 c_args.push_back(str.c_str());
610 }
611 c_args.push_back(nullptr);
612
613 android::base::unique_fd link[2];
614 {
615 int link_fd[2];
616
617 if (pipe(link_fd) == -1) {
618 return result;
619 }
620 link[0].reset(link_fd[0]);
621 link[1].reset(link_fd[1]);
622 }
623
624 result.stage = ForkAndExecResult::kFork;
625
626 pid_t pid = fork();
627 if (pid == -1) {
628 return result;
629 }
630
631 if (pid == 0) {
632 if (!post_fork()) {
633 LOG(ERROR) << "Failed post-fork function";
634 exit(1);
635 UNREACHABLE();
636 }
637
638 // Redirect stdout and stderr.
639 dup2(link[1].get(), STDOUT_FILENO);
640 dup2(link[1].get(), STDERR_FILENO);
641
642 link[0].reset();
643 link[1].reset();
644
645 execv(c_args[0], const_cast<char* const*>(c_args.data()));
646 exit(1);
647 UNREACHABLE();
648 }
649
650 result.stage = ForkAndExecResult::kWaitpid;
651 link[1].reset();
652
653 char buffer[128] = { 0 };
654 ssize_t bytes_read = 0;
655 while (TEMP_FAILURE_RETRY(bytes_read = read(link[0].get(), buffer, 128)) > 0) {
656 handler(buffer, bytes_read);
657 }
658 handler(buffer, 0u); // End with a virtual write of zero length to simplify clients.
659
660 link[0].reset();
661
662 if (waitpid(pid, &result.status_code, 0) == -1) {
663 return result;
664 }
665
666 result.stage = ForkAndExecResult::kFinished;
667 return result;
668 }
669
ForkAndExec(const std::vector<std::string> & argv,const PostForkFn & post_fork,std::string * output)670 CommonArtTestImpl::ForkAndExecResult CommonArtTestImpl::ForkAndExec(
671 const std::vector<std::string>& argv, const PostForkFn& post_fork, std::string* output) {
672 auto string_collect_fn = [output](char* buf, size_t len) {
673 *output += std::string(buf, len);
674 };
675 return ForkAndExec(argv, post_fork, string_collect_fn);
676 }
677
678 } // namespace art
679