1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <stdarg.h>
6 #include <string.h>
7 
8 #include "base/android/path_utils.h"
9 #include "base/files/file_path.h"
10 #include "base/logging.h"
11 #include "base/macros.h"
12 #include "base/memory/singleton.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/message_loop/message_pump_android.h"
15 #include "base/path_service.h"
16 #include "base/synchronization/waitable_event.h"
17 #include "base/test/multiprocess_test.h"
18 
19 namespace {
20 
21 base::FilePath* g_test_data_dir = nullptr;
22 
23 struct RunState {
RunState__anon6906c5fe0111::RunState24   RunState(base::MessagePump::Delegate* delegate, int run_depth)
25       : delegate(delegate),
26         run_depth(run_depth),
27         should_quit(false) {
28   }
29 
30   base::MessagePump::Delegate* delegate;
31 
32   // Used to count how many Run() invocations are on the stack.
33   int run_depth;
34 
35   // Used to flag that the current Run() invocation should return ASAP.
36   bool should_quit;
37 };
38 
39 RunState* g_state = nullptr;
40 
41 // A singleton WaitableEvent wrapper so we avoid a busy loop in
42 // MessagePumpForUIStub. Other platforms use the native event loop which blocks
43 // when there are no pending messages.
44 class Waitable {
45  public:
GetInstance()46   static Waitable* GetInstance() {
47     return base::Singleton<Waitable,
48                            base::LeakySingletonTraits<Waitable>>::get();
49   }
50 
51   // Signals that there are more work to do.
Signal()52   void Signal() { waitable_event_.Signal(); }
53 
54   // Blocks until more work is scheduled.
Block()55   void Block() { waitable_event_.Wait(); }
56 
Quit()57   void Quit() {
58     g_state->should_quit = true;
59     Signal();
60   }
61 
62  private:
63   friend struct base::DefaultSingletonTraits<Waitable>;
64 
Waitable()65   Waitable()
66       : waitable_event_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
67                         base::WaitableEvent::InitialState::NOT_SIGNALED) {}
68 
69   base::WaitableEvent waitable_event_;
70 
71   DISALLOW_COPY_AND_ASSIGN(Waitable);
72 };
73 
74 // The MessagePumpForUI implementation for test purpose.
75 class MessagePumpForUIStub : public base::MessagePumpForUI {
76  public:
MessagePumpForUIStub()77   MessagePumpForUIStub() : base::MessagePumpForUI() { Waitable::GetInstance(); }
~MessagePumpForUIStub()78   ~MessagePumpForUIStub() override {}
79 
IsTestImplementation() const80   bool IsTestImplementation() const override { return true; }
81 
82   // In tests, there isn't a native thread, as such RunLoop::Run() should be
83   // used to run the loop instead of attaching and delegating to the native
84   // loop. As such, this override ignores the Attach() request.
Attach(base::MessagePump::Delegate * delegate)85   void Attach(base::MessagePump::Delegate* delegate) override {}
86 
Run(base::MessagePump::Delegate * delegate)87   void Run(base::MessagePump::Delegate* delegate) override {
88     // The following was based on message_pump_glib.cc, except we're using a
89     // WaitableEvent since there are no native message loop to use.
90     RunState state(delegate, g_state ? g_state->run_depth + 1 : 1);
91 
92     RunState* previous_state = g_state;
93     g_state = &state;
94 
95     // When not nested we can use the real implementation, otherwise fall back
96     // to the stub implementation.
97     if (g_state->run_depth > 1) {
98       RunNested(delegate);
99     } else {
100       MessagePumpForUI::Run(delegate);
101     }
102 
103     g_state = previous_state;
104   }
105 
RunNested(base::MessagePump::Delegate * delegate)106   void RunNested(base::MessagePump::Delegate* delegate) {
107     bool more_work_is_plausible = true;
108 
109     for (;;) {
110       if (!more_work_is_plausible) {
111         Waitable::GetInstance()->Block();
112         if (g_state->should_quit)
113           break;
114       }
115 
116       more_work_is_plausible = g_state->delegate->DoWork();
117       if (g_state->should_quit)
118         break;
119 
120       base::TimeTicks delayed_work_time;
121       more_work_is_plausible |=
122           g_state->delegate->DoDelayedWork(&delayed_work_time);
123       if (g_state->should_quit)
124         break;
125 
126       if (more_work_is_plausible)
127         continue;
128 
129       more_work_is_plausible = g_state->delegate->DoIdleWork();
130       if (g_state->should_quit)
131         break;
132 
133       more_work_is_plausible |= !delayed_work_time.is_null();
134     }
135   }
136 
Quit()137   void Quit() override {
138     CHECK(g_state);
139     if (g_state->run_depth > 1) {
140       Waitable::GetInstance()->Quit();
141     } else {
142       MessagePumpForUI::Quit();
143     }
144   }
145 
ScheduleWork()146   void ScheduleWork() override {
147     if (g_state && g_state->run_depth > 1) {
148       Waitable::GetInstance()->Signal();
149     } else {
150       MessagePumpForUI::ScheduleWork();
151     }
152   }
153 
ScheduleDelayedWork(const base::TimeTicks & delayed_work_time)154   void ScheduleDelayedWork(const base::TimeTicks& delayed_work_time) override {
155     if (g_state && g_state->run_depth > 1) {
156       Waitable::GetInstance()->Signal();
157     } else {
158       MessagePumpForUI::ScheduleDelayedWork(delayed_work_time);
159     }
160   }
161 };
162 
CreateMessagePumpForUIStub()163 std::unique_ptr<base::MessagePump> CreateMessagePumpForUIStub() {
164   return std::unique_ptr<base::MessagePump>(new MessagePumpForUIStub());
165 };
166 
167 // Provides the test path for DIR_SOURCE_ROOT and DIR_ANDROID_APP_DATA.
GetTestProviderPath(int key,base::FilePath * result)168 bool GetTestProviderPath(int key, base::FilePath* result) {
169   switch (key) {
170     // TODO(agrieve): Stop overriding DIR_ANDROID_APP_DATA.
171     // https://crbug.com/617734
172     // Instead DIR_ASSETS should be used to discover assets file location in
173     // tests.
174     case base::DIR_ANDROID_APP_DATA:
175     case base::DIR_ASSETS:
176     case base::DIR_SOURCE_ROOT:
177       CHECK(g_test_data_dir != nullptr);
178       *result = *g_test_data_dir;
179       return true;
180     default:
181       return false;
182   }
183 }
184 
InitPathProvider(int key)185 void InitPathProvider(int key) {
186   base::FilePath path;
187   // If failed to override the key, that means the way has not been registered.
188   if (GetTestProviderPath(key, &path) &&
189       !base::PathService::Override(key, path)) {
190     base::PathService::RegisterProvider(&GetTestProviderPath, key, key + 1);
191   }
192 }
193 
194 }  // namespace
195 
196 namespace base {
197 
InitAndroidTestLogging()198 void InitAndroidTestLogging() {
199   logging::LoggingSettings settings;
200   settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
201   logging::InitLogging(settings);
202   // To view log output with IDs and timestamps use "adb logcat -v threadtime".
203   logging::SetLogItems(false,    // Process ID
204                        false,    // Thread ID
205                        false,    // Timestamp
206                        false);   // Tick count
207 }
208 
InitAndroidTestPaths(const FilePath & test_data_dir)209 void InitAndroidTestPaths(const FilePath& test_data_dir) {
210   if (g_test_data_dir) {
211     CHECK(test_data_dir == *g_test_data_dir);
212     return;
213   }
214   g_test_data_dir = new FilePath(test_data_dir);
215   InitPathProvider(DIR_SOURCE_ROOT);
216   InitPathProvider(DIR_ANDROID_APP_DATA);
217   InitPathProvider(DIR_ASSETS);
218 }
219 
InitAndroidTestMessageLoop()220 void InitAndroidTestMessageLoop() {
221   if (!MessageLoop::InitMessagePumpForUIFactory(&CreateMessagePumpForUIStub))
222     LOG(INFO) << "MessagePumpForUIFactory already set, unable to override.";
223 }
224 
225 }  // namespace base
226