// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include #include "base/android/path_utils.h" #include "base/files/file_path.h" #include "base/logging.h" #include "base/macros.h" #include "base/memory/singleton.h" #include "base/message_loop/message_loop.h" #include "base/message_loop/message_pump_android.h" #include "base/path_service.h" #include "base/synchronization/waitable_event.h" #include "base/test/multiprocess_test.h" namespace { base::FilePath* g_test_data_dir = nullptr; struct RunState { RunState(base::MessagePump::Delegate* delegate, int run_depth) : delegate(delegate), run_depth(run_depth), should_quit(false) { } base::MessagePump::Delegate* delegate; // Used to count how many Run() invocations are on the stack. int run_depth; // Used to flag that the current Run() invocation should return ASAP. bool should_quit; }; RunState* g_state = nullptr; // A singleton WaitableEvent wrapper so we avoid a busy loop in // MessagePumpForUIStub. Other platforms use the native event loop which blocks // when there are no pending messages. class Waitable { public: static Waitable* GetInstance() { return base::Singleton>::get(); } // Signals that there are more work to do. void Signal() { waitable_event_.Signal(); } // Blocks until more work is scheduled. void Block() { waitable_event_.Wait(); } void Quit() { g_state->should_quit = true; Signal(); } private: friend struct base::DefaultSingletonTraits; Waitable() : waitable_event_(base::WaitableEvent::ResetPolicy::AUTOMATIC, base::WaitableEvent::InitialState::NOT_SIGNALED) {} base::WaitableEvent waitable_event_; DISALLOW_COPY_AND_ASSIGN(Waitable); }; // The MessagePumpForUI implementation for test purpose. class MessagePumpForUIStub : public base::MessagePumpForUI { public: MessagePumpForUIStub() : base::MessagePumpForUI() { Waitable::GetInstance(); } ~MessagePumpForUIStub() override {} bool IsTestImplementation() const override { return true; } // In tests, there isn't a native thread, as such RunLoop::Run() should be // used to run the loop instead of attaching and delegating to the native // loop. As such, this override ignores the Attach() request. void Attach(base::MessagePump::Delegate* delegate) override {} void Run(base::MessagePump::Delegate* delegate) override { // The following was based on message_pump_glib.cc, except we're using a // WaitableEvent since there are no native message loop to use. RunState state(delegate, g_state ? g_state->run_depth + 1 : 1); RunState* previous_state = g_state; g_state = &state; // When not nested we can use the real implementation, otherwise fall back // to the stub implementation. if (g_state->run_depth > 1) { RunNested(delegate); } else { MessagePumpForUI::Run(delegate); } g_state = previous_state; } void RunNested(base::MessagePump::Delegate* delegate) { bool more_work_is_plausible = true; for (;;) { if (!more_work_is_plausible) { Waitable::GetInstance()->Block(); if (g_state->should_quit) break; } more_work_is_plausible = g_state->delegate->DoWork(); if (g_state->should_quit) break; base::TimeTicks delayed_work_time; more_work_is_plausible |= g_state->delegate->DoDelayedWork(&delayed_work_time); if (g_state->should_quit) break; if (more_work_is_plausible) continue; more_work_is_plausible = g_state->delegate->DoIdleWork(); if (g_state->should_quit) break; more_work_is_plausible |= !delayed_work_time.is_null(); } } void Quit() override { CHECK(g_state); if (g_state->run_depth > 1) { Waitable::GetInstance()->Quit(); } else { MessagePumpForUI::Quit(); } } void ScheduleWork() override { if (g_state && g_state->run_depth > 1) { Waitable::GetInstance()->Signal(); } else { MessagePumpForUI::ScheduleWork(); } } void ScheduleDelayedWork(const base::TimeTicks& delayed_work_time) override { if (g_state && g_state->run_depth > 1) { Waitable::GetInstance()->Signal(); } else { MessagePumpForUI::ScheduleDelayedWork(delayed_work_time); } } }; std::unique_ptr CreateMessagePumpForUIStub() { return std::unique_ptr(new MessagePumpForUIStub()); }; // Provides the test path for DIR_SOURCE_ROOT and DIR_ANDROID_APP_DATA. bool GetTestProviderPath(int key, base::FilePath* result) { switch (key) { // TODO(agrieve): Stop overriding DIR_ANDROID_APP_DATA. // https://crbug.com/617734 // Instead DIR_ASSETS should be used to discover assets file location in // tests. case base::DIR_ANDROID_APP_DATA: case base::DIR_ASSETS: case base::DIR_SOURCE_ROOT: CHECK(g_test_data_dir != nullptr); *result = *g_test_data_dir; return true; default: return false; } } void InitPathProvider(int key) { base::FilePath path; // If failed to override the key, that means the way has not been registered. if (GetTestProviderPath(key, &path) && !base::PathService::Override(key, path)) { base::PathService::RegisterProvider(&GetTestProviderPath, key, key + 1); } } } // namespace namespace base { void InitAndroidTestLogging() { logging::LoggingSettings settings; settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG; logging::InitLogging(settings); // To view log output with IDs and timestamps use "adb logcat -v threadtime". logging::SetLogItems(false, // Process ID false, // Thread ID false, // Timestamp false); // Tick count } void InitAndroidTestPaths(const FilePath& test_data_dir) { if (g_test_data_dir) { CHECK(test_data_dir == *g_test_data_dir); return; } g_test_data_dir = new FilePath(test_data_dir); InitPathProvider(DIR_SOURCE_ROOT); InitPathProvider(DIR_ANDROID_APP_DATA); InitPathProvider(DIR_ASSETS); } void InitAndroidTestMessageLoop() { if (!MessageLoop::InitMessagePumpForUIFactory(&CreateMessagePumpForUIStub)) LOG(INFO) << "MessagePumpForUIFactory already set, unable to override."; } } // namespace base