test_support_android.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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.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, base::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 base::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 if (!MessageLoop::InitMessagePumpForUIFactory(&CreateMessagePumpForUIStub)) 187 LOG(INFO) << "MessagePumpForUIFactory already set, unable to override."; 188} 189 190void InitAndroidTest() { 191 InitAndroidTestLogging(); 192 InitAndroidTestPaths(); 193 InitAndroidTestMessageLoop(); 194} 195} // namespace base 196