/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ART_LIBARTBASE_BASE_COMMON_ART_TEST_H_ #define ART_LIBARTBASE_BASE_COMMON_ART_TEST_H_ #include #include #include #include #include #include "base/globals.h" #include "base/mutex.h" #include "base/os.h" #include "base/unix_file/fd_file.h" #include "dex/art_dex_file_loader.h" #include "dex/compact_dex_level.h" #include "obj_ptr-inl.h" namespace art { using LogSeverity = android::base::LogSeverity; using ScopedLogSeverity = android::base::ScopedLogSeverity; template static inline ObjPtr MakeObjPtr(MirrorType* ptr) { return ptr; } template static inline ObjPtr MakeObjPtr(ObjPtr ptr) { return ptr; } // OBJ pointer helpers to avoid needing .Decode everywhere. #define EXPECT_OBJ_PTR_EQ(a, b) EXPECT_EQ(MakeObjPtr(a).Ptr(), MakeObjPtr(b).Ptr()) #define ASSERT_OBJ_PTR_EQ(a, b) ASSERT_EQ(MakeObjPtr(a).Ptr(), MakeObjPtr(b).Ptr()) #define EXPECT_OBJ_PTR_NE(a, b) EXPECT_NE(MakeObjPtr(a).Ptr(), MakeObjPtr(b).Ptr()) #define ASSERT_OBJ_PTR_NE(a, b) ASSERT_NE(MakeObjPtr(a).Ptr(), MakeObjPtr(b).Ptr()) class DexFile; class ScratchFile { public: ScratchFile(); explicit ScratchFile(const std::string& filename); ScratchFile(const ScratchFile& other, const char* suffix); ScratchFile(ScratchFile&& other) noexcept; ScratchFile& operator=(ScratchFile&& other) noexcept; explicit ScratchFile(File* file); ~ScratchFile(); const std::string& GetFilename() const { return filename_; } File* GetFile() const { return file_.get(); } int GetFd() const; void Close(); void Unlink(); private: std::string filename_; std::unique_ptr file_; }; class CommonArtTestImpl { public: CommonArtTestImpl() = default; virtual ~CommonArtTestImpl() = default; // Set up ANDROID_BUILD_TOP, ANDROID_HOST_OUT, ANDROID_ROOT, ANDROID_RUNTIME_ROOT, // and ANDROID_TZDATA_ROOT environment variables using sensible defaults if not already set. static void SetUpAndroidRootEnvVars(); // Set up the ANDROID_DATA environment variable, creating the directory if required. // Note: setting up ANDROID_DATA may create a temporary directory. If this is used in a // non-derived class, be sure to also call the corresponding tear-down below. static void SetUpAndroidDataDir(std::string& android_data); static void TearDownAndroidDataDir(const std::string& android_data, bool fail_on_error); // Get the names of the libcore modules. virtual std::vector GetLibCoreModuleNames() const; // Gets the paths of the libcore dex files for given modules. std::vector GetLibCoreDexFileNames(const std::vector& modules) const; // Gets the paths of the libcore dex files. std::vector GetLibCoreDexFileNames() const; // Gets the locations of the libcore dex files for given modules. std::vector GetLibCoreDexLocations(const std::vector& modules) const; // Gets the locations of the libcore dex files. std::vector GetLibCoreDexLocations() const; static std::string GetClassPathOption(const char* option, const std::vector& class_path); // Returns bin directory which contains host's prebuild tools. static std::string GetAndroidHostToolsDir(); // Retuerns the filename for a test dex (i.e. XandY or ManyMethods). std::string GetTestDexFileName(const char* name) const; template bool MutateDexFile(File* output_dex, const std::string& input_jar, const Mutator& mutator) { std::vector> dex_files; std::string error_msg; const ArtDexFileLoader dex_file_loader; CHECK(dex_file_loader.Open(input_jar.c_str(), input_jar.c_str(), /*verify*/ true, /*verify_checksum*/ true, &error_msg, &dex_files)) << error_msg; EXPECT_EQ(dex_files.size(), 1u) << "Only one input dex is supported"; const std::unique_ptr& dex = dex_files[0]; CHECK(dex->EnableWrite()) << "Failed to enable write"; DexFile* dex_file = const_cast(dex.get()); mutator(dex_file); const_cast(dex_file->GetHeader()).checksum_ = dex_file->CalculateChecksum(); if (!output_dex->WriteFully(dex->Begin(), dex->Size())) { return false; } if (output_dex->Flush() != 0) { PLOG(FATAL) << "Could not flush the output file."; } return true; } struct ForkAndExecResult { enum Stage { kLink, kFork, kWaitpid, kFinished, }; Stage stage; int status_code; bool StandardSuccess() { return stage == kFinished && WIFEXITED(status_code) && WEXITSTATUS(status_code) == 0; } }; using OutputHandlerFn = std::function; using PostForkFn = std::function; static ForkAndExecResult ForkAndExec(const std::vector& argv, const PostForkFn& post_fork, const OutputHandlerFn& handler); static ForkAndExecResult ForkAndExec(const std::vector& argv, const PostForkFn& post_fork, std::string* output); protected: static bool IsHost() { return !kIsTargetBuild; } // Helper - find directory with the following format: // ${ANDROID_BUILD_TOP}/${subdir1}/${subdir2}-${version}/${subdir3}/bin/ static std::string GetAndroidToolsDir(const std::string& subdir1, const std::string& subdir2, const std::string& subdir3); // File location to core.art, e.g. $ANDROID_HOST_OUT/system/framework/core.art static std::string GetCoreArtLocation(); // File location to core.oat, e.g. $ANDROID_HOST_OUT/system/framework/core.oat static std::string GetCoreOatLocation(); std::unique_ptr LoadExpectSingleDexFile(const char* location); void ClearDirectory(const char* dirpath, bool recursive = true); std::string GetTestAndroidRoot(); // Open a file (allows reading of framework jars). std::vector> OpenDexFiles(const char* filename); // Open a single dex file (aborts if there are more than one). std::unique_ptr OpenDexFile(const char* filename); // Open a test file (art-gtest-*.jar). std::vector> OpenTestDexFiles(const char* name); std::unique_ptr OpenTestDexFile(const char* name); std::string android_data_; std::string dalvik_cache_; virtual void SetUp(); virtual void TearDown(); // Creates the class path string for the given dex files (the list of dex file locations // separated by ':'). std::string CreateClassPath(const std::vector>& dex_files); // Same as CreateClassPath but add the dex file checksum after each location. The separator // is '*'. std::string CreateClassPathWithChecksums( const std::vector>& dex_files); static std::string GetCoreFileLocation(const char* suffix); std::vector> loaded_dex_files_; }; template class CommonArtTestBase : public TestType, public CommonArtTestImpl { public: CommonArtTestBase() {} virtual ~CommonArtTestBase() {} protected: void SetUp() override { CommonArtTestImpl::SetUp(); } void TearDown() override { CommonArtTestImpl::TearDown(); } }; using CommonArtTest = CommonArtTestBase; template using CommonArtTestWithParam = CommonArtTestBase>; #define TEST_DISABLED_FOR_TARGET() \ if (kIsTargetBuild) { \ printf("WARNING: TEST DISABLED FOR TARGET\n"); \ return; \ } #define TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS() \ if (!kHostStaticBuildEnabled) { \ printf("WARNING: TEST DISABLED FOR NON-STATIC HOST BUILDS\n"); \ return; \ } #define TEST_DISABLED_FOR_MEMORY_TOOL() \ if (kRunningOnMemoryTool) { \ printf("WARNING: TEST DISABLED FOR MEMORY TOOL\n"); \ return; \ } #define TEST_DISABLED_FOR_HEAP_POISONING() \ if (kPoisonHeapReferences) { \ printf("WARNING: TEST DISABLED FOR HEAP POISONING\n"); \ return; \ } } // namespace art #define TEST_DISABLED_FOR_MEMORY_TOOL_WITH_HEAP_POISONING() \ if (kRunningOnMemoryTool && kPoisonHeapReferences) { \ printf("WARNING: TEST DISABLED FOR MEMORY TOOL WITH HEAP POISONING\n"); \ return; \ } #endif // ART_LIBARTBASE_BASE_COMMON_ART_TEST_H_