Proper MessageLoop::IsIdleForTesting() that corresponds to the actual idleness criteria for MessageLoop.

A pre-requirement for a simpler ScopedTaskEnvironment::RunUntilIdle()
implementation.

R=fdoray@chromium.org

Bug: 708584
Change-Id: I6c35d72868ab313788c166c76e179c8cd3ace438
Reviewed-on: https://chromium-review.googlesource.com/847752
Reviewed-by: Fran├žois Doray <fdoray@chromium.org>
Commit-Queue: Gabriel Charette <gab@chromium.org>
Cr-Commit-Position: refs/heads/master@{#526750}
diff --git a/base/message_loop/incoming_task_queue.cc b/base/message_loop/incoming_task_queue.cc
index 941cbd8..f84b326 100644
--- a/base/message_loop/incoming_task_queue.cc
+++ b/base/message_loop/incoming_task_queue.cc
@@ -85,11 +85,6 @@
   return PostPendingTask(&pending_task);
 }
 
-bool IncomingTaskQueue::IsIdleForTesting() {
-  AutoLock lock(incoming_queue_lock_);
-  return incoming_queue_.empty();
-}
-
 void IncomingTaskQueue::WillDestroyCurrentMessageLoop() {
   {
     AutoLock auto_lock(incoming_queue_lock_);
@@ -181,6 +176,7 @@
 }
 
 void IncomingTaskQueue::TriageQueue::ReloadFromIncomingQueueIfEmpty() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(outer_->sequence_checker_);
   if (queue_.empty()) {
     // TODO(robliao): Since these high resolution tasks aren't yet in the
     // delayed queue, they technically shouldn't trigger high resolution timers
@@ -351,6 +347,8 @@
 }
 
 int IncomingTaskQueue::ReloadWorkQueue(TaskQueue* work_queue) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   // Make sure no tasks are lost.
   DCHECK(work_queue->empty());
 
diff --git a/base/message_loop/incoming_task_queue.h b/base/message_loop/incoming_task_queue.h
index 861f0fc..0a47636 100644
--- a/base/message_loop/incoming_task_queue.h
+++ b/base/message_loop/incoming_task_queue.h
@@ -77,9 +77,6 @@
                           TimeDelta delay,
                           Nestable nestable);
 
-  // Returns true if the message loop is "idle". Provided for testing.
-  bool IsIdleForTesting();
-
   // Disconnects |this| from the parent message loop.
   void WillDestroyCurrentMessageLoop();
 
@@ -109,8 +106,9 @@
   // maintaining three queue queues to process tasks:
   //
   // TriageQueue
-  // The first queue to receive all tasks for the processing sequence. Tasks are
-  // generally either dispatched immediately or sent to the queues below.
+  // The first queue to receive all tasks for the processing sequence (when
+  // reloading from the thread-safe |incoming_queue_|). Tasks are generally
+  // either dispatched immediately or sent to the queues below.
   //
   // DelayedQueue
   // The queue for holding tasks that should be run later and sorted by expected
@@ -242,7 +240,7 @@
 
   // An incoming queue of tasks that are acquired under a mutex for processing
   // on this instance's thread. These tasks have not yet been been pushed to
-  // |message_loop_|.
+  // |triage_tasks_|.
   TaskQueue incoming_queue_;
 
   // True if new tasks should be accepted.
diff --git a/base/message_loop/message_loop.cc b/base/message_loop/message_loop.cc
index 41c58bf..455a7d0 100644
--- a/base/message_loop/message_loop.cc
+++ b/base/message_loop/message_loop.cc
@@ -258,9 +258,12 @@
 }
 
 bool MessageLoop::IsIdleForTesting() {
-  // We only check the incoming queue, since we don't want to lock the work
-  // queue.
-  return incoming_task_queue_->IsIdleForTesting();
+  return !incoming_task_queue_->triage_tasks().HasTasks() &&
+         (!incoming_task_queue_->deferred_tasks().HasTasks() ||
+          RunLoop::IsNestedOnCurrentThread()) &&
+         (!incoming_task_queue_->delayed_tasks().HasTasks() ||
+          incoming_task_queue_->delayed_tasks().Peek().delayed_run_time >
+              TimeTicks::Now());
 }
 
 //------------------------------------------------------------------------------
diff --git a/base/message_loop/message_loop.h b/base/message_loop/message_loop.h
index 46c7ab9..90715a0 100644
--- a/base/message_loop/message_loop.h
+++ b/base/message_loop/message_loop.h
@@ -266,7 +266,10 @@
   void AddTaskObserver(TaskObserver* task_observer);
   void RemoveTaskObserver(TaskObserver* task_observer);
 
-  // Returns true if the message loop is "idle". Provided for testing.
+  // Returns true if the message loop is idle (same condition which triggers
+  // RunLoop::RunUntilIdle() to return: i.e. out of tasks which can be processed
+  // at the current run-level -- there might be deferred non-nestable tasks
+  // remaining if currently in a nested run level). Provided for testing.
   bool IsIdleForTesting();
 
   // Runs the specified PendingTask.