Home | History | Annotate | Download | only in test
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "content/public/test/nested_message_pump_android.h"
      6 
      7 #include "base/android/jni_android.h"
      8 #include "base/android/scoped_java_ref.h"
      9 #include "base/lazy_instance.h"
     10 #include "base/logging.h"
     11 #include "base/synchronization/waitable_event.h"
     12 #include "base/threading/thread_restrictions.h"
     13 #include "base/time/time.h"
     14 #include "jni/NestedSystemMessageHandler_jni.h"
     15 
     16 namespace {
     17 
     18 base::LazyInstance<base::android::ScopedJavaGlobalRef<jobject> >
     19     g_message_handler_obj = LAZY_INSTANCE_INITIALIZER;
     20 
     21 }  // namespace
     22 
     23 
     24 namespace content {
     25 
     26 struct NestedMessagePumpAndroid::RunState {
     27   RunState(base::MessagePump::Delegate* delegate, int run_depth)
     28       : delegate(delegate),
     29         run_depth(run_depth),
     30         should_quit(false),
     31         waitable_event(false, false) {
     32   }
     33 
     34   base::MessagePump::Delegate* delegate;
     35 
     36   // Used to count how many Run() invocations are on the stack.
     37   int run_depth;
     38 
     39   // Used to flag that the current Run() invocation should return ASAP.
     40   bool should_quit;
     41 
     42   // Used to sleep until there is more work to do.
     43   base::WaitableEvent waitable_event;
     44 
     45   // The time at which we should call DoDelayedWork.
     46   base::TimeTicks delayed_work_time;
     47 };
     48 
     49 NestedMessagePumpAndroid::NestedMessagePumpAndroid()
     50     : state_(NULL) {
     51 }
     52 
     53 NestedMessagePumpAndroid::~NestedMessagePumpAndroid() {
     54 }
     55 
     56 void NestedMessagePumpAndroid::Run(Delegate* delegate) {
     57   RunState state(delegate, state_ ? state_->run_depth + 1 : 1);
     58   RunState* previous_state = state_;
     59   state_ = &state;
     60 
     61   JNIEnv* env = base::android::AttachCurrentThread();
     62   DCHECK(env);
     63 
     64   // Need to cap the wait time to allow task processing on the java
     65   // side. Otherwise, a long wait time on the native will starve java
     66   // tasks.
     67   base::TimeDelta max_delay = base::TimeDelta::FromMilliseconds(100);
     68 
     69   for (;;) {
     70     if (state_->should_quit)
     71       break;
     72 
     73     bool did_work = state_->delegate->DoWork();
     74     if (state_->should_quit)
     75       break;
     76 
     77     did_work |= state_->delegate->DoDelayedWork(&state_->delayed_work_time);
     78     if (state_->should_quit)
     79       break;
     80 
     81     if (did_work) {
     82       continue;
     83     }
     84 
     85     did_work = state_->delegate->DoIdleWork();
     86     if (state_->should_quit)
     87       break;
     88 
     89     if (did_work)
     90       continue;
     91 
     92     // No native tasks to process right now. Process tasks from the Java
     93     // System message handler. This will return when the java message queue
     94     // is idle.
     95     bool ret = Java_NestedSystemMessageHandler_runNestedLoopTillIdle(env,
     96         g_message_handler_obj.Get().obj());
     97     CHECK(ret) << "Error running java message loop, tests will likely fail.";
     98 
     99     base::ThreadRestrictions::ScopedAllowWait allow_wait;
    100     if (state_->delayed_work_time.is_null()) {
    101       state_->waitable_event.TimedWait(max_delay);
    102     } else {
    103       base::TimeDelta delay =
    104           state_->delayed_work_time - base::TimeTicks::Now();
    105       if (delay > max_delay)
    106         delay = max_delay;
    107       if (delay > base::TimeDelta()) {
    108         state_->waitable_event.TimedWait(delay);
    109       } else {
    110         // It looks like delayed_work_time indicates a time in the past, so we
    111         // need to call DoDelayedWork now.
    112         state_->delayed_work_time = base::TimeTicks();
    113       }
    114     }
    115   }
    116 
    117   state_ = previous_state;
    118 }
    119 
    120 void NestedMessagePumpAndroid::Start(
    121     base::MessagePump::Delegate* delegate) {
    122   JNIEnv* env = base::android::AttachCurrentThread();
    123   DCHECK(env);
    124   g_message_handler_obj.Get().Reset(
    125       Java_NestedSystemMessageHandler_create(env));
    126 
    127   base::MessagePumpForUI::Start(delegate);
    128 }
    129 
    130 void NestedMessagePumpAndroid::Quit() {
    131   if (state_) {
    132     state_->should_quit = true;
    133     state_->waitable_event.Signal();
    134     return;
    135   }
    136   base::MessagePumpForUI::Quit();
    137 }
    138 
    139 void NestedMessagePumpAndroid::ScheduleWork() {
    140   if (state_) {
    141     state_->waitable_event.Signal();
    142     return;
    143   }
    144 
    145   base::MessagePumpForUI::ScheduleWork();
    146 }
    147 
    148 void NestedMessagePumpAndroid::ScheduleDelayedWork(
    149     const base::TimeTicks& delayed_work_time) {
    150   if (state_) {
    151     // We know that we can't be blocked on Wait right now since this method can
    152     // only be called on the same thread as Run, so we only need to update our
    153     // record of how long to sleep when we do sleep.
    154     state_->delayed_work_time = delayed_work_time;
    155     return;
    156   }
    157 
    158   base::MessagePumpForUI::ScheduleDelayedWork(delayed_work_time);
    159 }
    160 
    161 // static
    162 bool NestedMessagePumpAndroid::RegisterJni(JNIEnv* env) {
    163   return RegisterNativesImpl(env);
    164 }
    165 
    166 }  // namespace content
    167