diff --git a/b2g/chrome/content/shell.js b/b2g/chrome/content/shell.js index 60f97f1914e2..0423a229f6d6 100644 --- a/b2g/chrome/content/shell.js +++ b/b2g/chrome/content/shell.js @@ -334,6 +334,17 @@ nsBrowserAccess.prototype = { } }; +// Listen for system messages and relay them to Gaia. +Services.obs.addObserver(function(aSubject, aTopic, aData) { + let msg = JSON.parse(aData); + let origin = Services.io.newURI(msg.manifest, null, null).prePath; + shell.sendEvent(shell.contentBrowser.contentWindow, + "mozChromeEvent", { type: "open-app", + url: msg.uri, + origin: origin, + manifest: msg.manifest } ); +}, "system-messages-open-app", false); + (function Repl() { if (!Services.prefs.getBoolPref('b2g.remote-js.enabled')) { return; @@ -390,7 +401,7 @@ var CustomEventManager = { handleEvent: function custevt_handleEvent(evt) { let detail = evt.detail; - dump('XXX FIXME : Got a mozContentEvent: ' + detail.type); + dump('XXX FIXME : Got a mozContentEvent: ' + detail.type + "\n"); switch(detail.type) { case 'desktop-notification-click': diff --git a/b2g/confvars.sh b/b2g/confvars.sh index 7242c6e29986..dcb3de1ee13b 100755 --- a/b2g/confvars.sh +++ b/b2g/confvars.sh @@ -37,3 +37,5 @@ fi MOZ_APP_ID={3c2e2abc-06d4-11e1-ac3b-374f68613e61} MOZ_EXTENSION_MANAGER=1 ENABLE_MARIONETTE=1 + +MOZ_SYS_MSG=1 diff --git a/b2g/installer/package-manifest.in b/b2g/installer/package-manifest.in index 9d885a52a426..9f9ebefc18a0 100644 --- a/b2g/installer/package-manifest.in +++ b/b2g/installer/package-manifest.in @@ -178,6 +178,7 @@ @BINPATH@/components/dom_mms.xpt #endif @BINPATH@/components/dom_browserelement.xpt +@BINPATH@/components/dom_messages.xpt @BINPATH@/components/dom_power.xpt @BINPATH@/components/dom_range.xpt @BINPATH@/components/dom_settings.xpt @@ -463,6 +464,10 @@ @BINPATH@/components/AppsService.js @BINPATH@/components/AppsService.manifest +@BINPATH@/components/SystemMessageInternal.js +@BINPATH@/components/SystemMessageManager.js +@BINPATH@/components/SystemMessageManager.manifest + ; Modules @BINPATH@/modules/* diff --git a/config/autoconf.mk.in b/config/autoconf.mk.in index 8713524d6547..4bbd06e241a1 100644 --- a/config/autoconf.mk.in +++ b/config/autoconf.mk.in @@ -273,6 +273,8 @@ MOZ_NATIVE_NSS = @MOZ_NATIVE_NSS@ MOZ_B2G_RIL = @MOZ_B2G_RIL@ MOZ_B2G_BT = @MOZ_B2G_BT@ +MOZ_SYS_MSG = @MOZ_SYS_MSG@ + MOZ_ASAN = @MOZ_ASAN@ MOZ_CFLAGS_NSS = @MOZ_CFLAGS_NSS@ MOZ_NO_WLZDEFS = @MOZ_NO_WLZDEFS@ diff --git a/configure.in b/configure.in index 9f53fd1280a0..9015ca9e5126 100644 --- a/configure.in +++ b/configure.in @@ -7437,6 +7437,12 @@ if test -n "$MOZ_B2G_BT"; then fi AC_SUBST(MOZ_B2G_BT) +dnl ======================================================== +dnl = Enable Support for System Messages API +dnl ======================================================== + +AC_SUBST(MOZ_SYS_MSG) + dnl ======================================================== dnl = Support for demangling undefined symbols dnl ======================================================== diff --git a/content/base/public/nsContentPolicyUtils.h b/content/base/public/nsContentPolicyUtils.h index 702dbdd02d29..df3cc731aa84 100644 --- a/content/base/public/nsContentPolicyUtils.h +++ b/content/base/public/nsContentPolicyUtils.h @@ -125,14 +125,16 @@ NS_CP_ContentTypeName(PRUint32 contentType) return NS_ERROR_FAILURE; \ \ return policy-> action (contentType, contentLocation, requestOrigin, \ - context, mimeType, extra, decision); \ + context, mimeType, extra, originPrincipal, \ + decision); \ PR_END_MACRO /* Passes on parameters from its "caller"'s context. */ #define CHECK_CONTENT_POLICY_WITH_SERVICE(action, _policy) \ PR_BEGIN_MACRO \ return _policy-> action (contentType, contentLocation, requestOrigin, \ - context, mimeType, extra, decision); \ + context, mimeType, extra, originPrincipal, \ + decision); \ PR_END_MACRO /** diff --git a/content/base/public/nsIContentPolicy.idl b/content/base/public/nsIContentPolicy.idl index 3102ba8696a0..d703ab217091 100644 --- a/content/base/public/nsIContentPolicy.idl +++ b/content/base/public/nsIContentPolicy.idl @@ -5,6 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsISupports.idl" +#include "nsIPrincipal.idl" interface nsIURI; interface nsIDOMNode; @@ -18,7 +19,7 @@ interface nsIDOMNode; * by launching a dialog to prompt the user for something). */ -[scriptable,uuid(344f9cb0-9a17-44c5-ab96-ee707884266c)] +[scriptable,uuid(e590e74f-bac7-4876-8c58-54dde92befb2)] interface nsIContentPolicy : nsISupports { const unsigned long TYPE_OTHER = 1; @@ -209,7 +210,8 @@ interface nsIContentPolicy : nsISupports in nsIURI aRequestOrigin, in nsISupports aContext, in ACString aMimeTypeGuess, - in nsISupports aExtra); + in nsISupports aExtra, + [optional] in nsIPrincipal aRequestPrincipal); /** * Should the resource be processed? @@ -251,6 +253,7 @@ interface nsIContentPolicy : nsISupports in nsIURI aRequestOrigin, in nsISupports aContext, in ACString aMimeType, - in nsISupports aExtra); + in nsISupports aExtra, + [optional] in nsIPrincipal aRequestPrincipal); }; diff --git a/content/base/src/nsCSPService.cpp b/content/base/src/nsCSPService.cpp index 18be06697879..fc059275071e 100644 --- a/content/base/src/nsCSPService.cpp +++ b/content/base/src/nsCSPService.cpp @@ -57,6 +57,7 @@ CSPService::ShouldLoad(PRUint32 aContentType, nsISupports *aRequestContext, const nsACString &aMimeTypeGuess, nsISupports *aExtra, + nsIPrincipal *aRequestPrincipal, PRInt16 *aDecision) { if (!aContentLocation) @@ -123,6 +124,7 @@ CSPService::ShouldProcess(PRUint32 aContentType, nsISupports *aRequestContext, const nsACString &aMimeTypeGuess, nsISupports *aExtra, + nsIPrincipal *aRequestPrincipal, PRInt16 *aDecision) { if (!aContentLocation) diff --git a/content/base/src/nsContentPolicy.cpp b/content/base/src/nsContentPolicy.cpp index 874d3cbbf21d..02f1a653b388 100644 --- a/content/base/src/nsContentPolicy.cpp +++ b/content/base/src/nsContentPolicy.cpp @@ -76,6 +76,7 @@ nsContentPolicy::CheckPolicy(CPMethod policyMethod, nsISupports *requestingContext, const nsACString &mimeType, nsISupports *extra, + nsIPrincipal *requestPrincipal, PRInt16 *decision) { //sanity-check passed-through parameters @@ -122,7 +123,8 @@ nsContentPolicy::CheckPolicy(CPMethod policyMethod, /* check the appropriate policy */ rv = (entries[i]->*policyMethod)(contentType, contentLocation, requestingLocation, requestingContext, - mimeType, extra, decision); + mimeType, extra, requestPrincipal, + decision); if (NS_SUCCEEDED(rv) && NS_CP_REJECTED(*decision)) { /* policy says no, no point continuing to check */ @@ -177,13 +179,15 @@ nsContentPolicy::ShouldLoad(PRUint32 contentType, nsISupports *requestingContext, const nsACString &mimeType, nsISupports *extra, + nsIPrincipal *requestPrincipal, PRInt16 *decision) { // ShouldProcess does not need a content location, but we do NS_PRECONDITION(contentLocation, "Must provide request location"); nsresult rv = CheckPolicy(&nsIContentPolicy::ShouldLoad, contentType, contentLocation, requestingLocation, - requestingContext, mimeType, extra, decision); + requestingContext, mimeType, extra, + requestPrincipal, decision); LOG_CHECK("ShouldLoad"); return rv; @@ -196,11 +200,13 @@ nsContentPolicy::ShouldProcess(PRUint32 contentType, nsISupports *requestingContext, const nsACString &mimeType, nsISupports *extra, + nsIPrincipal *requestPrincipal, PRInt16 *decision) { nsresult rv = CheckPolicy(&nsIContentPolicy::ShouldProcess, contentType, contentLocation, requestingLocation, - requestingContext, mimeType, extra, decision); + requestingContext, mimeType, extra, + requestPrincipal, decision); LOG_CHECK("ShouldProcess"); return rv; diff --git a/content/base/src/nsContentPolicy.h b/content/base/src/nsContentPolicy.h index 5a781ca71de2..3ddf7be5d551 100644 --- a/content/base/src/nsContentPolicy.h +++ b/content/base/src/nsContentPolicy.h @@ -31,7 +31,8 @@ class nsContentPolicy : public nsIContentPolicy NS_STDCALL_FUNCPROTO(nsresult, CPMethod, nsIContentPolicy, ShouldProcess, (PRUint32, nsIURI*, nsIURI*, nsISupports*, - const nsACString &, nsISupports*, PRInt16*)); + const nsACString &, nsISupports*, nsIPrincipal*, + PRInt16*)); //Helper method that applies policyMethod across all policies in mPolicies // with the given parameters @@ -39,6 +40,7 @@ class nsContentPolicy : public nsIContentPolicy nsIURI *aURI, nsIURI *origURI, nsISupports *requestingContext, const nsACString &mimeGuess, nsISupports *extra, + nsIPrincipal *requestPrincipal, PRInt16 *decision); }; diff --git a/content/base/src/nsDataDocumentContentPolicy.cpp b/content/base/src/nsDataDocumentContentPolicy.cpp index 8bb5c60c7a62..b44d48a510ba 100644 --- a/content/base/src/nsDataDocumentContentPolicy.cpp +++ b/content/base/src/nsDataDocumentContentPolicy.cpp @@ -37,6 +37,7 @@ nsDataDocumentContentPolicy::ShouldLoad(PRUint32 aContentType, nsISupports *aRequestingContext, const nsACString &aMimeGuess, nsISupports *aExtra, + nsIPrincipal *aRequestPrincipal, PRInt16 *aDecision) { *aDecision = nsIContentPolicy::ACCEPT; @@ -129,8 +130,10 @@ nsDataDocumentContentPolicy::ShouldProcess(PRUint32 aContentType, nsISupports *aRequestingContext, const nsACString &aMimeGuess, nsISupports *aExtra, + nsIPrincipal *aRequestPrincipal, PRInt16 *aDecision) { return ShouldLoad(aContentType, aContentLocation, aRequestingLocation, - aRequestingContext, aMimeGuess, aExtra, aDecision); + aRequestingContext, aMimeGuess, aExtra, aRequestPrincipal, + aDecision); } diff --git a/content/base/src/nsNoDataProtocolContentPolicy.cpp b/content/base/src/nsNoDataProtocolContentPolicy.cpp index 29931280f8e3..cc61b9966cda 100644 --- a/content/base/src/nsNoDataProtocolContentPolicy.cpp +++ b/content/base/src/nsNoDataProtocolContentPolicy.cpp @@ -26,6 +26,7 @@ nsNoDataProtocolContentPolicy::ShouldLoad(PRUint32 aContentType, nsISupports *aRequestingContext, const nsACString &aMimeGuess, nsISupports *aExtra, + nsIPrincipal *aRequestPrincipal, PRInt16 *aDecision) { *aDecision = nsIContentPolicy::ACCEPT; @@ -70,8 +71,10 @@ nsNoDataProtocolContentPolicy::ShouldProcess(PRUint32 aContentType, nsISupports *aRequestingContext, const nsACString &aMimeGuess, nsISupports *aExtra, + nsIPrincipal *aRequestPrincipal, PRInt16 *aDecision) { return ShouldLoad(aContentType, aContentLocation, aRequestingLocation, - aRequestingContext, aMimeGuess, aExtra, aDecision); + aRequestingContext, aMimeGuess, aExtra, aRequestPrincipal, + aDecision); } diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 1a1a3ec3b755..c497410e776e 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -8162,8 +8162,8 @@ nsDocShell::InternalLoad(nsIURI * aURI, } // XXXbz would be nice to know the loading principal here... but we don't - nsCOMPtr loadingPrincipal; - if (aReferrer) { + nsCOMPtr loadingPrincipal = do_QueryInterface(aOwner); + if (!loadingPrincipal && aReferrer) { nsCOMPtr secMan = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); @@ -8171,7 +8171,7 @@ nsDocShell::InternalLoad(nsIURI * aURI, rv = secMan->GetCodebasePrincipal(aReferrer, getter_AddRefs(loadingPrincipal)); } - + rv = NS_CheckContentLoadPolicy(contentType, aURI, loadingPrincipal, diff --git a/dom/Makefile.in b/dom/Makefile.in index e02a3a9c5685..71301c6da298 100644 --- a/dom/Makefile.in +++ b/dom/Makefile.in @@ -53,6 +53,7 @@ DIRS += \ devicestorage \ file \ media \ + messages \ power \ settings \ sms \ diff --git a/dom/apps/src/Webapps.jsm b/dom/apps/src/Webapps.jsm index 018929a633f8..828cc989fbb9 100644 --- a/dom/apps/src/Webapps.jsm +++ b/dom/apps/src/Webapps.jsm @@ -2,6 +2,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ +"use strict"; + const Cu = Components.utils; const Cc = Components.classes; const Ci = Components.interfaces; @@ -23,6 +25,10 @@ XPCOMUtils.defineLazyGetter(this, "ppmm", function() { return Cc["@mozilla.org/parentprocessmessagemanager;1"].getService(Ci.nsIFrameMessageManager); }); +XPCOMUtils.defineLazyGetter(this, "msgmgr", function() { + return Cc["@mozilla.org/system-message-internal;1"].getService(Ci.nsISystemMessagesInternal); +}); + #ifdef MOZ_WIDGET_GONK const DIRECTORY_NAME = "webappsDir"; #else @@ -52,7 +58,14 @@ let DOMApplicationRegistry = { this.appsFile = FileUtils.getFile(DIRECTORY_NAME, ["webapps", "webapps.json"], true); if (this.appsFile.exists()) { - this._loadJSONAsync(this.appsFile, (function(aData) { this.webapps = aData; }).bind(this)); + this._loadJSONAsync(this.appsFile, (function(aData) { + this.webapps = aData; +#ifdef MOZ_SYS_MSG + for (let id in this.webapps) { + this._registerSystemMessagesForId(id); + }; +#endif + }).bind(this)); } try { @@ -64,6 +77,26 @@ let DOMApplicationRegistry = { } catch(e) { } }, +#ifdef MOZ_SYS_MSG + _registerSystemMessages: function(aManifest, aApp) { + if (aManifest.messages && Array.isArray(aManifest.messages) && aManifest.messages.length > 0) { + let manifest = new DOMApplicationManifest(aManifest, aApp.origin); + let launchPath = Services.io.newURI(manifest.fullLaunchPath(), null, null); + let manifestURL = Services.io.newURI(aApp.manifestURL, null, null); + aManifest.messages.forEach(function registerPages(aMessage) { + msgmgr.registerPage(aMessage, launchPath, manifestURL); + }); + } + }, + + _registerSystemMessagesForId: function(aId) { + let app = this.webapps[aId]; + this._readManifests([{ id: aId }], (function registerManifest(aResult) { + this._registerSystemMessages(aResult[0].manifest, app); + }).bind(this)); + }, +#endif + observe: function(aSubject, aTopic, aData) { if (aTopic == "xpcom-shutdown") { this.messages.forEach((function(msgName) { @@ -208,6 +241,10 @@ let DOMApplicationRegistry = { Services.obs.notifyObservers(this, "webapps-sync-install", appNote); }).bind(this)); +#ifdef MOZ_SYS_MSG + this._registerSystemMessages(id, app); +#endif + // if the manifest has an appcache_path property, use it to populate the appcache if (manifest.appcache_path) { let appcacheURI = Services.io.newURI(manifest.fullAppcachePath(), null, null); @@ -533,7 +570,7 @@ let DOMApplicationRegistry = { /** * Appcache download observer */ -AppcacheObserver = function(aApp) { +let AppcacheObserver = function(aApp) { this.app = aApp; }; @@ -580,7 +617,7 @@ AppcacheObserver.prototype = { /** * Helper object to access manifest information with locale support */ -DOMApplicationManifest = function(aManifest, aOrigin) { +let DOMApplicationManifest = function(aManifest, aOrigin) { this._origin = Services.io.newURI(aOrigin, null, null); this._manifest = aManifest; let chrome = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry) diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp index 6ab8c4a3b850..f75f4709f9c1 100644 --- a/dom/base/Navigator.cpp +++ b/dom/base/Navigator.cpp @@ -50,6 +50,8 @@ #include "BluetoothManager.h" #endif +#include "nsIDOMGlobalPropertyInitializer.h" + // This should not be in the namespace. DOMCI_DATA(Navigator, mozilla::dom::Navigator) @@ -109,6 +111,7 @@ NS_INTERFACE_MAP_BEGIN(Navigator) #ifdef MOZ_B2G_BT NS_INTERFACE_MAP_ENTRY(nsIDOMNavigatorBluetooth) #endif + NS_INTERFACE_MAP_ENTRY(nsIDOMNavigatorSystemMessages) NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Navigator) NS_INTERFACE_MAP_END @@ -172,6 +175,13 @@ Navigator::Invalidate() mBluetooth = nsnull; } #endif + +#ifdef MOZ_SYS_MSG + if (mMessagesManager) { + mMessagesManager = nsnull; + } +#endif + } nsPIDOMWindow * @@ -1249,6 +1259,67 @@ Navigator::GetMozBluetooth(nsIDOMBluetoothManager** aBluetooth) } #endif //MOZ_B2G_BT +//***************************************************************************** +// nsNavigator::nsIDOMNavigatorSystemMessages +//***************************************************************************** +#ifdef MOZ_SYS_MSG +NS_IMETHODIMP +Navigator::EnsureMessagesManager() +{ + if (mMessagesManager) { + return NS_OK; + } + + nsCOMPtr window = do_QueryReferent(mWindow); + NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); + + nsresult rv; + nsCOMPtr messageManager = + do_CreateInstance("@mozilla.org/system-message-manager;1", &rv); + + nsCOMPtr gpi = + do_QueryInterface(messageManager); + NS_ENSURE_TRUE(gpi, NS_ERROR_FAILURE); + + // We don't do anything with the return value. + jsval prop_val = JSVAL_VOID; + rv = gpi->Init(window, &prop_val); + NS_ENSURE_SUCCESS(rv, rv); + + mMessagesManager = messageManager.forget(); + + return NS_OK; +} +#endif + +NS_IMETHODIMP +Navigator::MozHasPendingMessage(const nsAString& aType, bool *aResult) +{ +#ifdef MOZ_SYS_MSG + *aResult = false; + nsresult rv = EnsureMessagesManager(); + NS_ENSURE_SUCCESS(rv, rv); + + return mMessagesManager->MozHasPendingMessage(aType, aResult); +#else + return NS_ERROR_NOT_IMPLEMENTED; +#endif +} + +NS_IMETHODIMP +Navigator::MozSetMessageHandler(const nsAString& aType, + nsIDOMSystemMessageCallback *aCallback) +{ +#ifdef MOZ_SYS_MSG + nsresult rv = EnsureMessagesManager(); + NS_ENSURE_SUCCESS(rv, rv); + + return mMessagesManager->MozSetMessageHandler(aType, aCallback); +#else + return NS_ERROR_NOT_IMPLEMENTED; +#endif +} + size_t Navigator::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const { diff --git a/dom/base/Navigator.h b/dom/base/Navigator.h index 208a326089e0..dc27f6ad2a01 100644 --- a/dom/base/Navigator.h +++ b/dom/base/Navigator.h @@ -38,6 +38,8 @@ class nsIDOMTelephony; #include "nsIDOMNavigatorBluetooth.h" #endif +#include "nsIDOMNavigatorSystemMessages.h" + //***************************************************************************** // Navigator: Script "navigator" object //***************************************************************************** @@ -79,7 +81,7 @@ class Navigator : public nsIDOMNavigator #ifdef MOZ_B2G_BT , public nsIDOMNavigatorBluetooth #endif - + , public nsIDOMNavigatorSystemMessages { public: Navigator(nsPIDOMWindow *aInnerWindow); @@ -104,6 +106,7 @@ public: #ifdef MOZ_B2G_BT NS_DECL_NSIDOMNAVIGATORBLUETOOTH #endif + NS_DECL_NSIDOMNAVIGATORSYSTEMMESSAGES static void Init(); @@ -126,6 +129,11 @@ public: */ void OnNavigation(); +#ifdef MOZ_SYS_MSG + // Helper to initialize mMessagesManager. + nsresult EnsureMessagesManager(); +#endif + private: bool IsSmsAllowed() const; bool IsSmsSupported() const; @@ -145,6 +153,7 @@ private: #ifdef MOZ_B2G_BT nsCOMPtr mBluetooth; #endif + nsCOMPtr mMessagesManager; nsWeakPtr mWindow; }; diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp index 782544f4674a..8629989a20a9 100644 --- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -522,6 +522,8 @@ using mozilla::dom::indexedDB::IDBWrapperCache; #include "BluetoothAdapter.h" #endif +#include "nsIDOMNavigatorSystemMessages.h" + #include "DOMError.h" #include "DOMRequest.h" #include "nsIOpenWindowEventDetail.h" @@ -2483,6 +2485,7 @@ nsDOMClassInfo::Init() #ifdef MOZ_B2G_BT DOM_CLASSINFO_MAP_ENTRY(nsIDOMNavigatorBluetooth) #endif + DOM_CLASSINFO_MAP_ENTRY(nsIDOMNavigatorSystemMessages) DOM_CLASSINFO_MAP_END DOM_CLASSINFO_MAP_BEGIN(Plugin, nsIDOMPlugin) diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp index fa3ddbe29bb3..a490ca37a70f 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -64,6 +64,7 @@ #include "sampler.h" #include "nsDOMBlobBuilder.h" #include "nsIDOMFileHandle.h" +#include "nsIDOMApplicationRegistry.h" using namespace mozilla; using namespace mozilla::dom; @@ -2569,3 +2570,16 @@ nsDOMWindowUtils::SetApp(const nsAString& aManifestURL) return static_cast(window.get())->SetApp(aManifestURL); } + +NS_IMETHODIMP +nsDOMWindowUtils::GetApp(mozIDOMApplication** aApplication) +{ + if (!IsUniversalXPConnectCapable()) { + return NS_ERROR_DOM_SECURITY_ERR; + } + + nsCOMPtr window = do_QueryReferent(mWindow); + NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); + + return static_cast(window.get())->GetApp(aApplication); +} diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 6a344059a23b..ade6203f508a 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -8715,12 +8715,12 @@ nsGlobalWindow::RegisterIdleObserver(nsIIdleObserver* aIdleObserver) return NS_OK; } - MOZ_ASSERT(mIdleCallbackIndex >= 0); - if (!mCurrentlyIdle) { return NS_OK; } + MOZ_ASSERT(mIdleCallbackIndex >= 0); + if (static_cast(insertAtIndex) < mIdleCallbackIndex) { NotifyIdleObserver(tmpIdleObserver.mIdleObserver, tmpIdleObserver.mTimeInS, @@ -8784,7 +8784,6 @@ nsresult nsGlobalWindow::UnregisterIdleObserver(nsIIdleObserver* aIdleObserver) { MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!"); - MOZ_ASSERT(mIdleTimer); PRInt32 removeElementIndex; nsresult rv = FindIndexOfElementToRemove(aIdleObserver, &removeElementIndex); @@ -8794,11 +8793,13 @@ nsGlobalWindow::UnregisterIdleObserver(nsIIdleObserver* aIdleObserver) } mIdleObservers.RemoveElementAt(removeElementIndex); + MOZ_ASSERT(mIdleTimer); if (mIdleObservers.IsEmpty() && mIdleService) { rv = mIdleService->RemoveIdleObserver(mObserver, MIN_IDLE_NOTIFICATION_TIME_S); NS_ENSURE_SUCCESS(rv, rv); mIdleService = nsnull; + mIdleTimer->Cancel(); mIdleCallbackIndex = -1; return NS_OK; } @@ -10677,22 +10678,14 @@ nsGlobalWindow::SetIsApp(bool aValue) bool nsGlobalWindow::IsPartOfApp() { - FORWARD_TO_OUTER(IsPartOfApp, (), TriState_False); + mozIDOMApplication* app; + nsresult rv = GetApp(&app); - // We go trough all window parents until we find one with |mIsApp| set to - // something. If none is found, we are not part of an application. - for (nsGlobalWindow* w = this; w; - w = static_cast(w->GetParentInternal())) { - if (w->mIsApp == TriState_True) { - // The window should be part of an application. - MOZ_ASSERT(w->mApp); - return true; - } else if (w->mIsApp == TriState_False) { - return false; - } + if (NS_FAILED(rv)) { + return false; } - return false; + return app != nsnull; } nsresult @@ -10722,6 +10715,30 @@ nsGlobalWindow::SetApp(const nsAString& aManifestURL) return NS_OK; } +nsresult +nsGlobalWindow::GetApp(mozIDOMApplication** aApplication) +{ + *aApplication = nsnull; + + FORWARD_TO_OUTER(GetApp, (aApplication), NS_OK); + + // We go trough all window parents until we find one with |mIsApp| set to + // something. If none is found, we are not part of an application. + for (nsGlobalWindow* w = this; w; + w = static_cast(w->GetParentInternal())) { + if (w->mIsApp == TriState_True) { + // The window should be part of an application. + MOZ_ASSERT(w->mApp); + NS_IF_ADDREF(*aApplication = w->mApp); + return NS_OK; + } else if (w->mIsApp == TriState_False) { + return NS_OK; + } + } + + return NS_OK; +} + // nsGlobalChromeWindow implementation NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalChromeWindow) diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h index 7aa2e21512fc..d6d5cc89a72e 100644 --- a/dom/base/nsGlobalWindow.h +++ b/dom/base/nsGlobalWindow.h @@ -894,6 +894,7 @@ protected: void SetIsApp(bool aValue); nsresult SetApp(const nsAString& aManifestURL); + nsresult GetApp(mozIDOMApplication** aApplication); // Implements Get{Real,Scriptable}Top. nsresult GetTopImpl(nsIDOMWindow **aWindow, bool aScriptable); diff --git a/dom/interfaces/base/nsIDOMWindowUtils.idl b/dom/interfaces/base/nsIDOMWindowUtils.idl index c3f91794c88e..f7525ae33bfa 100644 --- a/dom/interfaces/base/nsIDOMWindowUtils.idl +++ b/dom/interfaces/base/nsIDOMWindowUtils.idl @@ -38,6 +38,7 @@ interface nsIDOMFile; interface nsIFile; interface nsIDOMTouch; interface nsIDOMClientRect; +interface mozIDOMApplication; [scriptable, uuid(858578f1-9653-4d5c-821a-07479bf2d9b2)] interface nsIDOMWindowUtils : nsISupports { @@ -1165,4 +1166,9 @@ interface nsIDOMWindowUtils : nsISupports { * or isn't the manifest URL of an installed application. */ void setApp(in DOMString manifestURL); + /** + * Retrieves the Application object associated to this window. + * Can be null if |setApp()| has not been called. + */ + mozIDOMApplication getApp(); }; diff --git a/dom/messages/Makefile.in b/dom/messages/Makefile.in new file mode 100644 index 000000000000..51dbc721bd3f --- /dev/null +++ b/dom/messages/Makefile.in @@ -0,0 +1,22 @@ +# 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/. + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +relativesrcdir = dom/messages + +include $(DEPTH)/config/autoconf.mk + +PARALLEL_DIRS = interfaces + +EXTRA_COMPONENTS = \ + SystemMessageManager.js \ + SystemMessageInternal.js \ + SystemMessageManager.manifest \ + $(NULL) + +include $(topsrcdir)/config/rules.mk diff --git a/dom/messages/SystemMessageInternal.js b/dom/messages/SystemMessageInternal.js new file mode 100644 index 000000000000..0056f729edad --- /dev/null +++ b/dom/messages/SystemMessageInternal.js @@ -0,0 +1,121 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; +const Cr = Components.results; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); + +XPCOMUtils.defineLazyGetter(this, "ppmm", function() { + return Cc["@mozilla.org/parentprocessmessagemanager;1"].getService(Ci.nsIFrameMessageManager); +}); + +// Limit the number of pending messages for a given page. +let kMaxPendingMessages; +try { + kMaxPendingMessages = Services.prefs.getIntPref("dom.messages.maxPendingMessages"); +} catch(e) { + // getIntPref throws when the pref is not set. + kMaxPendingMessages = 5; +} + +function debug(aMsg) { + //dump("-- SystemMessageInternal " + Date.now() + " : " + aMsg + "\n"); +} + +// Implementation of the component used by internal users. + +function SystemMessageInternal() { + // The set of pages registered by installed apps. We keep the + // list of pending messages for each page here also. + this._pages = []; + Services.obs.addObserver(this, "xpcom-shutdown", false); + ppmm.addMessageListener("SystemMessageManager:GetPending", this); +} + +SystemMessageInternal.prototype = { + sendMessage: function sendMessage(aType, aMessage, aManifestURI) { + debug("Broadcasting " + aType + " " + JSON.stringify(aMessage)); + ppmm.sendAsyncMessage("SystemMessageManager:Message" , { type: aType, + msg: aMessage, + manifest: aManifestURI.spec }); + + // Queue the message for pages that registered an handler for this type. + this._pages.forEach(function sendMess_openPage(aPage) { + if (aPage.type != aType || aPage.manifest != aManifestURI.spec) { + return; + } + + aPage.pending.push(aMessage); + if (aPage.pending.length > kMaxPendingMessages) { + aPage.pending.splice(0, 1); + } + + // We don't need to send the full object to observers. + let page = { uri: aPage.uri, manifest: aPage.manifest }; + debug("Asking to open " + JSON.stringify(page)); + Services.obs.notifyObservers(this, "system-messages-open-app", JSON.stringify(page)); + }.bind(this)) + }, + + registerPage: function registerPage(aType, aPageURI, aManifestURI) { + if (!aPageURI || !aManifestURI) { + throw Cr.NS_ERROR_INVALID_ARG; + } + + this._pages.push({ type: aType, + uri: aPageURI.spec, + manifest: aManifestURI.spec, + pending: [] }); + }, + + receiveMessage: function receiveMessage(aMessage) { + debug("received SystemMessageManager:GetPending " + aMessage.json.type + " for " + aMessage.json.uri + " @ " + aMessage.json.manifest); + // This is a sync call, use to return the pending message for a page. + let msg = aMessage.json; + debug(JSON.stringify(msg)); + + // Find the right page. + let page = null; + this._pages.some(function(aPage) { + if (aPage.uri == msg.uri && + aPage.type == msg.type && + aPage.manifest == msg.manifest) { + page = aPage; + } + return page !== null; + }); + + if (!page) { + return null; + } + + let pending = page.pending; + // Clear the pending queue for this page. + // This is ok since we'll store pending events in SystemMessageManager.js + page.pending = []; + + return pending; + }, + + observe: function observe(aSubject, aTopic, aData) { + if (aTopic == "xpcom-shutdown") { + ppmm.removeMessageListener("SystemMessageManager:GetPending", this); + Services.obs.removeObserver(this, "xpcom-shutdown"); + ppmm = null; + this._pages = null; + } + }, + + classID: Components.ID("{70589ca5-91ac-4b9e-b839-d6a88167d714}"), + + QueryInterface: XPCOMUtils.generateQI([Ci.nsISystemMessagesInternal, Ci.nsIObserver]) +} + +const NSGetFactory = XPCOMUtils.generateNSGetFactory([SystemMessageInternal]); diff --git a/dom/messages/SystemMessageManager.js b/dom/messages/SystemMessageManager.js new file mode 100644 index 000000000000..60d62861c781 --- /dev/null +++ b/dom/messages/SystemMessageManager.js @@ -0,0 +1,172 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/DOMRequestHelper.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); + +XPCOMUtils.defineLazyGetter(this, "cpmm", function() { + return Cc["@mozilla.org/childprocessmessagemanager;1"] + .getService(Ci.nsIFrameMessageManager) + .QueryInterface(Ci.nsISyncMessageSender); +}); + +// Limit the number of pending messages for a given type. +let kMaxPendingMessages; +try { + kMaxPendingMessages = Services.prefs.getIntPref("dom.messages.maxPendingMessages"); +} catch(e) { + // getIntPref throws when the pref is not set. + kMaxPendingMessages = 5; +} + +function debug(aMsg) { + //dump("-- SystemMessageManager " + Date.now() + " : " + aMsg + "\n"); +} + +// Implementation of the DOM API for system messages + +function SystemMessageManager() { + // Message handlers for this page. + // We can have only one handler per message type. + this._handlers = {}; + + // Pending messages for this page, keyed by message type. + this._pendings = {}; +} + +SystemMessageManager.prototype = { + __proto__: DOMRequestIpcHelper.prototype, + + mozSetMessageHandler: function sysMessMgr_setMessageHandler(aType, aHandler) { + debug("setMessage handler for [" + aType + "] " + aHandler); + if (!aType) { + // Just bail out if we have no type. + return; + } + + let handlers = this._handlers; + if (!aHandler) { + // Setting the handler to null means we don't want to receive messages + // of this type anymore. + delete handlers[aType]; + return; + } + + // Last registered handler wins. + handlers[aType] = aHandler; + + // If we have pending messages, send them asynchronously. + if (this._getPendingMessages(aType, true)) { + let thread = Services.tm.mainThread; + let pending = this._pendings[aType]; + this._pendings[aType] = []; + pending.forEach(function dispatch_pending(aPending) { + thread.dispatch({ + run: function run() { + aHandler.handleMessage(aPending); + } + }, Ci.nsIEventTarget.DISPATCH_NORMAL); + }); + } + }, + + _getPendingMessages: function sysMessMgr_getPendingMessages(aType, aForceUpdate) { + debug("hasPendingMessage " + aType); + let pendings = this._pendings; + + // If we have a handler for this type, we can't have any pending message. + // If called from setMessageHandler, we still want to update the pending + // queue to deliver existing messages. + if (aType in this._handlers && !aForceUpdate) { + return false; + } + + // Send a sync message to the parent to check if we have a pending message + // for this type. + let messages = cpmm.sendSyncMessage("SystemMessageManager:GetPending", + { type: aType, + uri: this._uri, + manifest: this._manifest })[0]; + if (!messages) { + // No new pending messages, but the queue may not be empty yet. + return pendings[aType] && pendings[aType].length != 0; + } + + if (!pendings[aType]) { + pendings[aType] = []; + } + + // Doing that instead of pending.concat() to avoid array copy. + messages.forEach(function hpm_addPendings(aMessage) { + pendings[aType].push(aMessage); + if (pendings[aType].length > kMaxPendingMessages) { + pendings[aType].splice(0, 1); + } + }); + + return pendings[aType].length != 0; + }, + + mozHasPendingMessage: function sysMessMgr_hasPendingMessage(aType) { + return this._getPendingMessages(aType, false); + }, + + uninit: function sysMessMgr_uninit() { + this._handlers = null; + this._pendings = null; + }, + + receiveMessage: function sysMessMgr_receiveMessage(aMessage) { + debug("receiveMessage " + aMessage.name + " - " + + aMessage.json.type + " for " + aMessage.json.manifest + + " (" + this._manifest + ")"); + + let msg = aMessage.json; + if (msg.manifest != this._manifest) + return; + + // Bail out if we have no handlers registered for this type. + if (!(msg.type in this._handlers)) { + debug("No handler for this type"); + return; + } + + this._handlers[msg.type].handleMessage(msg.msg); + }, + + // nsIDOMGlobalPropertyInitializer implementation. + init: function sysMessMgr_init(aWindow) { + debug("init"); + this.initHelper(aWindow, ["SystemMessageManager:Message"]); + this._uri = aWindow.document.nodePrincipal.URI.spec; + let utils = aWindow.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Components.interfaces.nsIDOMWindowUtils); + + // Get the manifest url is this is an installed app. + this._manifest = null; + let app = utils.getApp(); + if (app) + this._manifest = app.manifestURL; + }, + + classID: Components.ID("{bc076ea0-609b-4d8f-83d7-5af7cbdc3bb2}"), + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMNavigatorSystemMessages, + Ci.nsIDOMGlobalPropertyInitializer]), + + classInfo: XPCOMUtils.generateCI({classID: Components.ID("{bc076ea0-609b-4d8f-83d7-5af7cbdc3bb2}"), + contractID: "@mozilla.org/system-message-manager;1", + interfaces: [Ci.nsIDOMNavigatorSystemMessages], + flags: Ci.nsIClassInfo.DOM_OBJECT, + classDescription: "System Messages"}) +} + +const NSGetFactory = XPCOMUtils.generateNSGetFactory([SystemMessageManager]); diff --git a/dom/messages/SystemMessageManager.manifest b/dom/messages/SystemMessageManager.manifest new file mode 100644 index 000000000000..307bd40d8979 --- /dev/null +++ b/dom/messages/SystemMessageManager.manifest @@ -0,0 +1,5 @@ +component {bc076ea0-609b-4d8f-83d7-5af7cbdc3bb2} SystemMessageManager.js +contract @mozilla.org/system-message-manager;1 {bc076ea0-609b-4d8f-83d7-5af7cbdc3bb2} + +component {70589ca5-91ac-4b9e-b839-d6a88167d714} SystemMessageInternal.js +contract @mozilla.org/system-message-internal;1 {70589ca5-91ac-4b9e-b839-d6a88167d714} diff --git a/dom/messages/interfaces/Makefile.in b/dom/messages/interfaces/Makefile.in new file mode 100644 index 000000000000..fc6cac0a31e3 --- /dev/null +++ b/dom/messages/interfaces/Makefile.in @@ -0,0 +1,21 @@ +# 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/. + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +XPIDL_MODULE = dom_messages + +include $(topsrcdir)/dom/dom-config.mk + +XPIDLSRCS = \ + nsIDOMNavigatorSystemMessages.idl \ + nsISystemMessagesInternal.idl \ + $(NULL) + +include $(topsrcdir)/config/rules.mk diff --git a/dom/messages/interfaces/nsIDOMNavigatorSystemMessages.idl b/dom/messages/interfaces/nsIDOMNavigatorSystemMessages.idl new file mode 100644 index 000000000000..855cfb0c8c70 --- /dev/null +++ b/dom/messages/interfaces/nsIDOMNavigatorSystemMessages.idl @@ -0,0 +1,19 @@ +/* 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 "domstubs.idl" + +[scriptable, function, uuid(42692976-57fd-4bb4-ab95-2b97ebdc5056)] +interface nsIDOMSystemMessageCallback : nsISupports +{ + void handleMessage(in jsval message); +}; + +[scriptable, uuid(091e90dd-0e8b-463d-8cdc-9225d3a6ff90)] +interface nsIDOMNavigatorSystemMessages : nsISupports +{ + void mozSetMessageHandler(in DOMString type, in nsIDOMSystemMessageCallback callback); + + boolean mozHasPendingMessage(in DOMString type); +}; diff --git a/dom/messages/interfaces/nsISystemMessagesInternal.idl b/dom/messages/interfaces/nsISystemMessagesInternal.idl new file mode 100644 index 000000000000..01316daf6b47 --- /dev/null +++ b/dom/messages/interfaces/nsISystemMessagesInternal.idl @@ -0,0 +1,29 @@ +/* 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 "domstubs.idl" + +interface nsIURI; + +// Implemented by the contract id @mozilla.org/system-message-internal;1 + +[scriptable, uuid(fdc1ba03-5d8f-4de9-894a-333c7a136c5f)] +interface nsISystemMessagesInternal : nsISupports +{ + /* + * Allow any internal user to broadcast a message of a given type. + * @param type The type of the message to be sent. + * @param message The message payload. + * @param manifestURI The webapp's manifest URI. + */ + void sendMessage(in DOMString type, in jsval message, in nsIURI manifestURI); + + /* + * Registration of a page that wants to be notified of a message type. + * @param type The message type. + * @param pageURI The URI of the page that will be opened. + * @param manifestURI The webapp's manifest URI. + */ + void registerPage(in DOMString type, in nsIURI pageURI, in nsIURI manifestURI); +}; diff --git a/dom/plugins/test/crashtests/752340.html b/dom/plugins/test/crashtests/752340.html new file mode 100644 index 000000000000..c4c8c464f5e9 --- /dev/null +++ b/dom/plugins/test/crashtests/752340.html @@ -0,0 +1,19 @@ + + + + + + +