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