Bug 624652 - Add memory watcher to reduce the chance of ooming on the Nexus S. r=mwu/cjones. a=blocking-fennec

--HG--
extra : rebase_source : faf23b65fe8b5c64080c1ee3f6d4794e8837097d
This commit is contained in:
Doug Turner 2011-01-19 22:14:12 -08:00
Родитель 73ae517d85
Коммит 2ed6ba5845
8 изменённых файлов: 187 добавлений и 2 удалений

Просмотреть файл

@ -75,6 +75,7 @@
#endif
#ifdef MOZ_CRASHREPORTER
#include "nsICrashReporter.h"
#include "nsExceptionHandler.h"
#endif
@ -82,10 +83,13 @@
#include "mozilla/dom/StorageParent.h"
#include "nsAccelerometer.h"
#include <android/log.h>
using namespace mozilla::ipc;
using namespace mozilla::net;
using namespace mozilla::places;
using mozilla::MonitorAutoEnter;
using base::KillProcess;
namespace mozilla {
namespace dom {
@ -365,6 +369,19 @@ ContentParent::Observe(nsISupports* aSubject,
// listening for memory pressure event
if (!strcmp(aTopic, "memory-pressure")) {
NS_ConvertUTF16toUTF8 dataStr(aData);
const char *deathPending = dataStr.get();
if (!strcmp(deathPending, "oom-kill")) {
#ifdef MOZ_CRASHREPORTER
nsCOMPtr<nsICrashReporter> cr = do_GetService("@mozilla.org/toolkit/crash-reporter;1");
if (cr) {
cr->AnnotateCrashReport(NS_LITERAL_CSTRING("oom"), NS_LITERAL_CSTRING("true"));
}
#endif
KillProcess(OtherProcess(), 0, false);
}
else
SendFlushMemory(nsDependentString(aData));
}
// listening for remotePrefs...

Просмотреть файл

@ -70,6 +70,7 @@ abstract public class GeckoApp
public static GeckoApp mAppContext;
public static boolean mFullscreen = false;
static Thread mLibLoadThread = null;
private static MemoryWatcher mMemoryWatcher = null;
enum LaunchState {PreLaunch, Launching, WaitButton,
Launched, GeckoRunning, GeckoExiting};
@ -212,7 +213,9 @@ abstract public class GeckoApp
else
surfaceView.mSplashStatusMsg =
getResources().getString(R.string.splash_screen_label);
mLibLoadThread.start();
mLibLoadThread.start();
mMemoryWatcher = new MemoryWatcher(this);
}
@Override
@ -272,6 +275,8 @@ abstract public class GeckoApp
// onPause will be followed by either onResume or onStop.
super.onPause();
mMemoryWatcher.StopMemoryWatcher();
}
@Override
@ -288,6 +293,8 @@ abstract public class GeckoApp
if (checkLaunchState(LaunchState.PreLaunch) ||
checkLaunchState(LaunchState.Launching))
onNewIntent(getIntent());
mMemoryWatcher.StartMemoryWatcher();
}
@Override
@ -346,7 +353,9 @@ abstract public class GeckoApp
@Override
public void onLowMemory()
{
Log.i("GeckoApp", "low memory");
// if you change this handler, please take a look at
// MemoryWatcher too.
Log.e("GeckoApp", "low memory");
if (checkLaunchState(LaunchState.GeckoRunning))
GeckoAppShell.onLowMemory();
super.onLowMemory();

Просмотреть файл

@ -97,6 +97,7 @@ class GeckoAppShell
public static native void putenv(String map);
public static native void onResume();
public static native void onLowMemory();
public static native void onCriticalOOM();
public static native void callObserver(String observerKey, String topic, String data);
public static native void removeObserver(String observerKey);
public static native void loadLibs(String apkName, boolean shouldExtract);

Просмотреть файл

@ -53,6 +53,7 @@ JAVAFILES = \
GeckoSurfaceView.java \
GeckoInputConnection.java \
AlertNotification.java \
MemoryWatcher.java \
$(NULL)
PROCESSEDJAVAFILES = \

Просмотреть файл

@ -0,0 +1,132 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Android code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package org.mozilla.gecko;
import android.os.*;
import android.app.*;
import android.app.ActivityManager.*;
import android.util.*;
// Memory Watcher
//
// the onLowMemory method is not called on the foreground
// activity. Hence we need something that monitors memory
// growth, and broadcasts onLowMemory when we get low on
// resources. We can also use this to test to see if the
// system is responsive. For example, if a call to get
// available memory takes too much time, we can assume that
// the system is unstable and we should try our best to reduce
// resources. Much of this is a hack and should only be used
// on devices that don't kill us during low memory. Forgive
// me.
public class MemoryWatcher extends Handler
{
private static final long MEMORY_WATCHER_INTERVAL = 2000;
private static final long MEMORY_WATCHER_INTERVAL_DELAY_FACTOR = 5;
private static final long MEMORY_WATCHER_LOW_MEMORY_THRESHOLD = 39000000;
private static final long MEMORY_WATCHER_CRITICAL_MEMORY_THRESHOLD = 30000000;
private static final long MEMORY_WATCHER_CRITICAL_RESPONSE_THRESHOLD = 200; // in ms
private Handler mMemoryWatcherHandler;
private ActivityManager mActivityManager;
private MemoryInfo mMemoryInfo;
private boolean mMemoryWatcherKeepGoing;
private boolean mMemoryWatcherEnabled = false;
public MemoryWatcher(GeckoApp app) {
if (android.os.Build.MODEL.equals("Nexus S") == false)
return;
mMemoryWatcherEnabled = true;
mMemoryWatcherKeepGoing = true;
mMemoryInfo = new MemoryInfo();
mActivityManager = (ActivityManager) app.getSystemService("activity");
}
@Override
public void handleMessage(Message msg) {
long startTime = System.currentTimeMillis();
mActivityManager.getMemoryInfo(mMemoryInfo);
long took = System.currentTimeMillis() - startTime;
/*
Log.w("GeckoApp", String.format("OOM_CHECKER %d %d %b %s\n",
mMemoryInfo.availMem,
mMemoryInfo.threshold,
mMemoryInfo.lowMemory,
("took " + took + "ms")));
*/
// We will adjust the next time this is called if
// we fire a memory event.
long nextInterval = MEMORY_WATCHER_INTERVAL;
// if this call too long, something is very
// wrong with the device. fire a critical
// notification and hope things get better.
if (took > MEMORY_WATCHER_CRITICAL_RESPONSE_THRESHOLD ||
mMemoryInfo.availMem < MEMORY_WATCHER_CRITICAL_MEMORY_THRESHOLD) {
GeckoAppShell.onCriticalOOM();
nextInterval *= MEMORY_WATCHER_INTERVAL_DELAY_FACTOR;
}
else if (mMemoryInfo.lowMemory ||
mMemoryInfo.availMem < MEMORY_WATCHER_LOW_MEMORY_THRESHOLD) {
GeckoAppShell.onLowMemory();
nextInterval *= MEMORY_WATCHER_INTERVAL_DELAY_FACTOR;
}
if (mMemoryWatcherKeepGoing == true)
this.sendEmptyMessageDelayed(0, nextInterval);
}
public void StartMemoryWatcher() {
if (mMemoryWatcherEnabled == false)
return;
mMemoryWatcherKeepGoing = true;
sendEmptyMessageDelayed(0, MEMORY_WATCHER_INTERVAL);
}
public void StopMemoryWatcher() {
if (mMemoryWatcherEnabled == false)
return;
mMemoryWatcherKeepGoing = false;
removeMessages(0);
}
}

Просмотреть файл

@ -236,6 +236,7 @@ SHELL_WRAPPER1(notifyGeckoOfEvent, jobject)
SHELL_WRAPPER1(setSurfaceView, jobject)
SHELL_WRAPPER0(onResume)
SHELL_WRAPPER0(onLowMemory)
SHELL_WRAPPER0(onCriticalOOM)
SHELL_WRAPPER3(callObserver, jstring, jstring, jstring)
SHELL_WRAPPER1(removeObserver, jstring)
SHELL_WRAPPER1(onChangeNetworkLinkStatus, jstring)
@ -666,6 +667,7 @@ loadLibs(const char *apkName)
GETFUNC(setSurfaceView);
GETFUNC(onResume);
GETFUNC(onLowMemory);
GETFUNC(onCriticalOOM);
GETFUNC(callObserver);
GETFUNC(removeObserver);
GETFUNC(onChangeNetworkLinkStatus);

Просмотреть файл

@ -51,6 +51,11 @@
#include "mozilla/Services.h"
#include "nsINetworkLinkService.h"
#ifdef MOZ_CRASHREPORTER
#include "nsICrashReporter.h"
#endif
using namespace mozilla;
/* Forward declare all the JNI methods as extern "C" */
@ -61,6 +66,7 @@ extern "C" {
NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_setSurfaceView(JNIEnv *jenv, jclass, jobject sv);
NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_onResume(JNIEnv *, jclass);
NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_onLowMemory(JNIEnv *, jclass);
NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_onCriticalOOM(JNIEnv *, jclass);
NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_callObserver(JNIEnv *, jclass, jstring observerKey, jstring topic, jstring data);
NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_removeObserver(JNIEnv *jenv, jclass, jstring jObserverKey);
NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_onChangeNetworkLinkStatus(JNIEnv *, jclass, jstring status);
@ -101,6 +107,17 @@ Java_org_mozilla_gecko_GeckoAppShell_onLowMemory(JNIEnv *jenv, jclass jc)
}
}
NS_EXPORT void JNICALL
Java_org_mozilla_gecko_GeckoAppShell_onCriticalOOM(JNIEnv *jenv, jclass jc)
{
__android_log_print(ANDROID_LOG_ERROR, "GeckoAppShell", "Critical OOM reached!");
if (nsAppShell::gAppShell) {
nsAppShell::gAppShell->NotifyObservers(nsnull,
"memory-pressure",
NS_LITERAL_STRING("oom-kill").get());
}
}
NS_EXPORT void JNICALL
Java_org_mozilla_gecko_GeckoAppShell_onResume(JNIEnv *jenv, jclass jc)
{

Просмотреть файл

@ -67,6 +67,12 @@
* This will be passed as the extra data when the pressure
* observer has been asked to flush because a malloc() or
* realloc() has failed.
*
* "oom-kill"
* This will be passed as the extra data when the pressure
* observer notices that the application will crash or the
* system will hang if immediate steps are not taken to
* free as much as possible.
*/
[scriptable, uuid(59e7e77a-38e4-11d4-8cf5-0060b0fc14a3)]