diff options
Diffstat (limited to 'runtime/common_runtime_test.h')
-rw-r--r-- | runtime/common_runtime_test.h | 333 |
1 files changed, 41 insertions, 292 deletions
diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h index ac6d44b950..d0450317a3 100644 --- a/runtime/common_runtime_test.h +++ b/runtime/common_runtime_test.h @@ -17,73 +17,33 @@ #ifndef ART_RUNTIME_COMMON_RUNTIME_TEST_H_ #define ART_RUNTIME_COMMON_RUNTIME_TEST_H_ -#include <dirent.h> -#include <dlfcn.h> -#include <stdlib.h> -#include <sys/mman.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <fstream> -#include <memory> - -#include "../../external/icu/icu4c/source/common/unicode/uvernum.h" -#include "base/macros.h" -#include "base/stl_util.h" -#include "base/stringprintf.h" -#include "base/unix_file/fd_file.h" -#include "class_linker.h" -#include "dex_file-inl.h" -#include "entrypoints/entrypoint_utils.h" -#include "gc/heap.h" -#include "gtest/gtest.h" -#include "instruction_set.h" -#include "interpreter/interpreter.h" -#include "mirror/class_loader.h" -#include "noop_compiler_callbacks.h" -#include "oat_file.h" -#include "object_utils.h" +#include <gtest/gtest.h> +#include <jni.h> + +#include <string> + +#include "base/mutex.h" +#include "globals.h" #include "os.h" -#include "runtime.h" -#include "scoped_thread_state_change.h" -#include "ScopedLocalRef.h" -#include "thread.h" -#include "utils.h" -#include "verifier/method_verifier.h" -#include "verifier/method_verifier-inl.h" -#include "well_known_classes.h" namespace art { +class ClassLinker; +class CompilerCallbacks; +class DexFile; +class JavaVMExt; +class Runtime; +typedef std::vector<std::pair<std::string, const void*>> RuntimeOptions; + class ScratchFile { public: - ScratchFile() { - // ANDROID_DATA needs to be set - CHECK_NE(static_cast<char*>(nullptr), getenv("ANDROID_DATA")) << - "Are you subclassing RuntimeTest?"; - filename_ = getenv("ANDROID_DATA"); - filename_ += "/TmpFile-XXXXXX"; - int fd = mkstemp(&filename_[0]); - CHECK_NE(-1, fd); - file_.reset(new File(fd, GetFilename())); - } + ScratchFile(); - ScratchFile(const ScratchFile& other, const char* suffix) { - filename_ = other.GetFilename(); - filename_ += suffix; - int fd = open(filename_.c_str(), O_RDWR | O_CREAT, 0666); - CHECK_NE(-1, fd); - file_.reset(new File(fd, GetFilename())); - } + ScratchFile(const ScratchFile& other, const char* suffix); - explicit ScratchFile(File* file) { - CHECK(file != NULL); - filename_ = file->GetPath(); - file_.reset(file); - } + explicit ScratchFile(File* file); - ~ScratchFile() { - Unlink(); - } + ~ScratchFile(); const std::string& GetFilename() const { return filename_; @@ -93,17 +53,9 @@ class ScratchFile { return file_.get(); } - int GetFd() const { - return file_->Fd(); - } + int GetFd() const; - void Unlink() { - if (!OS::FileExists(filename_.c_str())) { - return; - } - int unlink_result = unlink(filename_.c_str()); - CHECK_EQ(0, unlink_result); - } + void Unlink(); private: std::string filename_; @@ -112,222 +64,37 @@ class ScratchFile { class CommonRuntimeTest : public testing::Test { public: - static void SetEnvironmentVariables(std::string& android_data) { - if (IsHost()) { - // $ANDROID_ROOT is set on the device, but not necessarily on the host. - // But it needs to be set so that icu4c can find its locale data. - const char* android_root_from_env = getenv("ANDROID_ROOT"); - if (android_root_from_env == nullptr) { - // Use ANDROID_HOST_OUT for ANDROID_ROOT if it is set. - const char* android_host_out = getenv("ANDROID_HOST_OUT"); - if (android_host_out != nullptr) { - setenv("ANDROID_ROOT", android_host_out, 1); - } else { - // Build it from ANDROID_BUILD_TOP or cwd - std::string root; - const char* android_build_top = getenv("ANDROID_BUILD_TOP"); - if (android_build_top != nullptr) { - root += android_build_top; - } else { - // Not set by build server, so default to current directory - char* cwd = getcwd(nullptr, 0); - setenv("ANDROID_BUILD_TOP", cwd, 1); - root += cwd; - free(cwd); - } -#if defined(__linux__) - root += "/out/host/linux-x86"; -#elif defined(__APPLE__) - root += "/out/host/darwin-x86"; -#else -#error unsupported OS -#endif - setenv("ANDROID_ROOT", root.c_str(), 1); - } - } - setenv("LD_LIBRARY_PATH", ":", 0); // Required by java.lang.System.<clinit>. - - // Not set by build server, so default - if (getenv("ANDROID_HOST_OUT") == nullptr) { - setenv("ANDROID_HOST_OUT", getenv("ANDROID_ROOT"), 1); - } - } - - // On target, Cannot use /mnt/sdcard because it is mounted noexec, so use subdir of dalvik-cache - android_data = (IsHost() ? "/tmp/art-data-XXXXXX" : "/data/dalvik-cache/art-data-XXXXXX"); - if (mkdtemp(&android_data[0]) == nullptr) { - PLOG(FATAL) << "mkdtemp(\"" << &android_data[0] << "\") failed"; - } - setenv("ANDROID_DATA", android_data.c_str(), 1); - } + static void SetEnvironmentVariables(std::string& android_data); + + CommonRuntimeTest(); + ~CommonRuntimeTest(); protected: static bool IsHost() { return !kIsTargetBuild; } - const DexFile* LoadExpectSingleDexFile(const char* location) { - std::vector<const DexFile*> dex_files; - std::string error_msg; - if (!DexFile::Open(location, location, &error_msg, &dex_files)) { - LOG(FATAL) << "Could not open .dex file '" << location << "': " << error_msg << "\n"; - return nullptr; - } else { - CHECK_EQ(1U, dex_files.size()) << "Expected only one dex file in " << location; - return dex_files[0]; - } - } + const DexFile* LoadExpectSingleDexFile(const char* location); - virtual void SetUp() { - SetEnvironmentVariables(android_data_); - dalvik_cache_.append(android_data_.c_str()); - dalvik_cache_.append("/dalvik-cache"); - int mkdir_result = mkdir(dalvik_cache_.c_str(), 0700); - ASSERT_EQ(mkdir_result, 0); - - std::string error_msg; - java_lang_dex_file_ = LoadExpectSingleDexFile(GetLibCoreDexFileName().c_str()); - boot_class_path_.push_back(java_lang_dex_file_); - - std::string min_heap_string(StringPrintf("-Xms%zdm", gc::Heap::kDefaultInitialSize / MB)); - std::string max_heap_string(StringPrintf("-Xmx%zdm", gc::Heap::kDefaultMaximumSize / MB)); - - Runtime::Options options; - options.push_back(std::make_pair("bootclasspath", &boot_class_path_)); - options.push_back(std::make_pair("-Xcheck:jni", nullptr)); - options.push_back(std::make_pair(min_heap_string.c_str(), nullptr)); - options.push_back(std::make_pair(max_heap_string.c_str(), nullptr)); - options.push_back(std::make_pair("compilercallbacks", &callbacks_)); - SetUpRuntimeOptions(&options); - if (!Runtime::Create(options, false)) { - LOG(FATAL) << "Failed to create runtime"; - return; - } - runtime_.reset(Runtime::Current()); - class_linker_ = runtime_->GetClassLinker(); - class_linker_->FixupDexCaches(runtime_->GetResolutionMethod()); - class_linker_->RunRootClinits(); - - // Runtime::Create acquired the mutator_lock_ that is normally given away when we - // Runtime::Start, give it away now and then switch to a more managable ScopedObjectAccess. - Thread::Current()->TransitionFromRunnableToSuspended(kNative); - - // We're back in native, take the opportunity to initialize well known classes. - WellKnownClasses::Init(Thread::Current()->GetJniEnv()); - - // Create the heap thread pool so that the GC runs in parallel for tests. Normally, the thread - // pool is created by the runtime. - runtime_->GetHeap()->CreateThreadPool(); - runtime_->GetHeap()->VerifyHeap(); // Check for heap corruption before the test - } + virtual void SetUp(); // Allow subclases such as CommonCompilerTest to add extra options. - virtual void SetUpRuntimeOptions(Runtime::Options *options) {} - - virtual void TearDown() { - const char* android_data = getenv("ANDROID_DATA"); - ASSERT_TRUE(android_data != nullptr); - DIR* dir = opendir(dalvik_cache_.c_str()); - ASSERT_TRUE(dir != nullptr); - dirent* e; - while ((e = readdir(dir)) != nullptr) { - if ((strcmp(e->d_name, ".") == 0) || (strcmp(e->d_name, "..") == 0)) { - continue; - } - std::string filename(dalvik_cache_); - filename.push_back('/'); - filename.append(e->d_name); - int unlink_result = unlink(filename.c_str()); - ASSERT_EQ(0, unlink_result); - } - closedir(dir); - int rmdir_cache_result = rmdir(dalvik_cache_.c_str()); - ASSERT_EQ(0, rmdir_cache_result); - int rmdir_data_result = rmdir(android_data_.c_str()); - ASSERT_EQ(0, rmdir_data_result); - - // icu4c has a fixed 10-element array "gCommonICUDataArray". - // If we run > 10 tests, we fill that array and u_setCommonData fails. - // There's a function to clear the array, but it's not public... - typedef void (*IcuCleanupFn)(); - void* sym = dlsym(RTLD_DEFAULT, "u_cleanup_" U_ICU_VERSION_SHORT); - CHECK(sym != nullptr) << dlerror(); - IcuCleanupFn icu_cleanup_fn = reinterpret_cast<IcuCleanupFn>(sym); - (*icu_cleanup_fn)(); - - STLDeleteElements(&opened_dex_files_); - - Runtime::Current()->GetHeap()->VerifyHeap(); // Check for heap corruption after the test - } + virtual void SetUpRuntimeOptions(RuntimeOptions* options) {} - std::string GetLibCoreDexFileName() { - return GetDexFileName("core-libart"); - } + virtual void TearDown(); - std::string GetDexFileName(const std::string& jar_prefix) { - if (IsHost()) { - const char* host_dir = getenv("ANDROID_HOST_OUT"); - CHECK(host_dir != nullptr); - return StringPrintf("%s/framework/%s-hostdex.jar", host_dir, jar_prefix.c_str()); - } - return StringPrintf("%s/framework/%s.jar", GetAndroidRoot(), jar_prefix.c_str()); - } + std::string GetLibCoreDexFileName(); - std::string GetTestAndroidRoot() { - if (IsHost()) { - const char* host_dir = getenv("ANDROID_HOST_OUT"); - CHECK(host_dir != nullptr); - return host_dir; - } - return GetAndroidRoot(); - } + std::string GetDexFileName(const std::string& jar_prefix); + + std::string GetTestAndroidRoot(); std::vector<const DexFile*> OpenTestDexFiles(const char* name) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - CHECK(name != nullptr); - std::string filename; - if (IsHost()) { - filename += getenv("ANDROID_HOST_OUT"); - filename += "/framework/"; - } else { - filename += "/data/nativetest/art/"; - } - filename += "art-gtest-"; - filename += name; - filename += ".jar"; - std::string error_msg; - std::vector<const DexFile*> dex_files; - bool success = DexFile::Open(filename.c_str(), filename.c_str(), &error_msg, &dex_files); - CHECK(success) << "Failed to open '" << filename << "': " << error_msg; - for (const DexFile* dex_file : dex_files) { - CHECK_EQ(PROT_READ, dex_file->GetPermissions()); - CHECK(dex_file->IsReadOnly()); - } - opened_dex_files_.insert(opened_dex_files_.end(), dex_files.begin(), dex_files.end()); - return dex_files; - } + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - const DexFile* OpenTestDexFile(const char* name) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - std::vector<const DexFile*> vector = OpenTestDexFiles(name); - EXPECT_EQ(1U, vector.size()); - return vector[0]; - } + const DexFile* OpenTestDexFile(const char* name) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - jobject LoadDex(const char* dex_name) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - std::vector<const DexFile*> dex_files = OpenTestDexFiles(dex_name); - CHECK_NE(0U, dex_files.size()); - for (const DexFile* dex_file : dex_files) { - class_linker_->RegisterDexFile(*dex_file); - } - ScopedObjectAccessUnchecked soa(Thread::Current()); - ScopedLocalRef<jobject> class_loader_local(soa.Env(), - soa.Env()->AllocObject(WellKnownClasses::dalvik_system_PathClassLoader)); - jobject class_loader = soa.Env()->NewGlobalRef(class_loader_local.get()); - soa.Self()->SetClassLoaderOverride(soa.Decode<mirror::ClassLoader*>(class_loader_local.get())); - Runtime::Current()->SetCompileTimeClassPath(class_loader, dex_files); - return class_loader; - } + jobject LoadDex(const char* dex_name) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); std::string android_data_; std::string dalvik_cache_; @@ -338,7 +105,7 @@ class CommonRuntimeTest : public testing::Test { ClassLinker* class_linker_; private: - NoopCompilerCallbacks callbacks_; + std::unique_ptr<CompilerCallbacks> callbacks_; std::vector<const DexFile*> opened_dex_files_; }; @@ -346,29 +113,14 @@ class CommonRuntimeTest : public testing::Test { // rather than aborting, so be careful! class CheckJniAbortCatcher { public: - CheckJniAbortCatcher() : vm_(Runtime::Current()->GetJavaVM()) { - vm_->check_jni_abort_hook = Hook; - vm_->check_jni_abort_hook_data = &actual_; - } + CheckJniAbortCatcher(); - ~CheckJniAbortCatcher() { - vm_->check_jni_abort_hook = nullptr; - vm_->check_jni_abort_hook_data = nullptr; - EXPECT_TRUE(actual_.empty()) << actual_; - } + ~CheckJniAbortCatcher(); - void Check(const char* expected_text) { - EXPECT_TRUE(actual_.find(expected_text) != std::string::npos) << "\n" - << "Expected to find: " << expected_text << "\n" - << "In the output : " << actual_; - actual_.clear(); - } + void Check(const char* expected_text); private: - static void Hook(void* data, const std::string& reason) { - // We use += because when we're hooking the aborts like this, multiple problems can be found. - *reinterpret_cast<std::string*>(data) += reason; - } + static void Hook(void* data, const std::string& reason); JavaVMExt* vm_; std::string actual_; @@ -399,10 +151,7 @@ namespace std { // TODO: isn't gtest supposed to be able to print STL types for itself? template <typename T> -std::ostream& operator<<(std::ostream& os, const std::vector<T>& rhs) { - os << ::art::ToString(rhs); - return os; -} +std::ostream& operator<<(std::ostream& os, const std::vector<T>& rhs); } // namespace std |