• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
RunStatecontent::NestedMessagePumpAndroid::RunState27   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 
NestedMessagePumpAndroid()49 NestedMessagePumpAndroid::NestedMessagePumpAndroid()
50     : state_(NULL) {
51 }
52 
~NestedMessagePumpAndroid()53 NestedMessagePumpAndroid::~NestedMessagePumpAndroid() {
54 }
55 
Run(Delegate * delegate)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 
Start(base::MessagePump::Delegate * delegate)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 
Quit()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 
ScheduleWork()139 void NestedMessagePumpAndroid::ScheduleWork() {
140   if (state_) {
141     state_->waitable_event.Signal();
142     return;
143   }
144 
145   base::MessagePumpForUI::ScheduleWork();
146 }
147 
ScheduleDelayedWork(const base::TimeTicks & delayed_work_time)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
RegisterJni(JNIEnv * env)162 bool NestedMessagePumpAndroid::RegisterJni(JNIEnv* env) {
163   return RegisterNativesImpl(env);
164 }
165 
166 }  // namespace content
167