Bug 509249: Fast Startup component, r=luser,mfinkle, sr=gavin, original code by vlad

This commit is contained in:
Brian Crowder 2009-08-22 00:13:49 -07:00
Родитель 8f3bb7f680
Коммит 3ff16209ca
7 изменённых файлов: 385 добавлений и 6 удалений

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

@ -157,6 +157,7 @@ MOZ_PLACES = @MOZ_PLACES@
MOZ_PLACES_BOOKMARKS = @MOZ_PLACES_BOOKMARKS@
MOZ_STORAGE = @MOZ_STORAGE@
MOZ_SAFE_BROWSING = @MOZ_SAFE_BROWSING@
MOZ_FASTSTART = @MOZ_FASTSTART@
MOZ_URL_CLASSIFIER = @MOZ_URL_CLASSIFIER@
MOZ_ZIPWRITER = @MOZ_ZIPWRITER@
MOZ_MORK = @MOZ_MORK@

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

@ -4512,6 +4512,7 @@ MOZ_PSM=1
MOZ_RDF=1
MOZ_REFLOW_PERF=
MOZ_SAFE_BROWSING=
MOZ_FASTSTART=
MOZ_HELP_VIEWER=
MOZ_SPELLCHECK=1
MOZ_SPLASHSCREEN=
@ -6235,6 +6236,18 @@ if test -n "$MOZ_SAFE_BROWSING"; then
fi
AC_SUBST(MOZ_SAFE_BROWSING)
dnl ========================================================
dnl = Enable faststart component
dnl ========================================================
MOZ_ARG_ENABLE_BOOL(faststart,
[ --enable-faststart Enable the faststart component],
MOZ_FASTSTART=1,
MOZ_FASTSTART= )
if test -n "$MOZ_FASTSTART"; then
AC_DEFINE(MOZ_FASTSTART)
fi
AC_SUBST(MOZ_FASTSTART)
dnl ========================================================
dnl = Enable url-classifier
dnl ========================================================

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

@ -112,6 +112,10 @@ ifdef MOZ_URL_CLASSIFIER
DIRS += url-classifier
endif
ifdef MOZ_FASTSTART
DIRS += faststart
endif
DIRS += \
commandlines \
startup \

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

@ -0,0 +1,176 @@
/* -*- Mode: js2; js2-basic-offset: 4; 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 FastStartup.js
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@pobox.com>
* Brian Crowder <crowder@fiverocks.com>
*
* 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 ***** */
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
const Cu = Components.utils;
const Timer = Components.Constructor("@mozilla.org/timer;1", "nsITimer", "initWithCallback");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
function nsFastStartupObserver() {
this.fastStartObserver = null;
}
function getPreferredBrowserURI() {
let chromeURI;
try {
chromeURI = prefs.getCharPref("toolkit.defaultChromeURI");
} catch (e) { }
return chromeURI;
}
nsFastStartupObserver.prototype = {
_browserWindowCount: 0,
_memCleanupTimer: null,
stopMemoryCleanup: function() {
if (this._memCleanupTimer) {
this._memCleanupTimer.cancel();
this._memCleanupTimer = null;
}
},
scheduleMemoryCleanup: function() {
this.stopMemoryCleanup();
function memoryCleanup() {
var os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
// Do this 3 times, because of a comment in TestGtkEmbed that says this
// gives the cycle collector the best chance at purging things.
os.notifyObservers(null, "memory-pressure", "heap-minimize");
os.notifyObservers(null, "memory-pressure", "heap-minimize");
os.notifyObservers(null, "memory-pressure", "heap-minimize");
// XXX start our long (15 min?) stub restart timer here
this.fastStartObserver._memCleanupTimer = null;
};
// wait 30s until firing off the memory cleanup, in case the user
// opens another window right away
this._memCleanupTimer = new Timer(memoryCleanup, 30000, Ci.nsITimer.TYPE_ONE_SHOT);
},
//
// nsIObserver
//
observe: function fs_observe(subject, topic, data) {
var win = subject;
// XXX the window at this point won't actually have its document loaded --
// win.document.documentURI will pretty much always be about:blank. We need
// to attach a load handler to actually figure out which document gets loaded.
if (topic == "domwindowopened") {
var loadListener = function(e) {
if (win.document.documentURI == getPreferredBrowserURI()) {
this.fastStartObserver.stopMemoryCleanup();
this.fastStartObserver._browserWindowCount++;
}
win.removeEventListener("load", loadListener, false);
return false;
}
win.addEventListener("load", loadListener, false);
} else if (topic == "domwindowclosed") {
if (win.document.documentURI == getPreferredBrowserURI()) {
this.fastStartObserver._browserWindowCount--;
if (this.fastStartObserver._browserWindowCount == 0)
this.fastStartObserver.scheduleMemoryCleanup();
}
}
},
// QI
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver])
};
function nsFastStartupCLH() {
inited = false;
}
nsFastStartupCLH.prototype = {
//
// nsICommandLineHandler
//
handle: function fs_handle(cmdLine) {
// the rest of this only handles -faststart here
if (!cmdLine.handleFlag("faststart", false))
return;
cmdLine.preventDefault = true;
try {
// did we already initialize faststart? if so,
// nothing to do here.
if (this.inited)
return;
this.inited = true;
let wwatch = Cc["@mozilla.org/embedcomp/window-watcher;1"].
getService(Ci.nsIWindowWatcher);
wwatch.registerNotification(new nsFastStartupObserver());
let appstartup = Cc["@mozilla.org/toolkit/app-startup;1"].
getService(Ci.nsIAppStartup);
appstartup.enterLastWindowClosingSurvivalArea();
} catch (e) {
Cu.reportError(e);
}
},
helpInfo: " -faststart\n",
// QI
QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler]),
// XPCOMUtils factory
classDescription: "Fast Startup Component",
contractID: "@mozilla.org/browser/faststart;1",
classID: Components.ID("{580c6c51-f690-4ce1-9ecc-b678e0c031c7}"),
_xpcom_categories: [{ category: "command-line-handler", entry: "00-faststart" }],
};
var components = [ nsFastStartupCLH ];
function NSGetModule(compMgr, fileSpec) {
return XPCOMUtils.generateModule(components);
}

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

@ -0,0 +1,61 @@
# ***** 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 the Mozilla Browser code.
#
# The Initial Developer of the Original Code is
# Mozilla Corp
# Portions created by the Initial Developer are Copyright (C) 2009
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Vladimir Vukicevic <vladimir@pobox.com>
#
# 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 *****
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
EXTRA_PP_COMPONENTS = \
FastStartup.js \
$(NULL)
CPPSRCS = \
faststartstub.cpp \
$(NULL)
SIMPLE_PROGRAMS = $(CPPSRCS:.cpp=$(BIN_SUFFIX)) \
ifdef _MSC_VER
ifdef WINCE
WIN32_EXE_LDFLAGS += -ENTRY:WinMainCRTStartup
endif
endif
include $(topsrcdir)/config/rules.mk

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

@ -0,0 +1,39 @@
#include <windows.h>
#include <stdlib.h>
#include <tchar.h>
#include <stdio.h>
int WINAPI
WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
PROCESS_INFORMATION pi;
STARTUPINFOW si = { 0 };
wchar_t modfilename[MAX_PATH];
wchar_t execname[MAX_PATH];
wchar_t args[MAX_PATH];
wcscpy(args, L"-nosplash -faststart");
HMODULE mod = GetModuleHandle(NULL);
GetModuleFileNameW(mod, modfilename, sizeof(modfilename)/sizeof(modfilename[0]));
wchar_t *chomp = wcsstr(modfilename, L"faststart.exe");
if (!chomp) {
MessageBoxW(NULL, L"Couldn't figure out how to run the faststart service!", L"Faststart Fail", MB_OK);
return 0;
}
size_t len = chomp - modfilename;
wcsncpy(execname, modfilename, len);
execname[len] = 0;
wcscat(execname, L".exe");
BOOL ok = CreateProcessW(execname, args, NULL, NULL, FALSE, 0,
NULL, NULL, &si, &pi);
if (!ok) {
MessageBoxW(NULL, L"Couldn't figure out how to run the faststart service!", L"Faststart Fail", MB_OK);
return 0;
}
return 0;
}

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

@ -207,6 +207,33 @@
#define NS_CRASHREPORTER_CONTRACTID "@mozilla.org/toolkit/crash-reporter;1"
#endif
#ifdef WINCE
class WindowsMutex {
public:
WindowsMutex(const wchar_t *name) {
mHandle = CreateMutexW(0, FALSE, name);
}
~WindowsMutex() {
Unlock();
CloseHandle(mHandle);
}
PRBool Lock(DWORD timeout = INFINITE) {
DWORD state = WaitForSingleObject(mHandle, timeout);
return state == WAIT_OBJECT_0;
}
void Unlock() {
if (mHandle)
ReleaseMutex(mHandle);
}
protected:
HANDLE mHandle;
};
#endif
// on x86 linux, the current builds of some popular plugins (notably
// flashplayer and real) expect a few builtin symbols from libgcc
// which were available in some older versions of gcc. However,
@ -2578,10 +2605,7 @@ int
XRE_main(int argc, char* argv[], const nsXREAppData* aAppData)
{
#ifdef MOZ_SPLASHSCREEN
nsSplashScreen *splashScreen =
nsSplashScreen::GetOrCreate();
if (splashScreen)
splashScreen->Open();
nsSplashScreen *splashScreen = nsnull;
#endif
#ifdef XP_WIN
@ -2702,8 +2726,6 @@ XRE_main(int argc, char* argv[], const nsXREAppData* aAppData)
}
}
MOZ_SPLASHSCREEN_UPDATE(10);
ScopedAppData appData(aAppData);
gAppData = &appData;
@ -2718,6 +2740,64 @@ XRE_main(int argc, char* argv[], const nsXREAppData* aAppData)
return 1;
}
#ifdef MOZ_SPLASHSCREEN
// check to see if we need to do a splash screen
PRBool wantsSplash = PR_TRUE;
PRBool isNoSplash = (CheckArg("nosplash") == ARG_FOUND);
PRBool isNoRemote = (CheckArg("no-remote") == ARG_FOUND);
#ifdef WINCE
// synchronize startup; if it looks like we're going to have to
// wait, then open up a splash screen
WindowsMutex winStartupMutex(L"FirefoxStartupMutex");
// try to lock the mutex, but only wait 100ms to do so
PRBool needsMutexLock = ! winStartupMutex.Lock(100);
// If we failed to lock the mutex quickly, then we'll want
// a splash screen for sure.
//
// If we did manage to lock it, then we'll only want one
// a splash screen if there is no existing message window;
// that is, if we are the first instance of the app.
if (!needsMutexLock && !isNoRemote) {
// check to see if there's a remote firefox up
static PRUnichar classNameBuffer[128];
_snwprintf(classNameBuffer, sizeof(classNameBuffer) / sizeof(PRUnichar),
L"%S%s",
gAppData->name, L"MessageWindow");
HANDLE h = FindWindowW(classNameBuffer, 0);
if (h) {
// Someone else has the window, and we were able to grab the mutex,
// meaning the other instance ahs presumably already finished starting
// up by now. So no need for a splash screen.
wantsSplash = PR_FALSE;
CloseHandle(h);
} else {
// We couldn't find another window, and we were able to lock the mutex;
// we're likely the first instance starting up, so make sure a splash
// screen gets thrown up.
wantsSplash = PR_TRUE;
}
}
#endif
if (wantsSplash && !isNoSplash)
splashScreen = nsSplashScreen::GetOrCreate();
if (splashScreen)
splashScreen->Open();
#ifdef WINCE
// Now that the splash screen is open, wait indefinitely
// for the startup mutex on this thread if we need to.
if (needsMutexLock)
winStartupMutex.Lock();
#endif
#endif
ScopedLogging log;
if (!appData.xreDirectory) {
@ -3122,6 +3202,11 @@ XRE_main(int argc, char* argv[], const nsXREAppData* aAppData)
rv = dirProvider.SetProfile(profD, profLD);
NS_ENSURE_SUCCESS(rv, 1);
#ifdef WINCE
// give up the mutex, let other app startups happen
winStartupMutex.Unlock();
#endif
//////////////////////// NOW WE HAVE A PROFILE ////////////////////////
#ifdef MOZ_CRASHREPORTER