summaryrefslogtreecommitdiffstats
path: root/mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/MemoryController.java
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/MemoryController.java')
-rw-r--r--mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/MemoryController.java74
1 files changed, 74 insertions, 0 deletions
diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/MemoryController.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/MemoryController.java
new file mode 100644
index 0000000000..f2dcb7a52b
--- /dev/null
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/MemoryController.java
@@ -0,0 +1,74 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.process;
+
+import android.content.ComponentCallbacks2;
+import android.content.res.Configuration;
+import android.util.Log;
+import androidx.annotation.NonNull;
+import org.mozilla.gecko.GeckoAppShell;
+
+public class MemoryController implements ComponentCallbacks2 {
+ private static final String LOGTAG = "MemoryController";
+ private long mLastLowMemoryNotificationTime = 0;
+
+ // Allowed elapsed time between full GCs while under constant memory pressure
+ private static final long LOW_MEMORY_ONGOING_RESET_TIME_MS = 10000;
+
+ private static final int LOW = 0;
+ private static final int MODERATE = 1;
+ private static final int CRITICAL = 2;
+
+ private int memoryLevelFromTrim(final int level) {
+ if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE
+ || level == ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL) {
+ return CRITICAL;
+ } else if (level >= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) {
+ return MODERATE;
+ }
+ return LOW;
+ }
+
+ public void onTrimMemory(final int level) {
+ Log.i(LOGTAG, "onTrimMemory(" + level + ")");
+ onMemoryNotification(memoryLevelFromTrim(level));
+ }
+
+ @Override
+ public void onConfigurationChanged(final @NonNull Configuration newConfig) {}
+
+ public void onLowMemory() {
+ Log.i(LOGTAG, "onLowMemory");
+ onMemoryNotification(CRITICAL);
+ }
+
+ private void onMemoryNotification(final int level) {
+ if (level == LOW) {
+ // The trim level is too low to be actionable
+ return;
+ }
+
+ // See nsIMemory.idl for descriptions of the various arguments to the "memory-pressure"
+ // observer.
+ final String observerArg;
+
+ final long currentNotificationTime = System.currentTimeMillis();
+ if (level == CRITICAL
+ || (currentNotificationTime - mLastLowMemoryNotificationTime)
+ >= LOW_MEMORY_ONGOING_RESET_TIME_MS) {
+ // We do a full "low-memory" notification for both new and last-ditch onTrimMemory requests.
+ observerArg = "low-memory";
+ mLastLowMemoryNotificationTime = currentNotificationTime;
+ } else {
+ // If it has been less than ten seconds since the last time we sent a "low-memory"
+ // notification, we send a "low-memory-ongoing" notification instead.
+ // This prevents Gecko from re-doing full GC's repeatedly over and over in succession,
+ // as they are expensive and quickly result in diminishing returns.
+ observerArg = "low-memory-ongoing";
+ }
+
+ GeckoAppShell.notifyObservers("memory-pressure", observerArg);
+ }
+}