blob: 532665886e1f24cbe15469c9e781218fb53aceb8 [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);
[email protected]61c86c62011-08-02 16:11:1638 // This is based on MessagePumpForUI::DoRunLoop() from desktop.
39 // Note however that our system queue is handled in the java side.
40 // In desktop we inspect and process a single system message and then
Michael Thiessen7681cfee2017-08-18 16:55:3741 // we call DoWork() / DoDelayedWork(). This is then wrapped in a for loop and
42 // repeated until no work is left to do, at which point DoIdleWork is called.
[email protected]61c86c62011-08-02 16:11:1643 // On Android, the java message queue may contain messages for other handlers
44 // that will be processed before calling here again.
Michael Thiessen7681cfee2017-08-18 16:55:3745 // This means that unlike Desktop, we can't wrap a for loop around this
46 // function and keep processing tasks until we have no work left to do - we
47 // have to return control back to the Android Looper after each message. This
48 // also means we have to perform idle detection differently, which is why we
49 // add an IdleHandler to the message queue in SystemMessageHandler.java, which
50 // calls DoIdleWork whenever control returns back to the looper and there are
51 // no tasks queued up to run immediately.
52 delegate->DoWork();
gsenntonebe2e2032016-08-18 22:34:1253 if (pump->ShouldAbort()) {
54 // There is a pending JNI exception, return to Java so that the exception is
55 // thrown correctly.
56 return;
57 }
[email protected]61c86c62011-08-02 16:11:1658
[email protected]97532f3f2014-03-11 09:24:4259 // In the java side, |SystemMessageHandler| keeps a single "delayed" message.
60 // It's an expensive operation to |removeMessage| there, so this is optimized
61 // to avoid those calls.
62 //
63 // At this stage, |next_delayed_work_time| can be:
64 // 1) The same as previously scheduled: nothing to be done, move along. This
65 // is the typical case, since this method is called for every single message.
66 //
67 // 2) Not previously scheduled: just post a new message in java.
68 //
69 // 3) Shorter than previously scheduled: far less common. In this case,
70 // |removeMessage| and post a new one.
71 //
72 // 4) Longer than previously scheduled (or null): nothing to be done, move
73 // along.
74 //
75 // Side note: base::TimeTicks is a C++ representation and can't be
76 // compared in java. When calling |scheduleDelayedWork|, pass the
77 // |InternalValue()| to java and then back to C++ so the comparisons can be
78 // done here.
79 // This roundtrip allows comparing TimeTicks directly (cheap) and
80 // avoid comparisons with TimeDelta / Now() (expensive).
81 base::TimeTicks next_delayed_work_time;
Michael Thiessen7681cfee2017-08-18 16:55:3782 delegate->DoDelayedWork(&next_delayed_work_time);
gsenntonebe2e2032016-08-18 22:34:1283 if (pump->ShouldAbort()) {
84 // There is a pending JNI exception, return to Java so that the exception is
85 // thrown correctly
86 return;
87 }
[email protected]d1d787eff2013-07-12 03:19:5588
[email protected]97532f3f2014-03-11 09:24:4289 if (!next_delayed_work_time.is_null()) {
90 // Schedule a new message if there's nothing already scheduled or there's a
91 // shorter delay than previously scheduled (see (2) and (3) above).
92 if (delayed_scheduled_time_ticks == 0 ||
93 next_delayed_work_time < base::TimeTicks::FromInternalValue(
94 delayed_scheduled_time_ticks)) {
95 Java_SystemMessageHandler_scheduleDelayedWork(env, obj,
96 next_delayed_work_time.ToInternalValue(),
97 (next_delayed_work_time -
98 base::TimeTicks::Now()).InMillisecondsRoundedUp());
99 }
[email protected]d1d787eff2013-07-12 03:19:55100 }
[email protected]61c86c62011-08-02 16:11:16101}
102
Michael Thiessen7681cfee2017-08-18 16:55:37103// This is called by the java SystemMessageHandler whenever the message queue
104// detects an idle state (as in, control returns to the looper and there are no
105// tasks available to be run immediately).
106// See the comments in DoRunLoopOnce for how this differs from the
107// implementation on other platforms.
108static void DoIdleWork(JNIEnv* env,
109 const JavaParamRef<jobject>& obj,
110 jlong native_delegate,
111 jlong native_message_pump) {
112 base::MessagePump::Delegate* delegate =
113 reinterpret_cast<base::MessagePump::Delegate*>(native_delegate);
114 DCHECK(delegate);
115 delegate->DoIdleWork();
116};
117
[email protected]61c86c62011-08-02 16:11:16118namespace base {
119
Michael Thiessendbeca242017-08-28 21:10:08120MessagePumpForUI::MessagePumpForUI() = default;
121MessagePumpForUI::~MessagePumpForUI() = default;
[email protected]61c86c62011-08-02 16:11:16122
123void MessagePumpForUI::Run(Delegate* delegate) {
124 NOTREACHED() << "UnitTests should rely on MessagePumpForUIStub in"
125 " test_stub_android.h";
126}
127
gsenntonebe2e2032016-08-18 22:34:12128JNIEnv* MessagePumpForUI::StartInternal() {
Michael Thiessendbeca242017-08-28 21:10:08129 DCHECK(!quit_);
[email protected]59e69e742013-06-18 20:27:52130 run_loop_ = new RunLoop();
[email protected]8e937c1e2012-06-28 22:57:30131 // Since the RunLoop was just created above, BeforeRun should be guaranteed to
132 // return true (it only returns false if the RunLoop has been Quit already).
133 if (!run_loop_->BeforeRun())
134 NOTREACHED();
[email protected]61c86c62011-08-02 16:11:16135
[email protected]3042d1b2013-07-02 18:54:05136 DCHECK(system_message_handler_obj_.is_null());
[email protected]61c86c62011-08-02 16:11:16137
138 JNIEnv* env = base::android::AttachCurrentThread();
139 DCHECK(env);
gsenntonebe2e2032016-08-18 22:34:12140 return env;
141}
[email protected]61c86c62011-08-02 16:11:16142
gsenntonebe2e2032016-08-18 22:34:12143void MessagePumpForUI::Start(Delegate* delegate) {
144 JNIEnv* env = StartInternal();
145 system_message_handler_obj_.Reset(Java_SystemMessageHandler_create(
146 env, reinterpret_cast<intptr_t>(delegate),
147 reinterpret_cast<intptr_t>(this)));
148}
149
150void MessagePumpForUI::StartForUnitTest(
151 Delegate* delegate,
152 base::android::JavaMessageHandlerFactory* factory,
153 WaitableEvent* test_done_event) {
154 JNIEnv* env = StartInternal();
[email protected]3042d1b2013-07-02 18:54:05155 system_message_handler_obj_.Reset(
gsenntonebe2e2032016-08-18 22:34:12156 factory->CreateMessageHandler(env, delegate, this, test_done_event));
[email protected]61c86c62011-08-02 16:11:16157}
158
159void MessagePumpForUI::Quit() {
Michael Thiessendbeca242017-08-28 21:10:08160 quit_ = true;
[email protected]3042d1b2013-07-02 18:54:05161 if (!system_message_handler_obj_.is_null()) {
[email protected]61c86c62011-08-02 16:11:16162 JNIEnv* env = base::android::AttachCurrentThread();
163 DCHECK(env);
164
torne948f3662016-08-16 15:10:44165 Java_SystemMessageHandler_removeAllPendingMessages(
166 env, system_message_handler_obj_);
[email protected]3042d1b2013-07-02 18:54:05167 system_message_handler_obj_.Reset();
[email protected]61c86c62011-08-02 16:11:16168 }
169
[email protected]8e937c1e2012-06-28 22:57:30170 if (run_loop_) {
171 run_loop_->AfterRun();
172 delete run_loop_;
173 run_loop_ = NULL;
[email protected]61c86c62011-08-02 16:11:16174 }
175}
176
177void MessagePumpForUI::ScheduleWork() {
Michael Thiessendbeca242017-08-28 21:10:08178 if (quit_)