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