Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / public / test / nested_message_pump_android.cc
blob4745c5384cf8d3f387620c844b6b6a57593fa0cf
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.
5 #include "content/public/test/nested_message_pump_android.h"
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"
16 namespace {
18 base::LazyInstance<base::android::ScopedJavaGlobalRef<jobject> >
19 g_message_handler_obj = LAZY_INSTANCE_INITIALIZER;
21 } // namespace
24 namespace content {
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) {
34 base::MessagePump::Delegate* delegate;
36 // Used to count how many Run() invocations are on the stack.
37 int run_depth;
39 // Used to flag that the current Run() invocation should return ASAP.
40 bool should_quit;
42 // Used to sleep until there is more work to do.
43 base::WaitableEvent waitable_event;
45 // The time at which we should call DoDelayedWork.
46 base::TimeTicks delayed_work_time;
49 NestedMessagePumpAndroid::NestedMessagePumpAndroid()
50 : state_(NULL) {
53 NestedMessagePumpAndroid::~NestedMessagePumpAndroid() {
56 void NestedMessagePumpAndroid::Run(Delegate* delegate) {
57 RunState state(delegate, state_ ? state_->run_depth + 1 : 1);
58 RunState* previous_state = state_;
59 state_ = &state;
61 JNIEnv* env = base::android::AttachCurrentThread();
62 DCHECK(env);
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);
69 for (;;) {
70 if (state_->should_quit)
71 break;
73 bool did_work = state_->delegate->DoWork();
74 if (state_->should_quit)
75 break;
77 did_work |= state_->delegate->DoDelayedWork(&state_->delayed_work_time);
78 if (state_->should_quit)
79 break;
81 if (did_work) {
82 continue;
85 did_work = state_->delegate->DoIdleWork();
86 if (state_->should_quit)
87 break;
89 if (did_work)
90 continue;
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.";
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();
117 state_ = previous_state;
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));
128 void NestedMessagePumpAndroid::Quit() {
129 if (state_) {
130 state_->should_quit = true;
131 state_->waitable_event.Signal();
132 return;
136 void NestedMessagePumpAndroid::ScheduleWork() {
137 if (state_) {
138 state_->waitable_event.Signal();
139 return;
143 void NestedMessagePumpAndroid::ScheduleDelayedWork(
144 const base::TimeTicks& delayed_work_time) {
145 if (state_) {
146 // We know that we can't be blocked on Wait right now since this method can
147 // only be called on the same thread as Run, so we only need to update our
148 // record of how long to sleep when we do sleep.
149 state_->delayed_work_time = delayed_work_time;
150 return;
154 // static
155 bool NestedMessagePumpAndroid::RegisterJni(JNIEnv* env) {
156 return RegisterNativesImpl(env);
159 } // namespace content