| // 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 <stdarg.h> | 
 | #include <string.h> | 
 |  | 
 | #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 = NULL; | 
 |  | 
 | // 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<Waitable, | 
 |                            base::LeakySingletonTraits<Waitable>>::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() | 
 |       : 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 { | 
 |   ~MessagePumpForUIStub() override {} | 
 |  | 
 |   void Start(base::MessagePump::Delegate* delegate) override { | 
 |     NOTREACHED() << "The Start() method shouldn't be called in test, using" | 
 |         " Run() method should be used."; | 
 |   } | 
 |  | 
 |   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; | 
 |  | 
 |     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(); | 
 |     } | 
 |  | 
 |     g_state = previous_state; | 
 |   } | 
 |  | 
 |   void Quit() override { Waitable::GetInstance()->Quit(); } | 
 |  | 
 |   void ScheduleWork() override { Waitable::GetInstance()->Signal(); } | 
 |  | 
 |   void ScheduleDelayedWork(const base::TimeTicks& delayed_work_time) override { | 
 |     Waitable::GetInstance()->Signal(); | 
 |   } | 
 | }; | 
 |  | 
 | std::unique_ptr<base::MessagePump> CreateMessagePumpForUIStub() { | 
 |   return std::unique_ptr<base::MessagePump>(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 |