Bug 781353 - Hook up "power" to Permission Manager. r=jlebar
authorKan-Ru Chen (陳侃如) <kanru@kanru.info>
Sat, 11 Aug 2012 19:40:43 +0800
changeset 102184 f111e43bc076331456c5aa3ae68b557d58c5afb1
parent 102183 4b7f0b17d69528e12bc7c73de101a42c85076ae2
child 102185 b753e1dce89f2d569bcd452285514729bbe401d2
push id23269
push useremorley@mozilla.com
push dateMon, 13 Aug 2012 18:08:43 +0000
treeherdermozilla-central@75cdb3f932c6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjlebar
bugs781353
milestone17.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 781353 - Hook up "power" to Permission Manager. r=jlebar
dom/base/Navigator.cpp
dom/power/PowerManager.cpp
dom/power/PowerManager.h
dom/power/test/browser_bug697132.js
dom/power/test/test_power_basics.html
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -49,16 +49,18 @@
 #include "nsIDOMBluetoothManager.h"
 #include "BluetoothManager.h"
 #endif
 #include "nsIDOMCameraManager.h"
 #include "DOMCameraManager.h"
 
 #include "nsIDOMGlobalPropertyInitializer.h"
 
+using namespace mozilla::dom::power;
+
 // This should not be in the namespace.
 DOMCI_DATA(Navigator, mozilla::dom::Navigator)
 
 namespace mozilla {
 namespace dom {
 
 static const char sJSStackContractID[] = "@mozilla.org/js/xpc/ContextStack;1";
 
@@ -1024,21 +1026,21 @@ Navigator::GetBattery(nsIDOMBatteryManag
 }
 
 NS_IMETHODIMP
 Navigator::GetMozPower(nsIDOMMozPowerManager** aPower)
 {
   *aPower = nullptr;
 
   if (!mPowerManager) {
-    nsCOMPtr<nsPIDOMWindow> win = do_QueryReferent(mWindow);
-    NS_ENSURE_TRUE(win, NS_OK);
+    nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
+    NS_ENSURE_TRUE(window, NS_OK);
 
-    mPowerManager = new power::PowerManager();
-    mPowerManager->Init(win);
+    mPowerManager = PowerManager::CheckPermissionAndCreateInstance(window);
+    NS_ENSURE_TRUE(mPowerManager, NS_OK);
   }
 
   nsCOMPtr<nsIDOMMozPowerManager> power(mPowerManager);
   power.forget(aPower);
 
   return NS_OK;
 }
 
--- a/dom/power/PowerManager.cpp
+++ b/dom/power/PowerManager.cpp
@@ -1,19 +1,20 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Hal.h"
 #include "PowerManager.h"
 #include "WakeLock.h"
-#include "nsContentUtils.h"
 #include "nsDOMClassInfoID.h"
 #include "nsIDOMWakeLockListener.h"
+#include "nsIDocument.h"
+#include "nsIPermissionManager.h"
 #include "nsIPowerManagerService.h"
 #include "nsIPrincipal.h"
 #include "nsPIDOMWindow.h"
 #include "nsServiceManagerUtils.h"
 #include "nsDOMError.h"
 
 DOMCI_DATA(MozPowerManager, mozilla::dom::power::PowerManager)
 
@@ -52,93 +53,61 @@ PowerManager::Shutdown()
     do_GetService(POWERMANAGERSERVICE_CONTRACTID);
   NS_ENSURE_STATE(pmService);
 
   // Remove ourself from the global notification list.
   pmService->RemoveWakeLockListener(this);
   return NS_OK;
 }
 
-bool
-PowerManager::CheckPermission()
-{
-  if (nsContentUtils::IsCallerChrome()) {
-    return true;
-  }
-
-  nsCOMPtr<nsPIDOMWindow> win = do_QueryReferent(mWindow);
-  NS_ENSURE_TRUE(win, false);
-  nsCOMPtr<nsIDocument> doc = do_QueryInterface(win->GetExtantDocument());
-  NS_ENSURE_TRUE(doc, false);
-
-  nsCOMPtr<nsIURI> uri;
-  doc->NodePrincipal()->GetURI(getter_AddRefs(uri));
-
-  if (!nsContentUtils::URIIsChromeOrInPref(uri, "dom.power.whitelist")) {
-    return false;
-  }
-
-  return true;
-}
-
 NS_IMETHODIMP
 PowerManager::Reboot()
 {
-  NS_ENSURE_TRUE(CheckPermission(), NS_ERROR_DOM_SECURITY_ERR);
-
   nsCOMPtr<nsIPowerManagerService> pmService =
     do_GetService(POWERMANAGERSERVICE_CONTRACTID);
   NS_ENSURE_STATE(pmService);
 
   pmService->Reboot();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::PowerOff()
 {
-  NS_ENSURE_TRUE(CheckPermission(), NS_ERROR_DOM_SECURITY_ERR);
-
   nsCOMPtr<nsIPowerManagerService> pmService =
     do_GetService(POWERMANAGERSERVICE_CONTRACTID);
   NS_ENSURE_STATE(pmService);
 
   pmService->PowerOff();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::AddWakeLockListener(nsIDOMMozWakeLockListener *aListener)
 {
-  NS_ENSURE_TRUE(CheckPermission(), NS_ERROR_DOM_SECURITY_ERR);
-
   // already added? bail out.
   if (mListeners.Contains(aListener))
     return NS_OK;
 
   mListeners.AppendElement(aListener);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::RemoveWakeLockListener(nsIDOMMozWakeLockListener *aListener)
 {
-  NS_ENSURE_TRUE(CheckPermission(), NS_ERROR_DOM_SECURITY_ERR);
-
   mListeners.RemoveElement(aListener);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::GetWakeLockState(const nsAString &aTopic, nsAString &aState)
 {
-  NS_ENSURE_TRUE(CheckPermission(), NS_ERROR_DOM_SECURITY_ERR);
-
   nsCOMPtr<nsIPowerManagerService> pmService =
     do_GetService(POWERMANAGERSERVICE_CONTRACTID);
   NS_ENSURE_STATE(pmService);
 
   return pmService->GetWakeLockState(aTopic, aState);
 }
 
 NS_IMETHODIMP
@@ -158,74 +127,81 @@ PowerManager::Callback(const nsAString &
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::GetScreenEnabled(bool *aEnabled)
 {
-  if (!CheckPermission()) {
-    *aEnabled = true;
-    return NS_OK;
-  }
-
   *aEnabled = hal::GetScreenEnabled();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::SetScreenEnabled(bool aEnabled)
 {
-  NS_ENSURE_TRUE(CheckPermission(), NS_ERROR_DOM_SECURITY_ERR);
-
-  // TODO bug 707589: When the screen's state changes, all visible windows
-  // should fire a visibility change event.
   hal::SetScreenEnabled(aEnabled);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::GetScreenBrightness(double *aBrightness)
 {
-  if (!CheckPermission()) {
-    *aBrightness = 1;
-    return NS_OK;
-  }
-
   *aBrightness = hal::GetScreenBrightness();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::SetScreenBrightness(double aBrightness)
 {
-  NS_ENSURE_TRUE(CheckPermission(), NS_ERROR_DOM_SECURITY_ERR);
-
   NS_ENSURE_TRUE(0 <= aBrightness && aBrightness <= 1, NS_ERROR_INVALID_ARG);
   hal::SetScreenBrightness(aBrightness);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::GetCpuSleepAllowed(bool *aAllowed)
 {
-  if (!CheckPermission()) {
-    *aAllowed = true;
-    return NS_OK;
-  }
-
   *aAllowed = hal::GetCpuSleepAllowed();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::SetCpuSleepAllowed(bool aAllowed)
 {
-  NS_ENSURE_TRUE(CheckPermission(), NS_ERROR_DOM_SECURITY_ERR);
-
   hal::SetCpuSleepAllowed(aAllowed);
   return NS_OK;
 }
 
+already_AddRefed<PowerManager>
+PowerManager::CheckPermissionAndCreateInstance(nsPIDOMWindow* aWindow)
+{
+  nsPIDOMWindow* innerWindow = aWindow->IsInnerWindow() ?
+    aWindow :
+    aWindow->GetCurrentInnerWindow();
+
+  // Need the document for security check.
+  nsCOMPtr<nsIDocument> document = innerWindow->GetExtantDoc();
+  NS_ENSURE_TRUE(document, nullptr);
+
+  nsCOMPtr<nsIPrincipal> principal = document->NodePrincipal();
+
+  nsCOMPtr<nsIPermissionManager> permMgr =
+    do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+  NS_ENSURE_TRUE(permMgr, nullptr);
+
+  PRUint32 permission = nsIPermissionManager::DENY_ACTION;
+  permMgr->TestPermissionFromPrincipal(principal, "power", &permission);
+
+  if (permission != nsIPermissionManager::ALLOW_ACTION) {
+    return nullptr;
+  }
+
+  nsRefPtr<PowerManager> powerManager = new PowerManager();
+  powerManager->Init(aWindow);
+
+  return powerManager.forget();
+}
+
 } // power
 } // dom
 } // mozilla
--- a/dom/power/PowerManager.h
+++ b/dom/power/PowerManager.h
@@ -7,16 +7,18 @@
 
 #include "nsCOMPtr.h"
 #include "nsTArray.h"
 #include "nsIDOMPowerManager.h"
 #include "nsIDOMWakeLockListener.h"
 #include "nsIDOMWindow.h"
 #include "nsWeakReference.h"
 
+class nsPIDOMWindow;
+
 namespace mozilla {
 namespace dom {
 namespace power {
 
 class PowerManager
   : public nsIDOMMozPowerManager
   , public nsIDOMMozWakeLockListener
 {
@@ -26,18 +28,20 @@ public:
   NS_DECL_NSIDOMMOZWAKELOCKLISTENER
 
   PowerManager() {};
   virtual ~PowerManager() {};
 
   nsresult Init(nsIDOMWindow *aWindow);
   nsresult Shutdown();
 
+  static already_AddRefed<PowerManager>
+  CheckPermissionAndCreateInstance(nsPIDOMWindow*);
+
 private:
-  bool CheckPermission();
 
   nsWeakPtr mWindow;
   nsTArray<nsCOMPtr<nsIDOMMozWakeLockListener> > mListeners;
 };
 
 } // namespace power
 } // namespace dom
 } // namespace mozilla
--- a/dom/power/test/browser_bug697132.js
+++ b/dom/power/test/browser_bug697132.js
@@ -1,24 +1,27 @@
+/* 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";
 
 waitForExplicitFinish();
 
-let kPrefNode = "dom.power.whitelist";
-let kPageSource1 = "data:text/html,1";
-let kPageSource2 = "data:text/html,2";
+let kUrlSource = "http://mochi.test:8888/";
+let kDataSource = "data:text/html,";
 
 let gOldPref;
 let gWin, gWin1, gWin2;
 let gTab, gTab1, gTab2;
 let gLock, gLock1, gLock2;
 let gCurStepIndex = -1;
 let gSteps = [
   function basicWakeLock() {
-    gTab = gBrowser.addTab(kPageSource1);
+    gTab = gBrowser.addTab(kUrlSource);
     gWin = gBrowser.getBrowserForTab(gTab).contentWindow;
     let browser = gBrowser.getBrowserForTab(gTab);
 
     browser.addEventListener("load", function onLoad(e) {
       browser.removeEventListener("load", onLoad, true);
       let nav = gWin.navigator;
       let power = nav.mozPower;
       gLock = nav.requestWakeLock("test");
@@ -46,17 +49,17 @@ let gSteps = [
       }
 
       gBrowser.removeTab(gTab);
 
       executeSoon(runNextStep);
     }, true);
   },
   function multiWakeLock() {
-    gTab = gBrowser.addTab(kPageSource1);
+    gTab = gBrowser.addTab(kUrlSource);
     gWin = gBrowser.getBrowserForTab(gTab).contentWindow;
     let browser = gBrowser.getBrowserForTab(gTab);
 
     browser.addEventListener("load", function onLoad(e) {
       browser.removeEventListener("load", onLoad, true);
       let nav = gWin.navigator;
       let power = nav.mozPower;
       let count = 0;
@@ -95,19 +98,19 @@ let gSteps = [
       gLock1.unlock();
       isnot(power.getWakeLockState("test"), "unlocked",
             "topic is locked");
 
       gLock2.unlock();
     }, true);
   },
   function crossTabWakeLock1() {
-    gTab1 = gBrowser.addTab(kPageSource1);
+    gTab1 = gBrowser.addTab(kUrlSource);
     gWin1 = gBrowser.getBrowserForTab(gTab1).contentWindow;
-    gTab2 = gBrowser.addTab(kPageSource1);
+    gTab2 = gBrowser.addTab(kUrlSource);
     gWin2 = gBrowser.getBrowserForTab(gTab2).contentWindow;
 
     gBrowser.selectedTab = gTab1;
     let browser = gBrowser.getBrowserForTab(gTab2);
 
     browser.addEventListener("load", function onLoad(e) {
       browser.removeEventListener("load", onLoad, true);
       gLock2 = gWin2.navigator.requestWakeLock("test");
@@ -133,17 +136,17 @@ let gSteps = [
     gWin2.addEventListener("pagehide", function onPageHide(e) {
       gWin2.removeEventListener("pagehide", onPageHide, true);
       executeSoon(runNextStep);
     }, true);
     gWin2.addEventListener("pageshow", function onPageShow(e) {
       gWin2.removeEventListener("pageshow", onPageShow, true);
       executeSoon(runNextStep);
     }, true);
-    gWin2.location = kPageSource2;
+    gWin2.location = kDataSource;
   },
   function crossTabWakeLock3() {
     is(gWin1.navigator.mozPower.getWakeLockState("test"), "unlocked",
        "wake lock should auto-unlock when page is unloaded");
     gWin2.back();
     // runNextStep called in onPageShow
   },
   function crossTabWakeLock4() {
@@ -161,17 +164,17 @@ let gSteps = [
     gWin2.addEventListener("pagehide", function onPageHide(e) {
       gWin2.removeEventListener("pagehide", onPageHide, true);
       executeSoon(runNextStep);
     }, true);
     gWin2.addEventListener("pageshow", function onPageShow(e) {
       gWin2.removeEventListener("pageshow", onPageShow, true);
       executeSoon(runNextStep);
     }, true);
-    gWin2.location = kPageSource2;
+    gWin2.location = kDataSource;
   },
   function crossTabWakeLock6() {
     is(gWin1.navigator.mozPower.getWakeLockState("test"), "unlocked",
        "wake lock should auto-unlock when page is unloaded");
     gWin2.back();
     // runNextStep called in onPageShow
   },
   function crossTabWakeLock7() {
@@ -214,23 +217,17 @@ let gSteps = [
   },
 ];
 
 function runNextStep() {
   gCurStepIndex++;
   if (gCurStepIndex < gSteps.length) {
     gSteps[gCurStepIndex]();
   } else {
-    Services.prefs.setCharPref(kPrefNode, gOldPref);
+    SpecialPowers.removePermission("power", kUrlSource);
     finish();
   }
 }
 
 function test() {
-  try {
-    gOldPref = Services.prefs.getCharPref(kPrefNode);
-  } catch (e) {
-    gOldPref = "";
-  }
-  // data url inherits its parent's principal, which is |about:| here.
-  Services.prefs.setCharPref(kPrefNode, "about:");
+  SpecialPowers.addPermission("power", true, kUrlSource);
   runNextStep();
 }
--- a/dom/power/test/test_power_basics.html
+++ b/dom/power/test/test_power_basics.html
@@ -11,12 +11,24 @@
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Power API **/
 
 ok('mozPower' in navigator, "navigator.mozPower should exist");
 
+/** Test permission **/
+
+SpecialPowers.removePermission("power", document);
+
+power = navigator.mozPower;
+ok(!power, "Shouldn't be able to access power manager without permission.");
+
+SpecialPowers.addPermission("power", true, document);
+
+power = navigator.mozPower;
+ok(power, "Shouldn be able to access power manager with permission.");
+
 </script>
 </pre>
 </body>
 </html>