diff --git a/embedding/android/GeckoApp.java b/embedding/android/GeckoApp.java index 8261936c951a..03e3de99ce87 100644 --- a/embedding/android/GeckoApp.java +++ b/embedding/android/GeckoApp.java @@ -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}; @@ -213,6 +214,8 @@ abstract public class GeckoApp surfaceView.mSplashStatusMsg = getResources().getString(R.string.splash_screen_label); 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 @@ -279,8 +284,7 @@ abstract public class GeckoApp { Log.i("GeckoApp", "resume"); if (checkLaunchState(LaunchState.GeckoRunning)) - GeckoAppShell.sendEventToGecko(new GeckoEvent(GeckoEvent.ACTIVITY_RESUMING)); - + GeckoAppShell.onResume(); // After an onPause, the activity is back in the foreground. // Undo whatever we did in onPause. super.onResume(); @@ -289,6 +293,41 @@ abstract public class GeckoApp if (checkLaunchState(LaunchState.PreLaunch) || checkLaunchState(LaunchState.Launching)) onNewIntent(getIntent()); + + mMemoryWatcher.StartMemoryWatcher(); + } + + @Override + public void onStop() + { + Log.i("GeckoApp", "stop"); + // We're about to be stopped, potentially in preparation for + // being destroyed. We're killable after this point -- as I + // understand it, in extreme cases the process can be terminated + // without going through onDestroy. + // + // We might also get an onRestart after this; not sure what + // that would mean for Gecko if we were to kill it here. + // Instead, what we should do here is save prefs, session, + // etc., and generally mark the profile as 'clean', and then + // dirty it again if we get an onResume. + + GeckoAppShell.sendEventToGecko(new GeckoEvent(GeckoEvent.ACTIVITY_STOPPING)); + super.onStop(); + } + + @Override + public void onRestart() + { + Log.i("GeckoApp", "restart"); + super.onRestart(); + } + + @Override + public void onStart() + { + Log.i("GeckoApp", "start"); + super.onStart(); } @Override @@ -314,6 +353,8 @@ abstract public class GeckoApp @Override public void onLowMemory() { + // if you change this handler, please take a look at + // MemoryWatcher too. Log.e("GeckoApp", "low memory"); if (checkLaunchState(LaunchState.GeckoRunning)) GeckoAppShell.onLowMemory(); diff --git a/embedding/android/GeckoAppShell.java b/embedding/android/GeckoAppShell.java index a3f0df415566..4dbfbf650b51 100644 --- a/embedding/android/GeckoAppShell.java +++ b/embedding/android/GeckoAppShell.java @@ -95,6 +95,7 @@ class GeckoAppShell // helper methods public static native void setSurfaceView(GeckoSurfaceView sv); 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); diff --git a/embedding/android/GeckoEvent.java b/embedding/android/GeckoEvent.java index 7cf76f014548..57a6d453e638 100644 --- a/embedding/android/GeckoEvent.java +++ b/embedding/android/GeckoEvent.java @@ -63,10 +63,11 @@ public class GeckoEvent { public static final int IME_EVENT = 5; public static final int DRAW = 6; public static final int SIZE_CHANGED = 7; - public static final int ACTIVITY_PAUSING = 8; - public static final int ACTIVITY_RESUMING = 9; + public static final int ACTIVITY_STOPPING = 8; + public static final int ACTIVITY_PAUSING = 9; public static final int ACTIVITY_SHUTDOWN = 10; public static final int LOAD_URI = 11; + public static final int SURFACE_CREATED = 12; public static final int SURFACE_DESTROYED = 13; diff --git a/embedding/android/Makefile.in b/embedding/android/Makefile.in index b5d0c920fb18..afc5c361d317 100644 --- a/embedding/android/Makefile.in +++ b/embedding/android/Makefile.in @@ -53,6 +53,7 @@ JAVAFILES = \ GeckoSurfaceView.java \ GeckoInputConnection.java \ AlertNotification.java \ + MemoryWatcher.java \ $(NULL) PROCESSEDJAVAFILES = \ diff --git a/widget/src/android/AndroidJNI.cpp b/widget/src/android/AndroidJNI.cpp index dbe2ddcf7a4f..05155c5a3ad7 100644 --- a/widget/src/android/AndroidJNI.cpp +++ b/widget/src/android/AndroidJNI.cpp @@ -64,6 +64,7 @@ extern "C" { NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_nativeInit(JNIEnv *, jclass); NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_notifyGeckoOfEvent(JNIEnv *, jclass, jobject event); 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); @@ -117,6 +118,13 @@ Java_org_mozilla_gecko_GeckoAppShell_onCriticalOOM(JNIEnv *jenv, jclass jc) } } +NS_EXPORT void JNICALL +Java_org_mozilla_gecko_GeckoAppShell_onResume(JNIEnv *jenv, jclass jc) +{ + if (nsAppShell::gAppShell) + nsAppShell::gAppShell->OnResume(); +} + NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_callObserver(JNIEnv *jenv, jclass, jstring jObserverKey, jstring jTopic, jstring jData) { diff --git a/widget/src/android/AndroidJavaWrappers.h b/widget/src/android/AndroidJavaWrappers.h index 281052d463a6..4acfddad0ce8 100644 --- a/widget/src/android/AndroidJavaWrappers.h +++ b/widget/src/android/AndroidJavaWrappers.h @@ -445,8 +445,8 @@ public: IME_EVENT = 5, DRAW = 6, SIZE_CHANGED = 7, - ACTIVITY_PAUSING = 8, - ACTIVITY_RESUMING = 9, + ACTIVITY_STOPPING = 8, + ACTIVITY_PAUSING = 9, ACTIVITY_SHUTDOWN = 10, LOAD_URI = 11, SURFACE_CREATED = 12, diff --git a/widget/src/android/Makefile.in b/widget/src/android/Makefile.in index 792be13eb455..40b7e7d93972 100644 --- a/widget/src/android/Makefile.in +++ b/widget/src/android/Makefile.in @@ -68,7 +68,6 @@ CPPSRCS = \ nsIMEPicker.cpp \ nsDeviceContextAndroid.cpp \ nsPrintOptionsAndroid.cpp \ - nsMemoryWatcher.cpp \ $(NULL) NOT_THERE_YET_CPPSRCS = \ diff --git a/widget/src/android/nsAppShell.cpp b/widget/src/android/nsAppShell.cpp index 8d5f71bc09e1..14e541ddbd50 100644 --- a/widget/src/android/nsAppShell.cpp +++ b/widget/src/android/nsAppShell.cpp @@ -49,7 +49,6 @@ #include "prenv.h" #include "AndroidBridge.h" -#include "nsMemoryWatcher.h" #include "nsAccelerometerSystem.h" #include #include @@ -123,10 +122,6 @@ nsAppShell::Init() if (obsServ) { obsServ->AddObserver(this, "xpcom-shutdown", PR_FALSE); } - - mMemoryWatcher = new nsMemoryWatcher(); - if (mMemoryWatcher) - mMemoryWatcher->StartWatching(); return rv; } @@ -256,6 +251,15 @@ nsAppShell::ProcessNextNativeEvent(PRBool mayWait) NS_WARNING("Received location event without geoposition!"); break; + case AndroidGeckoEvent::ACTIVITY_STOPPING: { + nsCOMPtr obsServ = + mozilla::services::GetObserverService(); + NS_NAMED_LITERAL_STRING(minimize, "heap-minimize"); + obsServ->NotifyObservers(nsnull, "memory-pressure", minimize.get()); + + break; + } + case AndroidGeckoEvent::ACTIVITY_SHUTDOWN: { nsCOMPtr obsServ = mozilla::services::GetObserverService(); @@ -268,17 +272,9 @@ nsAppShell::ProcessNextNativeEvent(PRBool mayWait) nsCOMPtr appSvc = do_GetService("@mozilla.org/toolkit/app-startup;1"); if (appSvc) appSvc->Quit(nsIAppStartup::eForceQuit); - - if (mMemoryWatcher) - mMemoryWatcher->StopWatching(); break; } - case AndroidGeckoEvent::ACTIVITY_RESUMING: { - if (mMemoryWatcher) - mMemoryWatcher->StartWatching(); - break; - } case AndroidGeckoEvent::ACTIVITY_PAUSING: { // We really want to send a notification like profile-before-change, // but profile-before-change ends up shutting some things down instead @@ -287,8 +283,6 @@ nsAppShell::ProcessNextNativeEvent(PRBool mayWait) if (prefs) prefs->SavePrefFile(nsnull); - if (mMemoryWatcher) - mMemoryWatcher->StopWatching(); break; } @@ -380,6 +374,11 @@ nsAppShell::RemoveNextEvent() PR_Unlock(mQueueLock); } +void +nsAppShell::OnResume() +{ +} + nsresult nsAppShell::AddObserver(const nsAString &aObserverKey, nsIObserver *aObserver) { diff --git a/widget/src/android/nsAppShell.h b/widget/src/android/nsAppShell.h index ed0255f4fc7f..5ddc08283ba1 100644 --- a/widget/src/android/nsAppShell.h +++ b/widget/src/android/nsAppShell.h @@ -43,8 +43,6 @@ #include "nsCOMPtr.h" #include "nsTArray.h" #include "nsInterfaceHashtable.h" -#include "nsMemoryWatcher.h" -#include "nsAutoPtr.h" #include "prcvar.h" @@ -74,6 +72,7 @@ public: void PostEvent(mozilla::AndroidGeckoEvent *event); void RemoveNextEvent(); + void OnResume(); nsresult AddObserver(const nsAString &aObserverKey, nsIObserver *aObserver); void CallObserver(const nsAString &aObserverKey, const nsAString &aTopic, const nsAString &aData); @@ -93,8 +92,6 @@ protected: mozilla::AndroidGeckoEvent *GetNextEvent(); mozilla::AndroidGeckoEvent *PeekNextEvent(); - - nsRefPtr mMemoryWatcher; }; #endif // nsAppShell_h__ diff --git a/widget/src/android/nsMemoryWatcher.cpp b/widget/src/android/nsMemoryWatcher.cpp deleted file mode 100644 index 35a1b144f68f..000000000000 --- a/widget/src/android/nsMemoryWatcher.cpp +++ /dev/null @@ -1,147 +0,0 @@ -/* -*- Mode: C++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* ***** 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.org 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 ***** */ - -#include "nsMemoryWatcher.h" -#include "nsComponentManagerUtils.h" -#include "android/log.h" -#include "nsString.h" -#include "nsAppShell.h" - -NS_IMPL_ISUPPORTS1(nsMemoryWatcher, nsITimerCallback) - -// These numbers were determined by inspecting the /proc/meminfo -// MemFree values on the Nexus S before there was a system failure. -// Seting these numbers lower we'd see no time to recover (by killing -// the child process). Setting these numbers hight resulted in not -// being able to load pages on phones with lots of services/apps -// running. -#define DEFAULT_TIMER_INTERVAL 2000 -#define DEFAULT_LOW_MEMORY_MARK 5000 -#define DEFAULT_HIGH_MEMORY_MARK 10000 - -nsMemoryWatcher::nsMemoryWatcher() - : mLowWaterMark(DEFAULT_LOW_MEMORY_MARK) - , mHighWaterMark(DEFAULT_HIGH_MEMORY_MARK) - , mLastLowNotification(0) - , mLastHighNotification(0) - , mMemInfoFile(nsnull) -{ -} - -nsMemoryWatcher::~nsMemoryWatcher() -{ - if (mTimer) - StopWatching(); -} - -void -nsMemoryWatcher::StartWatching() -{ - if (mTimer) - return; - - mMemInfoFile = fopen("/proc/meminfo", "r"); - NS_ASSERTION(mMemInfoFile, "Could not open /proc/meminfo for reading."); - - mTimer = do_CreateInstance("@mozilla.org/timer;1"); - NS_ASSERTION(mTimer, "Creating of a timer failed."); - - mTimer->InitWithCallback(this, DEFAULT_TIMER_INTERVAL, nsITimer::TYPE_REPEATING_SLACK); -} - -void -nsMemoryWatcher::StopWatching() -{ - if (!mTimer) - return; - - mTimer->Cancel(); - mTimer = nsnull; - - fclose(mMemInfoFile); - mMemInfoFile = nsnull; -} - -NS_IMETHODIMP -nsMemoryWatcher::Notify(nsITimer *aTimer) -{ - NS_ASSERTION(mMemInfoFile, "File* to /proc/meminfo is null"); - - rewind(mMemInfoFile); - - long memFree = -1; - char line[256]; - - while (fgets(line, 256, mMemInfoFile)) { - sscanf(line, "MemFree: %ld kB", &memFree); - } - NS_ASSERTION(memFree > 0, "Free memory should be greater than zero"); - - if (memFree < mLowWaterMark) { - __android_log_print(ANDROID_LOG_WARN, "Gecko", - "!!!!!!!!! Reached criticial memory level. MemFree = %ld", - memFree); - - if (PR_IntervalToSeconds(PR_IntervalNow() - mLastLowNotification) > 5) { - nsAppShell::gAppShell->NotifyObservers(nsnull, - "memory-pressure", - NS_LITERAL_STRING("oom-kill").get()); - mLastLowNotification = PR_IntervalNow(); - } - return NS_OK; - } - - if (memFree < mHighWaterMark) { - __android_log_print(ANDROID_LOG_WARN, "Gecko", - "!!!!!!!!! Reached low memory level. MemFree = %ld", - memFree); - if (PR_IntervalToSeconds(PR_IntervalNow() - mLastHighNotification) > 5) { - nsAppShell::gAppShell->NotifyObservers(nsnull, - "memory-pressure", - NS_LITERAL_STRING("low-memory").get()); - mLastHighNotification = PR_IntervalNow(); - } - // we should speed up the timer at this point so that we can more - // closely watch memory usage - aTimer->SetDelay(DEFAULT_TIMER_INTERVAL / 10); - return NS_OK; - } - - // Make sure the delay is set properly. - aTimer->SetDelay(DEFAULT_TIMER_INTERVAL); - return NS_OK; -} diff --git a/widget/src/android/nsMemoryWatcher.h b/widget/src/android/nsMemoryWatcher.h deleted file mode 100644 index a99a06443581..000000000000 --- a/widget/src/android/nsMemoryWatcher.h +++ /dev/null @@ -1,69 +0,0 @@ -/* -*- Mode: c++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 4; -*- */ -/* ***** 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.org 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 ***** */ - -#ifndef nsMemoryWatcher_h__ -#define nsMemoryWatcher_h__ - -#include -#include -#include -#include -#include - -class nsMemoryWatcher : public nsITimerCallback -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSITIMERCALLBACK - - nsMemoryWatcher(); - virtual ~nsMemoryWatcher(); - - void StartWatching(); - void StopWatching(); - -private: - long mTimerInterval; - long mLowWaterMark; - long mHighWaterMark; - PRIntervalTime mLastLowNotification; - PRIntervalTime mLastHighNotification; - nsCOMPtr mTimer; - FILE* mMemInfoFile; -}; - -#endif /* nsMemoryWatcher_h__ */