Merge last PGO-green changeset of mozilla-inbound to mozilla-central

This commit is contained in:
Ed Morley 2012-02-01 10:55:34 +00:00
commit 74d8e85167
102 changed files with 2733 additions and 679 deletions

View File

@ -162,6 +162,7 @@
@BINPATH@/components/dom_indexeddb.xpt
@BINPATH@/components/dom_offline.xpt
@BINPATH@/components/dom_json.xpt
@BINPATH@/components/dom_power.xpt
@BINPATH@/components/dom_range.xpt
@BINPATH@/components/dom_sidebar.xpt
@BINPATH@/components/dom_sms.xpt

View File

@ -65,6 +65,7 @@ pref("extensions.minCompatibleAppVersion", "4.0");
pref("extensions.getAddons.cache.enabled", true);
pref("extensions.getAddons.maxResults", 15);
pref("extensions.getAddons.get.url", "https://services.addons.mozilla.org/%LOCALE%/firefox/api/%API_VERSION%/search/guid:%IDS%?src=firefox&appOS=%OS%&appVersion=%VERSION%");
pref("extensions.getAddons.getWithPerformance.url", "https://services.addons.mozilla.org/%LOCALE%/firefox/api/%API_VERSION%/search/guid:%IDS%?src=firefox&appOS=%OS%&appVersion=%VERSION%&tMain=%TIME_MAIN%&tFirstPaint=%TIME_FIRST_PAINT%&tSessionRestored=%TIME_SESSION_RESTORED%");
pref("extensions.getAddons.search.browseURL", "https://addons.mozilla.org/%LOCALE%/firefox/search?q=%TERMS%");
pref("extensions.getAddons.search.url", "https://services.addons.mozilla.org/%LOCALE%/firefox/api/%API_VERSION%/search/%TERMS%/all/%MAX_RESULTS%/%OS%/%VERSION%/%COMPATIBILITY_MODE%?src=firefox");
pref("extensions.webservice.discoverURL", "https://services.addons.mozilla.org/%LOCALE%/firefox/discovery/pane/%VERSION%/%OS%/%COMPATIBILITY_MODE%");

View File

@ -402,6 +402,7 @@ user_pref("extensions.webservice.discoverURL", "http://%(server)s/extensions-dum
// Make sure AddonRepository won't hit the network
user_pref("extensions.getAddons.maxResults", 0);
user_pref("extensions.getAddons.get.url", "http://%(server)s/extensions-dummy/repositoryGetURL");
user_pref("extensions.getAddons.getWithPerformance.url", "http://%(server)s/extensions-dummy/repositoryGetWithPerformanceURL");
user_pref("extensions.getAddons.search.browseURL", "http://%(server)s/extensions-dummy/repositoryBrowseURL");
user_pref("extensions.getAddons.search.url", "http://%(server)s/extensions-dummy/repositorySearchURL");
""" % { "server" : self.webServer + ":" + str(self.httpPort) }

View File

@ -729,6 +729,7 @@ sys/pstat.h
sys/ptrace.h
sys/queue.h
sys/quota.h
sys/reboot.h
sys/reg.h
sys/regset.h
sys/resource.h

View File

@ -333,7 +333,7 @@ public:
virtual PRInt64 VideoQueueMemoryInUse() = 0;
virtual PRInt64 AudioQueueMemoryInUse() = 0;
virtual void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRUint32 aOffset) = 0;
virtual void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRInt64 aOffset) = 0;
// Causes the state machine to switch to buffering state, and to
// immediately stop playback and buffer downloaded data. Must be called
@ -504,7 +504,7 @@ class nsBuiltinDecoder : public nsMediaDecoder
return 0;
}
virtual void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRUint32 aOffset) {
virtual void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRInt64 aOffset) {
if (mDecoderStateMachine) {
mDecoderStateMachine->NotifyDataArrived(aBuffer, aLength, aOffset);
}

View File

@ -498,7 +498,7 @@ public:
// Only used by nsWebMReader for now, so stub here rather than in every
// reader than inherits from nsBuiltinDecoderReader.
virtual void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRUint32 aOffset) {}
virtual void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRInt64 aOffset) {}
protected:

View File

@ -1216,7 +1216,7 @@ void nsBuiltinDecoderStateMachine::ResetPlayback()
void nsBuiltinDecoderStateMachine::NotifyDataArrived(const char* aBuffer,
PRUint32 aLength,
PRUint32 aOffset)
PRInt64 aOffset)
{
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
mReader->NotifyDataArrived(aBuffer, aLength, aOffset);

View File

@ -223,7 +223,7 @@ public:
return 0;
}
void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRUint32 aOffset);
void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRInt64 aOffset);
PRInt64 GetEndMediaTime() const {
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();

View File

@ -335,7 +335,7 @@ public:
// Called as data arrives on the stream and is read into the cache. Called
// on the main thread only.
virtual void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRUint32 aOffset) = 0;
virtual void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRInt64 aOffset) = 0;
// Cleanup internal data structures. Must be called on the main
// thread by the owning object before that object disposes of this object.

View File

@ -257,7 +257,7 @@ void nsWebMBufferedState::CalculateBufferedForRange(nsTimeRanges* aBuffered,
aBuffered->Add(startTime, endTime);
}
void nsWebMBufferedState::NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRUint32 aOffset)
void nsWebMBufferedState::NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRInt64 aOffset)
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
PRUint32 idx;

View File

@ -224,7 +224,7 @@ public:
MOZ_COUNT_DTOR(nsWebMBufferedState);
}
void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRUint32 aOffset);
void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRInt64 aOffset);
void CalculateBufferedForRange(nsTimeRanges* aBuffered,
PRInt64 aStartOffset, PRInt64 aEndOffset,
PRUint64 aTimecodeScale,

View File

@ -800,7 +800,7 @@ nsresult nsWebMReader::GetBuffered(nsTimeRanges* aBuffered, PRInt64 aStartTime)
return NS_OK;
}
void nsWebMReader::NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRUint32 aOffset)
void nsWebMReader::NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRInt64 aOffset)
{
mBufferedState->NotifyDataArrived(aBuffer, aLength, aOffset);
}

View File

@ -161,7 +161,7 @@ public:
virtual nsresult ReadMetadata(nsVideoInfo* aInfo);
virtual nsresult Seek(PRInt64 aTime, PRInt64 aStartTime, PRInt64 aEndTime, PRInt64 aCurrentTime);
virtual nsresult GetBuffered(nsTimeRanges* aBuffered, PRInt64 aStartTime);
virtual void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRUint32 aOffset);
virtual void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRInt64 aOffset);
private:
// Value passed to NextPacket to determine if we are reading a video or an

View File

@ -27,8 +27,6 @@ function CheckList(aListObject, aExpectedListLength, aListDescription)
is(aListObject.numberOfItems, aExpectedListLength, aListDescription + ".numberOfItems");
is(aListObject.numberOfItems, aExpectedListLength, aListDescription + ".length");
for (let i = 0; i < aListObject.length; i++) {
if (aListDescription.indexOf("SVGStringList") > -1)
continue;
let item = aListObject.getItem(i);
ok(aListObject[i] === item, aListDescription + "[" + i + "]");
}

View File

@ -77,6 +77,7 @@ endif
DIRS += \
base \
battery \
power \
sms \
src \
locales \

View File

@ -69,6 +69,7 @@
#include "mozilla/Preferences.h"
#include "mozilla/Telemetry.h"
#include "BatteryManager.h"
#include "PowerManager.h"
#include "SmsManager.h"
#include "nsISmsService.h"
#include "mozilla/Hal.h"
@ -164,6 +165,8 @@ Navigator::Invalidate()
mBatteryManager = nsnull;
}
mPowerManager = nsnull;
if (mSmsManager) {
mSmsManager->Shutdown();
mSmsManager = nsnull;
@ -939,6 +942,18 @@ Navigator::GetMozBattery(nsIDOMMozBatteryManager** aBattery)
return NS_OK;
}
NS_IMETHODIMP
Navigator::GetMozPower(nsIDOMMozPowerManager** aPower)
{
if (!mPowerManager) {
mPowerManager = new power::PowerManager();
}
NS_ADDREF(*aPower = mPowerManager);
return NS_OK;
}
//*****************************************************************************
// Navigator::nsIDOMNavigatorSms
//*****************************************************************************

View File

@ -84,6 +84,10 @@ namespace network {
class Connection;
} // namespace Connection;
namespace power {
class PowerManager;
} // namespace power
class Navigator : public nsIDOMNavigator
, public nsIDOMClientInformation
, public nsIDOMNavigatorGeolocation
@ -136,6 +140,7 @@ private:
nsRefPtr<nsGeolocation> mGeolocation;
nsRefPtr<nsDesktopNotificationCenter> mNotification;
nsRefPtr<battery::BatteryManager> mBatteryManager;
nsRefPtr<power::PowerManager> mPowerManager;
nsRefPtr<sms::SmsManager> mSmsManager;
#ifdef MOZ_B2G_RIL
nsCOMPtr<nsIDOMTelephony> mTelephony;

View File

@ -488,6 +488,7 @@
#include "DOMSVGNumberList.h"
#include "DOMSVGPathSegList.h"
#include "DOMSVGPointList.h"
#include "DOMSVGStringList.h"
#include "DOMSVGTransformList.h"
#include "mozilla/dom/indexedDB/IDBWrapperCache.h"
@ -514,6 +515,7 @@ using mozilla::dom::indexedDB::IDBWrapperCache;
#include "nsIDOMBatteryManager.h"
#include "BatteryManager.h"
#include "nsIDOMPowerManager.h"
#include "nsIDOMSmsManager.h"
#include "nsIDOMSmsMessage.h"
#include "nsIDOMSmsEvent.h"
@ -1293,8 +1295,8 @@ static nsDOMClassInfoData sClassInfoData[] = {
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(SVGRect, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(SVGStringList, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(SVGStringList, nsSVGStringListSH,
ARRAY_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(SVGTransform, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(SVGTransformList, nsSVGTransformListSH,
@ -1443,6 +1445,9 @@ static nsDOMClassInfoData sClassInfoData[] = {
NS_DEFINE_CLASSINFO_DATA(MozBatteryManager, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(MozPowerManager, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(MozSmsManager, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
@ -4032,6 +4037,10 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(MozPowerManager, nsIDOMMozPowerManager)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozPowerManager)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(MozSmsManager, nsIDOMMozSmsManager)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozSmsManager)
DOM_CLASSINFO_MAP_END
@ -10881,3 +10890,45 @@ nsSVGListSH<ListInterfaceType, ListType>::GetItemAt(nsISupports *aNative,
return list->GetItemWithoutAddRef(aIndex);
}
// SVGStringList helper
nsresult
nsSVGStringListSH::GetStringAt(nsISupports *aNative, PRInt32 aIndex,
nsAString& aResult)
{
if (aIndex < 0) {
SetDOMStringToNull(aResult);
return NS_OK;
}
DOMSVGStringList* list = static_cast<DOMSVGStringList*>(
static_cast<nsIDOMSVGStringList*>(aNative));
#ifdef DEBUG
{
nsCOMPtr<nsIDOMSVGStringList> list_qi = do_QueryInterface(aNative);
// If this assertion fires the QI implementation for the object in
// question doesn't use the nsIDOMDOMSVGStringList pointer as the
// nsISupports pointer. That must be fixed, or we'll crash...
NS_ABORT_IF_FALSE(list_qi == list, "Uh, fix QI!");
}
#endif
nsresult rv = list->GetItem(aIndex, aResult);
#ifdef DEBUG
if (DOMStringIsNull(aResult)) {
PRUint32 length = 0;
list->GetLength(&length);
NS_ASSERTION(PRUint32(aIndex) >= length, "Item should only return null for out-of-bounds access");
}
#endif
if (rv == NS_ERROR_DOM_INDEX_SIZE_ERR) {
SetDOMStringToNull(aResult);
rv = NS_OK;
}
return rv;
}

View File

@ -1748,4 +1748,27 @@ typedef nsSVGListSH<nsIDOMSVGPathSegList, mozilla::DOMSVGPathSegList> nsSVGPathS
typedef nsSVGListSH<nsIDOMSVGPointList, mozilla::DOMSVGPointList> nsSVGPointListSH;
typedef nsSVGListSH<nsIDOMSVGTransformList, mozilla::DOMSVGTransformList> nsSVGTransformListSH;
// SVGStringList helper
class nsSVGStringListSH : public nsStringArraySH
{
protected:
nsSVGStringListSH(nsDOMClassInfoData* aData) : nsStringArraySH(aData)
{
}
virtual ~nsSVGStringListSH()
{
}
virtual nsresult GetStringAt(nsISupports *aNative, PRInt32 aIndex,
nsAString& aResult);
public:
static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
{
return new nsSVGStringListSH(aData);
}
};
#endif /* nsDOMClassInfo_h___ */

View File

@ -430,6 +430,8 @@ DOMCI_CLASS(GeoPositionError)
DOMCI_CLASS(MozBatteryManager)
DOMCI_CLASS(MozPowerManager)
DOMCI_CLASS(MozSmsManager)
DOMCI_CLASS(MozSmsMessage)
DOMCI_CLASS(MozSmsEvent)

View File

@ -7680,9 +7680,9 @@ void nsGlobalWindow::UpdateTouchState()
nsCOMPtr<nsIObserverService> observerService =
do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
if (observerService) {
nsPIDOMWindow *inner = GetCurrentInnerWindowInternal();
observerService->NotifyObservers(mainWidget,
observerService->NotifyObservers(static_cast<nsIDOMWindow*>(this),
DOM_TOUCH_LISTENER_ADDED,
nsnull);
}

View File

@ -1,6 +1,7 @@
DOM_SRCDIRS = \
dom/base \
dom/battery \
dom/power \
dom/network/src \
dom/sms/src \
dom/src/events \

View File

@ -129,3 +129,6 @@ interface nsIDOMPkcs11;
// Used font face (for inspector)
interface nsIDOMFontFace;
interface nsIDOMFontFaceList;
// Power
interface nsIDOMMozPowerManager;

View File

@ -39,26 +39,27 @@
#include "domstubs.idl"
[scriptable, uuid(a1ee08c1-0299-4908-a6ba-7cBc8da6531f)]
[scriptable, uuid(b1f4b1fa-49c2-4375-9ce8-bf97ecf6b428)]
interface nsIDOMNavigator : nsISupports
{
readonly attribute DOMString appCodeName;
readonly attribute DOMString appName;
readonly attribute DOMString appVersion;
readonly attribute DOMString language;
readonly attribute nsIDOMMimeTypeArray mimeTypes;
readonly attribute DOMString platform;
readonly attribute DOMString oscpu;
readonly attribute DOMString vendor;
readonly attribute DOMString vendorSub;
readonly attribute DOMString product;
readonly attribute DOMString productSub;
readonly attribute nsIDOMPluginArray plugins;
readonly attribute DOMString userAgent;
readonly attribute boolean cookieEnabled;
readonly attribute boolean onLine;
readonly attribute DOMString buildID;
readonly attribute DOMString doNotTrack;
readonly attribute DOMString appCodeName;
readonly attribute DOMString appName;
readonly attribute DOMString appVersion;
readonly attribute DOMString language;
readonly attribute nsIDOMMimeTypeArray mimeTypes;
readonly attribute DOMString platform;
readonly attribute DOMString oscpu;
readonly attribute DOMString vendor;
readonly attribute DOMString vendorSub;
readonly attribute DOMString product;
readonly attribute DOMString productSub;
readonly attribute nsIDOMPluginArray plugins;
readonly attribute DOMString userAgent;
readonly attribute boolean cookieEnabled;
readonly attribute boolean onLine;
readonly attribute DOMString buildID;
readonly attribute DOMString doNotTrack;
readonly attribute nsIDOMMozPowerManager mozPower;
boolean javaEnabled();

73
dom/power/Makefile.in Normal file
View File

@ -0,0 +1,73 @@
# ***** 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 build system.
#
# 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):
# Kan-Ru Chen <kchen@mozilla.com> (Original Author)
#
# 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
LIBRARY_NAME = dom_power_s
XPIDL_MODULE = dom_power
LIBXUL_LIBRARY = 1
FORCE_STATIC_LIB = 1
include $(topsrcdir)/dom/dom-config.mk
EXPORTS_NAMESPACES = mozilla/dom/power
EXPORTS_mozilla/dom/power = \
PowerManagerService.h \
$(NULL)
CPPSRCS = \
PowerManager.cpp \
PowerManagerService.cpp \
$(NULL)
XPIDLSRCS = \
nsIDOMPowerManager.idl \
nsIPowerManagerService.idl \
$(NULL)
ifdef ENABLE_TESTS
DIRS += test
endif
include $(topsrcdir)/config/config.mk
include $(topsrcdir)/ipc/chromium/chromium-config.mk
include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,89 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** 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):
* Kan-Ru Chen <kchen@mozilla.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either of 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 "PowerManager.h"
#include "nsContentUtils.h"
#include "nsDOMClassInfoID.h"
#include "nsIPowerManagerService.h"
#include "nsServiceManagerUtils.h"
DOMCI_DATA(MozPowerManager, mozilla::dom::power::PowerManager)
namespace mozilla {
namespace dom {
namespace power {
NS_INTERFACE_MAP_BEGIN(PowerManager)
NS_INTERFACE_MAP_ENTRY(nsIDOMMozPowerManager)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMMozPowerManager)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozPowerManager)
NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(PowerManager)
NS_IMPL_RELEASE(PowerManager)
NS_IMETHODIMP
PowerManager::Reboot()
{
NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_DOM_SECURITY_ERR);
nsCOMPtr<nsIPowerManagerService> pmService =
do_GetService(POWERMANAGERSERVICE_CONTRACTID);
NS_ENSURE_TRUE(pmService, NS_OK);
pmService->Reboot();
return NS_OK;
}
NS_IMETHODIMP
PowerManager::PowerOff()
{
NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_DOM_SECURITY_ERR);
nsCOMPtr<nsIPowerManagerService> pmService =
do_GetService(POWERMANAGERSERVICE_CONTRACTID);
NS_ENSURE_TRUE(pmService, NS_OK);
pmService->PowerOff();
return NS_OK;
}
} // power
} // dom
} // mozilla

61
dom/power/PowerManager.h Normal file
View File

@ -0,0 +1,61 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** 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):
* Kan-Ru Chen <kchen@mozilla.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either of 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 mozilla_dom_power_PowerManager_h
#define mozilla_dom_power_PowerManager_h
#include "nsIDOMPowerManager.h"
namespace mozilla {
namespace dom {
namespace power {
class PowerManager
: public nsIDOMMozPowerManager
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMMOZPOWERMANAGER
PowerManager() {};
virtual ~PowerManager() {};
};
} // namespace power
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_power_PowerManager_h

View File

@ -0,0 +1,73 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** 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):
* Kan-Ru Chen <kchen@mozilla.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either of 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 "mozilla/Hal.h"
#include "PowerManagerService.h"
namespace mozilla {
namespace dom {
namespace power {
NS_IMPL_ISUPPORTS1(PowerManagerService, nsIPowerManagerService)
/* static */ already_AddRefed<nsIPowerManagerService>
PowerManagerService::GetInstance()
{
nsCOMPtr<nsIPowerManagerService> pmService;
pmService = new PowerManagerService();
return pmService.forget();
}
NS_IMETHODIMP
PowerManagerService::Reboot()
{
hal::Reboot();
return NS_OK;
}
NS_IMETHODIMP
PowerManagerService::PowerOff()
{
hal::PowerOff();
return NS_OK;
}
} // power
} // dom
} // mozilla

View File

@ -0,0 +1,61 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** 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):
* Kan-Ru Chen <kchen@mozilla.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either of 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 mozilla_dom_power_PowerManagerService_h
#define mozilla_dom_power_PowerManagerService_h
#include "nsIPowerManagerService.h"
#include "nsCOMPtr.h" // for already_AddRefed
namespace mozilla {
namespace dom {
namespace power {
class PowerManagerService
: public nsIPowerManagerService
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIPOWERMANAGERSERVICE
static already_AddRefed<nsIPowerManagerService> GetInstance();
};
} // namespace power
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_power_PowerManagerService_h

View File

@ -0,0 +1,45 @@
/* -*- Mode: C++; tab-width: 4; 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.
*
* 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):
* Kan-Ru Chen <kchen@mozilla.com> (Original Author)
*
* 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 "nsISupports.idl"
[scriptable, uuid(6ec16abc-2fe8-4ab3-99b0-0f08405be81b)]
interface nsIDOMMozPowerManager : nsISupports
{
void powerOff();
void reboot();
};

View File

@ -0,0 +1,50 @@
/* -*- Mode: C++; tab-width: 4; 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.
*
* 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):
* Kan-Ru Chen <kchen@mozilla.com> (Original Author)
*
* 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 "nsISupports.idl"
%{C++
#define NS_POWERMANAGERSERVICE_CID { 0x18c2e238, 0x3a0a, 0x4153, {0x89, 0xfc, 0x16, 0x6b, 0x3b, 0x14, 0x65, 0xa1 } }
#define POWERMANAGERSERVICE_CONTRACTID "@mozilla.org/power/powermanagerservice;1"
%}
[scriptable, builtinclass, uuid(38919539-4641-4f0b-9f11-6b6294a9386f)]
interface nsIPowerManagerService : nsISupports
{
void powerOff();
void reboot();
};

View File

@ -0,0 +1,59 @@
# ***** 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 build system.
#
# 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):
# Kan-Ru Chen <kchen@mozilla.com> (Original Author)
#
# 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@
relativesrcdir = dom/power/test
include $(DEPTH)/config/autoconf.mk
DIRS = \
$(NULL)
include $(topsrcdir)/config/rules.mk
_TEST_FILES = \
test_power_basics.html \
$(NULL)
libs:: $(_TEST_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
#libs:: $(_CHROME_TEST_FILES)
# $(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/chrome/$(relativesrcdir)

View File

@ -0,0 +1,22 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for Power API</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Power API **/
ok('mozPower' in navigator, "navigator.mozPower should exist");
</script>
</pre>
</body>
</html>

View File

@ -372,5 +372,17 @@ NotifyNetworkChange(const NetworkInformation& aInfo)
sNetworkObservers.BroadcastCachedInformation();
}
void Reboot()
{
AssertMainThread();
PROXY_IF_SANDBOXED(Reboot());
}
void PowerOff()
{
AssertMainThread();
PROXY_IF_SANDBOXED(PowerOff());
}
} // namespace hal
} // namespace mozilla

View File

@ -192,6 +192,16 @@ void GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo);
*/
void NotifyNetworkChange(const hal::NetworkInformation& aNetworkInfo);
/**
* Reboot the device.
*/
void Reboot();
/**
* Power off the device.
*/
void PowerOff();
} // namespace MOZ_HAL_NAMESPACE
} // namespace mozilla

View File

@ -72,9 +72,9 @@ CPPSRCS = \
ifeq (android,$(MOZ_WIDGET_TOOLKIT))
CPPSRCS += AndroidHal.cpp
else ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
CPPSRCS += GonkHal.cpp
CPPSRCS += GonkHal.cpp Power.cpp
else ifeq (Linux,$(OS_TARGET))
CPPSRCS += LinuxHal.cpp
CPPSRCS += LinuxHal.cpp Power.cpp
ifdef MOZ_ENABLE_DBUS
CPPSRCS += UPowerClient.cpp
endif

View File

@ -173,6 +173,14 @@ GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo)
bridge->GetCurrentNetworkInformation(aNetworkInfo);
}
void
Reboot()
{}
void
PowerOff()
{}
} // hal_impl
} // mozilla

View File

@ -105,5 +105,13 @@ GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo)
aNetworkInfo->canBeMetered() = dom::network::kDefaultCanBeMetered;
}
void
Reboot()
{}
void
PowerOff()
{}
} // hal_impl
} // namespace mozilla

59
hal/linux/Power.cpp Normal file
View File

@ -0,0 +1,59 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** 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):
* Kan-Ru Chen <kchen@mozilla.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either of 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 "Hal.h"
#include <unistd.h>
#include <sys/reboot.h>
namespace mozilla {
namespace hal_impl {
void
Reboot()
{
reboot(RB_AUTOBOOT);
}
void
PowerOff()
{
reboot(RB_POWER_OFF);
}
} // hal_impl
} // mozilla

View File

@ -86,6 +86,9 @@ parent:
sync GetScreenBrightness() returns (double brightness);
SetScreenBrightness(double brightness);
Reboot();
PowerOff();
__delete__();
};

View File

@ -152,6 +152,18 @@ SetScreenBrightness(double brightness)
Hal()->SendSetScreenBrightness(brightness);
}
void
Reboot()
{
Hal()->SendReboot();
}
void
PowerOff()
{
Hal()->SendPowerOff();
}
class HalParent : public PHalParent
, public BatteryObserver
, public NetworkObserver
@ -267,6 +279,20 @@ public:
hal::SetScreenBrightness(brightness);
return true;
}
NS_OVERRIDE virtual bool
RecvReboot()
{
hal::Reboot();
return true;
}
NS_OVERRIDE virtual bool
RecvPowerOff()
{
hal::PowerOff();
return true;
}
};
class HalChild : public PHalChild {

View File

@ -84,5 +84,13 @@ GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo)
aNetworkInfo->canBeMetered() = dom::network::kDefaultCanBeMetered;
}
void
Reboot()
{}
void
PowerOff()
{}
} // hal_impl
} // mozilla

View File

@ -729,6 +729,7 @@ sys/pstat.h
sys/ptrace.h
sys/queue.h
sys/quota.h
sys/reboot.h
sys/reg.h
sys/regset.h
sys/resource.h

View File

@ -0,0 +1,115 @@
// Once a function proxy has been frozen, its handler's traps are no longer called,
// but its call traps are.
var callTrapCalls;
function handleCall() {
print('call');
callTrapCalls++;
return 'favor';
}
function handleConstruct() {
print('construct');
callTrapCalls++;
return 'compliment';
}
var descriptorForX = { configurable: true, enumerable: true, writable: true, value: 42 };
var trapCalls;
var handler = {
getOwnPropertyNames: function () {
print('getOwnPropertyNames');
trapCalls++;
return ['x'];
},
getPropertyNames: function() {
print('getPropertyNames');
trapCalls++;
return ['x'];
},
getOwnPropertyDescriptor: function(name) {
print('getOwnPropertyDescriptor');
trapCalls++;
assertEq(name, 'x');
return descriptorForX;
},
getPropertyDescriptor: function(name) {
print('getPropertyDescriptor');
trapCalls++;
assertEq(name, 'x');
return descriptorForX;
},
defineProperty: function(name, propertyDescriptor) {
print('defineProperty');
trapCalls++;
},
delete: function(name) {
print('delete');
trapCalls++;
return false;
},
fix: function() {
print('fix');
trapCalls++;
return { x: descriptorForX };
}
};
var fp = Proxy.createFunction(handler, handleCall, handleConstruct);
trapCalls = callTrapCalls = 0;
assertEq(Object.getOwnPropertyNames(fp)[0], 'x');
assertEq(trapCalls > 0, true);
assertEq(callTrapCalls, 0);
trapCalls = callTrapCalls = 0;
assertEq(Object.getOwnPropertyDescriptor(fp, 'x').value, 42);
assertEq(trapCalls > 0, true);
assertEq(callTrapCalls, 0);
trapCalls = callTrapCalls = 0;
assertEq(delete fp.x, false);
assertEq(trapCalls > 0, true);
assertEq(callTrapCalls, 0);
trapCalls = callTrapCalls = 0;
assertEq(fp(), 'favor');
assertEq(trapCalls, 0);
assertEq(callTrapCalls, 1);
trapCalls = callTrapCalls = 0;
assertEq(new fp, 'compliment');
assertEq(trapCalls, 0);
assertEq(callTrapCalls, 1);
trapCalls = callTrapCalls = 0;
Object.freeze(fp);
assertEq(trapCalls > 0, true);
assertEq(callTrapCalls, 0);
// Once the proxy has been frozen, its traps should never be invoked any
// more.
trapCalls = callTrapCalls = 0;
assertEq(Object.getOwnPropertyNames(fp)[0], 'x');
assertEq(trapCalls, 0);
trapCalls = callTrapCalls = 0;
assertEq(Object.getOwnPropertyDescriptor(fp, 'x').value, 42);
assertEq(trapCalls, 0);
trapCalls = callTrapCalls = 0;
assertEq(delete fp.x, false);
assertEq(trapCalls, 0);
trapCalls = callTrapCalls = 0;
assertEq(fp(), 'favor');
assertEq(trapCalls, 0);
assertEq(callTrapCalls, 1);
trapCalls = callTrapCalls = 0;
assertEq(new fp, 'compliment');
assertEq(trapCalls, 0);
assertEq(callTrapCalls, 1);
trapCalls = callTrapCalls = 0;
Object.freeze(fp);
assertEq(trapCalls, 0);

View File

@ -386,12 +386,22 @@ Jsvalify(Class *c)
{
return (JSClass *)c;
}
static JS_ALWAYS_INLINE const JSClass *
Jsvalify(const Class *c)
{
return (const JSClass *)c;
}
static JS_ALWAYS_INLINE Class *
Valueify(JSClass *c)
{
return (Class *)c;
}
static JS_ALWAYS_INLINE const Class *
Valueify(const JSClass *c)
{
return (const Class *)c;
}
/*
* Enumeration describing possible values of the [[Class]] internal property

View File

@ -343,31 +343,11 @@ js::BoxNonStrictThis(JSContext *cx, const CallReceiver &call)
const uint32_t JSSLOT_FOUND_FUNCTION = 0;
const uint32_t JSSLOT_SAVED_ID = 1;
static void
no_such_method_trace(JSTracer *trc, JSObject *obj)
{
gc::MarkValue(trc, obj->getSlotRef(JSSLOT_FOUND_FUNCTION), "found function");
gc::MarkValue(trc, obj->getSlotRef(JSSLOT_SAVED_ID), "saved id");
}
Class js_NoSuchMethodClass = {
"NoSuchMethod",
JSCLASS_HAS_RESERVED_SLOTS(2) | JSCLASS_IS_ANONYMOUS,
JS_PropertyStub, /* addProperty */
JS_PropertyStub, /* delProperty */
JS_PropertyStub, /* getProperty */
JS_StrictPropertyStub, /* setProperty */
JS_EnumerateStub,
JS_ResolveStub,
JS_ConvertStub,
NULL, /* finalize */
NULL, /* reserved0 */
NULL, /* checkAccess */
NULL, /* call */
NULL, /* construct */
NULL, /* XDR */
NULL, /* hasInstance */
no_such_method_trace /* trace */
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub,
};
/*
@ -2813,6 +2793,12 @@ BEGIN_CASE(JSOP_FUNAPPLY)
InitialFrameFlags initial = construct ? INITIAL_CONSTRUCT : INITIAL_NONE;
JSScript *newScript = fun->script();
if (newScript->compileAndGo && newScript->hasClearedGlobal()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CLEARED_SCOPE);
goto error;
}
if (!cx->stack.pushInlineFrame(cx, regs, args, *fun, newScript, initial))
goto error;

View File

@ -1460,7 +1460,7 @@ JS_FRIEND_DATA(Class) js::FunctionProxyClass = {
proxy_DeleteSpecial,
NULL, /* enumerate */
proxy_TypeOf,
NULL, /* fix */
proxy_Fix, /* fix */
NULL, /* thisObject */
NULL, /* clear */
}

View File

@ -55,6 +55,10 @@
#include "vm/RegExpObject-inl.h"
#include "vm/RegExpStatics-inl.h"
#ifdef JS_METHODJIT
#include "methodjit/Retcon.h"
#endif
using namespace js;
JSObject *
@ -360,6 +364,21 @@ GlobalObject::clear(JSContext *cx)
* prototypes cached on the global object are immutable.
*/
cx->compartment->newObjectCache.reset();
#ifdef JS_METHODJIT
/*
* Destroy compiled code for any scripts parented to this global. Call ICs
* can directly call scripts which have associated JIT code, and do so
* without checking whether the script's global has been cleared.
*/
for (gc::CellIter i(cx, cx->compartment, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
JSScript *script = i.get<JSScript>();
if (script->compileAndGo && script->hasJITCode() && script->hasClearedGlobal()) {
mjit::Recompiler::clearStackReferences(cx, script);
mjit::ReleaseScriptCode(cx, script);
}
}
#endif
}
bool

View File

@ -3248,6 +3248,29 @@ nsXPCComponents_utils_Sandbox::CallOrConstruct(nsIXPConnectWrappedNative *wrappe
}
}
// If there is no options object given, or no sandboxName property
// specified, use the caller's filename as sandboxName.
if (sandboxName.IsEmpty()) {
nsXPConnect* xpc = nsXPConnect::GetXPConnect();
if (!xpc)
return ThrowAndFail(NS_ERROR_XPC_UNEXPECTED, cx, _retval);
// Get the xpconnect native call context.
nsAXPCNativeCallContext *cc = nsnull;
xpc->GetCurrentNativeCallContext(&cc);
if (!cc)
return ThrowAndFail(NS_ERROR_INVALID_ARG, cx, _retval);
// Get the current source info from xpc.
nsCOMPtr<nsIStackFrame> frame;
xpc->GetCurrentJSStack(getter_AddRefs(frame));
if (frame)
frame->GetFilename(getter_Copies(sandboxName));
}
rv = xpc_CreateSandboxObject(cx, vp, prinOrSop, proto, wantXrays, sandboxName, identity);
if (NS_FAILED(rv)) {
@ -3672,12 +3695,12 @@ nsXPCComponents_Utils::NondeterministicGetWeakMapKeys(const jsval &aMap,
JSContext *aCx,
jsval *aKeys)
{
if(!JSVAL_IS_OBJECT(aMap)) {
if (!JSVAL_IS_OBJECT(aMap)) {
*aKeys = JSVAL_VOID;
return NS_OK;
}
JSObject *objRet;
if(!JS_NondeterministicGetWeakMapKeys(aCx, JSVAL_TO_OBJECT(aMap), &objRet))
if (!JS_NondeterministicGetWeakMapKeys(aCx, JSVAL_TO_OBJECT(aMap), &objRet))
return NS_ERROR_OUT_OF_MEMORY;
*aKeys = objRet ? OBJECT_TO_JSVAL(objRet) : JSVAL_VOID;
return NS_OK;

View File

@ -36,7 +36,8 @@ function go() {
f().cross_origin_property;
ok(false, "should have thrown an exception");
} catch (e) {
ok(/Permission denied/.test(e), "threw the correct exception");
ok(/Permission denied/.test(e) || /attempt to run compile-and-go script/.test(e),
"threw the correct exception");
}
SimpleTest.finish();
break;

View File

@ -93,6 +93,7 @@ SHARED_LIBRARY_LIBS = \
$(DEPTH)/view/src/$(LIB_PREFIX)gkview_s.$(LIB_SUFFIX) \
$(DEPTH)/dom/base/$(LIB_PREFIX)jsdombase_s.$(LIB_SUFFIX) \
$(DEPTH)/dom/battery/$(LIB_PREFIX)dom_battery_s.$(LIB_SUFFIX) \
$(DEPTH)/dom/power/$(LIB_PREFIX)dom_power_s.$(LIB_SUFFIX) \
$(DEPTH)/dom/network/src/$(LIB_PREFIX)dom_network_s.$(LIB_SUFFIX) \
$(DEPTH)/dom/sms/src/$(LIB_PREFIX)dom_sms_s.$(LIB_SUFFIX) \
$(DEPTH)/dom/src/events/$(LIB_PREFIX)jsdomevents_s.$(LIB_SUFFIX) \

View File

@ -253,9 +253,14 @@ static void Shutdown();
#include "nsISmsService.h"
#include "nsISmsDatabaseService.h"
#include "mozilla/dom/sms/SmsServicesFactory.h"
#include "nsIPowerManagerService.h"
using namespace mozilla::dom::sms;
#include "mozilla/dom/power/PowerManagerService.h"
using mozilla::dom::power::PowerManagerService;
// Transformiix
/* 5d5d92cd-6bf8-11d9-bf4a-000a95dc234c */
#define TRANSFORMIIX_NODESET_CID \
@ -302,6 +307,8 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsHapticFeedback)
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(ThirdPartyUtil, Init)
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsISmsService, SmsServicesFactory::CreateSmsService)
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsISmsDatabaseService, SmsServicesFactory::CreateSmsDatabaseService)
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIPowerManagerService,
PowerManagerService::GetInstance)
//-----------------------------------------------------------------------------
@ -793,6 +800,7 @@ NS_DEFINE_NAMED_CID(NS_HAPTICFEEDBACK_CID);
#endif
NS_DEFINE_NAMED_CID(SMS_SERVICE_CID);
NS_DEFINE_NAMED_CID(SMS_DATABASE_SERVICE_CID);
NS_DEFINE_NAMED_CID(NS_POWERMANAGERSERVICE_CID);
static nsresult
CreateWindowCommandTableConstructor(nsISupports *aOuter,
@ -1063,6 +1071,7 @@ static const mozilla::Module::CIDEntry kLayoutCIDs[] = {
{ &kNS_STRUCTUREDCLONECONTAINER_CID, false, NULL, nsStructuredCloneContainerConstructor },
{ &kSMS_SERVICE_CID, false, NULL, nsISmsServiceConstructor },
{ &kSMS_DATABASE_SERVICE_CID, false, NULL, nsISmsDatabaseServiceConstructor },
{ &kNS_POWERMANAGERSERVICE_CID, false, NULL, nsIPowerManagerServiceConstructor },
{ NULL }
};
@ -1198,6 +1207,7 @@ static const mozilla::Module::ContractIDEntry kLayoutContracts[] = {
{ NS_STRUCTUREDCLONECONTAINER_CONTRACTID, &kNS_STRUCTUREDCLONECONTAINER_CID },
{ SMS_SERVICE_CONTRACTID, &kSMS_SERVICE_CID },
{ SMS_DATABASE_SERVICE_CONTRACTID, &kSMS_DATABASE_SERVICE_CID },
{ POWERMANAGERSERVICE_CONTRACTID, &kNS_POWERMANAGERSERVICE_CID },
{ NULL }
};

View File

@ -4,6 +4,6 @@
<meta charset="utf-8">
</head>
<body>
<div>&#x062A;<span>&#x0661;&#x0663;</span></div>
<div>&#x062A;<span>&#x0661;</span><span>&#x0663;</span></div>
</body>
</html>

View File

@ -4,6 +4,6 @@
<meta charset="utf-8">
</head>
<body>
<div><span>&#x0661;&#x0663;</span>&#x062A;</div>
<div><span>&#x0661;</span><span>&#x0663;</span>&#x062A;</div>
</body>
</html>

View File

@ -4,6 +4,6 @@
<meta charset="utf-8">
</head>
<body>
<div><span>&#x0661;&#x0663;</span></div>
<div><span>&#x0661;</span><span>&#x0663;</span></div>
</body>
</html>

View File

@ -137,6 +137,7 @@ function load() {
ID("logentry").value = params.log;
log_pasted();
}
window.addEventListener('keypress', maybe_load_image, false);
}
function build_mag() {
@ -374,6 +375,19 @@ function show_image(i) {
}
}
function maybe_load_image(event) {
switch (event.charCode) {
case 49: // "1" key
document.getElementById("radio1").checked = true;
show_image(1);
break;
case 50: // "2" key
document.getElementById("radio2").checked = true;
show_image(2);
break;
}
}
function show_differences(cb) {
ID("diffrect").style.display = cb.checked ? "" : "none";
}
@ -513,8 +527,8 @@ function show_pixelinfo(x, y, pix1rgb, pix1hex, pix2rgb, pix2hex) {
<div id="itemlist"></div>
<div id="images" style="display:none">
<form id="imgcontrols">
<label><input type="radio" name="which" value="0" onchange="show_image(1)" checked="checked" />Image 1</label>
<label><input type="radio" name="which" value="1" onchange="show_image(2)" />Image 2</label>
<label title="1"><input id="radio1" type="radio" name="which" value="0" onchange="show_image(1)" checked="checked" />Image 1</label>
<label title="2"><input id="radio2" type="radio" name="which" value="1" onchange="show_image(2)" />Image 2</label>
<label><input type="checkbox" onchange="show_differences(this)" />Circle differences</label>
</form>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="800px" height="1000px" viewBox="0 0 800 1000" id="svg">

View File

@ -40,6 +40,7 @@
package org.mozilla.gecko;
import org.mozilla.gecko.db.BrowserDB;
import org.mozilla.gecko.gfx.FloatSize;
import org.mozilla.gecko.gfx.GeckoSoftwareLayerClient;
import org.mozilla.gecko.gfx.IntSize;
@ -150,8 +151,6 @@ abstract public class GeckoApp
public int mOwnActivityDepth = 0;
private boolean mRestoreSession = false;
private Vector<View> mPluginViews = new Vector<View>();
public interface OnTabsChangedListener {
public void onTabsChanged(Tab tab);
}
@ -598,6 +597,13 @@ abstract public class GeckoApp
bitmap.compress(Bitmap.CompressFormat.PNG, 0, bos);
processThumbnail(tab, bitmap, bos.toByteArray());
} else {
if (!tab.hasLoaded()) {
byte[] thumbnail = BrowserDB.getThumbnailForUrl(getContentResolver(), tab.getURL());
if (thumbnail != null)
processThumbnail(tab, null, thumbnail);
return;
}
mLastScreen = null;
int sw = forceBigSceenshot ? mSoftwareLayerClient.getWidth() : tab.getMinScreenshotWidth();
int sh = forceBigSceenshot ? mSoftwareLayerClient.getHeight(): tab.getMinScreenshotHeight();
@ -741,6 +747,9 @@ abstract public class GeckoApp
mDoorHangerPopup.updatePopup();
mBrowserToolbar.setShadowVisibility(!(tab.getURL().startsWith("about:")));
mLayerController.setWaitForTouchListeners(false);
if (tab != null)
hidePluginViews(tab);
}
}
});
@ -1289,6 +1298,7 @@ abstract public class GeckoApp
return;
tab.updateTitle(title);
tab.setHasLoaded(true);
// Make the UI changes
mMainHandler.post(new Runnable() {
@ -1367,6 +1377,12 @@ abstract public class GeckoApp
JSONObject viewportObject;
ViewportMetrics pluginViewport;
Tabs tabs = Tabs.getInstance();
Tab tab = tabs.getSelectedTab();
if (tab == null)
return;
ViewportMetrics targetViewport = mLayerController.getViewportMetrics();
try {
@ -1389,13 +1405,14 @@ abstract public class GeckoApp
}
mPluginContainer.addView(view, lp);
mPluginViews.add(view);
tab.addPluginView(view);
} else {
lp = (PluginLayoutParams)view.getLayoutParams();
lp.reset(x, y, w, h, pluginViewport);
lp.reposition(targetViewport);
try {
mPluginContainer.updateViewLayout(view, lp);
view.setVisibility(View.VISIBLE);
} catch (IllegalArgumentException e) {
Log.i(LOGTAG, "e:" + e);
// it can be the case where we
@ -1412,14 +1429,30 @@ abstract public class GeckoApp
public void run() {
try {
mPluginContainer.removeView(view);
mPluginViews.remove(view);
Tabs tabs = Tabs.getInstance();
Tab tab = tabs.getSelectedTab();
if (tab == null)
return;
tab.removePluginView(view);
} catch (Exception e) {}
}
});
}
public void hidePluginViews() {
for (View view : mPluginViews) {
Tabs tabs = Tabs.getInstance();
Tab tab = tabs.getSelectedTab();
if (tab == null)
return;
hidePluginViews(tab);
}
public void hidePluginViews(Tab tab) {
for (View view : tab.getPluginViews()) {
view.setVisibility(View.GONE);
}
}
@ -1428,13 +1461,27 @@ abstract public class GeckoApp
repositionPluginViews(true);
}
public void showPluginViews(Tab tab) {
repositionPluginViews(tab, true);
}
public void repositionPluginViews(boolean setVisible) {
Tabs tabs = Tabs.getInstance();
Tab tab = tabs.getSelectedTab();
if (tab == null)
return;
repositionPluginViews(tab, setVisible);
}
public void repositionPluginViews(Tab tab, boolean setVisible) {
ViewportMetrics targetViewport = mLayerController.getViewportMetrics();
if (targetViewport == null)
return;
for (View view : mPluginViews) {
for (View view : tab.getPluginViews()) {
PluginLayoutParams lp = (PluginLayoutParams)view.getLayoutParams();
lp.reposition(targetViewport);

View File

@ -44,6 +44,7 @@ import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import org.json.JSONException;
import org.json.JSONObject;
@ -81,6 +82,8 @@ public final class Tab {
private String mDocumentURI;
private String mContentType;
private boolean mHasTouchListeners;
private ArrayList<View> mPluginViews;
private boolean mHasLoaded;
public static final class HistoryEntry {
public String mUri; // must never be null
@ -113,6 +116,8 @@ public final class Tab {
mFaviconLoadId = 0;
mDocumentURI = "";
mContentType = "";
mPluginViews = new ArrayList<View>();
mHasLoaded = false;
}
public int getId() {
@ -433,6 +438,14 @@ public final class Tab {
return mDoorHangers;
}
public void setHasLoaded(boolean hasLoaded) {
mHasLoaded = hasLoaded;
}
public boolean hasLoaded() {
return mHasLoaded;
}
void handleSessionHistoryMessage(String event, JSONObject message) throws JSONException {
if (event.equals("New")) {
final String uri = message.getString("uri");
@ -543,4 +556,16 @@ public final class Tab {
setBookmark(false);
}
}
public void addPluginView(View view) {
mPluginViews.add(view);
}
public void removePluginView(View view) {
mPluginViews.remove(view);
}
public View[] getPluginViews() {
return mPluginViews.toArray(new View[mPluginViews.size()]);
}
}

View File

@ -111,6 +111,7 @@ public class Tabs implements GeckoEventListener {
if (!tabs.containsKey(id))
return null;
final Tab oldTab = getSelectedTab();
final Tab tab = tabs.get(id);
// This avoids a NPE below, but callers need to be careful to
// handle this case
@ -133,6 +134,9 @@ public class Tabs implements GeckoEventListener {
GeckoApp.mBrowserToolbar.setProgressVisibility(tab.isLoading());
GeckoApp.mDoorHangerPopup.updatePopup();
GeckoApp.mBrowserToolbar.setShadowVisibility(!(tab.getURL().startsWith("about:")));
if (oldTab != null)
GeckoApp.mAppContext.hidePluginViews(oldTab);
}
}
});
@ -196,6 +200,7 @@ public class Tabs implements GeckoEventListener {
GeckoApp.mAppContext.onTabsChanged(closedTab);
GeckoApp.mBrowserToolbar.updateTabs(Tabs.getInstance().getCount());
GeckoApp.mDoorHangerPopup.updatePopup();
GeckoApp.mAppContext.hidePluginViews(closedTab);
}
});
@ -272,6 +277,8 @@ public class Tabs implements GeckoEventListener {
Tab tab = addTab(message);
if (message.getBoolean("selected"))
selectTab(tab.getId());
if (message.getBoolean("delayLoad"))
tab.setHasLoaded(false);
} else if (event.equals("Tab:Close")) {
Tab tab = getTab(message.getInt("tabID"));
closeTab(tab);
@ -279,7 +286,10 @@ public class Tabs implements GeckoEventListener {
selectTab(message.getInt("tabID"));
} else if (event.equals("Tab:ScreenshotData")) {
Tab tab = getTab(message.getInt("tabID"));
byte[] compressed = Base64.decode(message.getString("data").substring(22), Base64.DEFAULT);
String data = message.getString("data");
if (data.length() < 22)
return;
byte[] compressed = Base64.decode(data.substring(22), Base64.DEFAULT);
GeckoApp.mAppContext.processThumbnail(tab, null, compressed);
}
} catch (Exception e) {

View File

@ -369,6 +369,26 @@ public class AndroidBrowserDB implements BrowserDB.BrowserDBIface {
cr.insert(Browser.BOOKMARKS_URI, values);
}
public byte[] getThumbnailForUrl(ContentResolver cr, String uri) {
Cursor c = cr.query(Browser.BOOKMARKS_URI,
new String[] { URL_COLUMN_THUMBNAIL },
Browser.BookmarkColumns.URL + " = ?",
new String[] { uri },
null);
if (!c.moveToFirst()) {
c.close();
return null;
}
int thumbnailIndex = c.getColumnIndexOrThrow(URL_COLUMN_THUMBNAIL);
byte[] b = c.getBlob(thumbnailIndex);
c.close();
return b;
}
private static class AndroidDBCursor extends CursorWrapper {
public AndroidDBCursor(Cursor c) {
super(c);

View File

@ -88,6 +88,8 @@ public class BrowserDB {
public void updateFaviconForUrl(ContentResolver cr, String uri, BitmapDrawable favicon);
public void updateThumbnailForUrl(ContentResolver cr, String uri, BitmapDrawable thumbnail);
public byte[] getThumbnailForUrl(ContentResolver cr, String uri);
}
static {
@ -159,4 +161,8 @@ public class BrowserDB {
public static void updateThumbnailForUrl(ContentResolver cr, String uri, BitmapDrawable thumbnail) {
sDb.updateThumbnailForUrl(cr, uri, thumbnail);
}
public static byte[] getThumbnailForUrl(ContentResolver cr, String uri) {
return sDb.getThumbnailForUrl(cr, uri);
}
}

View File

@ -412,6 +412,26 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface {
cr.insert(appendProfile(Images.CONTENT_URI), values);
}
public byte[] getThumbnailForUrl(ContentResolver cr, String uri) {
Cursor c = cr.query(appendProfile(Images.CONTENT_URI),
new String[] { Images.THUMBNAIL },
Images.URL + " = ?",
new String[] { uri },
null);
if (!c.moveToFirst()) {
c.close();
return null;
}
int thumbnailIndex = c.getColumnIndexOrThrow(Images.THUMBNAIL);
byte[] b = c.getBlob(thumbnailIndex);
c.close();
return b;
}
private static class LocalDBCursor extends CursorWrapper {
public LocalDBCursor(Cursor c) {
super(c);

View File

@ -20,7 +20,7 @@
</view>
<LinearLayout android:layout_width="4dp"
android:layout_height="match_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:layout_alignParentRight="true"/>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<org.mozilla.gecko.AwesomeBarTabs xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/awesomebar_tabs"
android:layout_width="match_parent"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<LinearLayout android:orientation="vertical"

View File

@ -2,7 +2,7 @@
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<TextView android:id="@+id/doorhanger_title"
android:layout_width="match_parent"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorPrimary"
@ -10,7 +10,7 @@
<LinearLayout android:id="@+id/doorhanger_choices"
style="@android:style/ButtonBar"
android:layout_width="match_parent"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"/>

View File

@ -1,15 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<ScrollView android:layout_width="match_parent"
<ScrollView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dip"
android:layout_alignParentTop="true">
<LinearLayout android:id="@+id/doorhanger_container"
android:layout_width="match_parent"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@drawable/doorhanger_popup_bg"/>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:paddingLeft="16dip"
android:paddingRight="16dip"
@ -16,8 +16,8 @@
android:scaleType="fitCenter"/>
<TextView android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_vertical"
android:textAppearance="?android:attr/textAppearanceLargeInverse"
android:ellipsize="marquee"

View File

@ -3,8 +3,8 @@
<view xmlns:android="http://schemas.android.com/apk/res/android"
class="android.widget.ListView"
android:id="@+id/select_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:cacheColorHint="@null"
android:scrollbars="vertical"
android:overScrollMode="ifContentScrolls" />

View File

@ -1,5 +1,5 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
@ -8,7 +8,7 @@
<TextView android:id="@+id/title"
style="?android:attr/windowTitleStyle"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_width="match_parent"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingTop="6dip"
android:paddingBottom="0dip"
@ -18,7 +18,7 @@
<TextView android:id="@+id/host"
style="?android:attr/windowTitleStyle"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="match_parent"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingTop="2dip"
android:paddingBottom="6dip"

View File

@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<view class="org.mozilla.gecko.TabsTray$TabsListContainer"
android:layout_width="match_parent"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@drawable/tabs_tray_bg_repeat">
@ -15,12 +15,12 @@
style="@style/TabsList"
android:divider="@drawable/tabs_tray_list_divider"/>
<LinearLayout android:layout_width="match_parent"
<LinearLayout android:layout_width="fill_parent"
android:layout_height="2dp"
android:background="@drawable/tabs_tray_list_divider"/>
<LinearLayout android:id="@+id/add_tab"
android:layout_width="match_parent"
android:layout_width="fill_parent"
android:layout_height="50dip"
android:orientation="horizontal"
android:gravity="center|left"

View File

@ -8,21 +8,21 @@
<!-- BrowserToolbar -->
<style name="BrowserToolbar">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">match_parent</item>
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">fill_parent</item>
<item name="android:orientation">vertical</item>
</style>
<!-- Address bar -->
<style name="AddressBar">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">match_parent</item>
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">fill_parent</item>
<item name="android:orientation">horizontal</item>
</style>
<!-- Lists in AwesomeBar -->
<style name="AwesomeBarList" parent="android:style/Widget.Holo.ListView">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">fill_parent</item>
<item name="android:layout_weight">1</item>
</style>

View File

@ -3,8 +3,8 @@
<!-- Layout -->
<style name="Layout">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">match_parent</item>
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">fill_parent</item>
</style>
<!-- Horizontal Layout -->
@ -29,7 +29,7 @@
<!-- BrowserToolbar -->
<style name="BrowserToolbar">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:orientation">vertical</item>
<item name="android:background">#000000</item>
@ -37,14 +37,14 @@
<!-- Address bar -->
<style name="AddressBar">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">42dip</item>
<item name="android:orientation">horizontal</item>
</style>
<!-- Address bar - Button -->
<style name="AddressBar.Button">
<item name="android:layout_height">match_parent</item>
<item name="android:layout_height">fill_parent</item>
<item name="android:textSize">16sp</item>
<item name="android:background">@android:color/transparent</item>
</style>
@ -57,21 +57,21 @@
<!-- Lists in AwesomeBar -->
<style name="AwesomeBarList" parent="android:style/Widget.ListView.White">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">fill_parent</item>
<item name="android:layout_weight">1</item>
</style>
<!-- Lists in TabsTray -->
<style name="TabsList" parent="android:style/Widget.ListView">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">fill_parent</item>
<item name="android:layout_weight">1</item>
</style>
<!-- TabWidget -->
<style name="TabWidget">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">48dip</item>
<item name="android:background">@drawable/tabs_tray_bg_repeat</item>
</style>

View File

@ -381,10 +381,14 @@ var BrowserApp = {
},
set selectedTab(aTab) {
if (this._selectedTab)
this._selectedTab.setActive(false);
this._selectedTab = aTab;
if (!aTab)
return;
aTab.setActive(true);
aTab.updateViewport(false);
this.deck.selectedPanel = aTab.vbox;
},
@ -474,7 +478,9 @@ var BrowserApp = {
let newTab = new Tab(aURI, aParams);
this._tabs.push(newTab);
newTab.active = "selected" in aParams ? aParams.selected : true;
let selected = "selected" in aParams ? aParams.selected : true;
if (selected)
this.selectedTab = newTab;
let evt = document.createEvent("UIEvents");
evt.initUIEvent("TabOpen", true, false, window, null);
@ -566,12 +572,11 @@ var BrowserApp = {
// This method updates the state in BrowserApp after a tab has been selected
// in the Java UI.
_handleTabSelected: function _handleTabSelected(aTab) {
this.selectedTab = aTab;
aTab.active = true;
this.selectedTab = aTab;
let evt = document.createEvent("UIEvents");
evt.initUIEvent("TabSelect", true, false, window, null);
aTab.browser.dispatchEvent(evt);
let evt = document.createEvent("UIEvents");
evt.initUIEvent("TabSelect", true, false, window, null);
aTab.browser.dispatchEvent(evt);
let message = {
gecko: {
@ -1419,7 +1424,7 @@ Tab.prototype = {
BrowserApp.deck.appendChild(this.vbox);
this.browser = document.createElement("browser");
this.browser.setAttribute("type", "content");
this.browser.setAttribute("type", "content-targetable");
this.setBrowserSize(980, 480);
this.browser.style.MozTransformOrigin = "0 0";
this.vbox.appendChild(this.browser);
@ -1440,7 +1445,8 @@ Tab.prototype = {
parentId: ("parentId" in aParams) ? aParams.parentId : -1,
external: ("external" in aParams) ? aParams.external : false,
selected: ("selected" in aParams) ? aParams.selected : true,
title: aParams.title || ""
title: aParams.title || "",
delayLoad: aParams.delayLoad || false
}
};
sendMessageToJava(message);
@ -1513,25 +1519,21 @@ Tab.prototype = {
this.documentIdForCurrentViewport = null;
},
set active(aActive) {
// This should be called to update the browser when the tab gets selected/unselected
setActive: function setActive(aActive) {
if (!this.browser)
return;
if (aActive) {
this.browser.setAttribute("type", "content-primary");
this.browser.focus();
BrowserApp.selectedTab = this;
this.browser.docShellIsActive = true;
} else {
this.browser.setAttribute("type", "content");
this.browser.setAttribute("type", "content-targetable");
this.browser.docShellIsActive = false;
}
},
get active() {
if (!this.browser)
return false;
return this.browser.getAttribute("type") == "content-primary";
},
set viewport(aViewport) {
// Transform coordinates based on zoom
aViewport.x /= aViewport.zoom;

View File

@ -19,6 +19,7 @@
*
* Contributor(s):
* Mark 'evil' Finkle <mfinkle@mozilla.com>
* Brian Nicholson <bnicholson@mozilla.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
@ -457,7 +458,7 @@ SessionStore.prototype = {
if (aBrowser.__SS_restore) {
let data = aBrowser.__SS_data;
if (data.entries.length > 0)
aBrowser.loadURI(data.entries[data.index - 1].url);
this._restoreHistory(data, aBrowser.sessionHistory);
delete aBrowser.__SS_restore;
}
@ -977,21 +978,22 @@ SessionStore.prototype = {
for (let i=0; i<tabs.length; i++) {
let tabData = tabs[i];
let isSelected = (i + 1 <= selected) && aBringToFront;
let isSelected = (i + 1 == selected) && aBringToFront;
let entry = tabData.entries[tabData.index - 1];
// Add a tab, but don't load the URL until we need to
let params = { selected: isSelected, delayLoad: !isSelected, title: entry.title };
let params = { selected: isSelected, delayLoad: true, title: entry.title };
let tab = window.BrowserApp.addTab(entry.url, params);
if (!isSelected) {
if (isSelected) {
self._restoreHistory(tabData, tab.browser.sessionHistory);
} else {
// Make sure the browser has its session data for the delay reload
tab.browser.__SS_data = tabData;
tab.browser.__SS_restore = true;
}
tab.browser.__SS_extdata = tabData.extData;
self._restoreHistory(tabData, tab.browser.sessionHistory);
}
notifyObservers();

View File

@ -0,0 +1,563 @@
/* -*- Mode: C++; tab-width: 8; 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 "base/basictypes.h"
#include "GonkCaptureProvider.h"
#include "nsXULAppAPI.h"
#include "nsStreamUtils.h"
#include "nsThreadUtils.h"
#include "nsRawStructs.h"
#define USE_GS2_LIBCAMERA
#define CameraHardwareInterface CameraHardwareInterface_SGS2
#define HAL_openCameraHardware HAL_openCameraHardware_SGS2
#include "camera/CameraHardwareInterface.h"
#undef CameraHardwareInterface
#undef USE_GS2_LIBCAMERA
#undef HAL_openCameraHardware
#undef ANDROID_HARDWARE_CAMERA_HARDWARE_INTERFACE_H
// Needed to prevent a redefinition of 'struct android::image_rect_struct'...
#define image_rect_type image_rect_type2
#define image_rect_struct image_rect_struct2
#define USE_MAGURO_LIBCAMERA
#define CameraHardwareInterface CameraHardwareInterface_MAGURO
#define HAL_openCameraHardware HAL_openCameraHardware_MAGURO
#include "camera/CameraHardwareInterface.h"
#undef CameraHardwareInterface
#undef USE_MAGURO_LIBCAMERA
#undef HAL_openCameraHardware
#undef ANDROID_HARDWARE_CAMERA_HARDWARE_INTERFACE_H
#undef image_rect_type
#undef image_rect_struct
#define image_rect_type image_rect_type3
#define image_rect_struct image_rect_struct3
#define CameraHardwareInterface CameraHardwareInterface_DEFAULT
#include "camera/CameraHardwareInterface.h"
#undef CameraHardwareInterface
#include <dlfcn.h>
#include "cutils/properties.h"
using namespace android;
using namespace mozilla;
class CameraHardwareInterface {
public:
typedef enum {
CAMERA_SGS2,
CAMERA_MAGURO,
CAMERA_DEFAULT
} Type;
static Type getType() {
char propValue[PROPERTY_VALUE_MAX];
property_get("ro.product.board", propValue, NULL);
if (!strcmp(propValue, "GT-I9100"))
return CAMERA_SGS2;
if (!strcmp(propValue, "MSM7627A_SKU1"))
return CAMERA_MAGURO;
printf_stderr("CameraHardwareInterface : unsupported camera for device %s\n", propValue);
return CAMERA_DEFAULT;
}
static CameraHardwareInterface* openCamera(PRUint32 aCamera);
virtual ~CameraHardwareInterface() { };
virtual bool ok();
virtual void enableMsgType(int32_t msgType);
virtual void disableMsgType(int32_t msgType);
virtual bool msgTypeEnabled(int32_t msgType);
virtual void setCallbacks(notify_callback notify_cb,
data_callback data_cb,
data_callback_timestamp data_cb_timestamp,
void* user);
virtual status_t startPreview();
virtual void stopPreview();
virtual void release();
virtual status_t setParameters(const CameraParameters& params);
virtual CameraParameters getParameters() const;
protected:
CameraHardwareInterface(PRUint32 aCamera = 0) { };
};
class DlopenWrapper {
public:
DlopenWrapper() : mHandle(nsnull) { };
DlopenWrapper(const char* aLibrary) : mHandle(nsnull) {
mHandle = dlopen(aLibrary, RTLD_LAZY);
};
~DlopenWrapper() {
if (mHandle)
dlclose(mHandle);
};
bool opened() {
return mHandle != nsnull;
};
void* dlsym(const char* aFunction) {
return ::dlsym(mHandle, aFunction);
};
protected:
void* mHandle;
};
template<class T> class CameraImpl : public CameraHardwareInterface {
public:
typedef sp<T> (*HAL_openCameraHardware_DEFAULT)(int);
typedef sp<T> (*HAL_openCameraHardware_SGS2)(int);
typedef sp<T> (*HAL_openCameraHardware_MAGURO)(int, int);
CameraImpl(PRUint32 aCamera = 0) : mOk(false), mCamera(nsnull) {
DlopenWrapper wrapper("system/lib/libcamera.so");
if (!wrapper.opened())
return;
mOk = true;
void *hal = wrapper.dlsym("HAL_openCameraHardware");
HAL_openCameraHardware_DEFAULT funct0;
HAL_openCameraHardware_SGS2 funct1;
HAL_openCameraHardware_MAGURO funct2;
switch(getType()) {
case CAMERA_SGS2:
funct1 = reinterpret_cast<HAL_openCameraHardware_SGS2> (hal);
mCamera = funct1(aCamera);
break;
case CAMERA_MAGURO:
funct2 = reinterpret_cast<HAL_openCameraHardware_MAGURO> (hal);
mCamera = funct2(aCamera, 1);
break;
case CAMERA_DEFAULT:
funct0 = reinterpret_cast<HAL_openCameraHardware_DEFAULT> (hal);
mCamera = funct0(aCamera);
break;
}
}
bool ok() {
return mOk;
};
void enableMsgType(int32_t msgType) {
mCamera->enableMsgType(msgType);
};
void disableMsgType(int32_t msgType) {
mCamera->disableMsgType(msgType);
};
bool msgTypeEnabled(int32_t msgType) {
return mCamera->msgTypeEnabled(msgType);
};
void setCallbacks(notify_callback notify_cb,
data_callback data_cb,
data_callback_timestamp data_cb_timestamp,
void* user) {
mCamera->setCallbacks(notify_cb, data_cb, data_cb_timestamp, user);
};
status_t startPreview() {
return mCamera->startPreview();
};
void stopPreview() {
mCamera->stopPreview();
};
void release() {
return mCamera->release();
};
status_t setParameters(const CameraParameters& params) {
return mCamera->setParameters(params);
}
CameraParameters getParameters() const {
return mCamera->getParameters();
};
protected:
bool mOk;
sp<T> mCamera;
};
CameraHardwareInterface* CameraHardwareInterface::openCamera(PRUint32 aCamera) {
nsAutoPtr<CameraHardwareInterface> instance;
switch(getType()) {
case CAMERA_SGS2:
instance = new CameraImpl<CameraHardwareInterface_SGS2>(aCamera);
break;
case CAMERA_MAGURO:
instance = new CameraImpl<CameraHardwareInterface_MAGURO>(aCamera);
break;
case CAMERA_DEFAULT:
instance = new CameraImpl<CameraHardwareInterface_DEFAULT>(aCamera);
break;
}
if (!instance->ok()) {
return nsnull;
}
return instance.forget();
};
// The maximum number of frames we keep in our queue. Don't live in the past.
#define MAX_FRAMES_QUEUED 5
NS_IMPL_THREADSAFE_ISUPPORTS2(GonkCameraInputStream, nsIInputStream, nsIAsyncInputStream)
GonkCameraInputStream::GonkCameraInputStream() :
mAvailable(sizeof(nsRawVideoHeader)), mWidth(0), mHeight(0), mFps(30), mCamera(0),
mHeaderSent(false), mClosed(true), mIs420p(false), mFrameSize(0), mMonitor("GonkCamera.Monitor")
{
}
GonkCameraInputStream::~GonkCameraInputStream() {
// clear the frame queue
while (mFrameQueue.GetSize() > 0) {
free(mFrameQueue.PopFront());
}
// no need to close Close() since the stream is opened here :
// http://mxr.mozilla.org/mozilla-central/source/netwerk/base/src/nsBaseChannel.cpp#239
// and this leads to http://mxr.mozilla.org/mozilla-central/source/netwerk/base/src/nsBaseChannel.cpp#259
// that creates and input pump with closeWhenDone == true
// the pump cleans up properly at http://mxr.mozilla.org/mozilla-central/source/netwerk/base/src/nsInputStreamPump.cpp#565
}
void
GonkCameraInputStream::DataCallback(int32_t aMsgType, const sp<IMemory>& aDataPtr, void *aUser) {
GonkCameraInputStream* stream = (GonkCameraInputStream*)(aUser);
stream->ReceiveFrame((char*)aDataPtr->pointer(), aDataPtr->size());
}
NS_IMETHODIMP
GonkCameraInputStream::Init(nsACString& aContentType, nsCaptureParams* aParams)
{
if (XRE_GetProcessType() != GeckoProcessType_Default)
return NS_ERROR_NOT_IMPLEMENTED;
mContentType = aContentType;
mWidth = aParams->width;
mHeight = aParams->height;
mCamera = aParams->camera;
PRUint32 maxCameras = HAL_getNumberOfCameras();
if (mCamera >= maxCameras)
mCamera = maxCameras - 1;
mHardware = CameraHardwareInterface::openCamera(mCamera);
if (!mHardware)
return NS_ERROR_FAILURE;
mHardware->setCallbacks(NULL, GonkCameraInputStream::DataCallback, NULL, this);
mHardware->enableMsgType(CAMERA_MSG_PREVIEW_FRAME);
CameraParameters params = mHardware->getParameters();
printf_stderr("Preview format : %s\n", params.get(params.KEY_SUPPORTED_PREVIEW_FORMATS));
Vector<Size> previewSizes;
params.getSupportedPreviewSizes(previewSizes);
// find the available preview size closest to the requested size.
PRUint32 minSizeDelta = PR_UINT32_MAX;
PRUint32 bestWidth = mWidth;
PRUint32 bestHeight = mHeight;
for (PRUint32 i = 0; i < previewSizes.size(); i++) {
Size size = previewSizes[i];
PRUint32 delta = abs(size.width * size.height - mWidth * mHeight);
if (delta < minSizeDelta) {
minSizeDelta = delta;
bestWidth = size.width;
bestHeight = size.height;
}
}
mWidth = bestWidth;
mHeight = bestHeight;
params.setPreviewSize(mWidth, mHeight);
// try to set preferred image format
params.setPreviewFormat("yuv420p");
params.setPreviewFrameRate(mFps);
mHardware->setParameters(params);
params = mHardware->getParameters();
mFps = params.getPreviewFrameRate();
mIs420p = !strcmp(params.getPreviewFormat(), "yuv420p");
mHardware->startPreview();
mClosed = false;
return NS_OK;
}
void
GonkCameraInputStream::ReceiveFrame(char* frame, PRUint32 length) {
{
ReentrantMonitorAutoEnter enter(mMonitor);
if (mFrameQueue.GetSize() > MAX_FRAMES_QUEUED) {
free(mFrameQueue.PopFront());
mAvailable -= mFrameSize;
}
}
mFrameSize = sizeof(nsRawPacketHeader) + length;
char* fullFrame = (char*)moz_malloc(mFrameSize);
if (!fullFrame)
return;
nsRawPacketHeader* header = reinterpret_cast<nsRawPacketHeader*> (fullFrame);
header->packetID = 0xFF;
header->codecID = RAW_ID;
if (mIs420p) {
memcpy(fullFrame + sizeof(nsRawPacketHeader), frame, length);
} else {
// we copy the Y plane, and de-interlace the CrCb
PRUint32 yFrameSize = mWidth * mHeight;
PRUint32 uvFrameSize = yFrameSize / 4;
memcpy(fullFrame + sizeof(nsRawPacketHeader), frame, yFrameSize);
char* uFrame = fullFrame + sizeof(nsRawPacketHeader) + yFrameSize;
char* vFrame = fullFrame + sizeof(nsRawPacketHeader) + yFrameSize + uvFrameSize;
const char* yFrame = frame + yFrameSize;
for (PRUint32 i = 0; i < uvFrameSize; i++) {
uFrame[i] = yFrame[2 * i + 1];
vFrame[i] = yFrame[2 * i];
}
}
{
ReentrantMonitorAutoEnter enter(mMonitor);
mAvailable += mFrameSize;
mFrameQueue.Push((void*)fullFrame);
}
NotifyListeners();
}
NS_IMETHODIMP
GonkCameraInputStream::Available(PRUint32 *aAvailable)
{
ReentrantMonitorAutoEnter enter(mMonitor);
*aAvailable = mAvailable;
return NS_OK;
}
NS_IMETHODIMP GonkCameraInputStream::IsNonBlocking(bool *aNonBlock) {
*aNonBlock = true;
return NS_OK;
}
NS_IMETHODIMP GonkCameraInputStream::Read(char *aBuffer, PRUint32 aCount, PRUint32 *aRead NS_OUTPARAM) {
return ReadSegments(NS_CopySegmentToBuffer, aBuffer, aCount, aRead);
}
NS_IMETHODIMP GonkCameraInputStream::ReadSegments(nsWriteSegmentFun aWriter, void *aClosure, PRUint32 aCount, PRUint32 *aRead NS_OUTPARAM) {
*aRead = 0;
nsresult rv;
if (mAvailable == 0)
return NS_BASE_STREAM_WOULD_BLOCK;
if (aCount > mAvailable)
aCount = mAvailable;
if (!mHeaderSent) {
nsRawVideoHeader header;
header.headerPacketID = 0;
header.codecID = RAW_ID;
header.majorVersion = 0;
header.minorVersion = 1;
header.options = 1 | 1 << 1; // color, 4:2:0
header.alphaChannelBpp = 0;
header.lumaChannelBpp = 8;
header.chromaChannelBpp = 4;
header.colorspace = 1;
header.frameWidth = mWidth;
header.frameHeight = mHeight;
header.aspectNumerator = 1;
header.aspectDenominator = 1;
header.framerateNumerator = mFps;
header.framerateDenominator = 1;
rv = aWriter(this, aClosure, (const char*)&header, 0, sizeof(nsRawVideoHeader), aRead);
if (NS_FAILED(rv))
return NS_OK;
mHeaderSent = true;
aCount -= sizeof(nsRawVideoHeader);
mAvailable -= sizeof(nsRawVideoHeader);
}
{
ReentrantMonitorAutoEnter enter(mMonitor);
while ((mAvailable > 0) && (aCount >= mFrameSize)) {
PRUint32 readThisTime = 0;
char* frame = (char*)mFrameQueue.PopFront();
rv = aWriter(this, aClosure, (const char*)frame, *aRead, mFrameSize, &readThisTime);
if (readThisTime != mFrameSize) {
mFrameQueue.PushFront((void*)frame);
return NS_OK;
}
// nsRawReader does a copy when calling VideoData::Create()
free(frame);
if (NS_FAILED(rv))
return NS_OK;
aCount -= readThisTime;
mAvailable -= readThisTime;
*aRead += readThisTime;
}
}
return NS_OK;
}
NS_IMETHODIMP GonkCameraInputStream::Close() {
return CloseWithStatus(NS_OK);
}
void GonkCameraInputStream::doClose() {
ReentrantMonitorAutoEnter enter(mMonitor);
if (mClosed)
return;
mHardware->disableMsgType(CAMERA_MSG_ALL_MSGS);
mHardware->stopPreview();
mHardware->release();
delete mHardware;
mClosed = true;
}
void GonkCameraInputStream::NotifyListeners() {
ReentrantMonitorAutoEnter enter(mMonitor);
if (mCallback && (mAvailable > sizeof(nsRawVideoHeader))) {
nsCOMPtr<nsIInputStreamCallback> callback;
if (mCallbackTarget) {
NS_NewInputStreamReadyEvent(getter_AddRefs(callback), mCallback, mCallbackTarget);
} else {
callback = mCallback;
}
NS_ASSERTION(callback, "Shouldn't fail to make the callback!");
// Null the callback first because OnInputStreamReady may reenter AsyncWait
mCallback = nsnull;
mCallbackTarget = nsnull;
callback->OnInputStreamReady(this);
}
}
NS_IMETHODIMP GonkCameraInputStream::AsyncWait(nsIInputStreamCallback *aCallback, PRUint32 aFlags, PRUint32 aRequestedCount, nsIEventTarget *aTarget)
{
if (aFlags != 0)
return NS_ERROR_NOT_IMPLEMENTED;
if (mCallback || mCallbackTarget)
return NS_ERROR_UNEXPECTED;
mCallbackTarget = aTarget;
mCallback = aCallback;
// What we are being asked for may be present already
NotifyListeners();
return NS_OK;
}
NS_IMETHODIMP GonkCameraInputStream::CloseWithStatus(PRUint32 status)
{
GonkCameraInputStream::doClose();
return NS_OK;
}
/**
* GonkCaptureProvider implementation
*/
NS_IMPL_ISUPPORTS0(GonkCaptureProvider)
GonkCaptureProvider* GonkCaptureProvider::sInstance = NULL;
GonkCaptureProvider::GonkCaptureProvider() {
}
GonkCaptureProvider::~GonkCaptureProvider() {
GonkCaptureProvider::sInstance = NULL;
}
nsresult GonkCaptureProvider::Init(nsACString& aContentType,
nsCaptureParams* aParams,
nsIInputStream** aStream) {
NS_ENSURE_ARG_POINTER(aParams);
NS_ASSERTION(aParams->frameLimit == 0 || aParams->timeLimit == 0,
"Cannot set both a frame limit and a time limit!");
nsRefPtr<GonkCameraInputStream> stream;
if (aContentType.EqualsLiteral("video/x-raw-yuv")) {
stream = new GonkCameraInputStream();
if (stream) {
nsresult rv = stream->Init(aContentType, aParams);
if (NS_FAILED(rv))
return rv;
}
else {
return NS_ERROR_OUT_OF_MEMORY;
}
} else {
NS_NOTREACHED("Should not have asked Gonk for this type!");
}
return CallQueryInterface(stream, aStream);
}
already_AddRefed<GonkCaptureProvider> GetGonkCaptureProvider() {
if (!GonkCaptureProvider::sInstance) {
GonkCaptureProvider::sInstance = new GonkCaptureProvider();
}
GonkCaptureProvider::sInstance->AddRef();
return GonkCaptureProvider::sInstance;
}

View File

@ -0,0 +1,74 @@
/* -*- Mode: C++; tab-width: 8; 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 GonkDeviceCaptureProvider_h_
#define GonkDeviceCaptureProvider_h_
#include "nsDeviceCaptureProvider.h"
#include "nsIAsyncInputStream.h"
#include "nsCOMPtr.h"
#include "nsAutoPtr.h"
#include "nsString.h"
#include "nsIEventTarget.h"
#include "nsDeque.h"
#include "mozilla/ReentrantMonitor.h"
#include "binder/IMemory.h"
using namespace android;
class CameraHardwareInterface;
class GonkCaptureProvider : public nsDeviceCaptureProvider {
public:
GonkCaptureProvider();
~GonkCaptureProvider();
NS_DECL_ISUPPORTS
nsresult Init(nsACString& aContentType, nsCaptureParams* aParams, nsIInputStream** aStream);
static GonkCaptureProvider* sInstance;
};
class GonkCameraInputStream : public nsIAsyncInputStream {
public:
GonkCameraInputStream();
~GonkCameraInputStream();
NS_IMETHODIMP Init(nsACString& aContentType, nsCaptureParams* aParams);
NS_DECL_ISUPPORTS
NS_DECL_NSIINPUTSTREAM
NS_DECL_NSIASYNCINPUTSTREAM
void ReceiveFrame(char* frame, PRUint32 length);
static void DataCallback(int32_t aMsgType, const sp<IMemory>& aDataPtr, void *aUser);
protected:
void NotifyListeners();
void doClose();
private:
PRUint32 mAvailable;
nsCString mContentType;
PRUint32 mWidth;
PRUint32 mHeight;
PRUint32 mFps;
PRUint32 mCamera;
bool mHeaderSent;
bool mClosed;
bool mIs420p;
nsDeque mFrameQueue;
PRUint32 mFrameSize;
mozilla::ReentrantMonitor mMonitor;
nsCOMPtr<nsIInputStreamCallback> mCallback;
nsCOMPtr<nsIEventTarget> mCallbackTarget;
CameraHardwareInterface* mHardware;
};
already_AddRefed<GonkCaptureProvider> GetGonkCaptureProvider();
#endif

View File

@ -64,6 +64,11 @@ EXPORTS_mozilla/net += \
endif
ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
CPPSRCS += GonkCaptureProvider.cpp \
$(NULL)
endif
LOCAL_INCLUDES = -I$(srcdir)/../../base/src/ \
$(NULL)

View File

@ -45,6 +45,12 @@
#include "AndroidCaptureProvider.h"
#endif
#ifdef MOZ_WIDGET_GONK
#include "GonkCaptureProvider.h"
#endif
using namespace mozilla;
// Copied from image/decoders/icon/nsIconURI.cpp
// takes a string like ?size=32&contentType=text/html and returns a new string
// containing just the attribute values. i.e you could pass in this string with
@ -139,9 +145,14 @@ nsDeviceChannel::OpenContentStream(bool aAsync,
captureParams.height = buffer.ToInteger(&err);
if (!captureParams.height)
captureParams.height = 480;
extractAttributeValue(spec.get(), "camera=", buffer);
captureParams.camera = buffer.ToInteger(&err);
captureParams.bpp = 32;
#ifdef MOZ_WIDGET_ANDROID
capture = GetAndroidCaptureProvider();
#endif
#ifdef MOZ_WIDGET_GONK
capture = GetGonkCaptureProvider();
#endif
} else if (kNotFound != spec.Find(NS_LITERAL_CSTRING("type=video/x-raw-yuv"),
true,
@ -161,13 +172,19 @@ nsDeviceChannel::OpenContentStream(bool aAsync,
captureParams.height = buffer.ToInteger(&err);
if (!captureParams.height)
captureParams.height = 480;
extractAttributeValue(spec.get(), "camera=", buffer);
captureParams.camera = buffer.ToInteger(&err);
captureParams.bpp = 32;
captureParams.timeLimit = 0;
captureParams.frameLimit = 60000;
#ifdef MOZ_WIDGET_ANDROID
// only enable if "device.camera.enabled" is true.
if (mozilla::Preferences::GetBool("device.camera.enabled", false) == true)
if (Preferences::GetBool("device.camera.enabled", false) == true)
capture = GetAndroidCaptureProvider();
#endif
#ifdef MOZ_WIDGET_GONK
if (Preferences::GetBool("device.camera.enabled", false) == true)
capture = GetGonkCaptureProvider();
#endif
} else {
return NS_ERROR_NOT_IMPLEMENTED;

View File

@ -46,14 +46,18 @@ SyncRunnableBase::SyncRunnableBase()
nsresult
SyncRunnableBase::DispatchToMainThreadAndWait()
{
NS_ASSERTION(!NS_IsMainThread(),
"DispatchToMainThreadAndWait called on the main thread.");
mozilla::MonitorAutoLock lock(monitor);
nsresult rv = NS_DispatchToMainThread(this);
if (NS_SUCCEEDED(rv)) {
lock.Wait();
nsresult rv;
if (NS_IsMainThread()) {
RunOnTargetThread();
rv = NS_OK;
} else {
mozilla::MonitorAutoLock lock(monitor);
rv = NS_DispatchToMainThread(this);
if (NS_SUCCEEDED(rv)) {
lock.Wait();
}
}
return rv;
}

View File

@ -42,17 +42,22 @@
* ***** END LICENSE BLOCK ***** */
/*
* All I/O is done on the socket transport thread, including all calls into
* libssl. That is, all SSL_* functions must be called on the socket transport
* thread. This also means that all SSL callback functions will be called on
* the socket transport thread, including in particular the auth certificate
* hook.
* For connections that are not processed on the socket transport thread, we do
* NOT use the async logic described below. Instead, we authenticate the
* certificate on the thread that the connection's I/O happens on,
* synchronously. This allows us to do certificate verification for blocking
* (not non-blocking) sockets and sockets that have their I/O processed on a
* thread other than the socket transport service thread. Also, we DO NOT
* support blocking sockets on the socket transport service thread at all.
*
* During certificate authentication, we call CERT_PKIXVerifyCert or
* CERT_VerifyCert. These functions may make zero or more HTTP requests
* for OCSP responses, CRLs, intermediate certificates, etc.
* for OCSP responses, CRLs, intermediate certificates, etc. Our fetching logic
* for these requests processes them on the socket transport service thread.
*
* If our cert auth hook were to call the CERT_*Verify* functions directly,
* If the connection for which we are verifying the certificate is happening
* on the socket transport thread (the usually case, at least for HTTP), then
* if our cert auth hook were to call the CERT_*Verify* functions directly,
* there would be a deadlock: The CERT_*Verify* function would cause an event
* to be asynchronously posted to the socket transport thread, and then it
* would block the socket transport thread waiting to be notified of the HTTP
@ -60,11 +65,12 @@
* because the socket transport thread would be blocked and so it wouldn't be
* able process HTTP requests. (i.e. Deadlock.)
*
* Consequently, we must always call the CERT_*Verify* cert functions off the
* socket transport thread. To accomplish this, our auth cert hook dispatches a
* SSLServerCertVerificationJob to a pool of background threads, and then
* immediatley return SECWouldBlock to libssl. These jobs are where the
* CERT_*Verify* functions are actually called.
* Consequently, when we are asked to verify a certificate on the socket
* transport service thread, we must always call the CERT_*Verify* cert
* functions on another thread. To accomplish this, our auth cert hook
* dispatches a SSLServerCertVerificationJob to a pool of background threads,
* and then immediatley return SECWouldBlock to libssl. These jobs are where
* the CERT_*Verify* functions are actually called.
*
* When our auth cert hook returns SECWouldBlock, libssl will carry on the
* handshake while we validate the certificate. This will free up the socket
@ -79,7 +85,7 @@
* finished) and it will begin allowing us to send/receive data on the
* connection.
*
* Timeline of events:
* Timeline of events (for connections managed by the socket transport service):
*
* * libssl calls SSLServerCertVerificationJob::Dispatch on the socket
* transport thread.
@ -125,17 +131,24 @@
*/
#include "SSLServerCertVerification.h"
#include "nsIBadCertListener2.h"
#include "nsICertOverrideService.h"
#include "nsIStrictTransportSecurityService.h"
#include "nsNSSComponent.h"
#include "nsNSSCertificate.h"
#include "nsNSSCleaner.h"
#include "nsRecentBadCerts.h"
#include "nsNSSIOLayer.h"
#include "mozilla/Assertions.h"
#include "nsIThreadPool.h"
#include "nsXPCOMCIDInternal.h"
#include "nsComponentManagerUtils.h"
#include "nsServiceManagerUtils.h"
#include "PSMRunnable.h"
#include "ssl.h"
#include "secerr.h"
#include "secport.h"
#include "sslerr.h"
#ifdef PR_LOGGING
@ -145,6 +158,12 @@ extern PRLogModuleInfo* gPIPNSSLog;
namespace mozilla { namespace psm {
namespace {
NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
NSSCleanupAutoPtrClass(CERTCertificate, CERT_DestroyCertificate)
NSSCleanupAutoPtrClass_WithParam(PRArenaPool, PORT_FreeArena, FalseParam, false)
// do not use a nsCOMPtr to avoid static initializer/destructor
nsIThreadPool * gCertVerificationThreadPool = nsnull;
} // unnamed namespace
@ -197,6 +216,379 @@ void StopSSLServerCertVerificationThreads()
namespace {
// Dispatched to the STS thread to notify the socketInfo of the verification
// result.
//
// This will cause the PR_Poll in the STS thread to return, so things work
// correctly even if the STS thread is blocked polling (only) on the file
// descriptor that is waiting for this result.
class SSLServerCertVerificationResult : public nsRunnable
{
public:
NS_DECL_NSIRUNNABLE
SSLServerCertVerificationResult(nsNSSSocketInfo & socketInfo,
PRErrorCode errorCode,
SSLErrorMessageType errorMessageType =
PlainErrorMessage);
void Dispatch();
private:
const nsRefPtr<nsNSSSocketInfo> mSocketInfo;
public:
const PRErrorCode mErrorCode;
const SSLErrorMessageType mErrorMessageType;
};
class CertErrorRunnable : public SyncRunnableBase
{
public:
CertErrorRunnable(const void * fdForLogging,
nsIX509Cert * cert,
nsNSSSocketInfo * infoObject,
PRErrorCode defaultErrorCodeToReport,
PRUint32 collectedErrors,
PRErrorCode errorCodeTrust,
PRErrorCode errorCodeMismatch,
PRErrorCode errorCodeExpired)
: mFdForLogging(fdForLogging), mCert(cert), mInfoObject(infoObject),
mDefaultErrorCodeToReport(defaultErrorCodeToReport),
mCollectedErrors(collectedErrors),
mErrorCodeTrust(errorCodeTrust),
mErrorCodeMismatch(errorCodeMismatch),
mErrorCodeExpired(errorCodeExpired)
{
}
virtual void RunOnTargetThread();
nsRefPtr<SSLServerCertVerificationResult> mResult; // out
private:
SSLServerCertVerificationResult* CheckCertOverrides();
const void * const mFdForLogging; // may become an invalid pointer; do not dereference
const nsCOMPtr<nsIX509Cert> mCert;
const nsRefPtr<nsNSSSocketInfo> mInfoObject;
const PRErrorCode mDefaultErrorCodeToReport;
const PRUint32 mCollectedErrors;
const PRErrorCode mErrorCodeTrust;
const PRErrorCode mErrorCodeMismatch;
const PRErrorCode mErrorCodeExpired;
};
SSLServerCertVerificationResult *
CertErrorRunnable::CheckCertOverrides()
{
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p][%p] top of CheckCertOverrides\n",
mFdForLogging, this));
if (!NS_IsMainThread()) {
NS_ERROR("CertErrorRunnable::CheckCertOverrides called off main thread");
return new SSLServerCertVerificationResult(*mInfoObject,
mDefaultErrorCodeToReport);
}
PRInt32 port;
mInfoObject->GetPort(&port);
nsCString hostWithPortString;
hostWithPortString.AppendASCII(mInfoObject->GetHostName());
hostWithPortString.AppendLiteral(":");
hostWithPortString.AppendInt(port);
PRUint32 remaining_display_errors = mCollectedErrors;
nsresult nsrv;
// Enforce Strict-Transport-Security for hosts that are "STS" hosts:
// connections must be dropped when there are any certificate errors
// (STS Spec section 7.3).
bool strictTransportSecurityEnabled = false;
nsCOMPtr<nsIStrictTransportSecurityService> stss
= do_GetService(NS_STSSERVICE_CONTRACTID, &nsrv);
if (NS_SUCCEEDED(nsrv)) {
nsrv = stss->IsStsHost(mInfoObject->GetHostName(),
&strictTransportSecurityEnabled);
}
if (NS_FAILED(nsrv)) {
return new SSLServerCertVerificationResult(*mInfoObject,
mDefaultErrorCodeToReport);
}
if (!strictTransportSecurityEnabled) {
nsCOMPtr<nsICertOverrideService> overrideService =
do_GetService(NS_CERTOVERRIDE_CONTRACTID);
// it is fine to continue without the nsICertOverrideService
PRUint32 overrideBits = 0;
if (overrideService)
{
bool haveOverride;
bool isTemporaryOverride; // we don't care
nsCString hostString(mInfoObject->GetHostName());
nsrv = overrideService->HasMatchingOverride(hostString, port,
mCert,
&overrideBits,
&isTemporaryOverride,
&haveOverride);
if (NS_SUCCEEDED(nsrv) && haveOverride)
{
// remove the errors that are already overriden
remaining_display_errors -= overrideBits;
}
}
if (!remaining_display_errors) {
// all errors are covered by override rules, so let's accept the cert
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
("[%p][%p] All errors covered by override rules\n",
mFdForLogging, this));
return new SSLServerCertVerificationResult(*mInfoObject, 0);
}
} else {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
("[%p][%p] Strict-Transport-Security is violated: untrusted "
"transport layer\n", mFdForLogging, this));
}
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
("[%p][%p] Certificate error was not overridden\n",
mFdForLogging, this));
// Ok, this is a full stop.
// First, deliver the technical details of the broken SSL status.
// Try to get a nsIBadCertListener2 implementation from the socket consumer.
nsCOMPtr<nsIInterfaceRequestor> cb;
mInfoObject->GetNotificationCallbacks(getter_AddRefs(cb));
if (cb) {
nsCOMPtr<nsIBadCertListener2> bcl = do_GetInterface(cb);
if (bcl) {
nsIInterfaceRequestor *csi = static_cast<nsIInterfaceRequestor*>(mInfoObject);
bool suppressMessage = false; // obsolete, ignored
nsrv = bcl->NotifyCertProblem(csi, mInfoObject->SSLStatus(),
hostWithPortString, &suppressMessage);
}
}
nsCOMPtr<nsIRecentBadCertsService> recentBadCertsService =
do_GetService(NS_RECENTBADCERTS_CONTRACTID);
if (recentBadCertsService) {
NS_ConvertUTF8toUTF16 hostWithPortStringUTF16(hostWithPortString);
recentBadCertsService->AddBadCert(hostWithPortStringUTF16,
mInfoObject->SSLStatus());
}
// pick the error code to report by priority
PRErrorCode errorCodeToReport = mErrorCodeTrust ? mErrorCodeTrust
: mErrorCodeMismatch ? mErrorCodeMismatch
: mErrorCodeExpired ? mErrorCodeExpired
: mDefaultErrorCodeToReport;
return new SSLServerCertVerificationResult(*mInfoObject, errorCodeToReport,
OverridableCertErrorMessage);
}
void
CertErrorRunnable::RunOnTargetThread()
{
MOZ_ASSERT(NS_IsMainThread());
mResult = CheckCertOverrides();
MOZ_ASSERT(mResult);
}
// Returns null with the error code (PR_GetError()) set if it does not create
// the CertErrorRunnable.
CertErrorRunnable *
CreateCertErrorRunnable(PRErrorCode defaultErrorCodeToReport,
nsNSSSocketInfo * socketInfo,
CERTCertificate * cert,
const void * fdForLogging)
{
MOZ_ASSERT(socketInfo);
MOZ_ASSERT(cert);
// cert was revoked, don't do anything else
if (defaultErrorCodeToReport == SEC_ERROR_REVOKED_CERTIFICATE) {
PR_SetError(SEC_ERROR_REVOKED_CERTIFICATE, 0);
return nsnull;
}
if (defaultErrorCodeToReport == 0) {
NS_ERROR("No error code set during certificate validation failure.");
PR_SetError(PR_INVALID_STATE_ERROR, 0);
return nsnull;
}
nsRefPtr<nsNSSCertificate> nssCert;
nssCert = nsNSSCertificate::Create(cert);
if (!nssCert) {
NS_ERROR("nsNSSCertificate::Create failed");
PR_SetError(SEC_ERROR_NO_MEMORY, 0);
return nsnull;
}
SECStatus srv;
nsresult nsrv;
nsCOMPtr<nsINSSComponent> inss = do_GetService(kNSSComponentCID, &nsrv);
if (!inss) {
NS_ERROR("do_GetService(kNSSComponentCID) failed");
PR_SetError(defaultErrorCodeToReport, 0);
return nsnull;
}
nsRefPtr<nsCERTValInParamWrapper> survivingParams;
nsrv = inss->GetDefaultCERTValInParam(survivingParams);
if (NS_FAILED(nsrv)) {
NS_ERROR("GetDefaultCERTValInParam failed");
PR_SetError(defaultErrorCodeToReport, 0);
return nsnull;
}
PRArenaPool *log_arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
PRArenaPoolCleanerFalseParam log_arena_cleaner(log_arena);
if (!log_arena) {
NS_ERROR("PORT_NewArena failed");
return nsnull; // PORT_NewArena set error code
}
CERTVerifyLog *verify_log = PORT_ArenaZNew(log_arena, CERTVerifyLog);
if (!verify_log) {
NS_ERROR("PORT_ArenaZNew failed");
return nsnull; // PORT_ArenaZNew set error code
}
CERTVerifyLogContentsCleaner verify_log_cleaner(verify_log);
verify_log->arena = log_arena;
if (!nsNSSComponent::globalConstFlagUsePKIXVerification) {
srv = CERT_VerifyCertificate(CERT_GetDefaultCertDB(), cert,
true, certificateUsageSSLServer,
PR_Now(), static_cast<void*>(socketInfo),
verify_log, NULL);
}
else {
CERTValOutParam cvout[2];
cvout[0].type = cert_po_errorLog;
cvout[0].value.pointer.log = verify_log;
cvout[1].type = cert_po_end;
srv = CERT_PKIXVerifyCert(cert, certificateUsageSSLServer,
survivingParams->GetRawPointerForNSS(),
cvout, static_cast<void*>(socketInfo));
}
// We ignore the result code of the cert verification.
// Either it is a failure, which is expected, and we'll process the
// verify log below.
// Or it is a success, then a domain mismatch is the only
// possible failure.
PRErrorCode errorCodeMismatch = 0;
PRErrorCode errorCodeTrust = 0;
PRErrorCode errorCodeExpired = 0;
PRUint32 collected_errors = 0;
if (socketInfo->IsCertIssuerBlacklisted()) {
collected_errors |= nsICertOverrideService::ERROR_UNTRUSTED;
errorCodeTrust = defaultErrorCodeToReport;
}
// Check the name field against the desired hostname.
if (CERT_VerifyCertName(cert, socketInfo->GetHostName()) != SECSuccess) {
collected_errors |= nsICertOverrideService::ERROR_MISMATCH;
errorCodeMismatch = SSL_ERROR_BAD_CERT_DOMAIN;
}
CERTVerifyLogNode *i_node;
for (i_node = verify_log->head; i_node; i_node = i_node->next)
{
switch (i_node->error)
{
case SEC_ERROR_UNKNOWN_ISSUER:
case SEC_ERROR_CA_CERT_INVALID:
case SEC_ERROR_UNTRUSTED_ISSUER:
case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
case SEC_ERROR_UNTRUSTED_CERT:
case SEC_ERROR_INADEQUATE_KEY_USAGE:
// We group all these errors as "cert not trusted"
collected_errors |= nsICertOverrideService::ERROR_UNTRUSTED;
if (errorCodeTrust == SECSuccess) {
errorCodeTrust = i_node->error;
}
break;
case SSL_ERROR_BAD_CERT_DOMAIN:
collected_errors |= nsICertOverrideService::ERROR_MISMATCH;
if (errorCodeMismatch == SECSuccess) {
errorCodeMismatch = i_node->error;
}
break;
case SEC_ERROR_EXPIRED_CERTIFICATE:
collected_errors |= nsICertOverrideService::ERROR_TIME;
if (errorCodeExpired == SECSuccess) {
errorCodeExpired = i_node->error;
}
break;
default:
PR_SetError(i_node->error, 0);
return nsnull;
}
}
if (!collected_errors)
{
// This will happen when CERT_*Verify* only returned error(s) that are
// not on our whitelist of overridable certificate errors.
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] !collected_errors: %d\n",
fdForLogging, static_cast<int>(defaultErrorCodeToReport)));
PR_SetError(defaultErrorCodeToReport, 0);
return nsnull;
}
socketInfo->SetStatusErrorBits(*nssCert, collected_errors);
return new CertErrorRunnable(fdForLogging,
static_cast<nsIX509Cert*>(nssCert.get()),
socketInfo, defaultErrorCodeToReport,
collected_errors, errorCodeTrust,
errorCodeMismatch, errorCodeExpired);
}
// When doing async cert processing, we dispatch one of these runnables to the
// socket transport service thread, which blocks the socket transport
// service thread while it waits for the inner CertErrorRunnable to execute
// CheckCertOverrides on the main thread. CheckCertOverrides must block events
// on both of these threads because it calls nsNSSSocketInfo::GetInterface(),
// which may call nsHttpConnection::GetInterface() through
// nsNSSSocketInfo::mCallbacks. nsHttpConnection::GetInterface must always
// execute on the main thread, with the socket transport service thread
// blocked.
class CertErrorRunnableRunnable : public nsRunnable
{
public:
CertErrorRunnableRunnable(CertErrorRunnable * certErrorRunnable)
: mCertErrorRunnable(certErrorRunnable)
{
}
private:
NS_IMETHOD Run()
{
nsresult rv = mCertErrorRunnable->DispatchToMainThreadAndWait();
// The result must run on the socket transport thread, which we are already
// on, so we can just run it directly, instead of dispatching it.
if (NS_SUCCEEDED(rv)) {
rv = mCertErrorRunnable->mResult ? mCertErrorRunnable->mResult->Run()
: NS_ERROR_UNEXPECTED;
}
return rv;
}
nsRefPtr<CertErrorRunnable> mCertErrorRunnable;
};
class SSLServerCertVerificationJob : public nsRunnable
{
public:
@ -213,9 +605,6 @@ private:
CERTCertificate & cert);
~SSLServerCertVerificationJob();
// Runs on one of the background threads
SECStatus AuthCertificate(const nsNSSShutDownPreventionLock & proofOfLock);
const void * const mFdForLogging;
const nsRefPtr<nsNSSSocketInfo> mSocketInfo;
CERTCertificate * const mCert;
@ -235,12 +624,9 @@ SSLServerCertVerificationJob::~SSLServerCertVerificationJob()
CERT_DestroyCertificate(mCert);
}
static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
SECStatus
PSM_SSL_PKIX_AuthCertificate(CERTCertificate *peerCert, void * pinarg,
const char * hostname,
const nsNSSShutDownPreventionLock & /*proofOfLock*/)
const char * hostname)
{
SECStatus rv;
@ -434,19 +820,18 @@ BlockServerCertChangeForSpdy(nsNSSSocketInfo *infoObject,
}
SECStatus
SSLServerCertVerificationJob::AuthCertificate(
nsNSSShutDownPreventionLock const & nssShutdownPreventionLock)
AuthCertificate(nsNSSSocketInfo * socketInfo, CERTCertificate * cert)
{
if (BlockServerCertChangeForSpdy(mSocketInfo, mCert) != SECSuccess)
if (BlockServerCertChangeForSpdy(socketInfo, cert) != SECSuccess)
return SECFailure;
if (mCert->serialNumber.data &&
mCert->issuerName &&
!strcmp(mCert->issuerName,
if (cert->serialNumber.data &&
cert->issuerName &&
!strcmp(cert->issuerName,
"CN=UTN-USERFirst-Hardware,OU=http://www.usertrust.com,O=The USERTRUST Network,L=Salt Lake City,ST=UT,C=US")) {
unsigned char *server_cert_comparison_start = mCert->serialNumber.data;
unsigned int server_cert_comparison_len = mCert->serialNumber.len;
unsigned char *server_cert_comparison_start = cert->serialNumber.data;
unsigned int server_cert_comparison_len = cert->serialNumber.len;
while (server_cert_comparison_len) {
if (*server_cert_comparison_start != 0)
@ -478,33 +863,32 @@ SSLServerCertVerificationJob::AuthCertificate(
}
}
SECStatus rv = PSM_SSL_PKIX_AuthCertificate(mCert, mSocketInfo,
mSocketInfo->GetHostName(),
nssShutdownPreventionLock);
SECStatus rv = PSM_SSL_PKIX_AuthCertificate(cert, socketInfo,
socketInfo->GetHostName());
// We want to remember the CA certs in the temp db, so that the application can find the
// complete chain at any time it might need it.
// But we keep only those CA certs in the temp db, that we didn't already know.
nsRefPtr<nsSSLStatus> status = mSocketInfo->SSLStatus();
nsRefPtr<nsSSLStatus> status = socketInfo->SSLStatus();
nsRefPtr<nsNSSCertificate> nsc;
if (!status || !status->mServerCert) {
nsc = nsNSSCertificate::Create(mCert);
nsc = nsNSSCertificate::Create(cert);
}
CERTCertList *certList = nsnull;
certList = CERT_GetCertChainFromCert(mCert, PR_Now(), certUsageSSLCA);
certList = CERT_GetCertChainFromCert(cert, PR_Now(), certUsageSSLCA);
if (!certList) {
rv = SECFailure;
} else {
PRErrorCode blacklistErrorCode;
if (rv == SECSuccess) { // PSM_SSL_PKIX_AuthCertificate said "valid cert"
blacklistErrorCode = PSM_SSL_BlacklistDigiNotar(mCert, certList);
blacklistErrorCode = PSM_SSL_BlacklistDigiNotar(cert, certList);
} else { // PSM_SSL_PKIX_AuthCertificate said "invalid cert"
PRErrorCode savedErrorCode = PORT_GetError();
// Check if we want to worsen the error code to "revoked".
blacklistErrorCode = PSM_SSL_DigiNotarTreatAsRevoked(mCert, certList);
blacklistErrorCode = PSM_SSL_DigiNotarTreatAsRevoked(cert, certList);
if (blacklistErrorCode == 0) {
// we don't worsen the code, let's keep the original error code from NSS
PORT_SetError(savedErrorCode);
@ -512,7 +896,7 @@ SSLServerCertVerificationJob::AuthCertificate(
}
if (blacklistErrorCode != 0) {
mSocketInfo->SetCertIssuerBlacklisted();
socketInfo->SetCertIssuerBlacklisted();
PORT_SetError(blacklistErrorCode);
rv = SECFailure;
}
@ -540,7 +924,7 @@ SSLServerCertVerificationJob::AuthCertificate(
continue;
}
if (node->cert == mCert) {
if (node->cert == cert) {
// We don't want to remember the server cert,
// the code that cares for displaying page info does this already.
continue;
@ -568,19 +952,19 @@ SSLServerCertVerificationJob::AuthCertificate(
// to the caller that contains at least the cert and its status.
if (!status) {
status = new nsSSLStatus();
mSocketInfo->SetSSLStatus(status);
socketInfo->SetSSLStatus(status);
}
if (rv == SECSuccess) {
// Certificate verification succeeded delete any potential record
// of certificate error bits.
nsSSLIOLayerHelpers::mHostsWithCertErrors->RememberCertHasError(
mSocketInfo, nsnull, rv);
socketInfo, nsnull, rv);
}
else {
// Certificate verification failed, update the status' bits.
nsSSLIOLayerHelpers::mHostsWithCertErrors->LookupCertErrorBits(
mSocketInfo, status);
socketInfo, status);
}
if (status && !status->mServerCert) {
@ -599,12 +983,9 @@ SSLServerCertVerificationJob::Dispatch(const void * fdForLogging,
CERTCertificate * serverCert)
{
// Runs on the socket transport thread
if (!socketInfo || !serverCert) {
NS_ERROR("Invalid parameters for SSL server cert validation");
socketInfo->SetCertVerificationResult(PR_INVALID_STATE_ERROR,
PlainErrorMessage);
PR_SetError(PR_INVALID_STATE_ERROR, 0);
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
return SECFailure;
}
@ -619,10 +1000,16 @@ SSLServerCertVerificationJob::Dispatch(const void * fdForLogging,
nrv = gCertVerificationThreadPool->Dispatch(job, NS_DISPATCH_NORMAL);
}
if (NS_FAILED(nrv)) {
// We can't call SetCertVerificationResult here to change
// mCertVerificationState because SetCertVerificationResult will call
// libssl functions that acquire SSL locks that are already being held at
// this point. socketInfo->mCertVerificationState will be stuck at
// waiting_for_cert_verification here, but that is OK because we already
// have to be able to handle cases where we encounter non-cert errors while
// in that state.
PRErrorCode error = nrv == NS_ERROR_OUT_OF_MEMORY
? SEC_ERROR_NO_MEMORY
: PR_INVALID_STATE_ERROR;
socketInfo->SetCertVerificationResult(error, PlainErrorMessage);
PORT_SetError(error);
return SECFailure;
}
@ -648,7 +1035,7 @@ SSLServerCertVerificationJob::Run()
// Reset the error code here so we can detect if AuthCertificate fails to
// set the error code if/when it fails.
PR_SetError(0, 0);
SECStatus rv = AuthCertificate(nssShutdownPrevention);
SECStatus rv = AuthCertificate(mSocketInfo, mCert);
if (rv == SECSuccess) {
nsRefPtr<SSLServerCertVerificationResult> restart
= new SSLServerCertVerificationResult(*mSocketInfo, 0);
@ -658,17 +1045,35 @@ SSLServerCertVerificationJob::Run()
error = PR_GetError();
if (error != 0) {
rv = HandleBadCertificate(error, mSocketInfo, *mCert, mFdForLogging,
nssShutdownPrevention);
if (rv == SECSuccess) {
// The CertErrorRunnable will run on the main thread and it will dispatch
// the cert verification result to the socket transport thread, so we
// don't have to. This way, this verification thread doesn't need to
// wait for the CertErrorRunnable to complete.
return NS_OK;
nsRefPtr<CertErrorRunnable> runnable = CreateCertErrorRunnable(
error, mSocketInfo, mCert, mFdForLogging);
if (!runnable) {
// CreateCertErrorRunnable set a new error code
error = PR_GetError();
} else {
// We must block the the socket transport service thread while the
// main thread executes the CertErrorRunnable. The CertErrorRunnable
// will dispatch the result asynchronously, so we don't have to block
// this thread waiting for it.
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
("[%p][%p] Before dispatching CertErrorRunnable\n",
mFdForLogging, runnable.get()));
nsresult nrv;
nsCOMPtr<nsIEventTarget> stsTarget
= do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &nrv);
if (NS_SUCCEEDED(nrv)) {
nrv = stsTarget->Dispatch(new CertErrorRunnableRunnable(runnable),
NS_DISPATCH_NORMAL);
}
if (NS_SUCCEEDED(nrv)) {
return NS_OK;
}
NS_ERROR("Failed to dispatch CertErrorRunnable");
error = PR_INVALID_STATE_ERROR;
}
// DispatchCertErrorRunnable set a new error code.
error = PR_GetError();
}
}
@ -710,14 +1115,91 @@ AuthCertificateHook(void *arg, PRFileDesc *fd, PRBool checkSig, PRBool isServer)
}
CERTCertificate *serverCert = SSL_PeerCertificate(fd);
CERTCertificateCleaner serverCertCleaner(serverCert);
nsNSSSocketInfo *socketInfo = static_cast<nsNSSSocketInfo*>(arg);
SECStatus rv = SSLServerCertVerificationJob::Dispatch(
bool onSTSThread;
nsresult nrv;
nsCOMPtr<nsIEventTarget> sts
= do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &nrv);
if (NS_SUCCEEDED(nrv)) {
nrv = sts->IsOnCurrentThread(&onSTSThread);
}
if (NS_FAILED(nrv)) {
NS_ERROR("Could not get STS service or IsOnCurrentThread failed");
PR_SetError(PR_UNKNOWN_ERROR, 0);
return SECFailure;
}
if (onSTSThread) {
// We *must* do certificate verification on a background thread because
// we need the socket transport thread to be free for our OCSP requests,
// and we *want* to do certificate verification on a background thread
// because of the performance benefits of doing so.
SECStatus rv = SSLServerCertVerificationJob::Dispatch(
static_cast<const void *>(fd), socketInfo, serverCert);
return rv;
}
// We can't do certificate verification on a background thread, because the
// thread doing the network I/O may not interrupt its network I/O on receipt
// of our SSLServerCertVerificationResult event, and/or it might not even be
// a non-blocking socket.
SECStatus rv = AuthCertificate(socketInfo, serverCert);
if (rv == SECSuccess) {
return SECSuccess;
}
CERT_DestroyCertificate(serverCert);
PRErrorCode error = PR_GetError();
if (error != 0) {
nsRefPtr<CertErrorRunnable> runnable = CreateCertErrorRunnable(
error, socketInfo, serverCert,
static_cast<const void *>(fd));
if (!runnable) {
// CreateCertErrorRunnable sets a new error code when it fails
error = PR_GetError();
} else {
// We have to return SECSuccess or SECFailure based on the result of the
// override processing, so we must block this thread waiting for it. The
// CertErrorRunnable will NOT dispatch the result at all, since we passed
// false for CreateCertErrorRunnable's async parameter
nrv = runnable->DispatchToMainThreadAndWait();
if (NS_FAILED(nrv)) {
NS_ERROR("Failed to dispatch CertErrorRunnable");
PR_SetError(PR_INVALID_STATE_ERROR, 0);
return SECFailure;
}
return rv;
if (!runnable->mResult) {
NS_ERROR("CertErrorRunnable did not set result");
PR_SetError(PR_INVALID_STATE_ERROR, 0);
return SECFailure;
}
if (runnable->mResult->mErrorCode == 0) {
return SECSuccess; // cert error override occurred.
}
// We must call SetCanceled here to set the error message type
// in case it isn't PlainErrorMessage, which is what we would
// default to if we just called
// PR_SetError(runnable->mResult->mErrorCode, 0) and returned
// SECFailure without doing this.
socketInfo->SetCanceled(runnable->mResult->mErrorCode,
runnable->mResult->mErrorMessageType);
error = runnable->mResult->mErrorCode;
}
}
if (error == 0) {
NS_ERROR("error code not set");
error = PR_UNKNOWN_ERROR;
}
PR_SetError(error, 0);
return SECFailure;
}
SSLServerCertVerificationResult::SSLServerCertVerificationResult(

View File

@ -39,11 +39,7 @@
#define _SSLSERVERCERTVERIFICATION_H
#include "seccomon.h"
#include "nsAutoPtr.h"
#include "nsThreadUtils.h"
#include "nsIRunnable.h"
#include "prerror.h"
#include "nsNSSIOLayer.h"
#include "prio.h"
typedef struct PRFileDesc PRFileDesc;
typedef struct CERTCertificateStr CERTCertificate;
@ -55,35 +51,6 @@ namespace mozilla { namespace psm {
SECStatus AuthCertificateHook(void *arg, PRFileDesc *fd,
PRBool checkSig, PRBool isServer);
SECStatus HandleBadCertificate(PRErrorCode defaultErrorCodeToReport,
nsNSSSocketInfo * socketInfo,
CERTCertificate & cert,
const void * fdForLogging,
const nsNSSShutDownPreventionLock &);
// Dispatched from a cert verification thread to the STS thread to notify the
// socketInfo of the verification result.
//
// This will cause the PR_Poll in the STS thread to return, so things work
// correctly even if the STS thread is blocked polling (only) on the file
// descriptor that is waiting for this result.
class SSLServerCertVerificationResult : public nsRunnable
{
public:
NS_DECL_NSIRUNNABLE
SSLServerCertVerificationResult(nsNSSSocketInfo & socketInfo,
PRErrorCode errorCode,
SSLErrorMessageType errorMessageType =
PlainErrorMessage);
void Dispatch();
private:
const nsRefPtr<nsNSSSocketInfo> mSocketInfo;
const PRErrorCode mErrorCode;
const SSLErrorMessageType mErrorMessageType;
};
} } // namespace mozilla::psm
#endif

View File

@ -815,11 +815,7 @@ PK11PasswordPrompt(PK11SlotInfo* slot, PRBool retry, void* arg)
nsRefPtr<PK11PasswordPromptRunnable> runnable =
new PK11PasswordPromptRunnable(slot,
static_cast<nsIInterfaceRequestor*>(arg));
if (NS_IsMainThread()) {
runnable->RunOnTargetThread();
} else {
runnable->DispatchToMainThreadAndWait();
}
runnable->DispatchToMainThreadAndWait();
return runnable->mResult;
}
@ -836,7 +832,7 @@ void PR_CALLBACK HandshakeCallback(PRFileDesc* fd, void* client_data) {
// If the handshake completed, then we know the site is TLS tolerant (if this
// was a TLS connection).
nsSSLIOLayerHelpers::rememberTolerantSite(fd, infoObject);
nsSSLIOLayerHelpers::rememberTolerantSite(infoObject);
if (SECSuccess != SSL_SecurityStatus(fd, &sslStatus, &cipherName, &keyLength,
&encryptBits, &signer, nsnull)) {

View File

@ -57,12 +57,9 @@
#include "nsIClientAuthDialogs.h"
#include "nsClientAuthRemember.h"
#include "nsICertOverrideService.h"
#include "nsIBadCertListener2.h"
#include "nsISSLErrorListener.h"
#include "nsIObjectInputStream.h"
#include "nsIObjectOutputStream.h"
#include "nsRecentBadCerts.h"
#include "nsIStrictTransportSecurityService.h"
#include "nsXPIDLString.h"
#include "nsReadableUtils.h"
@ -75,7 +72,6 @@
#include "nsSSLStatus.h"
#include "nsNSSCertHelper.h"
#include "nsNSSCleaner.h"
#include "nsThreadUtils.h"
#include "nsIDocShell.h"
#include "nsIDocShellTreeItem.h"
#include "nsISecureBrowserUI.h"
@ -93,7 +89,6 @@
#include "certdb.h"
#include "cert.h"
#include "keyhi.h"
#include "secport.h"
#include "mozilla/Util.h"
@ -113,7 +108,6 @@ using namespace mozilla::psm;
NSSCleanupAutoPtrClass(CERTCertificate, CERT_DestroyCertificate)
NSSCleanupAutoPtrClass(void, PR_FREEIF)
NSSCleanupAutoPtrClass_WithParam(PRArenaPool, PORT_FreeArena, FalseParam, false)
static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
@ -164,6 +158,8 @@ nsNSSSocketInfo::nsNSSSocketInfo()
mErrorCode(0),
mErrorMessageType(PlainErrorMessage),
mForSTARTTLS(false),
mSSL3Enabled(false),
mTLSEnabled(false),
mHandshakePending(true),
mHasCleartextPhase(false),
mHandshakeInProgress(false),
@ -942,11 +938,6 @@ void nsNSSSocketInfo::GetPreviousCert(nsIX509Cert** _result)
NS_ASSERTION(_result, "_result parameter to GetPreviousCert is null");
*_result = nsnull;
if (NS_IsMainThread()) {
NS_ERROR("nsNSSSocketInfo::GetPreviousCert called on the main thread");
return;
}
nsRefPtr<PreviousCertRunnable> runnable = new PreviousCertRunnable(mCallbacks);
nsresult rv = runnable->DispatchToMainThreadAndWait();
NS_ASSERTION(NS_SUCCEEDED(rv), "runnable->DispatchToMainThreadAndWait() failed");
@ -965,6 +956,10 @@ nsNSSSocketInfo::SetCertVerificationWaiting()
mCertVerificationStarted = PR_IntervalNow();
}
// Be careful that SetCertVerificationResult does NOT get called while we are
// processing a SSL callback function, because SSL_AuthCertificateComplete will
// attempt to acquire locks that are already held by libssl when it calls
// callbacks.
void
nsNSSSocketInfo::SetCertVerificationResult(PRErrorCode errorCode,
SSLErrorMessageType errorMessageType)
@ -1759,16 +1754,13 @@ nsSSLIOLayerHelpers::getSiteKey(nsNSSSocketInfo *socketInfo, nsCSubstring &key)
// Call this function to report a site that is possibly TLS intolerant.
// This function will return true, if the given socket is currently using TLS.
bool
nsSSLIOLayerHelpers::rememberPossibleTLSProblemSite(PRFileDesc* ssl_layer_fd, nsNSSSocketInfo *socketInfo)
nsSSLIOLayerHelpers::rememberPossibleTLSProblemSite(nsNSSSocketInfo *socketInfo)
{
PRBool currentlyUsesTLS = false;
nsCAutoString key;
getSiteKey(socketInfo, key);
SSL_OptionGet(ssl_layer_fd, SSL_ENABLE_TLS, &currentlyUsesTLS);
if (!currentlyUsesTLS) {
// We were not using TLS but failed with an intolerant error using
if (!socketInfo->IsTLSEnabled()) {
// We did not offer TLS but failed with an intolerant error using
// a different protocol. To give TLS a try on next connection attempt again
// drop this site from the list of intolerant sites. TLS failure might be
// caused only by a traffic congestion while the server is TLS tolerant.
@ -1776,27 +1768,19 @@ nsSSLIOLayerHelpers::rememberPossibleTLSProblemSite(PRFileDesc* ssl_layer_fd, ns
return false;
}
PRBool enableSSL3 = false;
SSL_OptionGet(ssl_layer_fd, SSL_ENABLE_SSL3, &enableSSL3);
if (enableSSL3) {
if (socketInfo->IsSSL3Enabled()) {
// Add this site to the list of TLS intolerant sites.
addIntolerantSite(key);
}
return currentlyUsesTLS;
return socketInfo->IsTLSEnabled();
}
void
nsSSLIOLayerHelpers::rememberTolerantSite(PRFileDesc* ssl_layer_fd,
nsNSSSocketInfo *socketInfo)
nsSSLIOLayerHelpers::rememberTolerantSite(nsNSSSocketInfo *socketInfo)
{
PRBool usingSecurity = false;
PRBool currentlyUsesTLS = false;
SSL_OptionGet(ssl_layer_fd, SSL_SECURITY, &usingSecurity);
SSL_OptionGet(ssl_layer_fd, SSL_ENABLE_TLS, &currentlyUsesTLS);
if (!usingSecurity || !currentlyUsesTLS) {
if (!socketInfo->IsTLSEnabled())
return;
}
nsCAutoString key;
getSiteKey(socketInfo, key);
@ -2024,7 +2008,7 @@ PRInt32 checkHandshake(PRInt32 bytesTransfered, bool wasReading,
if (!wantRetry // no decision yet
&& isTLSIntoleranceError(err, socketInfo->GetHasCleartextPhase()))
{
wantRetry = nsSSLIOLayerHelpers::rememberPossibleTLSProblemSite(ssl_layer_fd, socketInfo);
wantRetry = nsSSLIOLayerHelpers::rememberPossibleTLSProblemSite(socketInfo);
}
}
@ -2052,7 +2036,7 @@ PRInt32 checkHandshake(PRInt32 bytesTransfered, bool wasReading,
&& !socketInfo->GetHasCleartextPhase()) // mirror PR_CONNECT_RESET_ERROR treament
{
wantRetry =
nsSSLIOLayerHelpers::rememberPossibleTLSProblemSite(ssl_layer_fd, socketInfo);
nsSSLIOLayerHelpers::rememberPossibleTLSProblemSite(socketInfo);
}
}
}
@ -3444,225 +3428,6 @@ done:
}
}
class CertErrorRunnable : public SyncRunnableBase
{
public:
CertErrorRunnable(const void * fdForLogging,
nsIX509Cert * cert,
nsNSSSocketInfo * infoObject,
PRErrorCode defaultErrorCodeToReport,
PRUint32 collectedErrors,
PRErrorCode errorCodeTrust,
PRErrorCode errorCodeMismatch,
PRErrorCode errorCodeExpired)
: mFdForLogging(fdForLogging), mCert(cert), mInfoObject(infoObject),
mDefaultErrorCodeToReport(defaultErrorCodeToReport),
mCollectedErrors(collectedErrors),
mErrorCodeTrust(errorCodeTrust),
mErrorCodeMismatch(errorCodeMismatch),
mErrorCodeExpired(errorCodeExpired)
{
}
NS_DECL_NSIRUNNABLE
virtual void RunOnTargetThread();
nsCOMPtr<nsIRunnable> mResult; // out
private:
SSLServerCertVerificationResult* CheckCertOverrides();
const void * const mFdForLogging; // may become an invalid pointer; do not dereference
const nsCOMPtr<nsIX509Cert> mCert;
const nsRefPtr<nsNSSSocketInfo> mInfoObject;
const PRErrorCode mDefaultErrorCodeToReport;
const PRUint32 mCollectedErrors;
const PRErrorCode mErrorCodeTrust;
const PRErrorCode mErrorCodeMismatch;
const PRErrorCode mErrorCodeExpired;
};
namespace mozilla { namespace psm {
// Returns SECSuccess if it dispatched the CertErrorRunnable. In that case,
// the caller should NOT dispatch its own SSLServerCertVerificationResult;
// the CertErrorRunnable will do it instead.
//
// Returns SECFailure with the error code set if it does not dispatch the
// CertErrorRunnable. In that case, the caller should dispatch its own
// SSLServerCertVerificationResult with the error code from PR_GetError().
SECStatus
HandleBadCertificate(PRErrorCode defaultErrorCodeToReport,
nsNSSSocketInfo * socketInfo, CERTCertificate & cert,
const void * fdForLogging,
const nsNSSShutDownPreventionLock & /*proofOfLock*/)
{
// cert was revoked, don't do anything else
if (defaultErrorCodeToReport == SEC_ERROR_REVOKED_CERTIFICATE) {
PR_SetError(SEC_ERROR_REVOKED_CERTIFICATE, 0);
return SECFailure;
}
if (defaultErrorCodeToReport == 0) {
NS_ERROR("No error code set during certificate validation failure.");
PR_SetError(PR_INVALID_STATE_ERROR, 0);
return SECFailure;
}
nsRefPtr<nsNSSCertificate> nssCert;
nssCert = nsNSSCertificate::Create(&cert);
if (!nssCert) {
NS_ERROR("nsNSSCertificate::Create failed in DispatchCertErrorRunnable");
PR_SetError(SEC_ERROR_NO_MEMORY, 0);
return SECFailure;
}
SECStatus srv;
nsresult nsrv;
nsCOMPtr<nsINSSComponent> inss = do_GetService(kNSSComponentCID, &nsrv);
if (!inss) {
NS_ERROR("do_GetService(kNSSComponentCID) failed in DispatchCertErrorRunnable");
PR_SetError(defaultErrorCodeToReport, 0);
return SECFailure;
}
nsRefPtr<nsCERTValInParamWrapper> survivingParams;
nsrv = inss->GetDefaultCERTValInParam(survivingParams);
if (NS_FAILED(nsrv)) {
NS_ERROR("GetDefaultCERTValInParam failed in DispatchCertErrorRunnable");
PR_SetError(defaultErrorCodeToReport, 0);
return SECFailure;
}
PRArenaPool *log_arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
PRArenaPoolCleanerFalseParam log_arena_cleaner(log_arena);
if (!log_arena) {
NS_ERROR("PORT_NewArena failed in DispatchCertErrorRunnable");
return SECFailure; // PORT_NewArena set error code
}
CERTVerifyLog *verify_log = PORT_ArenaZNew(log_arena, CERTVerifyLog);
if (!verify_log) {
NS_ERROR("PORT_ArenaZNew failed in DispatchCertErrorRunnable");
return SECFailure; // PORT_ArenaZNew set error code
}
CERTVerifyLogContentsCleaner verify_log_cleaner(verify_log);
verify_log->arena = log_arena;
if (!nsNSSComponent::globalConstFlagUsePKIXVerification) {
srv = CERT_VerifyCertificate(CERT_GetDefaultCertDB(), &cert,
true, certificateUsageSSLServer,
PR_Now(), static_cast<void*>(socketInfo),
verify_log, NULL);
}
else {
CERTValOutParam cvout[2];
cvout[0].type = cert_po_errorLog;
cvout[0].value.pointer.log = verify_log;
cvout[1].type = cert_po_end;
srv = CERT_PKIXVerifyCert(&cert, certificateUsageSSLServer,
survivingParams->GetRawPointerForNSS(),
cvout, static_cast<void*>(socketInfo));
}
// We ignore the result code of the cert verification.
// Either it is a failure, which is expected, and we'll process the
// verify log below.
// Or it is a success, then a domain mismatch is the only
// possible failure.
PRErrorCode errorCodeMismatch = 0;
PRErrorCode errorCodeTrust = 0;
PRErrorCode errorCodeExpired = 0;
PRUint32 collected_errors = 0;
if (socketInfo->IsCertIssuerBlacklisted()) {
collected_errors |= nsICertOverrideService::ERROR_UNTRUSTED;
errorCodeTrust = defaultErrorCodeToReport;
}
// Check the name field against the desired hostname.
if (CERT_VerifyCertName(&cert, socketInfo->GetHostName()) != SECSuccess) {
collected_errors |= nsICertOverrideService::ERROR_MISMATCH;
errorCodeMismatch = SSL_ERROR_BAD_CERT_DOMAIN;
}
CERTVerifyLogNode *i_node;
for (i_node = verify_log->head; i_node; i_node = i_node->next)
{
switch (i_node->error)
{
case SEC_ERROR_UNKNOWN_ISSUER:
case SEC_ERROR_CA_CERT_INVALID:
case SEC_ERROR_UNTRUSTED_ISSUER:
case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
case SEC_ERROR_UNTRUSTED_CERT:
case SEC_ERROR_INADEQUATE_KEY_USAGE:
// We group all these errors as "cert not trusted"
collected_errors |= nsICertOverrideService::ERROR_UNTRUSTED;
if (errorCodeTrust == SECSuccess) {
errorCodeTrust = i_node->error;
}
break;
case SSL_ERROR_BAD_CERT_DOMAIN:
collected_errors |= nsICertOverrideService::ERROR_MISMATCH;
if (errorCodeMismatch == SECSuccess) {
errorCodeMismatch = i_node->error;
}
break;
case SEC_ERROR_EXPIRED_CERTIFICATE:
collected_errors |= nsICertOverrideService::ERROR_TIME;
if (errorCodeExpired == SECSuccess) {
errorCodeExpired = i_node->error;
}
break;
default:
PR_SetError(i_node->error, 0);
return SECFailure;
}
}
if (!collected_errors)
{
// This will happen when CERT_*Verify* only returned error(s) that are
// not on our whitelist of overridable certificate errors.
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] !collected_errors: %d\n",
fdForLogging, static_cast<int>(defaultErrorCodeToReport)));
PR_SetError(defaultErrorCodeToReport, 0);
return SECFailure;
}
socketInfo->SetStatusErrorBits(*nssCert, collected_errors);
nsRefPtr<CertErrorRunnable> runnable =
new CertErrorRunnable(fdForLogging,
static_cast<nsIX509Cert*>(nssCert.get()),
socketInfo, defaultErrorCodeToReport,
collected_errors, errorCodeTrust,
errorCodeMismatch, errorCodeExpired);
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
("[%p][%p] Before dispatching CertErrorRunnable\n",
fdForLogging, runnable.get()));
nsresult nrv;
nsCOMPtr<nsIEventTarget> stsTarget
= do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &nrv);
if (NS_SUCCEEDED(nrv)) {
nrv = stsTarget->Dispatch(runnable, NS_DISPATCH_NORMAL);
}
if (NS_FAILED(nrv)) {
NS_ERROR("Failed to dispatch CertErrorRunnable");
PR_SetError(defaultErrorCodeToReport, 0);
return SECFailure;
}
return SECSuccess;
}
} } // namespace mozilla::psm
void
nsNSSSocketInfo::SetStatusErrorBits(nsIX509Cert & cert,
PRUint32 collected_errors)
@ -3686,162 +3451,6 @@ nsNSSSocketInfo::SetStatusErrorBits(nsIX509Cert & cert,
this, mSSLStatus, SECFailure);
}
SSLServerCertVerificationResult *
CertErrorRunnable::CheckCertOverrides()
{
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p][%p] top of CertErrorRunnable::Run\n",
mFdForLogging, this));
if (!NS_IsMainThread()) {
NS_ERROR("CertErrorRunnable::CheckCertOverrides called off main thread");
return new SSLServerCertVerificationResult(*mInfoObject,
mDefaultErrorCodeToReport);
}
PRInt32 port;
mInfoObject->GetPort(&port);
nsCString hostWithPortString;
hostWithPortString.AppendASCII(mInfoObject->GetHostName());
hostWithPortString.AppendLiteral(":");
hostWithPortString.AppendInt(port);
PRUint32 remaining_display_errors = mCollectedErrors;
nsresult nsrv;
// Enforce Strict-Transport-Security for hosts that are "STS" hosts:
// connections must be dropped when there are any certificate errors
// (STS Spec section 7.3).
bool strictTransportSecurityEnabled = false;
nsCOMPtr<nsIStrictTransportSecurityService> stss
= do_GetService(NS_STSSERVICE_CONTRACTID, &nsrv);
if (NS_SUCCEEDED(nsrv)) {
nsrv = stss->IsStsHost(mInfoObject->GetHostName(),
&strictTransportSecurityEnabled);
}
if (NS_FAILED(nsrv)) {
return new SSLServerCertVerificationResult(*mInfoObject,
mDefaultErrorCodeToReport);
}
if (!strictTransportSecurityEnabled) {
nsCOMPtr<nsICertOverrideService> overrideService =
do_GetService(NS_CERTOVERRIDE_CONTRACTID);
// it is fine to continue without the nsICertOverrideService
PRUint32 overrideBits = 0;
if (overrideService)
{
bool haveOverride;
bool isTemporaryOverride; // we don't care
nsCString hostString(mInfoObject->GetHostName());
nsrv = overrideService->HasMatchingOverride(hostString, port,
mCert,
&overrideBits,
&isTemporaryOverride,
&haveOverride);
if (NS_SUCCEEDED(nsrv) && haveOverride)
{
// remove the errors that are already overriden
remaining_display_errors -= overrideBits;
}
}
if (!remaining_display_errors) {
// all errors are covered by override rules, so let's accept the cert
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
("[%p][%p] All errors covered by override rules\n",
mFdForLogging, this));
return new SSLServerCertVerificationResult(*mInfoObject, 0);
}
} else {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
("[%p][%p] Strict-Transport-Security is violated: untrusted "
"transport layer\n", mFdForLogging, this));
}
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
("[%p][%p] Certificate error was not overridden\n",
mFdForLogging, this));
// Ok, this is a full stop.
// First, deliver the technical details of the broken SSL status.
// Try to get a nsIBadCertListener2 implementation from the socket consumer.
nsCOMPtr<nsIInterfaceRequestor> cb;
mInfoObject->GetNotificationCallbacks(getter_AddRefs(cb));
if (cb) {
nsCOMPtr<nsIBadCertListener2> bcl = do_GetInterface(cb);
if (bcl) {
nsIInterfaceRequestor *csi = static_cast<nsIInterfaceRequestor*>(mInfoObject);
bool suppressMessage = false; // obsolete, ignored
nsrv = bcl->NotifyCertProblem(csi, mInfoObject->SSLStatus(),
hostWithPortString, &suppressMessage);
}
}
nsCOMPtr<nsIRecentBadCertsService> recentBadCertsService =
do_GetService(NS_RECENTBADCERTS_CONTRACTID);
if (recentBadCertsService) {
NS_ConvertUTF8toUTF16 hostWithPortStringUTF16(hostWithPortString);
recentBadCertsService->AddBadCert(hostWithPortStringUTF16,
mInfoObject->SSLStatus());
}
// pick the error code to report by priority
PRErrorCode errorCodeToReport = mErrorCodeTrust ? mErrorCodeTrust
: mErrorCodeMismatch ? mErrorCodeMismatch
: mErrorCodeExpired ? mErrorCodeExpired
: mDefaultErrorCodeToReport;
return new SSLServerCertVerificationResult(*mInfoObject, errorCodeToReport,
OverridableCertErrorMessage);
}
NS_IMETHODIMP
CertErrorRunnable::Run()
{
// This code is confusing: First, Run() is called on the socket transport
// thread. Then we re-dispatch it to the main thread synchronously (step 1).
// On the main thread, we call CheckCertOverrides (step 2). Then we return
// from the main thread and are back on the socket transport thread. There,
// we run the result runnable directly (step 3).
if (!NS_IsMainThread()) {
// We are running on the socket transport thread. We need to re-dispatch
// ourselves synchronously to the main thread.
DispatchToMainThreadAndWait(); // step 1
// step 3
if (!mResult) {
// Either the dispatch failed or CheckCertOverrides wrongly returned null
NS_ERROR("Did not create a SSLServerCertVerificationResult");
mResult = new SSLServerCertVerificationResult(*mInfoObject,
PR_INVALID_STATE_ERROR);
}
return mResult->Run();
} else {
// block this thread (the socket transport thread) until RunOnTargetThread
// is complete.
return SyncRunnableBase::Run(); // step 2
}
}
void
CertErrorRunnable::RunOnTargetThread()
{
// Now we are running on the main thread, blocking the socket tranposrt
// thread. This is exactly the state we need to be in to call
// CheckCertOverrides; CheckCertOverrides must block events on both of
// these threads because it calls nsNSSSocketInfo::GetInterface(),
// which calls nsHttpConnection::GetInterface() through
// nsNSSSocketInfo::mCallbacks. nsHttpConnection::GetInterface must always
// execute on the main thread, with the socket transport thread blocked.
mResult = CheckCertOverrides();
}
static PRFileDesc*
nsSSLIOLayerImportFD(PRFileDesc *fd,
nsNSSSocketInfo *infoObject,
@ -3915,6 +3524,16 @@ nsSSLIOLayerSetOptions(PRFileDesc *fd, bool forSTARTTLS,
// on our single retry attempt.
}
PRBool enabled;
if (SECSuccess != SSL_OptionGet(fd, SSL_ENABLE_SSL3, &enabled)) {
return NS_ERROR_FAILURE;
}
infoObject->SetSSL3Enabled(enabled);
if (SECSuccess != SSL_OptionGet(fd, SSL_ENABLE_TLS, &enabled)) {
return NS_ERROR_FAILURE;
}
infoObject->SetTLSEnabled(enabled);
if (SECSuccess != SSL_OptionSet(fd, SSL_HANDSHAKE_AS_CLIENT, true)) {
return NS_ERROR_FAILURE;
}

View File

@ -177,7 +177,10 @@ public:
return mCertVerificationState == waiting_for_cert_verification;
}
bool IsSSL3Enabled() const { return mSSL3Enabled; }
void SetSSL3Enabled(bool enabled) { mSSL3Enabled = enabled; }
bool IsTLSEnabled() const { return mTLSEnabled; }
void SetTLSEnabled(bool enabled) { mTLSEnabled = enabled; }
protected:
mutable ::mozilla::Mutex mMutex;
@ -201,6 +204,8 @@ protected:
bool mDocShellDependentStuffKnown;
bool mExternalErrorReporting; // DocShellDependent
bool mForSTARTTLS;
bool mSSL3Enabled;
bool mTLSEnabled;
bool mHandshakePending;
bool mHasCleartextPhase;
bool mHandshakeInProgress;
@ -280,8 +285,8 @@ public:
static PRInt32 getWarnLevelMissingRFC5746();
static void getSiteKey(nsNSSSocketInfo *socketInfo, nsCSubstring &key);
static bool rememberPossibleTLSProblemSite(PRFileDesc* fd, nsNSSSocketInfo *socketInfo);
static void rememberTolerantSite(PRFileDesc* ssl_layer_fd, nsNSSSocketInfo *socketInfo);
static bool rememberPossibleTLSProblemSite(nsNSSSocketInfo *socketInfo);
static void rememberTolerantSite(nsNSSSocketInfo *socketInfo);
static void addIntolerantSite(const nsCString &str);
static void removeIntolerantSite(const nsCString &str);

View File

@ -12,7 +12,7 @@ Form History test: form field autocomplete
<p id="display"></p>
<!-- we presumably can't hide the content for this test. -->
<div id="content" style="direction: rtl;">
<div id="content">
<!-- unused -->
<form id="unused" onsubmit="return false;">
<input type="text" name="field1" value="unused">
@ -32,7 +32,6 @@ Form History test: form field autocomplete
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
var autocompletePopup = getAutocompletePopup();
autocompletePopup.style.direction = "ltr";
var input = $_(1, "field1");
@ -367,7 +366,6 @@ function runTest(testNum) {
case 211:
checkPopupOpen(false);
checkForm("");
is(autocompletePopup.style.direction, "rtl", "direction should have been changed from ltr to rtl");
SimpleTest.finish();
return;

View File

@ -72,6 +72,7 @@ _TEST_FILES = findbar_window.xul \
test_bug570192.xul \
test_bug624329.xul \
bug624329_window.xul \
test_bug649840.xul \
test_popup_preventdefault_chrome.xul \
window_popup_preventdefault_chrome.xul \
test_largemenu.xul \

View File

@ -0,0 +1,66 @@
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=649840
-->
<window title="Mozilla Bug 649840"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<textbox id="textLTR" type="autocomplete" autocompletesearch="simple"/>
<textbox id="textRTL" type="autocomplete" autocompletesearch="simple"/>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=649840"
target="_blank">Mozilla Bug 649840</a>
</body>
<!-- test code goes here -->
<script type="application/javascript">
<![CDATA[
/** Test for Bug 649840 **/
SimpleTest.waitForExplicitFinish();
addLoadEvent(runTest);
function runTest()
{
var textLTR = $("textLTR");
var textRTL = $("textRTL");
textLTR.style.direction = "ltr";
textRTL.style.direction = "rtl";
textLTR.value="abcd";
textRTL.value="ابجد";
// open and close the popups to update the popupdir attribute value
textLTR.openPopup();
textLTR.closePopup();
textRTL.openPopup();
textRTL.closePopup();
is(textLTR.popup.style.direction, textLTR.style.direction, "LTR textbox test fails");
is(textRTL.popup.style.direction, textRTL.style.direction, "RTL textbox test fails");
// switch directions of the two textboxes
textLTR.style.direction = "rtl";
textRTL.style.direction = "ltr";
// open and close the popups to update the popupdir attribute value
textLTR.openPopup();
textLTR.closePopup();
textRTL.openPopup();
textRTL.closePopup();
is(textLTR.popup.style.direction, textLTR.style.direction, "RTL-switched textbox test fails");
is(textRTL.popup.style.direction, textRTL.style.direction, "LTR-switched textbox test fails");
SimpleTest.finish();
}
]]>
</script>
</window>

View File

@ -426,6 +426,10 @@ OS_LIBS += \
-lhardware_legacy \
-lhardware \
-lutils \
-lcutils \
-lcamera \
-lcamera_client \
-lbinder \
$(NULL)
endif

View File

@ -762,7 +762,7 @@ var AddonManagerInternal = {
// Repopulate repository cache first, to ensure compatibility overrides
// are up to date before checking for addon updates.
scope.AddonRepository.repopulateCache(ids, function BUC_repopulateCacheCallback() {
scope.AddonRepository.backgroundUpdateCheck(ids, function BUC_backgroundUpdateCheckCallback() {
AddonManagerInternal.updateAddonRepositoryData(function BUC_updateAddonCallback() {
pendingUpdates += aAddons.length;

View File

@ -57,6 +57,7 @@ const PREF_GETADDONS_CACHE_TYPES = "extensions.getAddons.cache.types";
const PREF_GETADDONS_CACHE_ID_ENABLED = "extensions.%ID%.getAddons.cache.enabled"
const PREF_GETADDONS_BROWSEADDONS = "extensions.getAddons.browseAddons";
const PREF_GETADDONS_BYIDS = "extensions.getAddons.get.url";
const PREF_GETADDONS_BYIDS_PERFORMANCE = "extensions.getAddons.getWithPerformance.url";
const PREF_GETADDONS_BROWSERECOMMENDED = "extensions.getAddons.recommended.browseURL";
const PREF_GETADDONS_GETRECOMMENDED = "extensions.getAddons.recommended.url";
const PREF_GETADDONS_BROWSESEARCHRESULTS = "extensions.getAddons.search.browseURL";
@ -610,6 +611,10 @@ var AddonRepository = {
* The optional callback to call once complete
*/
repopulateCache: function(aIds, aCallback) {
this._repopulateCache(aIds, aCallback, false);
},
_repopulateCache: function(aIds, aCallback, aSendPerformance) {
// Completely remove cache if caching is not enabled
if (!this.cacheEnabled) {
this._addons = null;
@ -628,7 +633,7 @@ var AddonRepository = {
return;
}
self.getAddonsByIDs(aAddons, {
self._beginGetAddons(aAddons, {
searchSucceeded: function(aAddons) {
self._addons = {};
aAddons.forEach(function(aAddon) { self._addons[aAddon.id] = aAddon; });
@ -639,7 +644,7 @@ var AddonRepository = {
if (aCallback)
aCallback();
}
});
}, aSendPerformance);
});
},
@ -747,6 +752,21 @@ var AddonRepository = {
* The callback to pass results to
*/
getAddonsByIDs: function(aIDs, aCallback) {
return this._beginGetAddons(aIDs, aCallback, false);
},
/**
* Begins a search of add-ons, potentially sending performance data.
*
* @param aIDs
* Array of ids to search for.
* @param aCallback
* Function to pass results to.
* @param aSendPerformance
* Boolean indicating whether to send performance data with the
* request.
*/
_beginGetAddons: function(aIDs, aCallback, aSendPerformance) {
let ids = aIDs.slice(0);
let params = {
@ -754,7 +774,34 @@ var AddonRepository = {
IDS : ids.map(encodeURIComponent).join(',')
};
let url = this._formatURLPref(PREF_GETADDONS_BYIDS, params);
let pref = PREF_GETADDONS_BYIDS;
if (aSendPerformance) {
let type = Services.prefs.getPrefType(PREF_GETADDONS_BYIDS_PERFORMANCE);
if (type == Services.prefs.PREF_STRING) {
pref = PREF_GETADDONS_BYIDS_PERFORMANCE;
let startupInfo = Cc["@mozilla.org/toolkit/app-startup;1"].
getService(Ci.nsIAppStartup).
getStartupInfo();
if (startupInfo.process) {
if (startupInfo.main) {
params.TIME_MAIN = startupInfo.main - startupInfo.process;
}
if (startupInfo.firstPaint) {
params.TIME_FIRST_PAINT = startupInfo.firstPaint -
startupInfo.process;
}
if (startupInfo.sessionRestored) {
params.TIME_SESSION_RESTORED = startupInfo.sessionRestored -
startupInfo.process;
}
}
}
}
let url = this._formatURLPref(pref, params);
let self = this;
function handleResults(aElements, aTotalResults, aCompatData) {
@ -801,6 +848,23 @@ var AddonRepository = {
this._beginSearch(url, ids.length, aCallback, handleResults);
},
/**
* Performs the daily background update check.
*
* This API both searches for the add-on IDs specified and sends performance
* data. It is meant to be called as part of the daily update ping. It should
* not be used for any other purpose. Use repopulateCache instead.
*
* @param aIDs
* Array of add-on IDs to repopulate the cache with.
* @param aCallback
* Function to call when data is received. Function must be an object
* with the keys searchSucceeded and searchFailed.
*/
backgroundUpdateCheck: function(aIDs, aCallback) {
this._repopulateCache(aIDs, aCallback, true);
},
/**
* Begins a search for recommended add-ons in this repository. Results will
* be passed to the given callback.

View File

@ -201,6 +201,24 @@ var gIDTest = /^(\{[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\
})
}, this);
/**
* Sets permissions on a file
*
* @param aFile
* The file or directory to operate on.
* @param aPermissions
* The permisions to set
*/
function setFilePermissions(aFile, aPermissions) {
try {
aFile.permissions = aPermissions;
}
catch (e) {
WARN("Failed to set permissions " + aPermissions.toString(8) + " on " +
aFile.path, e);
}
}
/**
* A safe way to install a file or the contents of a directory to a new
* directory. The file or directory is moved or copied recursively and if
@ -279,7 +297,7 @@ SafeInstallOperation.prototype = {
// The directory should be empty by this point. If it isn't this will throw
// and all of the operations will be rolled back
try {
aDirectory.permissions = FileUtils.PERMS_DIRECTORY;
setFilePermissions(aDirectory, FileUtils.PERMS_DIRECTORY);
aDirectory.remove(false);
}
catch (e) {
@ -1085,7 +1103,13 @@ function extractFiles(aZipFile, aDir) {
continue;
zipReader.extract(entryName, target);
target.permissions |= FileUtils.PERMS_FILE;
try {
target.permissions |= FileUtils.PERMS_FILE;
}
catch (e) {
WARN("Failed to set permissions " + aPermissions.toString(8) + " on " +
target.path, e);
}
}
}
finally {
@ -1252,7 +1276,7 @@ function cleanStagingDir(aDir, aLeafNames) {
}
try {
aDir.permissions = FileUtils.PERMS_DIRECTORY;
setFilePermissions(aDir, FileUtils.PERMS_DIRECTORY);
aDir.remove(false);
}
catch (e) {
@ -1268,8 +1292,8 @@ function cleanStagingDir(aDir, aLeafNames) {
* The nsIFile to remove
*/
function recursiveRemove(aFile) {
aFile.permissions = aFile.isDirectory() ? FileUtils.PERMS_DIRECTORY
: FileUtils.PERMS_FILE;
setFilePermissions(aFile, aFile.isDirectory() ? FileUtils.PERMS_DIRECTORY
: FileUtils.PERMS_FILE);
try {
aFile.remove(true);
@ -8076,7 +8100,11 @@ DirectoryInstallLocation.prototype = {
let newFile = this._directory.clone().QueryInterface(Ci.nsILocalFile);
newFile.append(aSource.leafName);
newFile.lastModifiedTime = Date.now();
try {
newFile.lastModifiedTime = Date.now();
} catch (e) {
WARN("failed to set lastModifiedTime on " + newFile.path, e);
}
this._FileToIDMap[newFile.path] = aId;
this._IDToFileMap[aId] = newFile;

View File

@ -96,6 +96,7 @@ _MAIN_TEST_FILES = \
_TEST_FILES = \
head.js \
browser_addonrepository_performance.js \
browser_bug557956.js \
browser_bug616841.js \
browser_hotfix.js \

View File

@ -0,0 +1,71 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Tests that the metadata request includes startup time measurements
Components.utils.import("resource://gre/modules/AddonRepository.jsm");
var gManagerWindow;
var gProvider;
function parseParams(aQuery) {
let params = {};
aQuery.split("&").forEach(function(aParam) {
let [key, value] = aParam.split("=");
params[key] = value;
});
return params;
}
function test() {
waitForExplicitFinish();
var gSeenRequest = false;
gProvider = new MockProvider();
gProvider.createAddons([{
id: "test1@tests.mozilla.org",
name: "Test add-on"
}]);
function observe(aSubject, aTopic, aData) {
aSubject.QueryInterface(Ci.nsIChannel);
let url = aSubject.URI.QueryInterface(Ci.nsIURL);
if (url.filePath != "/extensions-dummy/metadata") {
return;
}
info(url.query);
let params = parseParams(url.query);
is(params.appOS, Services.appinfo.OS, "OS should be correct");
is(params.appVersion, Services.appinfo.version, "Version should be correct");
ok(params.tMain >= 0, "Should be a sensible tMain");
ok(params.tFirstPaint >= 0, "Should be a sensible tFirstPaint");
ok(params.tSessionRestored >= 0, "Should be a sensible tSessionRestored");
gSeenRequest = true;
}
const PREF = "extensions.getAddons.getWithPerformance.url";
// Watch HTTP requests
Services.obs.addObserver(observe, "http-on-modify-request", false);
Services.prefs.setCharPref(PREF,
"http://127.0.0.1:8888/extensions-dummy/metadata?appOS=%OS%&appVersion=%VERSION%&tMain=%TIME_MAIN%&tFirstPaint=%TIME_FIRST_PAINT%&tSessionRestored=%TIME_SESSION_RESTORED%");
registerCleanupFunction(function() {
Services.obs.removeObserver(observe, "http-on-modify-request");
});
AddonRepository._beginGetAddons(["test1@tests.mozilla.org"], {
searchFailed: function() {
ok(gSeenRequest, "Should have seen metadata request");
finish();
}
}, true);
}

View File

@ -55,6 +55,7 @@ var gRestorePrefs = [{name: PREF_LOGGING_ENABLED},
{name: "extensions.webservice.discoverURL"},
{name: "extensions.update.url"},
{name: "extensions.getAddons.get.url"},
{name: "extensions.getAddons.getWithPerformance.url"},
{name: "extensions.getAddons.search.browseURL"},
{name: "extensions.getAddons.search.url"},
{name: "extensions.getAddons.cache.enabled"},

View File

@ -15,6 +15,7 @@ const BASE_URL = "http://localhost:" + PORT;
const PREF_GETADDONS_CACHE_ENABLED = "extensions.getAddons.cache.enabled";
const PREF_GETADDONS_CACHE_TYPES = "extensions.getAddons.cache.types";
const PREF_GETADDONS_BYIDS = "extensions.getAddons.get.url";
const PREF_GETADDONS_BYIDS_PERF = "extensions.getAddons.getWithPerformance.url";
const GETADDONS_RESULTS = BASE_URL + "/data/test_AddonRepository_cache.xml";
const GETADDONS_EMPTY = BASE_URL + "/data/test_AddonRepository_empty.xml";
const GETADDONS_FAILED = BASE_URL + "/data/test_AddonRepository_failed.xml";
@ -704,7 +705,7 @@ function run_test_14() {
// Tests that the XPI add-ons correctly use the repository properties when
// caching is enabled and the repository information is available
function run_test_15() {
Services.prefs.setCharPref(PREF_GETADDONS_BYIDS, GETADDONS_RESULTS);
Services.prefs.setCharPref(PREF_GETADDONS_BYIDS_PERF, GETADDONS_RESULTS);
trigger_background_update(function() {
AddonManager.getAddonsByIDs(ADDON_IDS, function(aAddons) {

View File

@ -6,7 +6,7 @@
const PREF_GETADDONS_CACHE_ENABLED = "extensions.getAddons.cache.enabled";
const PREF_GETADDONS_BYIDS = "extensions.getAddons.get.url";
const PREF_GETADDONS_BYIDS = "extensions.getAddons.getWithPerformance.url";
const PORT = 4444;
const BASE_URL = "http://localhost:" + PORT;

View File

@ -6,7 +6,7 @@
const PREF_MATCH_OS_LOCALE = "intl.locale.matchOS";
const PREF_SELECTED_LOCALE = "general.useragent.locale";
const PREF_GETADDONS_BYIDS = "extensions.getAddons.get.url";
const PREF_GETADDONS_BYIDS = "extensions.getAddons.getWithPerformance.url";
const PREF_GETADDONS_CACHE_ENABLED = "extensions.getAddons.cache.enabled";
// The test extension uses an insecure update url.

View File

@ -231,15 +231,6 @@ static void glxtest()
if (length >= bufsize)
fatal_error("GL strings length too large for buffer size");
///// Check that no X error happened /////
// In case of X errors, our X error handler will exit() now.
// We really want to make sure that the system is able to create a GL context without generating X errors,
// as these would crash the application.
XSync(dpy, False);
///// Finally write data to the pipe /////
write(write_end_of_the_pipe, buf, length);
///// Clean up. Indeed, the parent process might fail to kill us (e.g. if it doesn't need to check GL info)
///// so we might be staying alive for longer than expected, so it's important to consume as little memory as
///// possible. Also we want to check that we're able to do that too without generating X errors.
@ -249,6 +240,9 @@ static void glxtest()
XFreePixmap(dpy, pixmap);
XCloseDisplay(dpy);
dlclose(libgl);
///// Finally write data to the pipe
write(write_end_of_the_pipe, buf, length);
}
/** \returns true in the child glxtest process, false in the parent process */

View File

@ -425,7 +425,7 @@ void TableTicker::doBacktrace(Profile &aProfile)
void *array[100];
int count = backtrace (array, 100);
aProfile.addTag(ProfileEntry('s', "XRE_Main", 0));
aProfile.addTag(ProfileEntry('s', "(root)", 0));
for (int i = 0; i < count; i++) {
if( (intptr_t)array[i] == -1 ) break;
@ -464,7 +464,7 @@ void TableTicker::doBacktrace(Profile &aProfile)
};
nsresult rv = NS_StackWalk(StackWalkCallback, 0, &array, thread);
if (NS_SUCCEEDED(rv)) {
aProfile.addTag(ProfileEntry('s', "XRE_Main", 0));
aProfile.addTag(ProfileEntry('s', "(root)", 0));
for (size_t i = array.count; i > 0; --i) {
aProfile.addTag(ProfileEntry('l', (const char*)array.array[i - 1]));

View File

@ -93,7 +93,8 @@ GfxInfo::GetData()
close(glxtest_pipe);
glxtest_pipe = 0;
// bytesread < 0 would mean that the above read() call failed. This should never happen.
// bytesread < 0 would mean that the above read() call failed.
// This should never happen. If it did, the outcome would be to blacklist anyway.
if (bytesread < 0)
bytesread = 0;
@ -111,10 +112,15 @@ GfxInfo::GetData()
wait_for_glxtest_process = false;
if (waitpid(glxtest_pid, &glxtest_status, 0) == -1) {
waitpid_errno = errno;
if (waitpid_errno == EINTR)
if (waitpid_errno == EINTR) {
wait_for_glxtest_process = true;
else
waiting_for_glxtest_process_failed = true;
} else {
// Bug 718629
// ECHILD happens when the glxtest process got reaped got reaped after a PR_CreateProcess
// as per bug 227246. This shouldn't matter, as we still seem to get the data
// from the pipe, and if we didn't, the outcome would be to blacklist anyway.
waiting_for_glxtest_process_failed = (waitpid_errno != ECHILD);
}
}
}

Some files were not shown because too many files have changed in this diff Show More