Bug 1359076: Disable all Device Sensor APIs except orientation and ambient light by default r?bkelly draft
authorFrederik Braun <fbraun@mozilla.com>
Mon, 24 Jul 2017 10:07:00 +0200
changeset 617341 504cb995282c234396be5cbaba87bd3f30f9a0dc
parent 617246 5845151f1a2cd00957fdd48e204542ccbdfaba1e
child 639808 d882e050b573adc2fb2d14d56d6356667ae352f0
push id71043
push userbmo:fbraun@mozilla.com
push dateFri, 28 Jul 2017 12:21:53 +0000
reviewersbkelly
bugs1359076
milestone56.0a1
Bug 1359076: Disable all Device Sensor APIs except orientation and ambient light by default r?bkelly This patch disables device sensors except orientation and ambient light by default. It implements per-sensor prefs to disable orientation, proximity and ambient light selectively. The patch also makes the pref checks happen at runtime (versus on process start) using Preferences::AddBoolVarCache. MozReview-Commit-ID: EA8ARjjtlkF
dom/events/test/test_bug742376.html
dom/system/nsDeviceSensors.cpp
dom/system/nsDeviceSensors.h
modules/libpref/init/all.js
--- a/dom/events/test/test_bug742376.html
+++ b/dom/events/test/test_bug742376.html
@@ -11,64 +11,69 @@ https://bugzilla.mozilla.org/show_bug.cg
 </head>
 
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=742376">Mozilla Bug 742376</a>
 <script class="testbody" type="text/javascript">
 
 /** Test for Bug 742376 **/
 
-function hasListeners() {
-
-  var Cc = SpecialPowers.Cc;
-  var Ci = SpecialPowers.Ci;
-  var dss = Cc["@mozilla.org/devicesensors;1"].getService(Ci.nsIDeviceSensors);
+SpecialPowers.pushPrefEnv({"set": [["device.sensors.enabled", true],
+                                   ["device.sensors.orientation.enabled", true]] })
+.then(function() {
 
-  return dss.hasWindowListener(Ci.nsIDeviceSensorData.TYPE_ORIENTATION, window) ||
-         dss.hasWindowListener(Ci.nsIDeviceSensorData.TYPE_ROTATION_VECTOR, window) ||
-         dss.hasWindowListener(Ci.nsIDeviceSensorData.TYPE_GAME_ROTATION_VECTOR, window);
-}
+  function hasListeners() {
 
-is(hasListeners(), false, "Must not have listeners before tests start");
+    var Cc = SpecialPowers.Cc;
+    var Ci = SpecialPowers.Ci;
+    var dss = Cc["@mozilla.org/devicesensors;1"].getService(Ci.nsIDeviceSensors);
 
-function dumbListener(event) {}
-function dumbListener2(event) {}
-function dumbListener3(event) {}
+    return dss.hasWindowListener(Ci.nsIDeviceSensorData.TYPE_ORIENTATION, window) ||
+           dss.hasWindowListener(Ci.nsIDeviceSensorData.TYPE_ROTATION_VECTOR, window) ||
+           dss.hasWindowListener(Ci.nsIDeviceSensorData.TYPE_GAME_ROTATION_VECTOR, window);
+  }
+
+  is(hasListeners(), false, "Must not have listeners before tests start");
 
-window.addEventListener("deviceorientation", dumbListener);
-window.addEventListener("random_event_name", function() {});
-window.addEventListener("deviceorientation", dumbListener2);
+  function dumbListener(event) {}
+  function dumbListener2(event) {}
+  function dumbListener3(event) {}
 
-is(hasListeners(), true, "Listeners should have been added");
+  window.addEventListener("deviceorientation", dumbListener);
+  window.addEventListener("random_event_name", function() {});
+  window.addEventListener("deviceorientation", dumbListener2);
 
-window.setTimeout(function() {
+  is(hasListeners(), true, "Listeners should have been added");
 
-  window.removeEventListener("deviceorientation", dumbListener);
-  is(hasListeners(), true, "Only some listeners should have been removed");
   window.setTimeout(function() {
 
-    window.removeEventListener("deviceorientation", dumbListener2);
+    window.removeEventListener("deviceorientation", dumbListener);
+    is(hasListeners(), true, "Only some listeners should have been removed");
     window.setTimeout(function() {
-      is(hasListeners(), false, "Listeners should have been removed");
-      testEventHandler();
+
+      window.removeEventListener("deviceorientation", dumbListener2);
+      window.setTimeout(function() {
+        is(hasListeners(), false, "Listeners should have been removed");
+        testEventHandler();
+      }, 0);
     }, 0);
   }, 0);
-}, 0);
 
-function testEventHandler() {
-  window.ondeviceorientation = function() {}
-  window.setTimeout(function() {
-    is(hasListeners(), true, "Handler should have been added");
-    window.ondeviceorientation = null;
+  function testEventHandler() {
+    window.ondeviceorientation = function() {}
     window.setTimeout(function() {
-      is(hasListeners(), false, "Handler should have been removed");
-      SimpleTest.finish();
-    }, 0);
-  }, 0)
-}
+      is(hasListeners(), true, "Handler should have been added");
+      window.ondeviceorientation = null;
+      window.setTimeout(function() {
+        is(hasListeners(), false, "Handler should have been removed");
+        SimpleTest.finish();
+      }, 0);
+    }, 0)
+  }
+});
 
 SimpleTest.waitForExplicitFinish();
 
 </script>
 </pre>
 </body>
 </html>
 
--- a/dom/system/nsDeviceSensors.cpp
+++ b/dom/system/nsDeviceSensors.cpp
@@ -31,16 +31,21 @@
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace hal;
 
 #undef near
 
 #define DEFAULT_SENSOR_POLL 100
 
+static bool gPrefSensorsEnabled= false;
+static bool gPrefOrientationSensorEnabled = false;
+static bool gPrefProximitySensorEnabled = false;
+static bool gPrefAmbientLightSensorEnabled = false;
+
 static const nsTArray<nsIDOMWindow*>::index_type NoIndex =
   nsTArray<nsIDOMWindow*>::NoIndex;
 
 class nsDeviceSensorData final : public nsIDeviceSensorData
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDEVICESENSORDATA
@@ -100,17 +105,28 @@ NS_IMETHODIMP nsDeviceSensorData::GetZ(d
 }
 
 NS_IMPL_ISUPPORTS(nsDeviceSensors, nsIDeviceSensors)
 
 nsDeviceSensors::nsDeviceSensors()
 {
   mIsUserProximityNear = false;
   mLastDOMMotionEventTime = TimeStamp::Now();
-  mEnabled = Preferences::GetBool("device.sensors.enabled", true);
+  Preferences::AddBoolVarCache(&gPrefSensorsEnabled,
+                              "device.sensors.enabled",
+                              true);
+  Preferences::AddBoolVarCache(&gPrefOrientationSensorEnabled,
+                              "device.sensors.orientation.enabled",
+                              true);
+  Preferences::AddBoolVarCache(&gPrefProximitySensorEnabled,
+                              "device.sensors.proximity.enabled",
+                              false);
+  Preferences::AddBoolVarCache(&gPrefAmbientLightSensorEnabled,
+                              "device.sensors.ambient_lightenabled",
+                              false);
 
   for (int i = 0; i < NUM_SENSOR_TYPE; i++) {
     nsTArray<nsIDOMWindow*> *windows = new nsTArray<nsIDOMWindow*>();
     mWindowListeners.AppendElement(windows);
   }
 
   mLastDOMMotionEventTime = TimeStamp::Now();
 }
@@ -124,17 +140,17 @@ nsDeviceSensors::~nsDeviceSensors()
 
   for (int i = 0; i < NUM_SENSOR_TYPE; i++) {
     delete mWindowListeners[i];
   }
 }
 
 NS_IMETHODIMP nsDeviceSensors::HasWindowListener(uint32_t aType, nsIDOMWindow *aWindow, bool *aRetVal)
 {
-  if (AreSensorEventsDisabled(aWindow))
+  if (!IsSensorAllowedByPref(aType, aWindow))
     *aRetVal = false;
   else
     *aRetVal = mWindowListeners[aType]->IndexOf(aWindow) != NoIndex;
 
   return NS_OK;
 }
 
 class DeviceSensorTestEvent : public Runnable
@@ -165,17 +181,17 @@ private:
   RefPtr<nsDeviceSensors> mTarget;
   uint32_t mType;
 };
 
 static bool sTestSensorEvents = false;
 
 NS_IMETHODIMP nsDeviceSensors::AddWindowListener(uint32_t aType, nsIDOMWindow *aWindow)
 {
-  if (AreSensorEventsDisabled(aWindow))
+  if (!IsSensorAllowedByPref(aType, aWindow))
     return NS_OK;
 
   if (mWindowListeners[aType]->IndexOf(aWindow) != NoIndex)
     return NS_OK;
 
   if (!IsSensorEnabled(aType)) {
     RegisterSensorObserver((SensorType)aType, this);
   }
@@ -565,22 +581,43 @@ nsDeviceSensors::FireDOMMotionEvent(nsID
 
   mLastRotationRate.reset();
   mLastAccelerationIncludingGravity.reset();
   mLastAcceleration.reset();
   mLastDOMMotionEventTime = TimeStamp::Now();
 }
 
 bool
-nsDeviceSensors::AreSensorEventsDisabled(nsIDOMWindow* aWindow)
+nsDeviceSensors::IsSensorAllowedByPref(uint32_t aType, nsIDOMWindow* aWindow)
 {
-  if (!mEnabled) {
-    return true;
+  // checks "device.sensors.enabled" master pref
+  if (!gPrefSensorsEnabled) {
+    return false;
+  }
+  switch (aType) {
+  case nsIDeviceSensorData::TYPE_LINEAR_ACCELERATION:
+  case nsIDeviceSensorData::TYPE_ACCELERATION:
+  case nsIDeviceSensorData::TYPE_GYROSCOPE:
+  case nsIDeviceSensorData::TYPE_GAME_ROTATION_VECTOR:
+  case nsIDeviceSensorData::TYPE_ORIENTATION:
+  case nsIDeviceSensorData::TYPE_ROTATION_VECTOR:
+    // checks "device.sensors.orientation.enabled" pref
+    if (!gPrefOrientationSensorEnabled) { return false; }
+    break;
+
+  case nsIDeviceSensorData::TYPE_PROXIMITY:
+    // checks "device.sensors.proximity.enabled" pref
+    if (!gPrefProximitySensorEnabled) { return false; }
+    break;
+  case nsIDeviceSensorData::TYPE_LIGHT:
+    // checks "device.sensors.ambient_light.enabled" pref
+    if (!gPrefAmbientLightSensorEnabled) { return false; }
+    break;
   }
 
   nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aWindow);
 
   if (!window) {
-    return false;
+    return true;
   }
 
-  return nsContentUtils::ShouldResistFingerprinting(window->GetDocShell());
+  return !nsContentUtils::ShouldResistFingerprinting(window->GetDocShell());
 }
--- a/dom/system/nsDeviceSensors.h
+++ b/dom/system/nsDeviceSensors.h
@@ -63,23 +63,21 @@ private:
   void FireDOMMotionEvent(class nsIDOMDocument *domDoc,
                           mozilla::dom::EventTarget* target,
                           uint32_t type,
                           PRTime timestamp,
                           double x,
                           double y,
                           double z);
 
-  bool mEnabled;
-
   inline bool IsSensorEnabled(uint32_t aType) {
     return mWindowListeners[aType]->Length() > 0;
   }
 
-  bool AreSensorEventsDisabled(nsIDOMWindow* aWindow);
+  bool IsSensorAllowedByPref(uint32_t aType, nsIDOMWindow* aWindow);
 
   mozilla::TimeStamp mLastDOMMotionEventTime;
   bool mIsUserProximityNear;
   mozilla::Maybe<DeviceAccelerationInit> mLastAcceleration;
   mozilla::Maybe<DeviceAccelerationInit> mLastAccelerationIncludingGravity;
   mozilla::Maybe<DeviceRotationRateInit> mLastRotationRate;
 };
 
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -4908,18 +4908,22 @@ pref("webrender.highlight-painted-layers
 pref("gfx.webrender.layers-free", false);
 
 // Enable/Disable the geolocation API for content
 pref("geo.enabled", true);
 
 // Timeout for outbound network geolocation provider XHR
 pref("geo.wifi.xhr.timeout", 60000);
 
-// Enable/Disable the orientation API for content
+// Enable/Disable the various sensor APIs for content
 pref("device.sensors.enabled", true);
+// orientation is for DOMOrientationEvent and DOMMotionEvent
+pref("device.sensors.orientation.enabled", true);
+pref("device.sensors.proximity.enabled", false);
+pref("device.sensors.ambient_light.enabled", false);
 
 // Enable/Disable the device storage API for content
 pref("device.storage.enabled", false);
 
 // Toggle which thread the HTML5 parser uses for stream parsing
 pref("html5.offmainthread", true);
 // Time in milliseconds between the time a network buffer is seen and the
 // timer firing when the timer hasn't fired previously in this parse in the