blob: 5f8981db03cc21342e618b3c438d2ec3cdb6ee65 [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
9#include "base/android/jni_android.h"
[email protected]449019ca2012-03-14 22:17:0010#include "base/android/scoped_java_ref.h"
11#include "base/lazy_instance.h"
[email protected]61c86c62011-08-02 16:11:1612#include "base/logging.h"
[email protected]8e937c1e2012-06-28 22:57:3013#include "base/run_loop.h"
[email protected]e46f66152012-07-19 20:02:5514#include "jni/SystemMessageHandler_jni.h"
[email protected]61c86c62011-08-02 16:11:1615
torne86560112016-08-04 15:59:0416using base::android::JavaParamRef;
[email protected]449019ca2012-03-14 22:17:0017using base::android::ScopedJavaLocalRef;
[email protected]61c86c62011-08-02 16:11:1618
Michael Thiessen781ddeb2017-11-15 17:07:2319namespace base {
20
21MessagePumpForUI::MessagePumpForUI() = default;
22MessagePumpForUI::~MessagePumpForUI() = default;
23
24// This is called by the java SystemMessageHandler whenever the message queue
25// detects an idle state (as in, control returns to the looper and there are no
26// tasks available to be run immediately).
27// See the comments in DoRunLoopOnce for how this differs from the
28// implementation on other platforms.
29void MessagePumpForUI::DoIdleWork(JNIEnv* env,
30 const JavaParamRef<jobject>& obj) {
31 delegate_->DoIdleWork();
32}
33
34void MessagePumpForUI::DoRunLoopOnce(JNIEnv* env,
35 const JavaParamRef<jobject>& obj,
36 jboolean delayed) {
37 if (delayed)
38 delayed_scheduled_time_ = base::TimeTicks();
39
Michael Thiessenfc7067fe2017-11-01 22:33:0140 // If the pump has been aborted, tasks may continue to be queued up, but
41 // shouldn't run.
Michael Thiessen781ddeb2017-11-15 17:07:2342 if (ShouldAbort())
Michael Thiessenfc7067fe2017-11-01 22:33:0143 return;
44
[email protected]61c86c62011-08-02 16:11:1645 // This is based on MessagePumpForUI::DoRunLoop() from desktop.
46 // Note however that our system queue is handled in the java side.
47 // In desktop we inspect and process a single system message and then
Michael Thiessen7681cfee2017-08-18 16:55:3748 // we call DoWork() / DoDelayedWork(). This is then wrapped in a for loop and
49 // repeated until no work is left to do, at which point DoIdleWork is called.
[email protected]61c86c62011-08-02 16:11:1650 // On Android, the java message queue may contain messages for other handlers
51 // that will be processed before calling here again.
Michael Thiessen7681cfee2017-08-18 16:55:3752 // This means that unlike Desktop, we can't wrap a for loop around this
53 // function and keep processing tasks until we have no work left to do - we
54 // have to return control back to the Android Looper after each message. This
55 // also means we have to perform idle detection differently, which is why we
56 // add an IdleHandler to the message queue in SystemMessageHandler.java, which
57 // calls DoIdleWork whenever control returns back to the looper and there are
58 // no tasks queued up to run immediately.
Michael Thiessen781ddeb2017-11-15 17:07:2359 delegate_->DoWork();
60 if (ShouldAbort()) {
gsenntonebe2e2032016-08-18 22:34:1261 // There is a pending JNI exception, return to Java so that the exception is
62 // thrown correctly.
63 return;
64 }
[email protected]61c86c62011-08-02 16:11:1665
[email protected]97532f3f2014-03-11 09:24:4266 base::TimeTicks next_delayed_work_time;
Michael Thiessen781ddeb2017-11-15 17:07:2367 delegate_->DoDelayedWork(&next_delayed_work_time);
68 if (ShouldAbort()) {
gsenntonebe2e2032016-08-18 22:34:1269 // There is a pending JNI exception, return to Java so that the exception is
70 // thrown correctly
71 return;
72 }
[email protected]d1d787eff2013-07-12 03:19:5573
Michael Thiessen781ddeb2017-11-15 17:07:2374 if (!next_delayed_work_time.is_null())
75 ScheduleDelayedWork(next_delayed_work_time);
[email protected]61c86c62011-08-02 16:11:1676}
77
[email protected]61c86c62011-08-02 16:11:1678void MessagePumpForUI::Run(Delegate* delegate) {
79 NOTREACHED() << "UnitTests should rely on MessagePumpForUIStub in"
Michael Thiessen781ddeb2017-11-15 17:07:2380 " test_stub_android.h";
[email protected]61c86c62011-08-02 16:11:1681}
82
Ran Ji3d6ec662018-07-09 21:18:3083void MessagePumpForUI::Attach(Delegate* delegate) {
Michael Thiessendbeca242017-08-28 21:10:0884 DCHECK(!quit_);
Michael Thiessen781ddeb2017-11-15 17:07:2385 delegate_ = delegate;
86 run_loop_ = std::make_unique<RunLoop>();
[email protected]8e937c1e2012-06-28 22:57:3087 // Since the RunLoop was just created above, BeforeRun should be guaranteed to
88 // return true (it only returns false if the RunLoop has been Quit already).
89 if (!run_loop_->BeforeRun())
90 NOTREACHED();
[email protected]61c86c62011-08-02 16:11:1691
[email protected]3042d1b2013-07-02 18:54:0592 DCHECK(system_message_handler_obj_.is_null());
[email protected]61c86c62011-08-02 16:11:1693
94 JNIEnv* env = base::android::AttachCurrentThread();
95 DCHECK(env);
[email protected]3042d1b2013-07-02 18:54:0596 system_message_handler_obj_.Reset(
Michael Thiessen781ddeb2017-11-15 17:07:2397 Java_SystemMessageHandler_create(env, reinterpret_cast<jlong>(this)));
[email protected]61c86c62011-08-02 16:11:1698}
99
100void MessagePumpForUI::Quit() {
Michael Thiessendbeca242017-08-28 21:10:08101 quit_ = true;
Michael Thiessen781ddeb2017-11-15 17:07:23102
[email protected]3042d1b2013-07-02 18:54:05103 if (!system_message_handler_obj_.is_null()) {
[email protected]61c86c62011-08-02 16:11:16104 JNIEnv* env = base::android::AttachCurrentThread();
105 DCHECK(env);
106
Michael Thiessen781ddeb2017-11-15 17:07:23107 Java_SystemMessageHandler_shutdown(env, system_message_handler_obj_);
[email protected]3042d1b2013-07-02 18:54:05108 system_message_handler_obj_.Reset();
[email protected]61c86c62011-08-02 16:11:16109 }
110
[email protected]8e937c1e2012-06-28 22:57:30111 if (run_loop_) {
112 run_loop_->AfterRun();
Michael Thiessen781ddeb2017-11-15 17:07:23113 run_loop_ = nullptr;
[email protected]61c86c62011-08-02 16:11:16114 }
115}
116
117void MessagePumpForUI::ScheduleWork() {
Michael Thiessendbeca242017-08-28 21:10:08118 if (quit_)
119 return;
[email protected]3042d1b2013-07-02 18:54:05120 DCHECK(!system_message_handler_obj_.is_null());
[email protected]61c86c62011-08-02 16:11:16121
122 JNIEnv* env = base::android::AttachCurrentThread();
123 DCHECK(env);
124
torne948f3662016-08-16 15:10:44125 Java_SystemMessageHandler_scheduleWork(env, system_message_handler_obj_);
[email protected]61c86c62011-08-02 16:11:16126}
127
128void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
Michael Thiessendbeca242017-08-28 21:10:08129 if (quit_)
130 return;
Michael Thiessen781ddeb2017-11-15 17:07:23131 // In the java side, |SystemMessageHandler| keeps a single "delayed" message.
132 // It's an expensive operation to |removeMessage| there, so this is optimized
133 // to avoid those calls.
134 //
135 // At this stage, |delayed_work_time| can be:
136 // 1) The same as previously scheduled: nothing to be done, move along. This
137 // is the typical case, since this method is called for every single message.
138 //
139 // 2) Not previously scheduled: just post a new message in java.
140 //
141 // 3) Shorter than previously scheduled: far less common. In this case,
142 // |removeMessage| and post a new one.
143 //
144 // 4) Longer than previously scheduled (or null): nothing to be done, move
145 // along.
146 if (!delayed_scheduled_time_.is_null() &&
147 delayed_work_time >= delayed_scheduled_time_) {
148 return;
149 }
150 DCHECK(!delayed_work_time.is_null());
[email protected]3042d1b2013-07-02 18:54:05151 DCHECK(!system_message_handler_obj_.is_null());
[email protected]61c86c62011-08-02 16:11:16152
153 JNIEnv* env = base::android::AttachCurrentThread();
154 DCHECK(env);
155
156 jlong millis =
[email protected]59e69e742013-06-18 20:27:52157 (delayed_work_time - TimeTicks::Now()).InMillisecondsRoundedUp();
Michael Thiessen781ddeb2017-11-15 17:07:23158 delayed_scheduled_time_ = delayed_work_time;
[email protected]61c86c62011-08-02 16:11:16159 // Note that we're truncating to milliseconds as required by the java side,
160 // even though delayed_work_time is microseconds resolution.
torne948f3662016-08-16 15:10:44161 Java_SystemMessageHandler_scheduleDelayedWork(
Michael Thiessen781ddeb2017-11-15 17:07:23162 env, system_message_handler_obj_, millis);
[email protected]61c86c62011-08-02 16:11:16163}
164
[email protected]61c86c62011-08-02 16:11:16165} // namespace base