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
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 ~MessagePumpForUIStub() {}
76
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
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
122  virtual void Quit() OVERRIDE {
123    Waitable::GetInstance()->Quit();
124  }
125
126  virtual void ScheduleWork() OVERRIDE {
127    Waitable::GetInstance()->Signal();
128  }
129
130  virtual void ScheduleDelayedWork(
131      const base::TimeTicks& delayed_work_time) OVERRIDE {
132    Waitable::GetInstance()->Signal();
133  }
134};
135
136scoped_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.
141bool GetTestProviderPath(int key, base::FilePath* result) {
142  switch (key) {
143    case base::DIR_ANDROID_APP_DATA: {
144      // For tests, app data is put in external storage.
145      return base::android::GetExternalStorageDirectory(result);
146    }
147    default:
148      return false;
149  }
150}
151
152void InitPathProvider(int key) {
153  base::FilePath path;
154  // If failed to override the key, that means the way has not been registered.
155  if (GetTestProviderPath(key, &path) && !PathService::Override(key, path))
156    PathService::RegisterProvider(&GetTestProviderPath, key, key + 1);
157}
158
159}  // namespace
160
161namespace base {
162
163void InitAndroidTestLogging() {
164  logging::LoggingSettings settings;
165  settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
166  logging::InitLogging(settings);
167  // To view log output with IDs and timestamps use "adb logcat -v threadtime".
168  logging::SetLogItems(false,    // Process ID
169                       false,    // Thread ID
170                       false,    // Timestamp
171                       false);   // Tick count
172}
173
174void InitAndroidTestPaths() {
175  InitPathProvider(DIR_MODULE);
176  InitPathProvider(DIR_ANDROID_APP_DATA);
177}
178
179void InitAndroidTestMessageLoop() {
180  if (!MessageLoop::InitMessagePumpForUIFactory(&CreateMessagePumpForUIStub))
181    LOG(INFO) << "MessagePumpForUIFactory already set, unable to override.";
182}
183
184void InitAndroidTest() {
185  InitAndroidTestLogging();
186  InitAndroidTestPaths();
187  InitAndroidTestMessageLoop();
188}
189}  // namespace base
190