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