зеркало из https://github.com/mozilla/pjs.git
Merge last PGO-green changeset of mozilla-inbound to mozilla-central
This commit is contained in:
Коммит
ce5670fc5e
|
@ -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
|
||||
|
|
|
@ -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%");
|
||||
|
|
|
@ -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) }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 + "]");
|
||||
}
|
||||
|
|
|
@ -77,6 +77,7 @@ endif
|
|||
DIRS += \
|
||||
base \
|
||||
battery \
|
||||
power \
|
||||
sms \
|
||||
src \
|
||||
locales \
|
||||
|
|
|
@ -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
|
||||
//*****************************************************************************
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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___ */
|
||||
|
|
|
@ -430,6 +430,8 @@ DOMCI_CLASS(GeoPositionError)
|
|||
|
||||
DOMCI_CLASS(MozBatteryManager)
|
||||
|
||||
DOMCI_CLASS(MozPowerManager)
|
||||
|
||||
DOMCI_CLASS(MozSmsManager)
|
||||
DOMCI_CLASS(MozSmsMessage)
|
||||
DOMCI_CLASS(MozSmsEvent)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
DOM_SRCDIRS = \
|
||||
dom/base \
|
||||
dom/battery \
|
||||
dom/power \
|
||||
dom/network/src \
|
||||
dom/sms/src \
|
||||
dom/src/events \
|
||||
|
|
|
@ -129,3 +129,6 @@ interface nsIDOMPkcs11;
|
|||
// Used font face (for inspector)
|
||||
interface nsIDOMFontFace;
|
||||
interface nsIDOMFontFaceList;
|
||||
|
||||
// Power
|
||||
interface nsIDOMMozPowerManager;
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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();
|
||||
};
|
|
@ -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();
|
||||
};
|
|
@ -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)
|
|
@ -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>
|
12
hal/Hal.cpp
12
hal/Hal.cpp
|
@ -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
|
||||
|
|
10
hal/Hal.h
10
hal/Hal.h
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -173,6 +173,14 @@ GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo)
|
|||
bridge->GetCurrentNetworkInformation(aNetworkInfo);
|
||||
}
|
||||
|
||||
void
|
||||
Reboot()
|
||||
{}
|
||||
|
||||
void
|
||||
PowerOff()
|
||||
{}
|
||||
|
||||
} // hal_impl
|
||||
} // mozilla
|
||||
|
||||
|
|
|
@ -105,5 +105,13 @@ GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo)
|
|||
aNetworkInfo->canBeMetered() = dom::network::kDefaultCanBeMetered;
|
||||
}
|
||||
|
||||
void
|
||||
Reboot()
|
||||
{}
|
||||
|
||||
void
|
||||
PowerOff()
|
||||
{}
|
||||
|
||||
} // hal_impl
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -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
|
|
@ -86,6 +86,9 @@ parent:
|
|||
sync GetScreenBrightness() returns (double brightness);
|
||||
SetScreenBrightness(double brightness);
|
||||
|
||||
Reboot();
|
||||
PowerOff();
|
||||
|
||||
__delete__();
|
||||
};
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -84,5 +84,13 @@ GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo)
|
|||
aNetworkInfo->canBeMetered() = dom::network::kDefaultCanBeMetered;
|
||||
}
|
||||
|
||||
void
|
||||
Reboot()
|
||||
{}
|
||||
|
||||
void
|
||||
PowerOff()
|
||||
{}
|
||||
|
||||
} // hal_impl
|
||||
} // mozilla
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 */
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -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 }
|
||||
};
|
||||
|
||||
|
|
|
@ -4,6 +4,6 @@
|
|||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
<div>ت<span>١٣</span></div>
|
||||
<div>ت<span>١</span><span>٣</span></div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -4,6 +4,6 @@
|
|||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
<div><span>١٣</span>ت</div>
|
||||
<div><span>١</span><span>٣</span>ت</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -4,6 +4,6 @@
|
|||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
<div><span>١٣</span></div>
|
||||
<div><span>١</span><span>٣</span></div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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()]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"/>
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"/>
|
||||
|
||||
|
|
|
@ -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"/>
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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, ¤tlyUsesTLS);
|
||||
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, ¤tlyUsesTLS);
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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>
|
|
@ -426,6 +426,10 @@ OS_LIBS += \
|
|||
-lhardware_legacy \
|
||||
-lhardware \
|
||||
-lutils \
|
||||
-lcutils \
|
||||
-lcamera \
|
||||
-lcamera_client \
|
||||
-lbinder \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -96,6 +96,7 @@ _MAIN_TEST_FILES = \
|
|||
|
||||
_TEST_FILES = \
|
||||
head.js \
|
||||
browser_addonrepository_performance.js \
|
||||
browser_bug557956.js \
|
||||
browser_bug616841.js \
|
||||
browser_hotfix.js \
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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"},
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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]));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче