Background full compaction for CC.

Invoke a full compaction with the CC collector when an app goes to the
background like the HSpace compaction for the CMS collector.

Bug: 31039431
Bug: 12687968
Test: test-art, Ritz EAAC, N9 libartd.so device boot with CC
Change-Id: I119aa26c1d3c167b12983fffcb16164929bf8f68
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index 42816a0..285b111 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -202,8 +202,10 @@
   immune_spaces_.Reset();
   bytes_moved_.StoreRelaxed(0);
   objects_moved_.StoreRelaxed(0);
-  if (GetCurrentIteration()->GetGcCause() == kGcCauseExplicit ||
-      GetCurrentIteration()->GetGcCause() == kGcCauseForNativeAlloc ||
+  GcCause gc_cause = GetCurrentIteration()->GetGcCause();
+  if (gc_cause == kGcCauseExplicit ||
+      gc_cause == kGcCauseForNativeAlloc ||
+      gc_cause == kGcCauseCollectorTransition ||
       GetCurrentIteration()->GetClearSoftReferences()) {
     force_evacuate_all_ = true;
   } else {
diff --git a/runtime/gc/collector_type.h b/runtime/gc/collector_type.h
index 7899a7c..b342cc7 100644
--- a/runtime/gc/collector_type.h
+++ b/runtime/gc/collector_type.h
@@ -40,6 +40,8 @@
   kCollectorTypeHeapTrim,
   // A (mostly) concurrent copying collector.
   kCollectorTypeCC,
+  // The background compaction of the concurrent copying collector.
+  kCollectorTypeCCBackground,
   // Instrumentation critical section fake collector.
   kCollectorTypeInstrumentation,
   // Fake collector for adding or removing application image spaces.
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 638c1d8..9e454ca 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -731,6 +731,7 @@
 }
 
 void Heap::DisableMovingGc() {
+  CHECK(!kUseReadBarrier);
   if (IsMovingGc(foreground_collector_type_)) {
     foreground_collector_type_ = kCollectorTypeCMS;
   }
@@ -970,7 +971,8 @@
       // Don't delay for debug builds since we may want to stress test the GC.
       // If background_collector_type_ is kCollectorTypeHomogeneousSpaceCompact then we have
       // special handling which does a homogenous space compaction once but then doesn't transition
-      // the collector.
+      // the collector. Similarly, we invoke a full compaction for kCollectorTypeCC but don't
+      // transition the collector.
       RequestCollectorTransition(background_collector_type_,
                                  kIsDebugBuild ? 0 : kCollectorTransitionWait);
     }
@@ -1384,6 +1386,16 @@
     } else {
       VLOG(gc) << "Homogeneous compaction ignored due to jank perceptible process state";
     }
+  } else if (desired_collector_type == kCollectorTypeCCBackground) {
+    DCHECK(kUseReadBarrier);
+    if (!CareAboutPauseTimes()) {
+      // Invoke CC full compaction.
+      CollectGarbageInternal(collector::kGcTypeFull,
+                             kGcCauseCollectorTransition,
+                             /*clear_soft_references*/false);
+    } else {
+      VLOG(gc) << "CC background compaction ignored due to jank perceptible process state";
+    }
   } else {
     TransitionCollector(desired_collector_type);
   }
@@ -1841,6 +1853,10 @@
         break;
       }
       case kAllocatorTypeNonMoving: {
+        if (kUseReadBarrier) {
+          // DisableMovingGc() isn't compatible with CC.
+          break;
+        }
         // Try to transition the heap if the allocation failure was due to the space being full.
         if (!IsOutOfMemoryOnAllocation<false>(allocator, alloc_size)) {
           // If we aren't out of memory then the OOM was probably from the non moving space being
@@ -2109,6 +2125,8 @@
 }
 
 void Heap::TransitionCollector(CollectorType collector_type) {
+  // Collector transition must not happen with CC
+  CHECK(!kUseReadBarrier);
   if (collector_type == collector_type_) {
     return;
   }
@@ -3798,6 +3816,12 @@
   if (desired_collector_type_ == collector_type_ || !CanAddHeapTask(self)) {
     return;
   }
+  if (collector_type_ == kCollectorTypeCC) {
+    // For CC, we invoke a full compaction when going to the background, but the collector type
+    // doesn't change.
+    DCHECK_EQ(desired_collector_type_, kCollectorTypeCCBackground);
+  }
+  DCHECK_NE(collector_type_, kCollectorTypeCCBackground);
   CollectorTransitionTask* added_task = nullptr;
   const uint64_t target_time = NanoTime() + delta_time;
   {
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index be8ed40..b357b87 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -537,7 +537,7 @@
   void DumpForSigQuit(std::ostream& os) REQUIRES(!*gc_complete_lock_, !native_histogram_lock_);
 
   // Do a pending collector transition.
-  void DoPendingCollectorTransition() REQUIRES(!*gc_complete_lock_);
+  void DoPendingCollectorTransition() REQUIRES(!*gc_complete_lock_, !*pending_task_lock_);
 
   // Deflate monitors, ... and trim the spaces.
   void Trim(Thread* self) REQUIRES(!*gc_complete_lock_);
@@ -708,8 +708,6 @@
     if (IsGcConcurrent() && IsMovingGc(collector_type_)) {
       // Assume no transition when a concurrent moving collector is used.
       DCHECK_EQ(collector_type_, foreground_collector_type_);
-      DCHECK_EQ(foreground_collector_type_, background_collector_type_)
-          << "Assume no transition such that collector_type_ won't change";
       return true;
     }
     return false;
@@ -828,6 +826,7 @@
         collector_type == kCollectorTypeSS ||
         collector_type == kCollectorTypeGSS ||
         collector_type == kCollectorTypeCC ||
+        collector_type == kCollectorTypeCCBackground ||
         collector_type == kCollectorTypeMC ||
         collector_type == kCollectorTypeHomogeneousSpaceCompact;
   }
@@ -997,7 +996,9 @@
   // What kind of concurrency behavior is the runtime after? Currently true for concurrent mark
   // sweep GC, false for other GC types.
   bool IsGcConcurrent() const ALWAYS_INLINE {
-    return collector_type_ == kCollectorTypeCMS || collector_type_ == kCollectorTypeCC;
+    return collector_type_ == kCollectorTypeCMS ||
+        collector_type_ == kCollectorTypeCC ||
+        collector_type_ == kCollectorTypeCCBackground;
   }
 
   // Trim the managed and native spaces by releasing unused memory back to the OS.