root/content/public/test/nested_message_pump_android.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. Run
  2. Start
  3. Quit
  4. ScheduleWork
  5. ScheduleDelayedWork
  6. RegisterJni

// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/public/test/nested_message_pump_android.h"

#include "base/android/jni_android.h"
#include "base/android/scoped_java_ref.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread_restrictions.h"
#include "base/time/time.h"
#include "jni/NestedSystemMessageHandler_jni.h"

namespace {

base::LazyInstance<base::android::ScopedJavaGlobalRef<jobject> >
    g_message_handler_obj = LAZY_INSTANCE_INITIALIZER;

}  // namespace


namespace content {

struct NestedMessagePumpAndroid::RunState {
  RunState(base::MessagePump::Delegate* delegate, int run_depth)
      : delegate(delegate),
        run_depth(run_depth),
        should_quit(false),
        waitable_event(false, false) {
  }

  base::MessagePump::Delegate* delegate;

  // Used to count how many Run() invocations are on the stack.
  int run_depth;

  // Used to flag that the current Run() invocation should return ASAP.
  bool should_quit;

  // Used to sleep until there is more work to do.
  base::WaitableEvent waitable_event;

  // The time at which we should call DoDelayedWork.
  base::TimeTicks delayed_work_time;
};

NestedMessagePumpAndroid::NestedMessagePumpAndroid()
    : state_(NULL) {
}

NestedMessagePumpAndroid::~NestedMessagePumpAndroid() {
}

void NestedMessagePumpAndroid::Run(Delegate* delegate) {
  RunState state(delegate, state_ ? state_->run_depth + 1 : 1);
  RunState* previous_state = state_;
  state_ = &state;

  JNIEnv* env = base::android::AttachCurrentThread();
  DCHECK(env);

  // Need to cap the wait time to allow task processing on the java
  // side. Otherwise, a long wait time on the native will starve java
  // tasks.
  base::TimeDelta max_delay = base::TimeDelta::FromMilliseconds(100);

  for (;;) {
    if (state_->should_quit)
      break;

    bool did_work = state_->delegate->DoWork();
    if (state_->should_quit)
      break;

    did_work |= state_->delegate->DoDelayedWork(&state_->delayed_work_time);
    if (state_->should_quit)
      break;

    if (did_work) {
      continue;
    }

    did_work = state_->delegate->DoIdleWork();
    if (state_->should_quit)
      break;

    if (did_work)
      continue;

    // No native tasks to process right now. Process tasks from the Java
    // System message handler. This will return when the java message queue
    // is idle.
    bool ret = Java_NestedSystemMessageHandler_runNestedLoopTillIdle(env,
        g_message_handler_obj.Get().obj());
    CHECK(ret) << "Error running java message loop, tests will likely fail.";

    base::ThreadRestrictions::ScopedAllowWait allow_wait;
    if (state_->delayed_work_time.is_null()) {
      state_->waitable_event.TimedWait(max_delay);
    } else {
      base::TimeDelta delay =
          state_->delayed_work_time - base::TimeTicks::Now();
      if (delay > max_delay)
        delay = max_delay;
      if (delay > base::TimeDelta()) {
        state_->waitable_event.TimedWait(delay);
      } else {
        // It looks like delayed_work_time indicates a time in the past, so we
        // need to call DoDelayedWork now.
        state_->delayed_work_time = base::TimeTicks();
      }
    }
  }

  state_ = previous_state;
}

void NestedMessagePumpAndroid::Start(
    base::MessagePump::Delegate* delegate) {
  JNIEnv* env = base::android::AttachCurrentThread();
  DCHECK(env);
  g_message_handler_obj.Get().Reset(
      Java_NestedSystemMessageHandler_create(env));

  base::MessagePumpForUI::Start(delegate);
}

void NestedMessagePumpAndroid::Quit() {
  if (state_) {
    state_->should_quit = true;
    state_->waitable_event.Signal();
    return;
  }
  base::MessagePumpForUI::Quit();
}

void NestedMessagePumpAndroid::ScheduleWork() {
  if (state_) {
    state_->waitable_event.Signal();
    return;
  }

  base::MessagePumpForUI::ScheduleWork();
}

void NestedMessagePumpAndroid::ScheduleDelayedWork(
    const base::TimeTicks& delayed_work_time) {
  if (state_) {
    // We know that we can't be blocked on Wait right now since this method can
    // only be called on the same thread as Run, so we only need to update our
    // record of how long to sleep when we do sleep.
    state_->delayed_work_time = delayed_work_time;
    return;
  }

  base::MessagePumpForUI::ScheduleDelayedWork(delayed_work_time);
}

// static
bool NestedMessagePumpAndroid::RegisterJni(JNIEnv* env) {
  return RegisterNativesImpl(env);
}

}  // namespace content

/* [<][>][^][v][top][bottom][index][help] */