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/memory/singleton.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/message_loop/message_pump_android.h"
14 #include "base/path_service.h"
15 #include "base/synchronization/waitable_event.h"
16
17 namespace {
18
19 struct RunState {
RunState__anon530541d80111::RunState20 RunState(base::MessagePump::Delegate* delegate, int run_depth)
21 : delegate(delegate),
22 run_depth(run_depth),
23 should_quit(false) {
24 }
25
26 base::MessagePump::Delegate* delegate;
27
28 // Used to count how many Run() invocations are on the stack.
29 int run_depth;
30
31 // Used to flag that the current Run() invocation should return ASAP.
32 bool should_quit;
33 };
34
35 RunState* g_state = NULL;
36
37 // A singleton WaitableEvent wrapper so we avoid a busy loop in
38 // MessagePumpForUIStub. Other platforms use the native event loop which blocks
39 // when there are no pending messages.
40 class Waitable {
41 public:
GetInstance()42 static Waitable* GetInstance() {
43 return Singleton<Waitable>::get();
44 }
45
46 // Signals that there are more work to do.
Signal()47 void Signal() {
48 waitable_event_.Signal();
49 }
50
51 // Blocks until more work is scheduled.
Block()52 void Block() {
53 waitable_event_.Wait();
54 }
55
Quit()56 void Quit() {
57 g_state->should_quit = true;
58 Signal();
59 }
60
61 private:
62 friend struct DefaultSingletonTraits<Waitable>;
63
Waitable()64 Waitable()
65 : waitable_event_(false, false) {
66 }
67
68 base::WaitableEvent waitable_event_;
69
70 DISALLOW_COPY_AND_ASSIGN(Waitable);
71 };
72
73 // The MessagePumpForUI implementation for test purpose.
74 class MessagePumpForUIStub : public base::MessagePumpForUI {
~MessagePumpForUIStub()75 virtual ~MessagePumpForUIStub() {}
76
Start(base::MessagePump::Delegate * delegate)77 virtual void Start(base::MessagePump::Delegate* delegate) OVERRIDE {
78 NOTREACHED() << "The Start() method shouldn't be called in test, using"
79 " Run() method should be used.";
80 }
81
Run(base::MessagePump::Delegate * delegate)82 virtual void Run(base::MessagePump::Delegate* delegate) OVERRIDE {
83 // The following was based on message_pump_glib.cc, except we're using a
84 // WaitableEvent since there are no native message loop to use.
85 RunState state(delegate, g_state ? g_state->run_depth + 1 : 1);
86
87 RunState* previous_state = g_state;
88 g_state = &state;
89
90 bool more_work_is_plausible = true;
91
92 for (;;) {
93 if (!more_work_is_plausible) {
94 Waitable::GetInstance()->Block();
95 if (g_state->should_quit)
96 break;
97 }
98
99 more_work_is_plausible = g_state->delegate->DoWork();
100 if (g_state->should_quit)
101 break;
102
103 base::TimeTicks delayed_work_time;
104 more_work_is_plausible |=
105 g_state->delegate->DoDelayedWork(&delayed_work_time);
106 if (g_state->should_quit)
107 break;
108
109 if (more_work_is_plausible)
110 continue;
111
112 more_work_is_plausible = g_state->delegate->DoIdleWork();
113 if (g_state->should_quit)
114 break;
115
116 more_work_is_plausible |= !delayed_work_time.is_null();
117 }
118
119 g_state = previous_state;
120 }
121
Quit()122 virtual void Quit() OVERRIDE {
123 Waitable::GetInstance()->Quit();
124 }
125
ScheduleWork()126 virtual void ScheduleWork() OVERRIDE {
127 Waitable::GetInstance()->Signal();
128 }
129
ScheduleDelayedWork(const base::TimeTicks & delayed_work_time)130 virtual void ScheduleDelayedWork(
131 const base::TimeTicks& delayed_work_time) OVERRIDE {
132 Waitable::GetInstance()->Signal();
133 }
134 };
135
CreateMessagePumpForUIStub()136 scoped_ptr<base::MessagePump> CreateMessagePumpForUIStub() {
137 return scoped_ptr<base::MessagePump>(new MessagePumpForUIStub());
138 };
139
140 // Provides the test path for DIR_MODULE and DIR_ANDROID_APP_DATA.
GetTestProviderPath(int key,base::FilePath * result)141 bool GetTestProviderPath(int key, base::FilePath* result) {
142 switch (key) {
143 case base::DIR_MODULE: {
144 return base::android::GetExternalStorageDirectory(result);
145 }
146 case base::DIR_ANDROID_APP_DATA: {
147 // For tests, app data is put in external storage.
148 return base::android::GetExternalStorageDirectory(result);
149 }
150 default:
151 return false;
152 }
153 }
154
InitPathProvider(int key)155 void InitPathProvider(int key) {
156 base::FilePath path;
157 // If failed to override the key, that means the way has not been registered.
158 if (GetTestProviderPath(key, &path) && !PathService::Override(key, path))
159 PathService::RegisterProvider(&GetTestProviderPath, key, key + 1);
160 }
161
162 } // namespace
163
164 namespace base {
165
InitAndroidTestLogging()166 void InitAndroidTestLogging() {
167 logging::LoggingSettings settings;
168 settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
169 logging::InitLogging(settings);
170 // To view log output with IDs and timestamps use "adb logcat -v threadtime".
171 logging::SetLogItems(false, // Process ID
172 false, // Thread ID
173 false, // Timestamp
174 false); // Tick count
175 }
176
InitAndroidTestPaths()177 void InitAndroidTestPaths() {
178 InitPathProvider(DIR_MODULE);
179 InitPathProvider(DIR_ANDROID_APP_DATA);
180 }
181
InitAndroidTestMessageLoop()182 void InitAndroidTestMessageLoop() {
183 if (!MessageLoop::InitMessagePumpForUIFactory(&CreateMessagePumpForUIStub))
184 LOG(INFO) << "MessagePumpForUIFactory already set, unable to override.";
185 }
186
InitAndroidTest()187 void InitAndroidTest() {
188 InitAndroidTestLogging();
189 InitAndroidTestPaths();
190 InitAndroidTestMessageLoop();
191 }
192 } // namespace base
193