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