Merge "Fix intrinsic Long.reverseBytes()."
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;"),