blob: 93f40a7b1904342c6ac46337a797151d3385dcc1 [file] [log] [blame]
[email protected]449019ca2012-03-14 22:17:001// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]61c86c62011-08-02 16:11:162// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]59e69e742013-06-18 20:27:525#include "base/message_loop/message_pump_android.h"
[email protected]61c86c62011-08-02 16:11:166
7#include <jni.h>
8
gsenntonebe2e2032016-08-18 22:34:129#include "base/android/java_message_handler_factory.h"
[email protected]61c86c62011-08-02 16:11:1610#include "base/android/jni_android.h"
[email protected]449019ca2012-03-14 22:17:0011#include "base/android/scoped_java_ref.h"
12#include "base/lazy_instance.h"
[email protected]61c86c62011-08-02 16:11:1613#include "base/logging.h"
gsenntonebe2e2032016-08-18 22:34:1214#include "base/message_loop/message_loop.h"
[email protected]8e937c1e2012-06-28 22:57:3015#include "base/run_loop.h"
[email protected]99084f62013-06-28 00:49:0716#include "base/time/time.h"
[email protected]e46f66152012-07-19 20:02:5517#include "jni/SystemMessageHandler_jni.h"
[email protected]61c86c62011-08-02 16:11:1618
torne86560112016-08-04 15:59:0419using base::android::JavaParamRef;
[email protected]449019ca2012-03-14 22:17:0020using base::android::ScopedJavaLocalRef;
[email protected]61c86c62011-08-02 16:11:1621
[email protected]61c86c62011-08-02 16:11:1622// ----------------------------------------------------------------------------
23// Native JNI methods called by Java.
24// ----------------------------------------------------------------------------
25// This method can not move to anonymous namespace as it has been declared as
26// 'static' in system_message_handler_jni.h.
torne89cc5d92015-09-04 11:16:3527static void DoRunLoopOnce(JNIEnv* env,
28 const JavaParamRef<jobject>& obj,
29 jlong native_delegate,
gsenntonebe2e2032016-08-18 22:34:1230 jlong native_message_pump,
torne89cc5d92015-09-04 11:16:3531 jlong delayed_scheduled_time_ticks) {
[email protected]61c86c62011-08-02 16:11:1632 base::MessagePump::Delegate* delegate =
33 reinterpret_cast<base::MessagePump::Delegate*>(native_delegate);
34 DCHECK(delegate);
gsenntonebe2e2032016-08-18 22:34:1235 base::MessagePumpForUI* pump =
36 reinterpret_cast<base::MessagePumpForUI*>(native_message_pump);
37 DCHECK(pump);
Michael Thiessenfc7067fe2017-11-01 22:33:0138 // If the pump has been aborted, tasks may continue to be queued up, but
39 // shouldn't run.
40 if (pump->ShouldAbort())
41 return;
42
[email protected]61c86c62011-08-02 16:11:1643 // This is based on MessagePumpForUI::DoRunLoop() from desktop.
44 // Note however that our system queue is handled in the java side.
45 // In desktop we inspect and process a single system message and then
Michael Thiessen7681cfee2017-08-18 16:55:3746 // we call DoWork() / DoDelayedWork(). This is then wrapped in a for loop and
47 // repeated until no work is left to do, at which point DoIdleWork is called.
[email protected]61c86c62011-08-02 16:11:1648 // On Android, the java message queue may contain messages for other handlers
49 // that will be processed before calling here again.
Michael Thiessen7681cfee2017-08-18 16:55:3750 // This means that unlike Desktop, we can't wrap a for loop around this
51 // function and keep processing tasks until we have no work left to do - we
52 // have to return control back to the Android Looper after each message. This
53 // also means we have to perform idle detection differently, which is why we
54 // add an IdleHandler to the message queue in SystemMessageHandler.java, which
55 // calls DoIdleWork whenever control returns back to the looper and there are
56 // no tasks queued up to run immediately.
57 delegate->DoWork();
gsenntonebe2e2032016-08-18 22:34:1258 if (pump->ShouldAbort()) {
59 // There is a pending JNI exception, return to Java so that the exception is
60 // thrown correctly.
61 return;
62 }
[email protected]61c86c62011-08-02 16:11:1663
[email protected]97532f3f2014-03-11 09:24:4264 // In the java side, |SystemMessageHandler| keeps a single "delayed" message.
65 // It's an expensive operation to |removeMessage| there, so this is optimized
66 // to avoid those calls.
67 //
68 // At this stage, |next_delayed_work_time| can be:
69 // 1) The same as previously scheduled: nothing to be done, move along. This
70 // is the typical case, since this method is called for every single message.
71 //
72 // 2) Not previously scheduled: just post a new message in java.
73 //
74 // 3) Shorter than previously scheduled: far less common. In this case,
75 // |removeMessage| and post a new one.
76 //
77 // 4) Longer than previously scheduled (or null): nothing to be done, move
78 // along.
79 //
80 // Side note: base::TimeTicks is a C++ representation and can't be
81 // compared in java. When calling |scheduleDelayedWork|, pass the
82 // |InternalValue()| to java and then back to C++ so the comparisons can be
83 // done here.
84 // This roundtrip allows comparing TimeTicks directly (cheap) and
85 // avoid comparisons with TimeDelta / Now() (expensive).
86 base::TimeTicks next_delayed_work_time;
Michael Thiessen7681cfee2017-08-18 16:55:3787 delegate->DoDelayedWork(&next_delayed_work_time);
gsenntonebe2e2032016-08-18 22:34:1288 if (pump->ShouldAbort()) {
89 // There is a pending JNI exception, return to Java so that the exception is
90 // thrown correctly
91 return;
92 }
[email protected]d1d787eff2013-07-12 03:19:5593
[email protected]97532f3f2014-03-11 09:24:4294 if (!next_delayed_work_time.is_null()) {
95 // Schedule a new message if there's nothing already scheduled or there's a
96 // shorter delay than previously scheduled (see (2) and (3) above).
97 if (delayed_scheduled_time_ticks == 0 ||
98 next_delayed_work_time < base::TimeTicks::FromInternalValue(
99 delayed_scheduled_time_ticks)) {
100 Java_SystemMessageHandler_scheduleDelayedWork(env, obj,
101 next_delayed_work_time.ToInternalValue(),
102 (next_delayed_work_time -
103 base::TimeTicks::Now()).InMillisecondsRoundedUp());
104 }
[email protected]d1d787eff2013-07-12 03:19:55105 }
[email protected]61c86c62011-08-02 16:11:16106}
107
Michael Thiessen7681cfee2017-08-18 16:55:37108// This is called by the java SystemMessageHandler whenever the message queue
109// detects an idle state (as in, control returns to the looper and there are no
110// tasks available to be run immediately).
111// See the comments in DoRunLoopOnce for how this differs from the
112// implementation on other platforms.
113static void DoIdleWork(JNIEnv* env,
114 const JavaParamRef<jobject>& obj,
115 jlong native_delegate,
116 jlong native_message_pump) {
117 base::MessagePump::Delegate* delegate =
118 reinterpret_cast<base::MessagePump::Delegate*>(native_delegate);
119 DCHECK(delegate);
120 delegate->DoIdleWork();
121};
122
[email protected]61c86c62011-08-02 16:11:16123namespace base {
124
Michael Thiessendbeca242017-08-28 21:10:08125MessagePumpForUI::MessagePumpForUI() = default;
126MessagePumpForUI::~MessagePumpForUI() = default;
[email protected]61c86c62011-08-02 16:11:16127
128void MessagePumpForUI::Run(Delegate* delegate) {
129 NOTREACHED() << "UnitTests should rely on MessagePumpForUIStub in"
130 " test_stub_android.h";
131}
132
gsenntonebe2e2032016-08-18 22:34:12133JNIEnv* MessagePumpForUI::StartInternal() {
Michael Thiessendbeca242017-08-28 21:10:08134 DCHECK(!quit_);
[email protected]59e69e742013-06-18 20:27:52135 run_loop_ = new RunLoop();
[email protected]8e937c1e2012-06-28 22:57:30136 // Since the RunLoop was just created above, BeforeRun should be guaranteed to
137 // return true (it only returns false if the RunLoop has been Quit already).
138 if (!run_loop_->BeforeRun())
139 NOTREACHED();
[email protected]61c86c62011-08-02 16:11:16140
[email protected]3042d1b2013-07-02 18:54:05141 DCHECK(system_message_handler_obj_.is_null());
[email protected]61c86c62011-08-02 16:11:16142
143 JNIEnv* env = base::android::AttachCurrentThread();
144 DCHECK(env);
gsenntonebe2e2032016-08-18 22:34:12145 return env;
146}
[email protected]61c86c62011-08-02 16:11:16147
gsenntonebe2e2032016-08-18 22:34:12148void MessagePumpForUI::Start(Delegate* delegate) {
149 JNIEnv* env = StartInternal();
150 system_message_handler_obj_.Reset(Java_SystemMessageHandler_create(
151 env, reinterpret_cast<intptr_t>(delegate),
152 reinterpret_cast<intptr_t>(this)));
153}
154
155void MessagePumpForUI::StartForUnitTest(
156 Delegate* delegate,
157 base::android::JavaMessageHandlerFactory* factory,
158 WaitableEvent* test_done_event) {
159 JNIEnv* env = StartInternal();
[email protected]3042d1b2013-07-02 18:54:05160 system_message_handler_obj_.Reset(
gsenntonebe2e2032016-08-18 22:34:12161 factory->CreateMessageHandler(env, delegate, this, test_done_event));
[email protected]61c86c62011-08-02 16:11:16162}
163
164void MessagePumpForUI::Quit() {
Michael Thiessendbeca242017-08-28 21:10:08165 quit_ = true;
[email protected]3042d1b2013-07-02 18:54:05166 if (!system_message_handler_obj_.is_null()) {
[email protected]61c86c62011-08-02 16:11:16167 JNIEnv* env = base::android::AttachCurrentThread();
168 DCHECK(env);
169
torne948f3662016-08-16 15:10:44170 Java_SystemMessageHandler_removeAllPendingMessages(
171 env, system_message_handler_obj_);
[email protected]3042d1b2013-07-02 18:54:05172 system_message_handler_obj_.Reset();
[email protected]61c86c62011-08-02 16:11:16173 }
174
[email protected]8e937c1e2012-06-28 22:57:30175 if (run_loop_) {
176 run_loop_->AfterRun();
177 delete run_loop_;
178 run_loop_ = NULL;
[email protected]61c86c62011-08-02 16:11:16179 }
180}
181
182void MessagePumpForUI::ScheduleWork() {
Michael Thiessendbeca242017-08-28 21:10:08183 if (quit_)
184 return;
[email protected]3042d1b2013-07-02 18:54:05185 DCHECK(!system_message_handler_obj_.is_null());
[email protected]61c86c62011-08-02 16:11:16186
187 JNIEnv* env = base::android::AttachCurrentThread();
188 DCHECK(env);
189
torne948f3662016-08-16 15:10:44190 Java_SystemMessageHandler_scheduleWork(env, system_message_handler_obj_);
[email protected]61c86c62011-08-02 16:11:16191}
192
193void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
Michael Thiessendbeca242017-08-28 21:10:08194 if (quit_)
195 return;
[email protected]3042d1b2013-07-02 18:54:05196 DCHECK(!system_message_handler_obj_.is_null());
[email protected]61c86c62011-08-02 16:11:16197
198 JNIEnv* env = base::android::AttachCurrentThread();
199 DCHECK(env);
200
201 jlong millis =
[email protected]59e69e742013-06-18 20:27:52202 (delayed_work_time - TimeTicks::Now()).InMillisecondsRoundedUp();
[email protected]61c86c62011-08-02 16:11:16203 // Note that we're truncating to milliseconds as required by the java side,
204 // even though delayed_work_time is microseconds resolution.
torne948f3662016-08-16 15:10:44205 Java_SystemMessageHandler_scheduleDelayedWork(
206 env, system_message_handler_obj_, delayed_work_time.ToInternalValue(),
207 millis);
[email protected]61c86c62011-08-02 16:11:16208}
209
[email protected]61c86c62011-08-02 16:11:16210} // namespace base