common_runtime_test.cc revision a7a4759946d9f11c88dc108b2b6a9518ce9c1e18
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_runtime_test.h" 18 19#include <cstdio> 20#include <dirent.h> 21#include <dlfcn.h> 22#include <fcntl.h> 23#include <ScopedLocalRef.h> 24#include <stdlib.h> 25 26#include "../../external/icu/icu4c/source/common/unicode/uvernum.h" 27#include "art_field-inl.h" 28#include "base/macros.h" 29#include "base/logging.h" 30#include "base/stl_util.h" 31#include "base/stringprintf.h" 32#include "base/unix_file/fd_file.h" 33#include "class_linker.h" 34#include "compiler_callbacks.h" 35#include "dex_file-inl.h" 36#include "gc_root-inl.h" 37#include "gc/heap.h" 38#include "gtest/gtest.h" 39#include "handle_scope-inl.h" 40#include "interpreter/unstarted_runtime.h" 41#include "jni_internal.h" 42#include "mirror/class-inl.h" 43#include "mirror/class_loader.h" 44#include "mem_map.h" 45#include "native/dalvik_system_DexFile.h" 46#include "noop_compiler_callbacks.h" 47#include "os.h" 48#include "primitive.h" 49#include "runtime-inl.h" 50#include "scoped_thread_state_change.h" 51#include "thread.h" 52#include "well_known_classes.h" 53 54int main(int argc, char **argv) { 55 // Gtests can be very noisy. For example, an executable with multiple tests will trigger native 56 // bridge warnings. The following line reduces the minimum log severity to ERROR and suppresses 57 // everything else. In case you want to see all messages, comment out the line. 58 setenv("ANDROID_LOG_TAGS", "*:e", 1); 59 60 art::InitLogging(argv); 61 LOG(::art::INFO) << "Running main() from common_runtime_test.cc..."; 62 testing::InitGoogleTest(&argc, argv); 63 return RUN_ALL_TESTS(); 64} 65 66namespace art { 67 68ScratchFile::ScratchFile() { 69 // ANDROID_DATA needs to be set 70 CHECK_NE(static_cast<char*>(nullptr), getenv("ANDROID_DATA")) << 71 "Are you subclassing RuntimeTest?"; 72 filename_ = getenv("ANDROID_DATA"); 73 filename_ += "/TmpFile-XXXXXX"; 74 int fd = mkstemp(&filename_[0]); 75 CHECK_NE(-1, fd); 76 file_.reset(new File(fd, GetFilename(), true)); 77} 78 79ScratchFile::ScratchFile(const ScratchFile& other, const char* suffix) { 80 filename_ = other.GetFilename(); 81 filename_ += suffix; 82 int fd = open(filename_.c_str(), O_RDWR | O_CREAT, 0666); 83 CHECK_NE(-1, fd); 84 file_.reset(new File(fd, GetFilename(), true)); 85} 86 87ScratchFile::ScratchFile(File* file) { 88 CHECK(file != nullptr); 89 filename_ = file->GetPath(); 90 file_.reset(file); 91} 92 93ScratchFile::~ScratchFile() { 94 Unlink(); 95} 96 97int ScratchFile::GetFd() const { 98 return file_->Fd(); 99} 100 101void ScratchFile::Close() { 102 if (file_.get() != nullptr) { 103 if (file_->FlushCloseOrErase() != 0) { 104 PLOG(WARNING) << "Error closing scratch file."; 105 } 106 } 107} 108 109void ScratchFile::Unlink() { 110 if (!OS::FileExists(filename_.c_str())) { 111 return; 112 } 113 Close(); 114 int unlink_result = unlink(filename_.c_str()); 115 CHECK_EQ(0, unlink_result); 116} 117 118static bool unstarted_initialized_ = false; 119 120CommonRuntimeTest::CommonRuntimeTest() {} 121CommonRuntimeTest::~CommonRuntimeTest() { 122 // Ensure the dex files are cleaned up before the runtime. 123 loaded_dex_files_.clear(); 124 runtime_.reset(); 125} 126 127void CommonRuntimeTest::SetUpAndroidRoot() { 128 if (IsHost()) { 129 // $ANDROID_ROOT is set on the device, but not necessarily on the host. 130 // But it needs to be set so that icu4c can find its locale data. 131 const char* android_root_from_env = getenv("ANDROID_ROOT"); 132 if (android_root_from_env == nullptr) { 133 // Use ANDROID_HOST_OUT for ANDROID_ROOT if it is set. 134 const char* android_host_out = getenv("ANDROID_HOST_OUT"); 135 if (android_host_out != nullptr) { 136 setenv("ANDROID_ROOT", android_host_out, 1); 137 } else { 138 // Build it from ANDROID_BUILD_TOP or cwd 139 std::string root; 140 const char* android_build_top = getenv("ANDROID_BUILD_TOP"); 141 if (android_build_top != nullptr) { 142 root += android_build_top; 143 } else { 144 // Not set by build server, so default to current directory 145 char* cwd = getcwd(nullptr, 0); 146 setenv("ANDROID_BUILD_TOP", cwd, 1); 147 root += cwd; 148 free(cwd); 149 } 150#if defined(__linux__) 151 root += "/out/host/linux-x86"; 152#elif defined(__APPLE__) 153 root += "/out/host/darwin-x86"; 154#else 155#error unsupported OS 156#endif 157 setenv("ANDROID_ROOT", root.c_str(), 1); 158 } 159 } 160 setenv("LD_LIBRARY_PATH", ":", 0); // Required by java.lang.System.<clinit>. 161 162 // Not set by build server, so default 163 if (getenv("ANDROID_HOST_OUT") == nullptr) { 164 setenv("ANDROID_HOST_OUT", getenv("ANDROID_ROOT"), 1); 165 } 166 } 167} 168 169void CommonRuntimeTest::SetUpAndroidData(std::string& android_data) { 170 // On target, Cannot use /mnt/sdcard because it is mounted noexec, so use subdir of dalvik-cache 171 if (IsHost()) { 172 const char* tmpdir = getenv("TMPDIR"); 173 if (tmpdir != nullptr && tmpdir[0] != 0) { 174 android_data = tmpdir; 175 } else { 176 android_data = "/tmp"; 177 } 178 } else { 179 android_data = "/data/dalvik-cache"; 180 } 181 android_data += "/art-data-XXXXXX"; 182 if (mkdtemp(&android_data[0]) == nullptr) { 183 PLOG(FATAL) << "mkdtemp(\"" << &android_data[0] << "\") failed"; 184 } 185 setenv("ANDROID_DATA", android_data.c_str(), 1); 186} 187 188void CommonRuntimeTest::TearDownAndroidData(const std::string& android_data, bool fail_on_error) { 189 if (fail_on_error) { 190 ASSERT_EQ(rmdir(android_data.c_str()), 0); 191 } else { 192 rmdir(android_data.c_str()); 193 } 194} 195 196// Helper - find directory with the following format: 197// ${ANDROID_BUILD_TOP}/${subdir1}/${subdir2}-${version}/${subdir3}/bin/ 198static std::string GetAndroidToolsDir(const std::string& subdir1, 199 const std::string& subdir2, 200 const std::string& subdir3) { 201 std::string root; 202 const char* android_build_top = getenv("ANDROID_BUILD_TOP"); 203 if (android_build_top != nullptr) { 204 root = android_build_top; 205 } else { 206 // Not set by build server, so default to current directory 207 char* cwd = getcwd(nullptr, 0); 208 setenv("ANDROID_BUILD_TOP", cwd, 1); 209 root = cwd; 210 free(cwd); 211 } 212 213 std::string toolsdir = root + "/" + subdir1; 214 std::string founddir; 215 DIR* dir; 216 if ((dir = opendir(toolsdir.c_str())) != nullptr) { 217 float maxversion = 0; 218 struct dirent* entry; 219 while ((entry = readdir(dir)) != nullptr) { 220 std::string format = subdir2 + "-%f"; 221 float version; 222 if (std::sscanf(entry->d_name, format.c_str(), &version) == 1) { 223 if (version > maxversion) { 224 maxversion = version; 225 founddir = toolsdir + "/" + entry->d_name + "/" + subdir3 + "/bin/"; 226 } 227 } 228 } 229 closedir(dir); 230 } 231 232 if (founddir.empty()) { 233 ADD_FAILURE() << "Can not find Android tools directory."; 234 } 235 return founddir; 236} 237 238std::string CommonRuntimeTest::GetAndroidHostToolsDir() { 239 return GetAndroidToolsDir("prebuilts/gcc/linux-x86/host", 240 "x86_64-linux-glibc2.15", 241 "x86_64-linux"); 242} 243 244std::string CommonRuntimeTest::GetAndroidTargetToolsDir(InstructionSet isa) { 245 switch (isa) { 246 case kArm: 247 case kThumb2: 248 return GetAndroidToolsDir("prebuilts/gcc/linux-x86/arm", 249 "arm-linux-androideabi", 250 "arm-linux-androideabi"); 251 case kArm64: 252 return GetAndroidToolsDir("prebuilts/gcc/linux-x86/aarch64", 253 "aarch64-linux-android", 254 "aarch64-linux-android"); 255 case kX86: 256 case kX86_64: 257 return GetAndroidToolsDir("prebuilts/gcc/linux-x86/x86", 258 "x86_64-linux-android", 259 "x86_64-linux-android"); 260 case kMips: 261 case kMips64: 262 return GetAndroidToolsDir("prebuilts/gcc/linux-x86/mips", 263 "mips64el-linux-android", 264 "mips64el-linux-android"); 265 case kNone: 266 break; 267 } 268 ADD_FAILURE() << "Invalid isa " << isa; 269 return ""; 270} 271 272std::string CommonRuntimeTest::GetCoreArtLocation() { 273 return GetCoreFileLocation("art"); 274} 275 276std::string CommonRuntimeTest::GetCoreOatLocation() { 277 return GetCoreFileLocation("oat"); 278} 279 280std::unique_ptr<const DexFile> CommonRuntimeTest::LoadExpectSingleDexFile(const char* location) { 281 std::vector<std::unique_ptr<const DexFile>> dex_files; 282 std::string error_msg; 283 MemMap::Init(); 284 if (!DexFile::Open(location, location, &error_msg, &dex_files)) { 285 LOG(FATAL) << "Could not open .dex file '" << location << "': " << error_msg << "\n"; 286 UNREACHABLE(); 287 } else { 288 CHECK_EQ(1U, dex_files.size()) << "Expected only one dex file in " << location; 289 return std::move(dex_files[0]); 290 } 291} 292 293void CommonRuntimeTest::SetUp() { 294 SetUpAndroidRoot(); 295 SetUpAndroidData(android_data_); 296 dalvik_cache_.append(android_data_.c_str()); 297 dalvik_cache_.append("/dalvik-cache"); 298 int mkdir_result = mkdir(dalvik_cache_.c_str(), 0700); 299 ASSERT_EQ(mkdir_result, 0); 300 301 std::string min_heap_string(StringPrintf("-Xms%zdm", gc::Heap::kDefaultInitialSize / MB)); 302 std::string max_heap_string(StringPrintf("-Xmx%zdm", gc::Heap::kDefaultMaximumSize / MB)); 303 304 305 RuntimeOptions options; 306 std::string boot_class_path_string = "-Xbootclasspath"; 307 for (const std::string &core_dex_file_name : GetLibCoreDexFileNames()) { 308 boot_class_path_string += ":"; 309 boot_class_path_string += core_dex_file_name; 310 } 311 312 options.push_back(std::make_pair(boot_class_path_string, nullptr)); 313 options.push_back(std::make_pair("-Xcheck:jni", nullptr)); 314 options.push_back(std::make_pair(min_heap_string, nullptr)); 315 options.push_back(std::make_pair(max_heap_string, nullptr)); 316 317 callbacks_.reset(new NoopCompilerCallbacks()); 318 319 SetUpRuntimeOptions(&options); 320 321 // Install compiler-callbacks if SetupRuntimeOptions hasn't deleted them. 322 if (callbacks_.get() != nullptr) { 323 options.push_back(std::make_pair("compilercallbacks", callbacks_.get())); 324 } 325 326 PreRuntimeCreate(); 327 if (!Runtime::Create(options, false)) { 328 LOG(FATAL) << "Failed to create runtime"; 329 return; 330 } 331 PostRuntimeCreate(); 332 runtime_.reset(Runtime::Current()); 333 class_linker_ = runtime_->GetClassLinker(); 334 class_linker_->FixupDexCaches(runtime_->GetResolutionMethod()); 335 336 // Initialize maps for unstarted runtime. This needs to be here, as running clinits needs this 337 // set up. 338 if (!unstarted_initialized_) { 339 interpreter::UnstartedRuntime::Initialize(); 340 unstarted_initialized_ = true; 341 } 342 343 class_linker_->RunRootClinits(); 344 boot_class_path_ = class_linker_->GetBootClassPath(); 345 java_lang_dex_file_ = boot_class_path_[0]; 346 347 348 // Runtime::Create acquired the mutator_lock_ that is normally given away when we 349 // Runtime::Start, give it away now and then switch to a more managable ScopedObjectAccess. 350 Thread::Current()->TransitionFromRunnableToSuspended(kNative); 351 352 // We're back in native, take the opportunity to initialize well known classes. 353 WellKnownClasses::Init(Thread::Current()->GetJniEnv()); 354 355 // Create the heap thread pool so that the GC runs in parallel for tests. Normally, the thread 356 // pool is created by the runtime. 357 runtime_->GetHeap()->CreateThreadPool(); 358 runtime_->GetHeap()->VerifyHeap(); // Check for heap corruption before the test 359 // Reduce timinig-dependent flakiness in OOME behavior (eg StubTest.AllocObject). 360 runtime_->GetHeap()->SetMinIntervalHomogeneousSpaceCompactionByOom(0U); 361 362 // Get the boot class path from the runtime so it can be used in tests. 363 boot_class_path_ = class_linker_->GetBootClassPath(); 364 ASSERT_FALSE(boot_class_path_.empty()); 365 java_lang_dex_file_ = boot_class_path_[0]; 366} 367 368void CommonRuntimeTest::ClearDirectory(const char* dirpath) { 369 ASSERT_TRUE(dirpath != nullptr); 370 DIR* dir = opendir(dirpath); 371 ASSERT_TRUE(dir != nullptr); 372 dirent* e; 373 struct stat s; 374 while ((e = readdir(dir)) != nullptr) { 375 if ((strcmp(e->d_name, ".") == 0) || (strcmp(e->d_name, "..") == 0)) { 376 continue; 377 } 378 std::string filename(dirpath); 379 filename.push_back('/'); 380 filename.append(e->d_name); 381 int stat_result = lstat(filename.c_str(), &s); 382 ASSERT_EQ(0, stat_result) << "unable to stat " << filename; 383 if (S_ISDIR(s.st_mode)) { 384 ClearDirectory(filename.c_str()); 385 int rmdir_result = rmdir(filename.c_str()); 386 ASSERT_EQ(0, rmdir_result) << filename; 387 } else { 388 int unlink_result = unlink(filename.c_str()); 389 ASSERT_EQ(0, unlink_result) << filename; 390 } 391 } 392 closedir(dir); 393} 394 395void CommonRuntimeTest::TearDown() { 396 const char* android_data = getenv("ANDROID_DATA"); 397 ASSERT_TRUE(android_data != nullptr); 398 ClearDirectory(dalvik_cache_.c_str()); 399 int rmdir_cache_result = rmdir(dalvik_cache_.c_str()); 400 ASSERT_EQ(0, rmdir_cache_result); 401 TearDownAndroidData(android_data_, true); 402 403 // icu4c has a fixed 10-element array "gCommonICUDataArray". 404 // If we run > 10 tests, we fill that array and u_setCommonData fails. 405 // There's a function to clear the array, but it's not public... 406 typedef void (*IcuCleanupFn)(); 407 void* sym = dlsym(RTLD_DEFAULT, "u_cleanup_" U_ICU_VERSION_SHORT); 408 CHECK(sym != nullptr) << dlerror(); 409 IcuCleanupFn icu_cleanup_fn = reinterpret_cast<IcuCleanupFn>(sym); 410 (*icu_cleanup_fn)(); 411 412 Runtime::Current()->GetHeap()->VerifyHeap(); // Check for heap corruption after the test 413 414 // Manually closing the JNI libraries. 415 // Runtime does not support repeatedly doing JNI->CreateVM, thus we need to manually clean up the 416 // dynamic linking loader so that gtests would not fail. 417 // Bug: 25785594 418 if (runtime_->IsStarted()) { 419 { 420 // We retrieve the handle by calling dlopen on the library. To close it, we need to call 421 // dlclose twice, the first time to undo our dlopen and the second time to actually unload it. 422 // See man dlopen. 423 void* handle = dlopen("libjavacore.so", RTLD_LAZY); 424 dlclose(handle); 425 CHECK_EQ(0, dlclose(handle)); 426 } 427 { 428 void* handle = dlopen("libopenjdk.so", RTLD_LAZY); 429 dlclose(handle); 430 CHECK_EQ(0, dlclose(handle)); 431 } 432 } 433} 434 435std::vector<std::string> CommonRuntimeTest::GetLibCoreDexFileNames() { 436 return std::vector<std::string>({GetDexFileName("core-oj"), GetDexFileName("core-libart")}); 437} 438 439std::string CommonRuntimeTest::GetDexFileName(const std::string& jar_prefix) { 440 if (IsHost()) { 441 const char* host_dir = getenv("ANDROID_HOST_OUT"); 442 CHECK(host_dir != nullptr); 443 return StringPrintf("%s/framework/%s-hostdex.jar", host_dir, jar_prefix.c_str()); 444 } 445 return StringPrintf("%s/framework/%s.jar", GetAndroidRoot(), jar_prefix.c_str()); 446} 447 448std::string CommonRuntimeTest::GetTestAndroidRoot() { 449 if (IsHost()) { 450 const char* host_dir = getenv("ANDROID_HOST_OUT"); 451 CHECK(host_dir != nullptr); 452 return host_dir; 453 } 454 return GetAndroidRoot(); 455} 456 457// Check that for target builds we have ART_TARGET_NATIVETEST_DIR set. 458#ifdef ART_TARGET 459#ifndef ART_TARGET_NATIVETEST_DIR 460#error "ART_TARGET_NATIVETEST_DIR not set." 461#endif 462// Wrap it as a string literal. 463#define ART_TARGET_NATIVETEST_DIR_STRING STRINGIFY(ART_TARGET_NATIVETEST_DIR) "/" 464#else 465#define ART_TARGET_NATIVETEST_DIR_STRING "" 466#endif 467 468std::string CommonRuntimeTest::GetTestDexFileName(const char* name) { 469 CHECK(name != nullptr); 470 std::string filename; 471 if (IsHost()) { 472 filename += getenv("ANDROID_HOST_OUT"); 473 filename += "/framework/"; 474 } else { 475 filename += ART_TARGET_NATIVETEST_DIR_STRING; 476 } 477 filename += "art-gtest-"; 478 filename += name; 479 filename += ".jar"; 480 return filename; 481} 482 483std::vector<std::unique_ptr<const DexFile>> CommonRuntimeTest::OpenTestDexFiles(const char* name) { 484 std::string filename = GetTestDexFileName(name); 485 std::string error_msg; 486 std::vector<std::unique_ptr<const DexFile>> dex_files; 487 bool success = DexFile::Open(filename.c_str(), filename.c_str(), &error_msg, &dex_files); 488 CHECK(success) << "Failed to open '" << filename << "': " << error_msg; 489 for (auto& dex_file : dex_files) { 490 CHECK_EQ(PROT_READ, dex_file->GetPermissions()); 491 CHECK(dex_file->IsReadOnly()); 492 } 493 return dex_files; 494} 495 496std::unique_ptr<const DexFile> CommonRuntimeTest::OpenTestDexFile(const char* name) { 497 std::vector<std::unique_ptr<const DexFile>> vector = OpenTestDexFiles(name); 498 EXPECT_EQ(1U, vector.size()); 499 return std::move(vector[0]); 500} 501 502std::vector<const DexFile*> CommonRuntimeTest::GetDexFiles(jobject jclass_loader) { 503 std::vector<const DexFile*> ret; 504 505 ScopedObjectAccess soa(Thread::Current()); 506 507 StackHandleScope<2> hs(soa.Self()); 508 Handle<mirror::ClassLoader> class_loader = hs.NewHandle( 509 soa.Decode<mirror::ClassLoader*>(jclass_loader)); 510 511 DCHECK_EQ(class_loader->GetClass(), 512 soa.Decode<mirror::Class*>(WellKnownClasses::dalvik_system_PathClassLoader)); 513 DCHECK_EQ(class_loader->GetParent()->GetClass(), 514 soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_BootClassLoader)); 515 516 // The class loader is a PathClassLoader which inherits from BaseDexClassLoader. 517 // We need to get the DexPathList and loop through it. 518 ArtField* cookie_field = soa.DecodeField(WellKnownClasses::dalvik_system_DexFile_cookie); 519 ArtField* dex_file_field = 520 soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList__Element_dexFile); 521 mirror::Object* dex_path_list = 522 soa.DecodeField(WellKnownClasses::dalvik_system_PathClassLoader_pathList)-> 523 GetObject(class_loader.Get()); 524 if (dex_path_list != nullptr && dex_file_field!= nullptr && cookie_field != nullptr) { 525 // DexPathList has an array dexElements of Elements[] which each contain a dex file. 526 mirror::Object* dex_elements_obj = 527 soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList_dexElements)-> 528 GetObject(dex_path_list); 529 // Loop through each dalvik.system.DexPathList$Element's dalvik.system.DexFile and look 530 // at the mCookie which is a DexFile vector. 531 if (dex_elements_obj != nullptr) { 532 Handle<mirror::ObjectArray<mirror::Object>> dex_elements = 533 hs.NewHandle(dex_elements_obj->AsObjectArray<mirror::Object>()); 534 for (int32_t i = 0; i < dex_elements->GetLength(); ++i) { 535 mirror::Object* element = dex_elements->GetWithoutChecks(i); 536 if (element == nullptr) { 537 // Should never happen, fall back to java code to throw a NPE. 538 break; 539 } 540 mirror::Object* dex_file = dex_file_field->GetObject(element); 541 if (dex_file != nullptr) { 542 mirror::LongArray* long_array = cookie_field->GetObject(dex_file)->AsLongArray(); 543 DCHECK(long_array != nullptr); 544 int32_t long_array_size = long_array->GetLength(); 545 for (int32_t j = kDexFileIndexStart; j < long_array_size; ++j) { 546 const DexFile* cp_dex_file = reinterpret_cast<const DexFile*>(static_cast<uintptr_t>( 547 long_array->GetWithoutChecks(j))); 548 if (cp_dex_file == nullptr) { 549 LOG(WARNING) << "Null DexFile"; 550 continue; 551 } 552 ret.push_back(cp_dex_file); 553 } 554 } 555 } 556 } 557 } 558 559 return ret; 560} 561 562const DexFile* CommonRuntimeTest::GetFirstDexFile(jobject jclass_loader) { 563 std::vector<const DexFile*> tmp(GetDexFiles(jclass_loader)); 564 DCHECK(!tmp.empty()); 565 const DexFile* ret = tmp[0]; 566 DCHECK(ret != nullptr); 567 return ret; 568} 569 570jobject CommonRuntimeTest::LoadDex(const char* dex_name) { 571 std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles(dex_name); 572 std::vector<const DexFile*> class_path; 573 CHECK_NE(0U, dex_files.size()); 574 for (auto& dex_file : dex_files) { 575 class_path.push_back(dex_file.get()); 576 loaded_dex_files_.push_back(std::move(dex_file)); 577 } 578 579 Thread* self = Thread::Current(); 580 jobject class_loader = Runtime::Current()->GetClassLinker()->CreatePathClassLoader(self, 581 class_path, 582 nullptr); 583 self->SetClassLoaderOverride(class_loader); 584 return class_loader; 585} 586 587std::string CommonRuntimeTest::GetCoreFileLocation(const char* suffix) { 588 CHECK(suffix != nullptr); 589 590 std::string location; 591 if (IsHost()) { 592 const char* host_dir = getenv("ANDROID_HOST_OUT"); 593 CHECK(host_dir != nullptr); 594 location = StringPrintf("%s/framework/core.%s", host_dir, suffix); 595 } else { 596 location = StringPrintf("/data/art-test/core.%s", suffix); 597 } 598 599 return location; 600} 601 602CheckJniAbortCatcher::CheckJniAbortCatcher() : vm_(Runtime::Current()->GetJavaVM()) { 603 vm_->SetCheckJniAbortHook(Hook, &actual_); 604} 605 606CheckJniAbortCatcher::~CheckJniAbortCatcher() { 607 vm_->SetCheckJniAbortHook(nullptr, nullptr); 608 EXPECT_TRUE(actual_.empty()) << actual_; 609} 610 611void CheckJniAbortCatcher::Check(const char* expected_text) { 612 EXPECT_TRUE(actual_.find(expected_text) != std::string::npos) << "\n" 613 << "Expected to find: " << expected_text << "\n" 614 << "In the output : " << actual_; 615 actual_.clear(); 616} 617 618void CheckJniAbortCatcher::Hook(void* data, const std::string& reason) { 619 // We use += because when we're hooking the aborts like this, multiple problems can be found. 620 *reinterpret_cast<std::string*>(data) += reason; 621} 622 623} // namespace art 624 625namespace std { 626 627template <typename T> 628std::ostream& operator<<(std::ostream& os, const std::vector<T>& rhs) { 629os << ::art::ToString(rhs); 630return os; 631} 632 633} // namespace std 634