diff options
Diffstat (limited to 'runtime')
-rw-r--r-- | runtime/class_linker.cc | 130 | ||||
-rw-r--r-- | runtime/common_test.h | 53 | ||||
-rw-r--r-- | runtime/gc/space/image_space.cc | 50 | ||||
-rw-r--r-- | runtime/oat_file.cc | 1 | ||||
-rw-r--r-- | runtime/runtime.cc | 61 | ||||
-rw-r--r-- | runtime/runtime.h | 77 | ||||
-rw-r--r-- | runtime/thread_list.cc | 1 | ||||
-rw-r--r-- | runtime/utils.cc | 53 | ||||
-rw-r--r-- | runtime/utils.h | 3 | ||||
-rw-r--r-- | runtime/utils_test.cc | 22 |
10 files changed, 160 insertions, 291 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 48ec5ab..52dd541 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -550,101 +550,41 @@ bool ClassLinker::GenerateOatFile(const char* dex_filename, const char* class_path = Runtime::Current()->GetClassPathString().c_str(); gc::Heap* heap = Runtime::Current()->GetHeap(); - std::string boot_image_option_string("--boot-image="); - boot_image_option_string += heap->GetImageSpace()->GetImageFilename(); - const char* boot_image_option = boot_image_option_string.c_str(); - - std::string dex_file_option_string("--dex-file="); - dex_file_option_string += dex_filename; - const char* dex_file_option = dex_file_option_string.c_str(); - - std::string oat_fd_option_string("--oat-fd="); - StringAppendF(&oat_fd_option_string, "%d", oat_fd); - const char* oat_fd_option = oat_fd_option_string.c_str(); - - std::string oat_location_option_string("--oat-location="); - oat_location_option_string += oat_cache_filename; - const char* oat_location_option = oat_location_option_string.c_str(); - - std::string oat_compiler_filter_string("-compiler-filter:"); - Runtime::CompilerFilter filter = Runtime::Current()->GetCompilerFilter(); - switch (filter) { - case Runtime::kInterpretOnly: - oat_compiler_filter_string += "interpret-only"; - break; - case Runtime::kSpace: - oat_compiler_filter_string += "space"; - break; - case Runtime::kBalanced: - oat_compiler_filter_string += "balanced"; - break; - case Runtime::kSpeed: - oat_compiler_filter_string += "speed"; - break; - case Runtime::kEverything: - oat_compiler_filter_string += "everything"; - break; - default: - LOG(FATAL) << "Unexpected case: " << filter; - } - const char* oat_compiler_filter_option = oat_compiler_filter_string.c_str(); - - // fork and exec dex2oat - pid_t pid = fork(); - if (pid == 0) { - // no allocation allowed between fork and exec - - // change process groups, so we don't get reaped by ProcessManager - setpgid(0, 0); - - // gLogVerbosity.class_linker = true; - VLOG(class_linker) << dex2oat - << " --runtime-arg -Xms64m" - << " --runtime-arg -Xmx64m" - << " --runtime-arg -classpath" - << " --runtime-arg " << class_path - << " --runtime-arg " << oat_compiler_filter_option -#if !defined(ART_TARGET) - << " --host" -#endif - << " " << boot_image_option - << " " << dex_file_option - << " " << oat_fd_option - << " " << oat_location_option; - - execl(dex2oat, dex2oat, - "--runtime-arg", "-Xms64m", - "--runtime-arg", "-Xmx64m", - "--runtime-arg", "-classpath", - "--runtime-arg", class_path, - "--runtime-arg", oat_compiler_filter_option, -#if !defined(ART_TARGET) - "--host", -#endif - boot_image_option, - dex_file_option, - oat_fd_option, - oat_location_option, - NULL); - - PLOG(FATAL) << "execl(" << dex2oat << ") failed"; - return false; - } else { - // wait for dex2oat to finish - int status; - pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0)); - if (got_pid != pid) { - *error_msg = StringPrintf("Failed to create oat file. Waitpid failed: wanted %d, got %d", - pid, got_pid); - return false; - } - if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { - *error_msg = StringPrintf("Failed to create oat file. %s failed with dex-file '%s'", - dex2oat, dex_filename); - return false; - } - } - return true; + std::string boot_image_option("--boot-image="); + boot_image_option += heap->GetImageSpace()->GetImageFilename(); + + std::string dex_file_option("--dex-file="); + dex_file_option += dex_filename; + + std::string oat_fd_option("--oat-fd="); + StringAppendF(&oat_fd_option, "%d", oat_fd); + + std::string oat_location_option("--oat-location="); + oat_location_option += oat_cache_filename; + + std::vector<std::string> argv; + argv.push_back(dex2oat); + argv.push_back("--runtime-arg"); + argv.push_back("-Xms64m"); + argv.push_back("--runtime-arg"); + argv.push_back("-Xmx64m"); + argv.push_back("--runtime-arg"); + argv.push_back("-classpath"); + argv.push_back("--runtime-arg"); + argv.push_back(class_path); + if (!kIsTargetBuild) { + argv.push_back("--host"); + } + argv.push_back(boot_image_option); + argv.push_back(dex_file_option); + argv.push_back(oat_fd_option); + argv.push_back(oat_location_option); + const std::vector<std::string>& compiler_options = Runtime::Current()->GetCompilerOptions(); + for (size_t i = 0; compiler_options.size(); ++i) { + argv.push_back(compiler_options[i].c_str()); + } + + return Exec(argv, error_msg); } const OatFile* ClassLinker::RegisterOatFile(const OatFile* oat_file) { diff --git a/runtime/common_test.h b/runtime/common_test.h index 7f9b6b1..e3843be 100644 --- a/runtime/common_test.h +++ b/runtime/common_test.h @@ -28,7 +28,9 @@ #include "../compiler/compiler_backend.h" #include "../compiler/dex/quick/dex_file_to_method_inliner_map.h" #include "../compiler/dex/verification_results.h" +#include "../compiler/driver/compiler_callbacks_impl.h" #include "../compiler/driver/compiler_driver.h" +#include "../compiler/driver/compiler_options.h" #include "base/macros.h" #include "base/stl_util.h" #include "base/stringprintf.h" @@ -458,11 +460,13 @@ class CommonTest : public testing::Test { ? CompilerBackend::kPortable : CompilerBackend::kQuick; - verification_results_.reset(new VerificationResults); + compiler_options_.reset(new CompilerOptions); + verification_results_.reset(new VerificationResults(compiler_options_.get())); method_inliner_map_.reset(new DexFileToMethodInlinerMap); - callbacks_.Reset(verification_results_.get(), method_inliner_map_.get()); + callbacks_.reset(new CompilerCallbacksImpl(verification_results_.get(), + method_inliner_map_.get())); Runtime::Options options; - options.push_back(std::make_pair("compilercallbacks", static_cast<CompilerCallbacks*>(&callbacks_))); + options.push_back(std::make_pair("compilercallbacks", callbacks_.get())); options.push_back(std::make_pair("bootclasspath", &boot_class_path_)); options.push_back(std::make_pair("-Xcheck:jni", reinterpret_cast<void*>(NULL))); options.push_back(std::make_pair(min_heap_string.c_str(), reinterpret_cast<void*>(NULL))); @@ -472,8 +476,8 @@ class CommonTest : public testing::Test { return; } runtime_.reset(Runtime::Current()); - // 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. + // 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); { ScopedObjectAccess soa(Thread::Current()); @@ -512,7 +516,8 @@ class CommonTest : public testing::Test { } class_linker_->FixupDexCaches(runtime_->GetResolutionMethod()); timer_.reset(new CumulativeLogger("Compilation times")); - compiler_driver_.reset(new CompilerDriver(verification_results_.get(), + compiler_driver_.reset(new CompilerDriver(compiler_options_.get(), + verification_results_.get(), method_inliner_map_.get(), compiler_backend, instruction_set, instruction_set_features, @@ -563,9 +568,10 @@ class CommonTest : public testing::Test { compiler_driver_.reset(); timer_.reset(); - callbacks_.Reset(nullptr, nullptr); + callbacks_.reset(); method_inliner_map_.reset(); verification_results_.reset(); + compiler_options_.reset(); STLDeleteElements(&opened_dex_files_); Runtime::Current()->GetHeap()->VerifyHeap(); // Check for heap corruption after the test @@ -693,36 +699,6 @@ class CommonTest : public testing::Test { image_reservation_.reset(); } - class TestCompilerCallbacks : public CompilerCallbacks { - public: - TestCompilerCallbacks() : verification_results_(nullptr), method_inliner_map_(nullptr) {} - - void Reset(VerificationResults* verification_results, - DexFileToMethodInlinerMap* method_inliner_map) { - verification_results_ = verification_results; - method_inliner_map_ = method_inliner_map; - } - - virtual bool MethodVerified(verifier::MethodVerifier* verifier) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - CHECK(verification_results_); - bool result = verification_results_->ProcessVerifiedMethod(verifier); - if (result && method_inliner_map_ != nullptr) { - MethodReference ref = verifier->GetMethodReference(); - method_inliner_map_->GetMethodInliner(ref.dex_file) - ->AnalyseMethodCode(verifier); - } - return result; - } - virtual void ClassRejected(ClassReference ref) { - verification_results_->AddRejectedClass(ref); - } - - private: - VerificationResults* verification_results_; - DexFileToMethodInlinerMap* method_inliner_map_; - }; - std::string android_data_; std::string dalvik_cache_; const DexFile* java_lang_dex_file_; // owned by runtime_ @@ -730,9 +706,10 @@ class CommonTest : public testing::Test { UniquePtr<Runtime> runtime_; // Owned by the runtime ClassLinker* class_linker_; + UniquePtr<CompilerOptions> compiler_options_; UniquePtr<VerificationResults> verification_results_; UniquePtr<DexFileToMethodInlinerMap> method_inliner_map_; - TestCompilerCallbacks callbacks_; + UniquePtr<CompilerCallbacksImpl> callbacks_; UniquePtr<CompilerDriver> compiler_driver_; UniquePtr<CumulativeLogger> timer_; diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc index ebad8dd..86dee1d 100644 --- a/runtime/gc/space/image_space.cc +++ b/runtime/gc/space/image_space.cc @@ -89,52 +89,14 @@ static bool GenerateImage(const std::string& image_file_name, std::string* error arg_vector.push_back("--host"); } - std::string command_line(Join(arg_vector, ' ')); - LOG(INFO) << "GenerateImage: " << command_line; - - // Convert the args to char pointers. - std::vector<char*> char_args; - for (std::vector<std::string>::iterator it = arg_vector.begin(); it != arg_vector.end(); - ++it) { - char_args.push_back(const_cast<char*>(it->c_str())); + const std::vector<std::string>& compiler_options = Runtime::Current()->GetImageCompilerOptions(); + for (size_t i = 0; compiler_options.size(); ++i) { + arg_vector.push_back(compiler_options[i].c_str()); } - char_args.push_back(NULL); - - // fork and exec dex2oat - pid_t pid = fork(); - if (pid == 0) { - // no allocation allowed between fork and exec - - // change process groups, so we don't get reaped by ProcessManager - setpgid(0, 0); - execv(dex2oat.c_str(), &char_args[0]); - - PLOG(FATAL) << "execv(" << dex2oat << ") failed"; - return false; - } else { - if (pid == -1) { - *error_msg = StringPrintf("Failed to generate image '%s' because fork failed: %s", - image_file_name.c_str(), strerror(errno)); - return false; - } - - // wait for dex2oat to finish - int status; - pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0)); - if (got_pid != pid) { - *error_msg = StringPrintf("Failed to generate image '%s' because waitpid failed: " - "wanted %d, got %d: %s", - image_file_name.c_str(), pid, got_pid, strerror(errno)); - return false; - } - if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { - *error_msg = StringPrintf("Failed to generate image '%s' because dex2oat failed: %s", - image_file_name.c_str(), command_line.c_str()); - return false; - } - } - return true; + std::string command_line(Join(arg_vector, ' ')); + LOG(INFO) << "GenerateImage: " << command_line; + return Exec(arg_vector, error_msg); } ImageSpace* ImageSpace::Create(const char* original_image_file_name) { diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index 00a8506..61f023c 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -84,6 +84,7 @@ OatFile* OatFile::Open(const std::string& filename, // This won't work for portable runtime execution because it doesn't process relocations. UniquePtr<File> file(OS::OpenFileForReading(filename.c_str())); if (file.get() == NULL) { + *error_msg = StringPrintf("Failed to open oat filename for reading: %s", strerror(errno)); return NULL; } return OpenElfFile(file.get(), location, requested_base, false, executable, error_msg); diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 3ccea36..1ef15f7 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -77,13 +77,6 @@ Runtime::Runtime() is_zygote_(false), is_concurrent_gc_enabled_(true), is_explicit_gc_disabled_(false), - compiler_filter_(kSpeed), - huge_method_threshold_(0), - large_method_threshold_(0), - small_method_threshold_(0), - tiny_method_threshold_(0), - num_dex_methods_threshold_(0), - sea_ir_mode_(false), default_stack_size_(0), heap_(nullptr), max_spins_before_thin_lock_inflation_(Monitor::kDefaultMaxSpinsBeforeThinLockInflation), @@ -452,14 +445,6 @@ Runtime::ParsedOptions* Runtime::ParsedOptions::Create(const Options& options, b parsed->hook_exit_ = exit; parsed->hook_abort_ = NULL; // We don't call abort(3) by default; see Runtime::Abort. - parsed->compiler_filter_ = Runtime::kDefaultCompilerFilter; - parsed->huge_method_threshold_ = Runtime::kDefaultHugeMethodThreshold; - parsed->large_method_threshold_ = Runtime::kDefaultLargeMethodThreshold; - parsed->small_method_threshold_ = Runtime::kDefaultSmallMethodThreshold; - parsed->tiny_method_threshold_ = Runtime::kDefaultTinyMethodThreshold; - parsed->num_dex_methods_threshold_ = Runtime::kDefaultNumDexMethodsThreshold; - - parsed->sea_ir_mode_ = false; // gLogVerbosity.class_linker = true; // TODO: don't check this in! // gLogVerbosity.compiler = true; // TODO: don't check this in! // gLogVerbosity.verifier = true; // TODO: don't check this in! @@ -721,28 +706,22 @@ Runtime::ParsedOptions* Runtime::ParsedOptions::Create(const Options& options, b } else if (StartsWith(option, "-Xprofile-backoff:")) { parsed->profile_backoff_coefficient_ = ParseDoubleOrDie( option, ':', 1.0, 10.0, ignore_unrecognized, parsed->profile_backoff_coefficient_); - } else if (option == "-compiler-filter:interpret-only") { - parsed->compiler_filter_ = kInterpretOnly; - } else if (option == "-compiler-filter:space") { - parsed->compiler_filter_ = kSpace; - } else if (option == "-compiler-filter:balanced") { - parsed->compiler_filter_ = kBalanced; - } else if (option == "-compiler-filter:speed") { - parsed->compiler_filter_ = kSpeed; - } else if (option == "-compiler-filter:everything") { - parsed->compiler_filter_ = kEverything; - } else if (option == "-sea_ir") { - parsed->sea_ir_mode_ = true; - } else if (StartsWith(option, "-huge-method-max:")) { - parsed->huge_method_threshold_ = ParseIntegerOrDie(option, ':'); - } else if (StartsWith(option, "-large-method-max:")) { - parsed->large_method_threshold_ = ParseIntegerOrDie(option, ':'); - } else if (StartsWith(option, "-small-method-max:")) { - parsed->small_method_threshold_ = ParseIntegerOrDie(option, ':'); - } else if (StartsWith(option, "-tiny-method-max:")) { - parsed->tiny_method_threshold_ = ParseIntegerOrDie(option, ':'); - } else if (StartsWith(option, "-num-dex-methods-max:")) { - parsed->num_dex_methods_threshold_ = ParseIntegerOrDie(option, ':'); + } else if (option == "-Xcompiler-option") { + i++; + if (i == options.size()) { + // TODO: usage + LOG(FATAL) << "Missing required compiler option for " << option; + return NULL; + } + parsed->compiler_options_.push_back(options[i].first); + } else if (option == "-Ximage-compiler-option") { + i++; + if (i == options.size()) { + // TODO: usage + LOG(FATAL) << "Missing required compiler option for " << option; + return NULL; + } + parsed->image_compiler_options_.push_back(options[i].first); } else { if (!ignore_unrecognized) { // TODO: print usage via vfprintf @@ -988,14 +967,6 @@ bool Runtime::Init(const Options& raw_options, bool ignore_unrecognized) { is_zygote_ = options->is_zygote_; is_explicit_gc_disabled_ = options->is_explicit_gc_disabled_; - compiler_filter_ = options->compiler_filter_; - huge_method_threshold_ = options->huge_method_threshold_; - large_method_threshold_ = options->large_method_threshold_; - small_method_threshold_ = options->small_method_threshold_; - tiny_method_threshold_ = options->tiny_method_threshold_; - num_dex_methods_threshold_ = options->num_dex_methods_threshold_; - - sea_ir_mode_ = options->sea_ir_mode_; vfprintf_ = options->hook_vfprintf_; exit_ = options->hook_exit_; abort_ = options->hook_abort_; diff --git a/runtime/runtime.h b/runtime/runtime.h index 223b8d5..8924921 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -72,26 +72,6 @@ class Runtime { public: typedef std::vector<std::pair<std::string, const void*> > Options; - enum CompilerFilter { - kInterpretOnly, // Compile nothing. - kSpace, // Maximize space savings. - kBalanced, // Try to get the best performance return on compilation investment. - kSpeed, // Maximize runtime performance. - kEverything // Force compilation (Note: excludes compilaton of class initializers). - }; - - // Guide heuristics to determine whether to compile method if profile data not available. -#if ART_SMALL_MODE - static const CompilerFilter kDefaultCompilerFilter = kInterpretOnly; -#else - static const CompilerFilter kDefaultCompilerFilter = kSpeed; -#endif - static const size_t kDefaultHugeMethodThreshold = 10000; - static const size_t kDefaultLargeMethodThreshold = 600; - static const size_t kDefaultSmallMethodThreshold = 60; - static const size_t kDefaultTinyMethodThreshold = 20; - static const size_t kDefaultNumDexMethodsThreshold = 900; - class ParsedOptions { public: // returns null if problem parsing and ignore_unrecognized is false @@ -140,13 +120,8 @@ class Runtime { void (*hook_exit_)(jint status); void (*hook_abort_)(); std::vector<std::string> properties_; - CompilerFilter compiler_filter_; - size_t huge_method_threshold_; - size_t large_method_threshold_; - size_t small_method_threshold_; - size_t tiny_method_threshold_; - size_t num_dex_methods_threshold_; - bool sea_ir_mode_; + std::vector<std::string> compiler_options_; + std::vector<std::string> image_compiler_options_; bool profile_; std::string profile_output_filename_; int profile_period_s_; @@ -178,42 +153,12 @@ class Runtime { return is_explicit_gc_disabled_; } -#ifdef ART_SEA_IR_MODE - bool IsSeaIRMode() const { - return sea_ir_mode_; - } -#endif - - void SetSeaIRMode(bool sea_ir_mode) { - sea_ir_mode_ = sea_ir_mode; - } - - CompilerFilter GetCompilerFilter() const { - return compiler_filter_; - } - - void SetCompilerFilter(CompilerFilter compiler_filter) { - compiler_filter_ = compiler_filter; + const std::vector<std::string>& GetCompilerOptions() const { + return compiler_options_; } - size_t GetHugeMethodThreshold() const { - return huge_method_threshold_; - } - - size_t GetLargeMethodThreshold() const { - return large_method_threshold_; - } - - size_t GetSmallMethodThreshold() const { - return small_method_threshold_; - } - - size_t GetTinyMethodThreshold() const { - return tiny_method_threshold_; - } - - size_t GetNumDexMethodsThreshold() const { - return num_dex_methods_threshold_; + const std::vector<std::string>& GetImageCompilerOptions() const { + return image_compiler_options_; } const std::string& GetHostPrefix() const { @@ -525,14 +470,8 @@ class Runtime { bool is_concurrent_gc_enabled_; bool is_explicit_gc_disabled_; - CompilerFilter compiler_filter_; - size_t huge_method_threshold_; - size_t large_method_threshold_; - size_t small_method_threshold_; - size_t tiny_method_threshold_; - size_t num_dex_methods_threshold_; - - bool sea_ir_mode_; + std::vector<std::string> compiler_options_; + std::vector<std::string> image_compiler_options_; // The host prefix is used during cross compilation. It is removed // from the start of host paths such as: diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc index 74e6f1c..d311945 100644 --- a/runtime/thread_list.cc +++ b/runtime/thread_list.cc @@ -269,6 +269,7 @@ size_t ThreadList::RunCheckpoint(Closure* checkpoint_function) { void ThreadList::SuspendAll() { Thread* self = Thread::Current(); + DCHECK(self != nullptr); VLOG(threads) << *self << " SuspendAll starting..."; diff --git a/runtime/utils.cc b/runtime/utils.cc index aad21bc..8e6ddaf 100644 --- a/runtime/utils.cc +++ b/runtime/utils.cc @@ -24,6 +24,7 @@ #include <unistd.h> #include "UniquePtr.h" +#include "base/stl_util.h" #include "base/unix_file/fd_file.h" #include "dex_file-inl.h" #include "mirror/art_field-inl.h" @@ -1203,4 +1204,56 @@ bool IsOatMagic(uint32_t magic) { sizeof(OatHeader::kOatMagic)) == 0); } +bool Exec(std::vector<std::string>& arg_vector, std::string* error_msg) { + const std::string command_line(Join(arg_vector, ' ')); + + CHECK_GE(arg_vector.size(), 1U) << command_line; + + // Convert the args to char pointers. + const char* program = arg_vector[0].c_str(); + std::vector<char*> args; + for (std::vector<std::string>::const_iterator it = arg_vector.begin(); it != arg_vector.end(); + ++it) { + CHECK(*it != nullptr); + args.push_back(const_cast<char*>(it->c_str())); + } + args.push_back(NULL); + + // fork and exec + pid_t pid = fork(); + if (pid == 0) { + // no allocation allowed between fork and exec + + // change process groups, so we don't get reaped by ProcessManager + setpgid(0, 0); + + execv(program, &args[0]); + + *error_msg = StringPrintf("Failed to execv(%s): %s", command_line.c_str(), strerror(errno)); + return false; + } else { + if (pid == -1) { + *error_msg = StringPrintf("Failed to execv(%s) because fork failed: %s", + command_line.c_str(), strerror(errno)); + return false; + } + + // wait for subprocess to finish + int status; + pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0)); + if (got_pid != pid) { + *error_msg = StringPrintf("Failed after fork for execv(%s) because waitpid failed: " + "wanted %d, got %d: %s", + command_line.c_str(), pid, got_pid, strerror(errno)); + return false; + } + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + *error_msg = StringPrintf("Failed execv(%s) because non-0 exit status", + command_line.c_str()); + return false; + } + } + return true; +} + } // namespace art diff --git a/runtime/utils.h b/runtime/utils.h index e2d8966..0bb06de 100644 --- a/runtime/utils.h +++ b/runtime/utils.h @@ -396,6 +396,9 @@ bool IsZipMagic(uint32_t magic); bool IsDexMagic(uint32_t magic); bool IsOatMagic(uint32_t magic); +// Wrapper on fork/execv to run a command in a subprocess. +bool Exec(std::vector<std::string>& arg_vector, std::string* error_msg); + class VoidFunctor { public: template <typename A> diff --git a/runtime/utils_test.cc b/runtime/utils_test.cc index b43177b..ff65e47 100644 --- a/runtime/utils_test.cc +++ b/runtime/utils_test.cc @@ -349,4 +349,26 @@ TEST_F(UtilsTest, GetDalvikCacheFilenameOrDie) { CheckGetDalvikCacheFilenameOrDie("/system/framework/boot.art", "system@framework@boot.art"); } +TEST_F(UtilsTest, ExecSuccess) { + std::vector<std::string> command; + if (kIsTargetBuild) { + command.push_back("/system/bin/id"); + } else { + command.push_back("/usr/bin/id"); + } + std::string error_msg; + EXPECT_TRUE(Exec(command, &error_msg)); + EXPECT_EQ(0U, error_msg.size()) << error_msg; +} + +// TODO: Disabled due to hang tearing down CommonTest. +// Renable after splitting into RuntimeTest and CompilerTest. +TEST_F(UtilsTest, DISABLED_ExecError) { + std::vector<std::string> command; + command.push_back("bogus"); + std::string error_msg; + EXPECT_FALSE(Exec(command, &error_msg)); + EXPECT_NE(0U, error_msg.size()); +} + } // namespace art |