• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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