1 // Copyright 2013 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 "content/public/test/nested_message_pump_android.h" 6 7 #include "base/android/jni_android.h" 8 #include "base/android/scoped_java_ref.h" 9 #include "base/lazy_instance.h" 10 #include "base/logging.h" 11 #include "base/synchronization/waitable_event.h" 12 #include "base/threading/thread_restrictions.h" 13 #include "base/time/time.h" 14 #include "jni/NestedSystemMessageHandler_jni.h" 15 16 namespace { 17 18 base::LazyInstance<base::android::ScopedJavaGlobalRef<jobject> > 19 g_message_handler_obj = LAZY_INSTANCE_INITIALIZER; 20 21 } // namespace 22 23 24 namespace content { 25 26 struct NestedMessagePumpAndroid::RunState { 27 RunState(base::MessagePump::Delegate* delegate, int run_depth) 28 : delegate(delegate), 29 run_depth(run_depth), 30 should_quit(false), 31 waitable_event(false, false) { 32 } 33 34 base::MessagePump::Delegate* delegate; 35 36 // Used to count how many Run() invocations are on the stack. 37 int run_depth; 38 39 // Used to flag that the current Run() invocation should return ASAP. 40 bool should_quit; 41 42 // Used to sleep until there is more work to do. 43 base::WaitableEvent waitable_event; 44 45 // The time at which we should call DoDelayedWork. 46 base::TimeTicks delayed_work_time; 47 }; 48 49 NestedMessagePumpAndroid::NestedMessagePumpAndroid() 50 : state_(NULL) { 51 } 52 53 NestedMessagePumpAndroid::~NestedMessagePumpAndroid() { 54 } 55 56 void NestedMessagePumpAndroid::Run(Delegate* delegate) { 57 RunState state(delegate, state_ ? state_->run_depth + 1 : 1); 58 RunState* previous_state = state_; 59 state_ = &state; 60 61 JNIEnv* env = base::android::AttachCurrentThread(); 62 DCHECK(env); 63 64 // Need to cap the wait time to allow task processing on the java 65 // side. Otherwise, a long wait time on the native will starve java 66 // tasks. 67 base::TimeDelta max_delay = base::TimeDelta::FromMilliseconds(100); 68 69 for (;;) { 70 if (state_->should_quit) 71 break; 72 73 bool did_work = state_->delegate->DoWork(); 74 if (state_->should_quit) 75 break; 76 77 did_work |= state_->delegate->DoDelayedWork(&state_->delayed_work_time); 78 if (state_->should_quit) 79 break; 80 81 if (did_work) { 82 continue; 83 } 84 85 did_work = state_->delegate->DoIdleWork(); 86 if (state_->should_quit) 87 break; 88 89 if (did_work) 90 continue; 91 92 // No native tasks to process right now. Process tasks from the Java 93 // System message handler. This will return when the java message queue 94 // is idle. 95 bool ret = Java_NestedSystemMessageHandler_runNestedLoopTillIdle(env, 96 g_message_handler_obj.Get().obj()); 97 CHECK(ret) << "Error running java message loop, tests will likely fail."; 98 99 base::ThreadRestrictions::ScopedAllowWait allow_wait; 100 if (state_->delayed_work_time.is_null()) { 101 state_->waitable_event.TimedWait(max_delay); 102 } else { 103 base::TimeDelta delay = 104 state_->delayed_work_time - base::TimeTicks::Now(); 105 if (delay > max_delay) 106 delay = max_delay; 107 if (delay > base::TimeDelta()) { 108 state_->waitable_event.TimedWait(delay); 109 } else { 110 // It looks like delayed_work_time indicates a time in the past, so we 111 // need to call DoDelayedWork now. 112 state_->delayed_work_time = base::TimeTicks(); 113 } 114 } 115 } 116 117 state_ = previous_state; 118 } 119 120 void NestedMessagePumpAndroid::Start( 121 base::MessagePump::Delegate* delegate) { 122 JNIEnv* env = base::android::AttachCurrentThread(); 123 DCHECK(env); 124 g_message_handler_obj.Get().Reset( 125 Java_NestedSystemMessageHandler_create(env)); 126 127 base::MessagePumpForUI::Start(delegate); 128 } 129 130 void NestedMessagePumpAndroid::Quit() { 131 if (state_) { 132 state_->should_quit = true; 133 state_->waitable_event.Signal(); 134 return; 135 } 136 base::MessagePumpForUI::Quit(); 137 } 138 139 void NestedMessagePumpAndroid::ScheduleWork() { 140 if (state_) { 141 state_->waitable_event.Signal(); 142 return; 143 } 144 145 base::MessagePumpForUI::ScheduleWork(); 146 } 147 148 void NestedMessagePumpAndroid::ScheduleDelayedWork( 149 const base::TimeTicks& delayed_work_time) { 150 if (state_) { 151 // We know that we can't be blocked on Wait right now since this method can 152 // only be called on the same thread as Run, so we only need to update our 153 // record of how long to sleep when we do sleep. 154 state_->delayed_work_time = delayed_work_time; 155 return; 156 } 157 158 base::MessagePumpForUI::ScheduleDelayedWork(delayed_work_time); 159 } 160 161 // static 162 bool NestedMessagePumpAndroid::RegisterJni(JNIEnv* env) { 163 return RegisterNativesImpl(env); 164 } 165 166 } // namespace content 167