import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo

This commit is contained in:
Roy Tam 2018-01-19 03:59:58 +08:00
commit dcd9973243
150858 changed files with 23884658 additions and 0 deletions

View file

@ -0,0 +1,36 @@
/* 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/. */
#include "StartupTimeline.h"
#include "mozilla/Telemetry.h"
#include "mozilla/TimeStamp.h"
#include "nsXULAppAPI.h"
namespace mozilla {
TimeStamp StartupTimeline::sStartupTimeline[StartupTimeline::MAX_EVENT_ID];
const char *StartupTimeline::sStartupTimelineDesc[StartupTimeline::MAX_EVENT_ID] = {
#define mozilla_StartupTimeline_Event(ev, desc) desc,
#include "StartupTimeline.h"
#undef mozilla_StartupTimeline_Event
};
} /* namespace mozilla */
using mozilla::StartupTimeline;
using mozilla::TimeStamp;
/**
* The XRE_StartupTimeline_Record function is to be used by embedding
* applications that can't use mozilla::StartupTimeline::Record() directly.
*
* @param aEvent The event to be recorded, must correspond to an element of the
* mozilla::StartupTimeline::Event enumartion
* @param aWhen The time at which the event happened
*/
void
XRE_StartupTimelineRecord(int aEvent, TimeStamp aWhen)
{
StartupTimeline::Record((StartupTimeline::Event)aEvent, aWhen);
}

View file

@ -0,0 +1,100 @@
/* 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/. */
#ifdef mozilla_StartupTimeline_Event
mozilla_StartupTimeline_Event(PROCESS_CREATION, "process")
mozilla_StartupTimeline_Event(START, "start")
mozilla_StartupTimeline_Event(MAIN, "main")
mozilla_StartupTimeline_Event(SELECT_PROFILE, "selectProfile")
mozilla_StartupTimeline_Event(AFTER_PROFILE_LOCKED, "afterProfileLocked")
// Record the beginning and end of startup crash detection to compare with crash stats to know whether
// detection should be improved to start or end sooner.
mozilla_StartupTimeline_Event(STARTUP_CRASH_DETECTION_BEGIN, "startupCrashDetectionBegin")
mozilla_StartupTimeline_Event(STARTUP_CRASH_DETECTION_END, "startupCrashDetectionEnd")
mozilla_StartupTimeline_Event(FIRST_PAINT, "firstPaint")
mozilla_StartupTimeline_Event(SESSION_RESTORE_INIT, "sessionRestoreInit")
mozilla_StartupTimeline_Event(SESSION_RESTORED, "sessionRestored")
mozilla_StartupTimeline_Event(CREATE_TOP_LEVEL_WINDOW, "createTopLevelWindow")
mozilla_StartupTimeline_Event(LINKER_INITIALIZED, "linkerInitialized")
mozilla_StartupTimeline_Event(LIBRARIES_LOADED, "librariesLoaded")
mozilla_StartupTimeline_Event(FIRST_LOAD_URI, "firstLoadURI")
// The following are actually shutdown events, used to monitor the duration of shutdown
mozilla_StartupTimeline_Event(QUIT_APPLICATION, "quitApplication")
mozilla_StartupTimeline_Event(PROFILE_BEFORE_CHANGE, "profileBeforeChange")
#else
#ifndef mozilla_StartupTimeline
#define mozilla_StartupTimeline
#include "mozilla/TimeStamp.h"
#include "nscore.h"
#include "GeckoProfiler.h"
#ifdef MOZ_LINKER
extern "C" {
/* This symbol is resolved by the custom linker. The function it resolves
* to dumps some statistics about the linker at the key events recorded
* by the startup timeline. */
extern void __moz_linker_stats(const char *str)
NS_VISIBILITY_DEFAULT __attribute__((weak));
} /* extern "C" */
#else
#endif
namespace mozilla {
void RecordShutdownEndTimeStamp();
void RecordShutdownStartTimeStamp();
class StartupTimeline {
public:
enum Event {
#define mozilla_StartupTimeline_Event(ev, z) ev,
#include "StartupTimeline.h"
#undef mozilla_StartupTimeline_Event
MAX_EVENT_ID
};
static TimeStamp Get(Event ev) {
return sStartupTimeline[ev];
}
static const char *Describe(Event ev) {
return sStartupTimelineDesc[ev];
}
static void Record(Event ev) {
PROFILER_MARKER(Describe(ev));
Record(ev, TimeStamp::Now());
}
static void Record(Event ev, TimeStamp when) {
sStartupTimeline[ev] = when;
#ifdef MOZ_LINKER
if (__moz_linker_stats)
__moz_linker_stats(Describe(ev));
#endif
}
static void RecordOnce(Event ev) {
if (!HasRecord(ev))
Record(ev);
}
static bool HasRecord(Event ev) {
return !sStartupTimeline[ev].IsNull();
}
private:
static NS_EXTERNAL_VIS_(TimeStamp) sStartupTimeline[MAX_EVENT_ID];
static NS_EXTERNAL_VIS_(const char *) sStartupTimelineDesc[MAX_EVENT_ID];
};
} // namespace mozilla
#endif /* mozilla_StartupTimeline */
#endif /* mozilla_StartupTimeline_Event */

View file

@ -0,0 +1,38 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
DIRS += ['public']
EXPORTS.mozilla += [
'StartupTimeline.h',
]
BROWSER_CHROME_MANIFESTS += ['tests/browser/browser.ini']
XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
UNIFIED_SOURCES += [
'nsAppStartup.cpp',
'StartupTimeline.cpp',
]
if CONFIG['OS_ARCH'] == 'WINNT':
# This file cannot be built in unified mode because of name clashes with Windows headers.
SOURCES += [
'nsUserInfoWin.cpp',
]
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
UNIFIED_SOURCES += [
'nsUserInfoMac.mm',
]
else:
UNIFIED_SOURCES += [
'nsUserInfoUnix.cpp',
]
FINAL_LIBRARY = 'xul'
with Files('**'):
BUG_COMPONENT = ('Toolkit', 'Startup and Profile System')

View file

@ -0,0 +1,29 @@
#pragma namespace("\\\\.\\root\\wmi")
#pragma autorecover
[dynamic: ToInstance, Description("Mozilla Generic Provider"),
Guid("{509962E0-406B-46F4-99BA-5A009F8D2225}")]
class MozillaProvider : EventTrace
{
};
[dynamic: ToInstance, Description("Mozilla Event: Places Init is complete."): Amended,
Guid("{A3DA04E0-57D7-482A-A1C1-61DA5F95BACB}"),
EventType(1)]
class MozillaEventPlacesInit : MozillaProvider
{
};
[dynamic: ToInstance, Description("Mozilla Event: Session Store Window Restored."): Amended,
Guid("{917B96B1-ECAD-4DAB-A760-8D49027748AE}"),
EventType(1)]
class MozillaEventSessionStoreWindowRestored : MozillaProvider
{
};
[dynamic: ToInstance, Description("Mozilla Event: XPCOM Shutdown."): Amended,
Guid("{26D1E091-0AE7-4F49-A554-4214445C505C}"),
EventType(1)]
class MozillaEventXPCOMShutdown : MozillaProvider
{
};

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,76 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#ifndef nsAppStartup_h__
#define nsAppStartup_h__
#include "nsIAppStartup.h"
#include "nsIWindowCreator2.h"
#include "nsIObserver.h"
#include "nsWeakReference.h"
#include "nsINativeAppSupport.h"
#include "nsIAppShell.h"
#include "mozilla/Attributes.h"
#if defined(XP_WIN)
//XPerf-backed probes
#include "mozilla/perfprobe.h"
#include "nsAutoPtr.h"
#endif //defined(XP_WIN)
// {7DD4D320-C84B-4624-8D45-7BB9B2356977}
#define NS_TOOLKIT_APPSTARTUP_CID \
{ 0x7dd4d320, 0xc84b, 0x4624, { 0x8d, 0x45, 0x7b, 0xb9, 0xb2, 0x35, 0x69, 0x77 } }
class nsAppStartup final : public nsIAppStartup,
public nsIWindowCreator2,
public nsIObserver,
public nsSupportsWeakReference
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIAPPSTARTUP
NS_DECL_NSIWINDOWCREATOR
NS_DECL_NSIWINDOWCREATOR2
NS_DECL_NSIOBSERVER
nsAppStartup();
nsresult Init();
private:
~nsAppStartup() { }
void CloseAllWindows();
friend class nsAppExitEvent;
nsCOMPtr<nsIAppShell> mAppShell;
int32_t mConsiderQuitStopper; // if > 0, Quit(eConsiderQuit) fails
bool mRunning; // Have we started the main event loop?
bool mShuttingDown; // Quit method reentrancy check
bool mStartingUp; // Have we passed final-ui-startup?
bool mAttemptingQuit; // Quit(eAttemptQuit) still trying
bool mRestart; // Quit(eRestart)
bool mInterrupted; // Was startup interrupted by an interactive prompt?
bool mIsSafeModeNecessary; // Whether safe mode is necessary
bool mStartupCrashTrackingEnded; // Whether startup crash tracking has already ended
bool mRestartNotSameProfile; // Quit(eRestartNotSameProfile)
#if defined(XP_WIN)
//Interaction with OS-provided profiling probes
typedef mozilla::probes::ProbeManager ProbeManager;
typedef mozilla::probes::Probe Probe;
RefPtr<ProbeManager> mProbesManager;
RefPtr<Probe> mPlacesInitCompleteProbe;
RefPtr<Probe> mSessionWindowRestoredProbe;
RefPtr<Probe> mXPCOMShutdownProbe;
#endif
};
#endif // nsAppStartup_h__

View file

@ -0,0 +1,23 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#ifndef __nsUserInfo_h
#define __nsUserInfo_h
#include "nsIUserInfo.h"
class nsUserInfo: public nsIUserInfo
{
public:
nsUserInfo(void);
NS_DECL_ISUPPORTS
NS_DECL_NSIUSERINFO
protected:
virtual ~nsUserInfo();
};
#endif /* __nsUserInfo_h */

View file

@ -0,0 +1,25 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#ifndef __nsUserInfoMac_h
#define __nsUserInfoMac_h
#include "nsIUserInfo.h"
#include "nsReadableUtils.h"
class nsUserInfo: public nsIUserInfo
{
public:
nsUserInfo();
NS_DECL_ISUPPORTS
NS_DECL_NSIUSERINFO
nsresult GetPrimaryEmailAddress(nsCString &aEmailAddress);
protected:
virtual ~nsUserInfo() {}
};
#endif /* __nsUserInfo_h */

View file

@ -0,0 +1,84 @@
/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#include "nsUserInfoMac.h"
#include "nsObjCExceptions.h"
#include "nsString.h"
#import <Cocoa/Cocoa.h>
#import <AddressBook/AddressBook.h>
NS_IMPL_ISUPPORTS(nsUserInfo, nsIUserInfo)
nsUserInfo::nsUserInfo() {}
NS_IMETHODIMP
nsUserInfo::GetFullname(char16_t **aFullname)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT
NS_ConvertUTF8toUTF16 fullName([NSFullUserName() UTF8String]);
*aFullname = ToNewUnicode(fullName);
return NS_OK;
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT
}
NS_IMETHODIMP
nsUserInfo::GetUsername(char **aUsername)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT
nsAutoCString username([NSUserName() UTF8String]);
*aUsername = ToNewCString(username);
return NS_OK;
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT
}
nsresult
nsUserInfo::GetPrimaryEmailAddress(nsCString &aEmailAddress)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT
// Try to get this user's primary email from the system addressbook's "me card"
// (if they've filled it)
ABPerson *me = [[ABAddressBook sharedAddressBook] me];
ABMultiValue *emailAddresses = [me valueForProperty:kABEmailProperty];
if ([emailAddresses count] > 0) {
// get the index of the primary email, in case there are more than one
int primaryEmailIndex = [emailAddresses indexForIdentifier:[emailAddresses primaryIdentifier]];
aEmailAddress.Assign([[emailAddresses valueAtIndex:primaryEmailIndex] UTF8String]);
return NS_OK;
}
return NS_ERROR_FAILURE;
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT
}
NS_IMETHODIMP
nsUserInfo::GetEmailAddress(char **aEmailAddress)
{
nsAutoCString email;
if (NS_SUCCEEDED(GetPrimaryEmailAddress(email)))
*aEmailAddress = ToNewCString(email);
return NS_OK;
}
NS_IMETHODIMP
nsUserInfo::GetDomain(char **aDomain)
{
nsAutoCString email;
if (NS_SUCCEEDED(GetPrimaryEmailAddress(email))) {
int32_t index = email.FindChar('@');
if (index != -1) {
// chop off everything before, and including the '@'
*aDomain = ToNewCString(Substring(email, index + 1));
}
}
return NS_OK;
}

View file

@ -0,0 +1,167 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#include "nsUserInfo.h"
#include "nsCRT.h"
#include <pwd.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/utsname.h>
#include "nsString.h"
#include "nsXPIDLString.h"
#include "nsReadableUtils.h"
#include "nsNativeCharsetUtils.h"
/* Some UNIXy platforms don't have pw_gecos. In this case we use pw_name */
#if defined(NO_PW_GECOS)
#define PW_GECOS pw_name
#else
#define PW_GECOS pw_gecos
#endif
nsUserInfo::nsUserInfo()
{
}
nsUserInfo::~nsUserInfo()
{
}
NS_IMPL_ISUPPORTS(nsUserInfo,nsIUserInfo)
NS_IMETHODIMP
nsUserInfo::GetFullname(char16_t **aFullname)
{
struct passwd *pw = nullptr;
pw = getpwuid (geteuid());
if (!pw || !pw->PW_GECOS) return NS_ERROR_FAILURE;
#ifdef DEBUG_sspitzer
printf("fullname = %s\n", pw->PW_GECOS);
#endif
nsAutoCString fullname(pw->PW_GECOS);
// now try to parse the GECOS information, which will be in the form
// Full Name, <other stuff> - eliminate the ", <other stuff>
// also, sometimes GECOS uses "&" to mean "the user name" so do
// the appropriate substitution
// truncate at first comma (field delimiter)
int32_t index;
if ((index = fullname.Find(",")) != kNotFound)
fullname.Truncate(index);
// replace ampersand with username
if (pw->pw_name) {
nsAutoCString username(pw->pw_name);
if (!username.IsEmpty() && nsCRT::IsLower(username.CharAt(0)))
username.SetCharAt(nsCRT::ToUpper(username.CharAt(0)), 0);
fullname.ReplaceSubstring("&", username.get());
}
nsAutoString unicodeFullname;
NS_CopyNativeToUnicode(fullname, unicodeFullname);
*aFullname = ToNewUnicode(unicodeFullname);
if (*aFullname)
return NS_OK;
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsUserInfo::GetUsername(char * *aUsername)
{
struct passwd *pw = nullptr;
// is this portable? those are POSIX compliant calls, but I need to check
pw = getpwuid(geteuid());
if (!pw || !pw->pw_name) return NS_ERROR_FAILURE;
#ifdef DEBUG_sspitzer
printf("username = %s\n", pw->pw_name);
#endif
*aUsername = strdup(pw->pw_name);
return NS_OK;
}
NS_IMETHODIMP
nsUserInfo::GetDomain(char * *aDomain)
{
nsresult rv = NS_ERROR_FAILURE;
struct utsname buf;
char *domainname = nullptr;
if (uname(&buf) < 0) {
return rv;
}
#if defined(__linux__)
domainname = buf.domainname;
#endif
if (domainname && domainname[0]) {
*aDomain = strdup(domainname);
rv = NS_OK;
}
else {
// try to get the hostname from the nodename
// on machines that use DHCP, domainname may not be set
// but the nodename might.
if (buf.nodename[0]) {
// if the nodename is foo.bar.org, use bar.org as the domain
char *pos = strchr(buf.nodename,'.');
if (pos) {
*aDomain = strdup(pos+1);
rv = NS_OK;
}
}
}
return rv;
}
NS_IMETHODIMP
nsUserInfo::GetEmailAddress(char * *aEmailAddress)
{
// use username + "@" + domain for the email address
nsresult rv;
nsAutoCString emailAddress;
nsXPIDLCString username;
nsXPIDLCString domain;
rv = GetUsername(getter_Copies(username));
if (NS_FAILED(rv)) return rv;
rv = GetDomain(getter_Copies(domain));
if (NS_FAILED(rv)) return rv;
if (!username.IsEmpty() && !domain.IsEmpty()) {
emailAddress = (const char *)username;
emailAddress += "@";
emailAddress += (const char *)domain;
}
else {
return NS_ERROR_FAILURE;
}
*aEmailAddress = ToNewCString(emailAddress);
return NS_OK;
}

View file

@ -0,0 +1,133 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#include "nsUserInfo.h"
#include "mozilla/ArrayUtils.h" // ArrayLength
#include "nsString.h"
#include "windows.h"
#include "nsCRT.h"
#include "nsXPIDLString.h"
#define SECURITY_WIN32
#include "lm.h"
#include "security.h"
nsUserInfo::nsUserInfo()
{
}
nsUserInfo::~nsUserInfo()
{
}
NS_IMPL_ISUPPORTS(nsUserInfo, nsIUserInfo)
NS_IMETHODIMP
nsUserInfo::GetUsername(char **aUsername)
{
NS_ENSURE_ARG_POINTER(aUsername);
*aUsername = nullptr;
// ULEN is the max username length as defined in lmcons.h
wchar_t username[UNLEN +1];
DWORD size = mozilla::ArrayLength(username);
if (!GetUserNameW(username, &size))
return NS_ERROR_FAILURE;
*aUsername = ToNewUTF8String(nsDependentString(username));
return (*aUsername) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsUserInfo::GetFullname(char16_t **aFullname)
{
NS_ENSURE_ARG_POINTER(aFullname);
*aFullname = nullptr;
wchar_t fullName[512];
DWORD size = mozilla::ArrayLength(fullName);
if (GetUserNameExW(NameDisplay, fullName, &size)) {
*aFullname = ToNewUnicode(nsDependentString(fullName));
} else {
DWORD getUsernameError = GetLastError();
// Try to use the net APIs regardless of the error because it may be
// able to obtain the information.
wchar_t username[UNLEN + 1];
size = mozilla::ArrayLength(username);
if (!GetUserNameW(username, &size)) {
// ERROR_NONE_MAPPED means the user info is not filled out on this computer
return getUsernameError == ERROR_NONE_MAPPED ?
NS_ERROR_NOT_AVAILABLE : NS_ERROR_FAILURE;
}
const DWORD level = 2;
LPBYTE info;
// If the NetUserGetInfo function has no full name info it will return
// success with an empty string.
NET_API_STATUS status = NetUserGetInfo(nullptr, username, level, &info);
if (status != NERR_Success) {
// We have an error with NetUserGetInfo but we know the info is not
// filled in because GetUserNameExW returned ERROR_NONE_MAPPED.
return getUsernameError == ERROR_NONE_MAPPED ?
NS_ERROR_NOT_AVAILABLE : NS_ERROR_FAILURE;
}
nsDependentString fullName =
nsDependentString(reinterpret_cast<USER_INFO_2 *>(info)->usri2_full_name);
// NetUserGetInfo returns an empty string if the full name is not filled out
if (fullName.Length() == 0) {
NetApiBufferFree(info);
return NS_ERROR_NOT_AVAILABLE;
}
*aFullname = ToNewUnicode(fullName);
NetApiBufferFree(info);
}
return (*aFullname) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsUserInfo::GetDomain(char **aDomain)
{
NS_ENSURE_ARG_POINTER(aDomain);
*aDomain = nullptr;
const DWORD level = 100;
LPBYTE info;
NET_API_STATUS status = NetWkstaGetInfo(nullptr, level, &info);
if (status == NERR_Success) {
*aDomain =
ToNewUTF8String(nsDependentString(reinterpret_cast<WKSTA_INFO_100 *>(info)->
wki100_langroup));
NetApiBufferFree(info);
}
return (*aDomain) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsUserInfo::GetEmailAddress(char **aEmailAddress)
{
NS_ENSURE_ARG_POINTER(aEmailAddress);
*aEmailAddress = nullptr;
// RFC3696 says max length of an email address is 254
wchar_t emailAddress[255];
DWORD size = mozilla::ArrayLength(emailAddress);
if (!GetUserNameExW(NameUserPrincipal, emailAddress, &size)) {
DWORD getUsernameError = GetLastError();
return getUsernameError == ERROR_NONE_MAPPED ?
NS_ERROR_NOT_AVAILABLE : NS_ERROR_FAILURE;
}
*aEmailAddress = ToNewUTF8String(nsDependentString(emailAddress));
return (*aEmailAddress) ? NS_OK : NS_ERROR_FAILURE;
}

View file

@ -0,0 +1,13 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
XPIDL_SOURCES += [
'nsIAppStartup.idl',
'nsIUserInfo.idl',
]
XPIDL_MODULE = 'appstartup'

View file

@ -0,0 +1,195 @@
/* -*- Mode: IDL; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
#include "nsISupports.idl"
interface nsICmdLineService;
interface nsIToolkitProfile;
[scriptable, uuid(6621f6d5-6c04-4a0e-9e74-447db221484e)]
interface nsIAppStartup : nsISupports
{
/**
* Create the hidden window.
*/
void createHiddenWindow();
/**
* Destroys the hidden window. This will have no effect if the hidden window
* has not yet been created.
*/
void destroyHiddenWindow();
/**
* Runs an application event loop: normally the main event pump which
* defines the lifetime of the application. If there are no windows open
* and no outstanding calls to enterLastWindowClosingSurvivalArea this
* method will exit immediately.
*
* @returnCode NS_SUCCESS_RESTART_APP
* This return code indicates that the application should be
* restarted because quit was called with the eRestart flag.
* @returnCode NS_SUCCESS_RESTART_APP_NOT_SAME_PROFILE
* This return code indicates that the application should be
* restarted without necessarily using the same profile because
* quit was called with the eRestartNotSameProfile flag.
*/
void run();
/**
* There are situations where all application windows will be
* closed but we don't want to take this as a signal to quit the
* app. Bracket the code where the last window could close with
* these.
*/
void enterLastWindowClosingSurvivalArea();
void exitLastWindowClosingSurvivalArea();
/**
* Startup Crash Detection
*
* Keeps track of application startup begining and success using flags to
* determine whether the application is crashing on startup.
* When the number of crashes crosses the acceptable threshold, safe mode
* or other repair procedures are performed.
*/
/**
* Whether automatic safe mode is necessary at this time. This gets set
* in trackStartupCrashBegin.
*
* @see trackStartupCrashBegin
*/
readonly attribute boolean automaticSafeModeNecessary;
/**
* Restart the application in safe mode
* @param aQuitMode
* This parameter modifies how the app is shutdown.
* @see nsIAppStartup::quit
*/
void restartInSafeMode(in uint32_t aQuitMode);
/**
* Run a new instance of this app with a specified profile
* @param aProfile
* The profile we want to use.
* @see nsIAppStartup::quit
*/
void createInstanceWithProfile(in nsIToolkitProfile aProfile);
/**
* If the last startup crashed then increment a counter.
* Set a flag so on next startup we can detect whether TrackStartupCrashEnd
* was called (and therefore the application crashed).
* @return whether safe mode is necessary
*/
bool trackStartupCrashBegin();
/**
* We have succesfully started without crashing. Clear flags that were
* tracking past crashes.
*/
void trackStartupCrashEnd();
/**
* The following flags may be passed as the aMode parameter to the quit
* method. One and only one of the "Quit" flags must be specified. The
* eRestart flag may be bit-wise combined with one of the "Quit" flags to
* cause the application to restart after it quits.
*/
/**
* Attempt to quit if all windows are closed.
*/
const uint32_t eConsiderQuit = 0x01;
/**
* Try to close all windows, then quit if successful.
*/
const uint32_t eAttemptQuit = 0x02;
/**
* Quit, damnit!
*/
const uint32_t eForceQuit = 0x03;
/**
* Restart the application after quitting. The application will be
* restarted with the same profile and an empty command line.
*/
const uint32_t eRestart = 0x10;
/**
* When restarting attempt to start in the i386 architecture. Only supported
* on OSX.
*/
const uint32_t eRestarti386 = 0x20;
/**
* When restarting attempt to start in the x86_64 architecture. Only
* supported on OSX.
*/
const uint32_t eRestartx86_64 = 0x40;
/**
* Restart the application after quitting. The application will be
* restarted with an empty command line and the normal profile selection
* process will take place on startup.
*/
const uint32_t eRestartNotSameProfile = 0x100;
/**
* Exit the event loop, and shut down the app.
*
* @param aMode
* This parameter modifies how the app is shutdown, and it is
* constructed from the constants defined above.
*/
void quit(in uint32_t aMode);
/**
* True if the application is in the process of shutting down.
*/
readonly attribute boolean shuttingDown;
/**
* True if the application is in the process of starting up.
*
* Startup is complete once all observers of final-ui-startup have returned.
*/
readonly attribute boolean startingUp;
/**
* Mark the startup as completed.
*
* Called at the end of startup by nsAppRunner.
*/
[noscript] void doneStartingUp();
/**
* True if the application is being restarted
*/
readonly attribute boolean restarting;
/**
* True if this is the startup following restart, i.e. if the application
* was restarted using quit(eRestart*).
*/
readonly attribute boolean wasRestarted;
/**
* Returns an object with main, process, firstPaint, sessionRestored properties.
* Properties may not be available depending on platform or application
*/
[implicit_jscontext] jsval getStartupInfo();
/**
* True if startup was interrupted by an interactive prompt.
*/
attribute boolean interrupted;
};

View file

@ -0,0 +1,32 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#include "nsISupports.idl"
[scriptable, uuid(6c1034f0-1dd2-11b2-aa14-e6657ed7bb0b)]
interface nsIUserInfo : nsISupports
{
/* these are things the system may know about the current user */
readonly attribute wstring fullname;
readonly attribute string emailAddress;
/* should this be a wstring? */
readonly attribute string username;
readonly attribute string domain;
};
%{C++
// 14c13684-1dd2-11b2-9463-bb10ba742554
#define NS_USERINFO_CID \
{ 0x14c13684, 0x1dd2, 0x11b2, \
{0x94, 0x63, 0xbb, 0x10, 0xba, 0x74, 0x25, 0x54}}
#define NS_USERINFO_CONTRACTID "@mozilla.org/userinfo;1"
%}

View file

@ -0,0 +1,7 @@
"use strict";
module.exports = {
"extends": [
"../../../../../testing/mochitest/browser.eslintrc.js"
]
};

View file

@ -0,0 +1,10 @@
<html>
<script>
window.onbeforeunload = function(event) {
event.returnValue = 'Test beforeunload handler';
}
</script>
<body>
Test page
</body>
</html>

View file

@ -0,0 +1,8 @@
[DEFAULT]
support-files =
head.js
beforeunload.html
[browser_bug511456.js]
[browser_bug537449.js]
[browser_crash_detection.js]

View file

@ -0,0 +1,47 @@
/* 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/. */
"use strict";
const TEST_URL = "http://example.com/browser/toolkit/components/startup/tests/browser/beforeunload.html";
SpecialPowers.pushPrefEnv({"set": [["dom.require_user_interaction_for_beforeunload", false]]});
function test() {
waitForExplicitFinish();
ignoreAllUncaughtExceptions();
let win2 = window.openDialog(location, "", "chrome,all,dialog=no", "about:blank");
win2.addEventListener("load", function onLoad() {
win2.removeEventListener("load", onLoad);
gBrowser.selectedTab = gBrowser.addTab(TEST_URL);
let browser = gBrowser.selectedBrowser;
whenBrowserLoaded(browser, function () {
let seenDialog = false;
// Cancel the prompt the first time.
waitForOnBeforeUnloadDialog(browser, (btnLeave, btnStay) => {
seenDialog = true;
btnStay.click();
});
let appStartup = Cc['@mozilla.org/toolkit/app-startup;1'].
getService(Ci.nsIAppStartup);
appStartup.quit(Ci.nsIAppStartup.eAttemptQuit);
ok(seenDialog, "Should have seen a prompt dialog");
ok(!win2.closed, "Shouldn't have closed the additional window");
win2.close();
// Leave the page the second time.
waitForOnBeforeUnloadDialog(browser, (btnLeave, btnStay) => {
btnLeave.click();
});
gBrowser.removeTab(gBrowser.selectedTab);
executeSoon(finish);
});
});
}

View file

@ -0,0 +1,53 @@
/* 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/. */
"use strict";
//
// Whitelisting this test.
// As part of bug 1077403, the leaking uncaught rejection should be fixed.
//
thisTestLeaksUncaughtRejectionsAndShouldBeFixed("TypeError: this.docShell is null");
SpecialPowers.pushPrefEnv({"set": [["dom.require_user_interaction_for_beforeunload", false]]});
const TEST_URL = "http://example.com/browser/toolkit/components/startup/tests/browser/beforeunload.html";
function test() {
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab(TEST_URL);
let browser = gBrowser.selectedBrowser;
whenBrowserLoaded(browser, function () {
let seenDialog = false;
// Cancel the prompt the first time.
waitForOnBeforeUnloadDialog(browser, (btnLeave, btnStay) => {
seenDialog = true;
btnStay.click();
});
let appStartup = Cc['@mozilla.org/toolkit/app-startup;1'].
getService(Ci.nsIAppStartup);
appStartup.quit(Ci.nsIAppStartup.eAttemptQuit);
ok(seenDialog, "Should have seen a prompt dialog");
ok(!window.closed, "Shouldn't have closed the window");
let win2 = window.openDialog(location, "", "chrome,all,dialog=no", "about:blank");
ok(win2 != null, "Should have been able to open a new window");
win2.addEventListener("load", function onLoad() {
win2.removeEventListener("load", onLoad);
win2.close();
// Leave the page the second time.
waitForOnBeforeUnloadDialog(browser, (btnLeave, btnStay) => {
btnLeave.click();
});
gBrowser.removeTab(gBrowser.selectedTab);
executeSoon(finish);
});
});
}

View file

@ -0,0 +1,23 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
function test() {
function checkLastSuccess() {
let lastSuccess = Services.prefs.getIntPref("toolkit.startup.last_success");
let si = Services.startup.getStartupInfo();
is(lastSuccess, parseInt(si["main"].getTime() / 1000, 10),
"Startup tracking pref should be set after a delay at the end of startup");
finish();
}
if (Services.prefs.getPrefType("toolkit.startup.max_resumed_crashes") == Services.prefs.PREF_INVALID) {
info("Skipping this test since startup crash detection is disabled");
return;
}
const startupCrashEndDelay = 35 * 1000;
waitForExplicitFinish();
requestLongerTimeout(2);
setTimeout(checkLastSuccess, startupCrashEndDelay);
}

View file

@ -0,0 +1,29 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
function whenBrowserLoaded(browser, callback) {
return BrowserTestUtils.browserLoaded(browser).then(callback);
}
function waitForOnBeforeUnloadDialog(browser, callback) {
browser.addEventListener("DOMWillOpenModalDialog", function onModalDialog(event) {
if (Cu.isCrossProcessWrapper(event.target)) {
// This event fires in both the content and chrome processes. We
// want to ignore the one in the content process.
return;
}
browser.removeEventListener("DOMWillOpenModalDialog", onModalDialog, true);
executeSoon(() => {
let stack = browser.parentNode;
let dialogs = stack.getElementsByTagNameNS(XUL_NS, "tabmodalprompt");
let {button0, button1} = dialogs[0].ui;
callback(button0, button1);
});
}, true);
}

View file

@ -0,0 +1,7 @@
"use strict";
module.exports = {
"extends": [
"../../../../../testing/xpcshell/xpcshell.eslintrc.js"
]
};

View file

@ -0,0 +1,30 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const XULRUNTIME_CONTRACTID = "@mozilla.org/xre/runtime;1";
const XULRUNTIME_CID = Components.ID("7685dac8-3637-4660-a544-928c5ec0e714}");
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
var gAppInfo = null;
function createAppInfo(ID, name, version, platformVersion="1.0") {
let tmp = {};
Components.utils.import("resource://testing-common/AppInfo.jsm", tmp);
gAppInfo = tmp.newAppInfo({
ID, name, version, platformVersion,
crashReporter: true,
replacedLockTime: 0,
});
let XULAppInfoFactory = {
createInstance: function (outer, iid) {
if (outer != null)
throw Components.results.NS_ERROR_NO_AGGREGATION;
return gAppInfo.QueryInterface(iid);
}
};
let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
registrar.registerFactory(XULRUNTIME_CID, "XULRuntime",
XULRUNTIME_CONTRACTID, XULAppInfoFactory);
}

View file

@ -0,0 +1,300 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
Components.utils.import("resource://gre/modules/Services.jsm");
var Cc = Components.classes;
var Ci = Components.interfaces;
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "10.0");
var prefService = Services.prefs;
var appStartup = Cc["@mozilla.org/toolkit/app-startup;1"].
getService(Ci.nsIAppStartup);
const pref_last_success = "toolkit.startup.last_success";
const pref_recent_crashes = "toolkit.startup.recent_crashes";
const pref_max_resumed_crashes = "toolkit.startup.max_resumed_crashes";
const pref_always_use_safe_mode = "toolkit.startup.always_use_safe_mode";
function run_test() {
prefService.setBoolPref(pref_always_use_safe_mode, true);
resetTestEnv(0);
test_trackStartupCrashBegin();
test_trackStartupCrashEnd();
test_trackStartupCrashBegin_safeMode();
test_trackStartupCrashEnd_safeMode();
test_maxResumed();
resetTestEnv(0);
prefService.clearUserPref(pref_always_use_safe_mode);
}
// reset prefs to default
function resetTestEnv(replacedLockTime) {
try {
// call begin to reset mStartupCrashTrackingEnded
appStartup.trackStartupCrashBegin();
} catch (x) { }
prefService.setIntPref(pref_max_resumed_crashes, 2);
prefService.clearUserPref(pref_recent_crashes);
gAppInfo.replacedLockTime = replacedLockTime;
prefService.clearUserPref(pref_last_success);
}
function now_seconds() {
return ms_to_s(Date.now());
}
function ms_to_s(ms) {
return Math.floor(ms / 1000);
}
function test_trackStartupCrashBegin() {
let max_resumed = prefService.getIntPref(pref_max_resumed_crashes);
do_check_false(gAppInfo.inSafeMode);
// first run with startup crash tracking - existing profile lock
let replacedLockTime = Date.now();
resetTestEnv(replacedLockTime);
do_check_false(prefService.prefHasUserValue(pref_recent_crashes));
do_check_false(prefService.prefHasUserValue(pref_last_success));
do_check_eq(replacedLockTime, gAppInfo.replacedLockTime);
try {
do_check_false(appStartup.trackStartupCrashBegin());
do_throw("Should have thrown since last_success is not set");
} catch (x) { }
do_check_false(prefService.prefHasUserValue(pref_last_success));
do_check_false(prefService.prefHasUserValue(pref_recent_crashes));
do_check_false(appStartup.automaticSafeModeNecessary);
// first run with startup crash tracking - no existing profile lock
replacedLockTime = 0;
resetTestEnv(replacedLockTime);
do_check_false(prefService.prefHasUserValue(pref_recent_crashes));
do_check_false(prefService.prefHasUserValue(pref_last_success));
do_check_eq(replacedLockTime, gAppInfo.replacedLockTime);
try {
do_check_false(appStartup.trackStartupCrashBegin());
do_throw("Should have thrown since last_success is not set");
} catch (x) { }
do_check_false(prefService.prefHasUserValue(pref_last_success));
do_check_false(prefService.prefHasUserValue(pref_recent_crashes));
do_check_false(appStartup.automaticSafeModeNecessary);
// normal startup - last startup was success
replacedLockTime = Date.now();
resetTestEnv(replacedLockTime);
do_check_false(prefService.prefHasUserValue(pref_recent_crashes));
prefService.setIntPref(pref_last_success, ms_to_s(replacedLockTime));
do_check_eq(ms_to_s(replacedLockTime), prefService.getIntPref(pref_last_success));
do_check_false(appStartup.trackStartupCrashBegin());
do_check_eq(ms_to_s(replacedLockTime), prefService.getIntPref(pref_last_success));
do_check_false(prefService.prefHasUserValue(pref_recent_crashes));
do_check_false(appStartup.automaticSafeModeNecessary);
// normal startup with 1 recent crash
resetTestEnv(replacedLockTime);
prefService.setIntPref(pref_recent_crashes, 1);
prefService.setIntPref(pref_last_success, ms_to_s(replacedLockTime));
do_check_false(appStartup.trackStartupCrashBegin());
do_check_eq(ms_to_s(replacedLockTime), prefService.getIntPref(pref_last_success));
do_check_eq(1, prefService.getIntPref(pref_recent_crashes));
do_check_false(appStartup.automaticSafeModeNecessary);
// normal startup with max_resumed_crashes crash
resetTestEnv(replacedLockTime);
prefService.setIntPref(pref_recent_crashes, max_resumed);
prefService.setIntPref(pref_last_success, ms_to_s(replacedLockTime));
do_check_false(appStartup.trackStartupCrashBegin());
do_check_eq(ms_to_s(replacedLockTime), prefService.getIntPref(pref_last_success));
do_check_eq(max_resumed, prefService.getIntPref(pref_recent_crashes));
do_check_false(appStartup.automaticSafeModeNecessary);
// normal startup with too many recent crashes
resetTestEnv(replacedLockTime);
prefService.setIntPref(pref_recent_crashes, max_resumed + 1);
prefService.setIntPref(pref_last_success, ms_to_s(replacedLockTime));
do_check_true(appStartup.trackStartupCrashBegin());
// should remain the same since the last startup was not a crash
do_check_eq(max_resumed + 1, prefService.getIntPref(pref_recent_crashes));
do_check_true(appStartup.automaticSafeModeNecessary);
// normal startup with too many recent crashes and startup crash tracking disabled
resetTestEnv(replacedLockTime);
prefService.setIntPref(pref_max_resumed_crashes, -1);
prefService.setIntPref(pref_recent_crashes, max_resumed + 1);
prefService.setIntPref(pref_last_success, ms_to_s(replacedLockTime));
do_check_false(appStartup.trackStartupCrashBegin());
// should remain the same since the last startup was not a crash
do_check_eq(max_resumed + 1, prefService.getIntPref(pref_recent_crashes));
// returns false when disabled
do_check_false(appStartup.automaticSafeModeNecessary);
do_check_eq(-1, prefService.getIntPref(pref_max_resumed_crashes));
// normal startup after 1 non-recent crash (1 year ago), no other recent
replacedLockTime = Date.now() - 365 * 24 * 60 * 60 * 1000;
resetTestEnv(replacedLockTime);
prefService.setIntPref(pref_last_success, ms_to_s(replacedLockTime) - 365 * 24 * 60 * 60);
do_check_false(appStartup.trackStartupCrashBegin());
// recent crash count pref should be unset since the last crash was not recent
do_check_false(prefService.prefHasUserValue(pref_recent_crashes));
do_check_false(appStartup.automaticSafeModeNecessary);
// normal startup after 1 crash (1 minute ago), no other recent
replacedLockTime = Date.now() - 60 * 1000;
resetTestEnv(replacedLockTime);
prefService.setIntPref(pref_last_success, ms_to_s(replacedLockTime) - 60 * 60); // last success - 1 hour ago
do_check_false(appStartup.trackStartupCrashBegin());
// recent crash count pref should be created with value 1
do_check_eq(1, prefService.getIntPref(pref_recent_crashes));
do_check_false(appStartup.automaticSafeModeNecessary);
// normal startup after another crash (1 minute ago), 1 already
prefService.setIntPref(pref_last_success, ms_to_s(replacedLockTime) - 60 * 60); // last success - 1 hour ago
replacedLockTime = Date.now() - 60 * 1000;
gAppInfo.replacedLockTime = replacedLockTime;
do_check_false(appStartup.trackStartupCrashBegin());
// recent crash count pref should be incremented by 1
do_check_eq(2, prefService.getIntPref(pref_recent_crashes));
do_check_false(appStartup.automaticSafeModeNecessary);
// normal startup after another crash (1 minute ago), 2 already
prefService.setIntPref(pref_last_success, ms_to_s(replacedLockTime) - 60 * 60); // last success - 1 hour ago
do_check_true(appStartup.trackStartupCrashBegin());
// recent crash count pref should be incremented by 1
do_check_eq(3, prefService.getIntPref(pref_recent_crashes));
do_check_true(appStartup.automaticSafeModeNecessary);
// normal startup after 1 non-recent crash (1 year ago), 3 crashes already
replacedLockTime = Date.now() - 365 * 24 * 60 * 60 * 1000;
resetTestEnv(replacedLockTime);
prefService.setIntPref(pref_last_success, ms_to_s(replacedLockTime) - 60 * 60); // last success - 1 hour ago
do_check_false(appStartup.trackStartupCrashBegin());
// recent crash count should be unset since the last crash was not recent
do_check_false(prefService.prefHasUserValue(pref_recent_crashes));
do_check_false(appStartup.automaticSafeModeNecessary);
}
function test_trackStartupCrashEnd() {
// successful startup with no last_success (upgrade test)
let replacedLockTime = Date.now() - 10 * 1000; // 10s ago
resetTestEnv(replacedLockTime);
try {
appStartup.trackStartupCrashBegin(); // required to be called before end
do_throw("Should have thrown since last_success is not set");
} catch (x) { }
appStartup.trackStartupCrashEnd();
do_check_false(prefService.prefHasUserValue(pref_recent_crashes));
do_check_false(prefService.prefHasUserValue(pref_last_success));
// successful startup - should set last_success
replacedLockTime = Date.now() - 10 * 1000; // 10s ago
resetTestEnv(replacedLockTime);
prefService.setIntPref(pref_last_success, ms_to_s(replacedLockTime));
appStartup.trackStartupCrashBegin(); // required to be called before end
appStartup.trackStartupCrashEnd();
// ensure last_success was set since we have declared a succesful startup
// main timestamp doesn't get set in XPCShell so approximate with now
do_check_true(prefService.getIntPref(pref_last_success) <= now_seconds());
do_check_true(prefService.getIntPref(pref_last_success) >= now_seconds() - 4 * 60 * 60);
do_check_false(prefService.prefHasUserValue(pref_recent_crashes));
// successful startup with 1 recent crash
resetTestEnv(replacedLockTime);
prefService.setIntPref(pref_last_success, ms_to_s(replacedLockTime));
prefService.setIntPref(pref_recent_crashes, 1);
appStartup.trackStartupCrashBegin(); // required to be called before end
appStartup.trackStartupCrashEnd();
// ensure recent_crashes was cleared since we have declared a succesful startup
do_check_false(prefService.prefHasUserValue(pref_recent_crashes));
}
function test_trackStartupCrashBegin_safeMode() {
gAppInfo.inSafeMode = true;
resetTestEnv(0);
let max_resumed = prefService.getIntPref(pref_max_resumed_crashes);
// check manual safe mode doesn't change prefs without crash
let replacedLockTime = Date.now() - 10 * 1000; // 10s ago
resetTestEnv(replacedLockTime);
prefService.setIntPref(pref_last_success, ms_to_s(replacedLockTime));
do_check_false(prefService.prefHasUserValue(pref_recent_crashes));
do_check_true(prefService.prefHasUserValue(pref_last_success));
do_check_false(appStartup.automaticSafeModeNecessary);
do_check_false(appStartup.trackStartupCrashBegin());
do_check_false(prefService.prefHasUserValue(pref_recent_crashes));
do_check_true(prefService.prefHasUserValue(pref_last_success));
do_check_false(appStartup.automaticSafeModeNecessary);
// check forced safe mode doesn't change prefs without crash
replacedLockTime = Date.now() - 10 * 1000; // 10s ago
resetTestEnv(replacedLockTime);
prefService.setIntPref(pref_last_success, ms_to_s(replacedLockTime));
prefService.setIntPref(pref_recent_crashes, max_resumed + 1);
do_check_eq(max_resumed + 1, prefService.getIntPref(pref_recent_crashes));
do_check_true(prefService.prefHasUserValue(pref_last_success));
do_check_false(appStartup.automaticSafeModeNecessary);
do_check_true(appStartup.trackStartupCrashBegin());
do_check_eq(max_resumed + 1, prefService.getIntPref(pref_recent_crashes));
do_check_true(prefService.prefHasUserValue(pref_last_success));
do_check_true(appStartup.automaticSafeModeNecessary);
// check forced safe mode after old crash
replacedLockTime = Date.now() - 365 * 24 * 60 * 60 * 1000;
resetTestEnv(replacedLockTime);
// one year ago
let last_success = ms_to_s(replacedLockTime) - 365 * 24 * 60 * 60;
prefService.setIntPref(pref_last_success, last_success);
prefService.setIntPref(pref_recent_crashes, max_resumed + 1);
do_check_eq(max_resumed + 1, prefService.getIntPref(pref_recent_crashes));
do_check_true(prefService.prefHasUserValue(pref_last_success));
do_check_true(appStartup.automaticSafeModeNecessary);
do_check_true(appStartup.trackStartupCrashBegin());
do_check_eq(max_resumed + 1, prefService.getIntPref(pref_recent_crashes));
do_check_eq(last_success, prefService.getIntPref(pref_last_success));
do_check_true(appStartup.automaticSafeModeNecessary);
}
function test_trackStartupCrashEnd_safeMode() {
gAppInfo.inSafeMode = true;
let replacedLockTime = Date.now();
resetTestEnv(replacedLockTime);
let max_resumed = prefService.getIntPref(pref_max_resumed_crashes);
prefService.setIntPref(pref_last_success, ms_to_s(replacedLockTime) - 24 * 60 * 60);
// ensure recent_crashes were not cleared in manual safe mode
prefService.setIntPref(pref_recent_crashes, 1);
appStartup.trackStartupCrashBegin(); // required to be called before end
appStartup.trackStartupCrashEnd();
do_check_eq(1, prefService.getIntPref(pref_recent_crashes));
// recent_crashes should be set to max_resumed in forced safe mode to allow the user
// to try and start in regular mode after making changes.
prefService.setIntPref(pref_recent_crashes, max_resumed + 1);
appStartup.trackStartupCrashBegin(); // required to be called before end
appStartup.trackStartupCrashEnd();
do_check_eq(max_resumed, prefService.getIntPref(pref_recent_crashes));
}
function test_maxResumed() {
resetTestEnv(0);
gAppInfo.inSafeMode = false;
let max_resumed = prefService.getIntPref(pref_max_resumed_crashes);
let replacedLockTime = Date.now();
resetTestEnv(replacedLockTime);
prefService.setIntPref(pref_max_resumed_crashes, -1);
prefService.setIntPref(pref_recent_crashes, max_resumed + 1);
prefService.setIntPref(pref_last_success, ms_to_s(replacedLockTime) - 24 * 60 * 60);
appStartup.trackStartupCrashBegin();
// should remain the same since the last startup was not a crash
do_check_eq(max_resumed + 2, prefService.getIntPref(pref_recent_crashes));
do_check_false(appStartup.automaticSafeModeNecessary);
}

View file

@ -0,0 +1,6 @@
[DEFAULT]
head = head_startup.js
tail =
skip-if = toolkit == 'android'
[test_startup_crash.js]