Merge "Add interface for updating process state."
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 5e62729..1e3689b 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -107,9 +107,8 @@
       activity_thread_(NULL),
       application_thread_(NULL),
       last_process_state_id_(NULL),
-      // Initially care about pauses in case we never get notified of process states, or if the JNI
-      // code becomes broken.
-      care_about_pause_times_(true),
+      // Initially assume we perceive jank in case the process state is never updated.
+      process_state_(kProcessStateJankPerceptible),
       concurrent_start_bytes_(concurrent_gc_ ? initial_size - kMinConcurrentRemainingBytes
           :  std::numeric_limits<size_t>::max()),
       total_bytes_freed_ever_(0),
@@ -325,6 +324,10 @@
   --gc_disable_count_;
 }
 
+void Heap::UpdateProcessState(ProcessState process_state) {
+  process_state_ = process_state;
+}
+
 void Heap::CreateThreadPool() {
   const size_t num_threads = std::max(parallel_gc_threads_, conc_gc_threads_);
   if (num_threads != 0) {
@@ -373,124 +376,6 @@
   thread_pool_.reset(nullptr);
 }
 
-static bool ReadStaticInt(JNIEnvExt* env, jclass clz, const char* name, int* out_value) {
-  DCHECK(out_value != NULL);
-  jfieldID field = env->GetStaticFieldID(clz, name, "I");
-  if (field == NULL) {
-    env->ExceptionClear();
-    return false;
-  }
-  *out_value = env->GetStaticIntField(clz, field);
-  return true;
-}
-
-void Heap::ListenForProcessStateChange() {
-  VLOG(heap) << "Heap notified of process state change";
-
-  Thread* self = Thread::Current();
-  JNIEnvExt* env = self->GetJniEnv();
-
-  if (!have_zygote_space_) {
-    return;
-  }
-
-  if (activity_thread_class_ == NULL) {
-    jclass clz = env->FindClass("android/app/ActivityThread");
-    if (clz == NULL) {
-      env->ExceptionClear();
-      LOG(WARNING) << "Could not find activity thread class in process state change";
-      return;
-    }
-    activity_thread_class_ = reinterpret_cast<jclass>(env->NewGlobalRef(clz));
-  }
-
-  if (activity_thread_class_ != NULL && activity_thread_ == NULL) {
-    jmethodID current_activity_method = env->GetStaticMethodID(activity_thread_class_,
-                                                               "currentActivityThread",
-                                                               "()Landroid/app/ActivityThread;");
-    if (current_activity_method == NULL) {
-      env->ExceptionClear();
-      LOG(WARNING) << "Could not get method for currentActivityThread";
-      return;
-    }
-
-    jobject obj = env->CallStaticObjectMethod(activity_thread_class_, current_activity_method);
-    if (obj == NULL) {
-      env->ExceptionClear();
-      LOG(WARNING) << "Could not get current activity";
-      return;
-    }
-    activity_thread_ = env->NewGlobalRef(obj);
-  }
-
-  if (process_state_cares_about_pause_time_.empty()) {
-    // Just attempt to do this the first time.
-    jclass clz = env->FindClass("android/app/ActivityManager");
-    if (clz == NULL) {
-      LOG(WARNING) << "Activity manager class is null";
-      return;
-    }
-    ScopedLocalRef<jclass> activity_manager(env, clz);
-    std::vector<const char*> care_about_pauses;
-    care_about_pauses.push_back("PROCESS_STATE_TOP");
-    care_about_pauses.push_back("PROCESS_STATE_IMPORTANT_BACKGROUND");
-    // Attempt to read the constants and classify them as whether or not we care about pause times.
-    for (size_t i = 0; i < care_about_pauses.size(); ++i) {
-      int process_state = 0;
-      if (ReadStaticInt(env, activity_manager.get(), care_about_pauses[i], &process_state)) {
-        process_state_cares_about_pause_time_.insert(process_state);
-        VLOG(heap) << "Adding process state " << process_state
-                   << " to set of states which care about pause time";
-      }
-    }
-  }
-
-  if (application_thread_class_ == NULL) {
-    jclass clz = env->FindClass("android/app/ActivityThread$ApplicationThread");
-    if (clz == NULL) {
-      env->ExceptionClear();
-      LOG(WARNING) << "Could not get application thread class";
-      return;
-    }
-    application_thread_class_ = reinterpret_cast<jclass>(env->NewGlobalRef(clz));
-    last_process_state_id_ = env->GetFieldID(application_thread_class_, "mLastProcessState", "I");
-    if (last_process_state_id_ == NULL) {
-      env->ExceptionClear();
-      LOG(WARNING) << "Could not get last process state member";
-      return;
-    }
-  }
-
-  if (application_thread_class_ != NULL && application_thread_ == NULL) {
-    jmethodID get_application_thread =
-        env->GetMethodID(activity_thread_class_, "getApplicationThread",
-                         "()Landroid/app/ActivityThread$ApplicationThread;");
-    if (get_application_thread == NULL) {
-      LOG(WARNING) << "Could not get method ID for get application thread";
-      return;
-    }
-
-    jobject obj = env->CallObjectMethod(activity_thread_, get_application_thread);
-    if (obj == NULL) {
-      LOG(WARNING) << "Could not get application thread";
-      return;
-    }
-
-    application_thread_ = env->NewGlobalRef(obj);
-  }
-
-  if (application_thread_ != NULL && last_process_state_id_ != NULL) {
-    int process_state = env->GetIntField(application_thread_, last_process_state_id_);
-    env->ExceptionClear();
-
-    care_about_pause_times_ = process_state_cares_about_pause_time_.find(process_state) !=
-        process_state_cares_about_pause_time_.end();
-
-    VLOG(heap) << "New process state " << process_state
-               << " care about pauses " << care_about_pause_times_;
-  }
-}
-
 void Heap::AddSpace(space::Space* space) {
   DCHECK(space != NULL);
   WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
@@ -1426,7 +1311,7 @@
   // Grow the heap so that we know when to perform the next GC.
   GrowForUtilization(gc_type, collector->GetDurationNs());
 
-  if (care_about_pause_times_) {
+  if (CareAboutPauseTimes()) {
     const size_t duration = collector->GetDurationNs();
     std::vector<uint64_t> pauses = collector->GetPauseTimes();
     // GC for alloc pauses the allocating thread, so consider it as a pause.
@@ -2143,10 +2028,9 @@
   }
 
   last_trim_time_ms_ = ms_time;
-  ListenForProcessStateChange();
 
   // Trim only if we do not currently care about pause times.
-  if (!care_about_pause_times_) {
+  if (!CareAboutPauseTimes()) {
     JNIEnv* env = self->GetJniEnv();
     DCHECK(WellKnownClasses::java_lang_Daemons != NULL);
     DCHECK(WellKnownClasses::java_lang_Daemons_requestHeapTrim != NULL);
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 8c5746d..046fbac 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -119,6 +119,18 @@
 // If true, use rosalloc/RosAllocSpace instead of dlmalloc/DlMallocSpace
 static constexpr bool kUseRosAlloc = true;
 
+// The process state passed in from the activity manager, used to determine when to do trimming
+// and compaction.
+enum ProcessState {
+  kProcessStateJankPerceptible = 0,
+  kProcessStateJankImperceptible = 1,
+};
+
+// If true, measure the total allocation time.
+static constexpr bool kMeasureAllocationTime = false;
+// Primitive arrays larger than this size are put in the large object space.
+static constexpr size_t kLargeObjectThreshold = 3 * kPageSize;
+
 class Heap {
  public:
   // If true, measure the total allocation time.
@@ -287,6 +299,9 @@
   // waited for.
   collector::GcType WaitForGcToComplete(Thread* self) LOCKS_EXCLUDED(gc_complete_lock_);
 
+  // Update the heap's process state to a new value, may cause compaction to occur.
+  void UpdateProcessState(ProcessState process_state);
+
   const std::vector<space::ContinuousSpace*>& GetContinuousSpaces() const {
     return continuous_spaces_;
   }
@@ -451,10 +466,7 @@
 
   // Mark the specified allocation stack as live.
   void MarkAllocStackAsLive(accounting::ObjectStack* stack)
-        EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
-
-  // Gets called when we get notified by ActivityThread that the process state has changed.
-  void ListenForProcessStateChange();
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
   // DEPRECATED: Should remove in "near" future when support for multiple image spaces is added.
   // Assumes there is only one image space.
@@ -475,7 +487,7 @@
 
   // Returns true if we currently care about pause times.
   bool CareAboutPauseTimes() const {
-    return care_about_pause_times_;
+    return process_state_ == kProcessStateJankPerceptible;
   }
 
   // Thread pool.
@@ -713,11 +725,8 @@
   jobject application_thread_;
   jfieldID last_process_state_id_;
 
-  // Process states which care about pause times.
-  std::set<int> process_state_cares_about_pause_time_;
-
   // Whether or not we currently care about pause times.
-  bool care_about_pause_times_;
+  ProcessState process_state_;
 
   // When num_bytes_allocated_ exceeds this amount then a concurrent GC should be requested so that
   // it completes ahead of an allocation failing.
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index fd3d91e..726a8f1 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -166,6 +166,10 @@
   Runtime::Current()->GetHeap()->RegisterNativeFree(env, bytes);
 }
 
+static void VMRuntime_updateProcessState(JNIEnv* env, jobject, jint process_state) {
+  Runtime::Current()->GetHeap()->UpdateProcessState(static_cast<gc::ProcessState>(process_state));
+}
+
 static void VMRuntime_trimHeap(JNIEnv*, jobject) {
   Runtime::Current()->GetHeap()->Trim();
 }
@@ -496,6 +500,7 @@
   NATIVE_METHOD(VMRuntime, setTargetSdkVersionNative, "(I)V"),
   NATIVE_METHOD(VMRuntime, registerNativeAllocation, "(I)V"),
   NATIVE_METHOD(VMRuntime, registerNativeFree, "(I)V"),
+  NATIVE_METHOD(VMRuntime, updateProcessState, "(I)V"),
   NATIVE_METHOD(VMRuntime, startJitCompilation, "()V"),
   NATIVE_METHOD(VMRuntime, trimHeap, "()V"),
   NATIVE_METHOD(VMRuntime, vmVersion, "()Ljava/lang/String;"),