1eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Copyright 2013 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "content/public/test/nested_message_pump_android.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/android/jni_android.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/android/scoped_java_ref.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/lazy_instance.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/synchronization/waitable_event.h"
1258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/threading/thread_restrictions.h"
13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
14eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "jni/NestedSystemMessageHandler_jni.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::LazyInstance<base::android::ScopedJavaGlobalRef<jobject> >
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    g_message_handler_obj = LAZY_INSTANCE_INITIALIZER;
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace content {
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
26eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstruct NestedMessagePumpAndroid::RunState {
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RunState(base::MessagePump::Delegate* delegate, int run_depth)
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : delegate(delegate),
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        run_depth(run_depth),
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        should_quit(false),
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        waitable_event(false, false) {
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::MessagePump::Delegate* delegate;
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Used to count how many Run() invocations are on the stack.
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int run_depth;
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Used to flag that the current Run() invocation should return ASAP.
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool should_quit;
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Used to sleep until there is more work to do.
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::WaitableEvent waitable_event;
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The time at which we should call DoDelayedWork.
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeTicks delayed_work_time;
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
49eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochNestedMessagePumpAndroid::NestedMessagePumpAndroid()
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : state_(NULL) {
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
53eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochNestedMessagePumpAndroid::~NestedMessagePumpAndroid() {
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
56eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid NestedMessagePumpAndroid::Run(Delegate* delegate) {
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RunState state(delegate, state_ ? state_->run_depth + 1 : 1);
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RunState* previous_state = state_;
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  state_ = &state;
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  JNIEnv* env = base::android::AttachCurrentThread();
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(env);
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Need to cap the wait time to allow task processing on the java
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // side. Otherwise, a long wait time on the native will starve java
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // tasks.
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeDelta max_delay = base::TimeDelta::FromMilliseconds(100);
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (;;) {
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (state_->should_quit)
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool did_work = state_->delegate->DoWork();
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (state_->should_quit)
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    did_work |= state_->delegate->DoDelayedWork(&state_->delayed_work_time);
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (state_->should_quit)
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (did_work) {
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    did_work = state_->delegate->DoIdleWork();
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (state_->should_quit)
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (did_work)
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // No native tasks to process right now. Process tasks from the Java
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // System message handler. This will return when the java message queue
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // is idle.
95eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    bool ret = Java_NestedSystemMessageHandler_runNestedLoopTillIdle(env,
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        g_message_handler_obj.Get().obj());
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CHECK(ret) << "Error running java message loop, tests will likely fail.";
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    base::ThreadRestrictions::ScopedAllowWait allow_wait;
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (state_->delayed_work_time.is_null()) {
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      state_->waitable_event.TimedWait(max_delay);
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::TimeDelta delay =
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          state_->delayed_work_time - base::TimeTicks::Now();
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (delay > max_delay)
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        delay = max_delay;
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (delay > base::TimeDelta()) {
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        state_->waitable_event.TimedWait(delay);
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else {
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // It looks like delayed_work_time indicates a time in the past, so we
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // need to call DoDelayedWork now.
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        state_->delayed_work_time = base::TimeTicks();
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  state_ = previous_state;
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
120eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid NestedMessagePumpAndroid::Start(
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::MessagePump::Delegate* delegate) {
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  JNIEnv* env = base::android::AttachCurrentThread();
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(env);
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  g_message_handler_obj.Get().Reset(
125eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      Java_NestedSystemMessageHandler_create(env));
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::MessagePumpForUI::Start(delegate);
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
130eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid NestedMessagePumpAndroid::Quit() {
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (state_) {
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    state_->should_quit = true;
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    state_->waitable_event.Signal();
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::MessagePumpForUI::Quit();
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
139eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid NestedMessagePumpAndroid::ScheduleWork() {
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (state_) {
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    state_->waitable_event.Signal();
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::MessagePumpForUI::ScheduleWork();
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
148eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid NestedMessagePumpAndroid::ScheduleDelayedWork(
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::TimeTicks& delayed_work_time) {
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (state_) {
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // We know that we can't be blocked on Wait right now since this method can
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // only be called on the same thread as Run, so we only need to update our
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // record of how long to sleep when we do sleep.
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    state_->delayed_work_time = delayed_work_time;
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::MessagePumpForUI::ScheduleDelayedWork(delayed_work_time);
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
162eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool NestedMessagePumpAndroid::RegisterJni(JNIEnv* env) {
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return RegisterNativesImpl(env);
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace content
167