Merge mozilla-central and b2g-inbound
authorEd Morley <emorley@mozilla.com>
Fri, 25 Oct 2013 12:12:23 +0100
changeset 166969 26d96c3c038044c4224bc36d1cad179737fd3f18
parent 166894 9f8233fcce1d3f0676bc720303dc7bbd7e246c13 (current diff)
parent 166968 d00aeb9200a3f4ee24e41a9e43171d89d508cbe3 (diff)
child 166970 94f86cf99b1ddc0aa78270fb259eac615d0e02cf
push id428
push userbbajaj@mozilla.com
push dateTue, 28 Jan 2014 00:16:25 +0000
treeherdermozilla-release@cd72a7ff3a75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone27.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
Merge mozilla-central and b2g-inbound
content/base/src/nsFrameMessageManager.cpp
content/events/src/Makefile.in
dom/mobilemessage/src/moz.build
dom/mobilemessage/tests/test_smsdatabaseservice.xul
dom/network/src/moz.build
dom/system/gonk/moz.build
dom/system/moz.build
dom/telephony/moz.build
dom/webidl/Navigator.webidl
layout/build/Makefile.in
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,4 +1,4 @@
 {
-    "revision": "e3564b8656fcd189d4a83379e94bef1ab7d657b5", 
+    "revision": "d9d422e52a7a45dfb075fd2bf4fd48c956276baa", 
     "repo_path": "/integration/gaia-central"
 }
--- a/dom/bluetooth/linux/BluetoothDBusService.cpp
+++ b/dom/bluetooth/linux/BluetoothDBusService.cpp
@@ -1573,37 +1573,41 @@ EventFilter(DBusConnection* aConn, DBusM
     task = new DistributeBluetoothSignalTask(signal);
   }
 
   NS_DispatchToMainThread(task);
 
   return DBUS_HANDLER_RESULT_HANDLED;
 }
 
-static bool
-GetDefaultAdapterPath(BluetoothValue& aValue, nsString& aError)
+static void
+OnDefaultAdapterReply(DBusMessage* aReply, void* aData)
 {
-  // This could block. It should never be run on the main thread.
-  MOZ_ASSERT(!NS_IsMainThread());
+  MOZ_ASSERT(!NS_IsMainThread()); // DBus thread
+
+  if (!aReply || dbus_message_is_error(aReply, DBUS_ERROR_TIMEOUT)) {
+    return;
+  }
 
   DBusError err;
   dbus_error_init(&err);
 
-  DBusMessage* msg;
-  bool success = gThreadConnection->SendWithError(&msg, &err, 1000, "/",
-                                                  DBUS_MANAGER_IFACE,
-                                                  "DefaultAdapter",
-                                                  DBUS_TYPE_INVALID);
-  NS_ENSURE_TRUE(success, false);
-
-  UnpackObjectPathMessage(msg, &err, aValue, aError);
-
-  dbus_message_unref(msg);
-
-  return aError.IsEmpty();
+  BluetoothValue v;
+  nsAutoString errorString;
+
+  UnpackObjectPathMessage(aReply, &err, v, errorString);
+
+  if (!errorString.IsEmpty()) {
+    return;
+  }
+
+  nsRefPtr<PrepareAdapterRunnable> b = new PrepareAdapterRunnable(v.get_nsString());
+  if (NS_FAILED(NS_DispatchToMainThread(b))) {
+    BT_WARNING("Failed to dispatch to main thread!");
+  }
 }
 
 bool
 BluetoothDBusService::IsReady()
 {
   if (!IsEnabled() || !mConnection || !gThreadConnection || IsToggling()) {
     BT_WARNING("Bluetooth service is not ready yet!");
     return false;
@@ -1664,27 +1668,27 @@ BluetoothDBusService::StartInternal()
     BT_WARNING("Cannot create DBus Event Filter for DBus Thread!");
     return NS_ERROR_FAILURE;
   }
 
   if (!sPairingReqTable) {
     sPairingReqTable = new nsDataHashtable<nsStringHashKey, DBusMessage* >;
   }
 
-  BluetoothValue v;
-  nsAutoString replyError;
-  if (!GetDefaultAdapterPath(v, replyError)) {
-    // Adapter path is not ready yet
-    // Let's do PrepareAdapterRunnable when we receive signal 'AdapterAdded'
-  } else {
-    // Adapter path has been ready. let's do PrepareAdapterRunnable now
-    nsRefPtr<PrepareAdapterRunnable> b = new PrepareAdapterRunnable(v.get_nsString());
-    if (NS_FAILED(NS_DispatchToMainThread(b))) {
-      BT_WARNING("Failed to dispatch to main thread!");
-    }
+  // Normally we'll receive the signal 'AdapterAdded' for the default
+  // adapter from the DBus daemon during start up. If we restart after
+  // a crash, the default adapter might already be available, so we ask
+  // the daemon explicitly here.
+  bool success = mConnection->SendWithReply(OnDefaultAdapterReply, nullptr,
+                                            1000, "/",
+                                            DBUS_ADAPTER_IFACE,
+                                            "DefaultAdapter",
+                                            DBUS_TYPE_INVALID);
+  if (!success) {
+    BT_WARNING("Failed to query default adapter!");
   }
 
   return NS_OK;
 }
 
 PLDHashOperator
 UnrefDBusMessages(const nsAString& key, DBusMessage* value, void* arg)
 {
--- a/dom/system/gonk/RILContentHelper.js
+++ b/dom/system/gonk/RILContentHelper.js
@@ -13,17 +13,16 @@
  * limitations under the License.
  */
 
 "use strict";
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
-Cu.import("resource://gre/modules/ObjectWrapper.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 var RIL = {};
 Cu.import("resource://gre/modules/ril_consts.js", RIL);
 
 const NS_XPCOM_SHUTDOWN_OBSERVER_ID = "xpcom-shutdown";
 
@@ -1763,18 +1762,17 @@ RILContentHelper.prototype = {
         prop.tel.push({value: c.anr[i]});
       }
 
       let contact = new window.mozContact(prop);
       contact.id = message.iccid + c.recordId;
       return contact;
     });
 
-    this.fireRequestSuccess(message.requestId,
-                            ObjectWrapper.wrap(result, window));
+    this.fireRequestSuccess(message.requestId, result);
   },
 
   handleVoicemailNotification: function handleVoicemailNotification(message) {
     let changed = false;
     if (!this.voicemailStatus) {
       this.voicemailStatus = new VoicemailStatus();
     }
 
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -3232,18 +3232,20 @@ function RILNetworkInterface(radioInterf
   this.connectedTypes = [];
 }
 
 RILNetworkInterface.prototype = {
   classID:   RILNETWORKINTERFACE_CID,
   classInfo: XPCOMUtils.generateCI({classID: RILNETWORKINTERFACE_CID,
                                     classDescription: "RILNetworkInterface",
                                     interfaces: [Ci.nsINetworkInterface,
+                                                 Ci.nsIRilNetworkInterface,
                                                  Ci.nsIRILDataCallback]}),
   QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkInterface,
+                                         Ci.nsIRilNetworkInterface,
                                          Ci.nsIRILDataCallback]),
 
   // nsINetworkInterface
 
   NETWORK_STATE_UNKNOWN:       Ci.nsINetworkInterface.NETWORK_STATE_UNKNOWN,
   NETWORK_STATE_CONNECTING:    Ci.nsINetworkInterface.CONNECTING,
   NETWORK_STATE_CONNECTED:     Ci.nsINetworkInterface.CONNECTED,
   NETWORK_STATE_DISCONNECTING: Ci.nsINetworkInterface.DISCONNECTING,
@@ -3299,16 +3301,25 @@ RILNetworkInterface.prototype = {
   get httpProxyHost() {
     return this.apnSetting.proxy || '';
   },
 
   get httpProxyPort() {
     return this.apnSetting.port || '';
   },
 
+  get serviceId() {
+    return this.radioInterface.clientId;
+  },
+
+  get iccId() {
+    let iccInfo = this.radioInterface.rilContext.iccInfo;
+    return iccInfo && iccInfo.iccid;
+  },
+
   debug: function debug(s) {
     dump("-*- RILNetworkInterface[" + this.radioInterface.clientId + ":" +
          this.type + "]: " + s + "\n");
   },
 
   // nsIRILDataCallback
 
   dataCallError: function dataCallError(message) {
--- a/dom/system/gonk/nsIRadioInterfaceLayer.idl
+++ b/dom/system/gonk/nsIRadioInterfaceLayer.idl
@@ -1,18 +1,26 @@
 /* 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 "nsISupports.idl"
+#include "nsINetworkManager.idl"
 
 interface nsIDOMMozIccInfo;
 interface nsIDOMMozMobileConnectionInfo;
 interface nsIMobileMessageCallback;
 
+[scriptable, uuid(a15769f1-538e-4b4b-81da-c52866d38f88)]
+interface nsIRilNetworkInterface : nsINetworkInterface
+{
+  readonly attribute unsigned long serviceId;
+  readonly attribute DOMString iccId;
+};
+
 [scriptable, uuid(1e602d20-d066-4399-8997-daf36b3158ef)]
 interface nsIRILDataCallInfo : nsISupports
 {
   /**
    * Current data call state, one of the
    * nsINetworkInterface::NETWORK_STATE_* constants.
    */
   readonly attribute unsigned long state;
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -81,16 +81,19 @@ let RILQUIRKS_V5_LEGACY = libcutils.prop
 let RILQUIRKS_REQUEST_USE_DIAL_EMERGENCY_CALL = libcutils.property_get("ro.moz.ril.dial_emergency_call", "false") === "true";
 let RILQUIRKS_MODEM_DEFAULTS_TO_EMERGENCY_MODE = libcutils.property_get("ro.moz.ril.emergency_by_default", "false") === "true";
 let RILQUIRKS_SIM_APP_STATE_EXTRA_FIELDS = libcutils.property_get("ro.moz.ril.simstate_extra_field", "false") === "true";
 // Needed for call-waiting on Peak device
 let RILQUIRKS_EXTRA_UINT32_2ND_CALL = libcutils.property_get("ro.moz.ril.extra_int_2nd_call", "false") == "true";
 // On the emulator we support querying the number of lock retries
 let RILQUIRKS_HAVE_QUERY_ICC_LOCK_RETRY_COUNT = libcutils.property_get("ro.moz.ril.query_icc_count", "false") == "true";
 
+// Ril quirk to Send STK Profile Download
+let RILQUIRKS_SEND_STK_PROFILE_DOWNLOAD = libcutils.property_get("ro.moz.ril.send_stk_profile_dl", "false") == "true";
+
 // Marker object.
 let PENDING_NETWORK_TYPE = {};
 
 let Buf = {
   __proto__: (function(){
     return require("resource://gre/modules/workers/worker_buf.js").Buf;
   })(),
 
@@ -3009,20 +3012,24 @@ let RIL = {
       this.iccInfo.iccType = GECKO_CARD_TYPE[this.appType];
 
       // For type SIM, we need to check EF_phase first.
       // Other types of ICC we can send Terminal_Profile immediately.
       if (this.appType == CARD_APPTYPE_SIM) {
         ICCRecordHelper.readICCPhase();
         ICCRecordHelper.fetchICCRecords();
       } else if (this.appType == CARD_APPTYPE_USIM) {
-        this.sendStkTerminalProfile(STK_SUPPORTED_TERMINAL_PROFILE);
+        if (RILQUIRKS_SEND_STK_PROFILE_DOWNLOAD) {
+          this.sendStkTerminalProfile(STK_SUPPORTED_TERMINAL_PROFILE);
+        }
         ICCRecordHelper.fetchICCRecords();
       } else if (this.appType == CARD_APPTYPE_RUIM) {
-        this.sendStkTerminalProfile(STK_SUPPORTED_TERMINAL_PROFILE);
+        if (RILQUIRKS_SEND_STK_PROFILE_DOWNLOAD) {
+          this.sendStkTerminalProfile(STK_SUPPORTED_TERMINAL_PROFILE);
+        }
         RuimRecordHelper.fetchRuimRecords();
       }
       this.reportStkServiceIsRunning();
     }
 
     this.cardState = newCardState;
     this.sendChromeMessage({rilMessageType: "cardstatechange",
                             cardState: this.cardState});
@@ -10377,17 +10384,17 @@ let ComprehensionTlvHelper = {
       if (length < 0x010000) {
         RIL.sendStkTerminalResponse({
           resultCode: STK_RESULT_CMD_DATA_NOT_UNDERSTOOD});
         throw new Error("Invalid length in 4-byte Comprehension TLV :" + length);
       }
     } else {
       RIL.sendStkTerminalResponse({
         resultCode: STK_RESULT_CMD_DATA_NOT_UNDERSTOOD});
-      throw new Error("Invalid octet in Comprehension TLV :" + length);
+      throw new Error("Invalid octet in Comprehension TLV :" + temp);
     }
 
     let ctlv = {
       tag: tag,
       length: length,
       value: StkProactiveCmdHelper.retrieve(tag, length),
       cr: cr,
       hlen: hlen
@@ -11021,17 +11028,18 @@ let ICCRecordHelper = {
    */
   readICCPhase: function readICCPhase() {
     function callback() {
       let strLen = Buf.readInt32();
 
       let phase = GsmPDUHelper.readHexOctet();
       // If EF_phase is coded '03' or greater, an ME supporting STK shall
       // perform the PROFILE DOWNLOAD procedure.
-      if (phase >= ICC_PHASE_2_PROFILE_DOWNLOAD_REQUIRED) {
+      if (RILQUIRKS_SEND_STK_PROFILE_DOWNLOAD &&
+          phase >= ICC_PHASE_2_PROFILE_DOWNLOAD_REQUIRED) {
         RIL.sendStkTerminalProfile(STK_SUPPORTED_TERMINAL_PROFILE);
       }
 
       Buf.readStringDelimiter(strLen);
     }
 
     ICCIOHelper.loadTransparentEF({fileId: ICC_EF_PHASE,
                                    callback: callback.bind(this)});
--- a/dom/system/gonk/tests/test_ril_worker_stk.js
+++ b/dom/system/gonk/tests/test_ril_worker_stk.js
@@ -56,16 +56,41 @@ function newUint8SupportOutgoingIndexWor
   };
 
   worker.debug = do_print;
 
   return worker;
 }
 
 // Test RIL requests related to STK.
+/**
+ * Verify if RIL.sendStkTerminalProfile be called.
+ */
+add_test(function test_if_send_stk_terminal_profile() {
+  let worker = newUint8Worker();
+  let profileSend = false;
+  worker.RIL.sendStkTerminalProfile = function (data) {
+    profileSend = true;
+  };
+
+  let iccStatus = {
+    gsmUmtsSubscriptionAppIndex: 0,
+    apps: [{
+      app_state: CARD_APPSTATE_READY,
+      app_type: CARD_APPTYPE_USIM
+    }],
+  };
+  worker.RILQUIRKS_SEND_STK_PROFILE_DOWNLOAD = false;
+
+  worker.RIL._processICCStatus(iccStatus);
+
+  do_check_eq(profileSend, false);
+
+  run_next_test();
+});
 
 /**
  * Verify RIL.sendStkTerminalProfile
  */
 add_test(function test_send_stk_terminal_profile() {
   let worker = newUint8Worker();
   let ril = worker.RIL;
   let buf = worker.Buf;
--- a/gfx/layers/composite/APZCTreeManager.cpp
+++ b/gfx/layers/composite/APZCTreeManager.cpp
@@ -112,17 +112,21 @@ APZCTreeManager::UpdatePanZoomController
       const CompositorParent::LayerTreeState* state = CompositorParent::GetIndirectShadowTree(aLayersId);
       if (state && state->mController.get()) {
         // If we get here, aLayer is a scrollable container layer and somebody
         // has registered a GeckoContentController for it, so we need to ensure
         // it has an APZC instance to manage its scrolling.
 
         apzc = container->GetAsyncPanZoomController();
 
-        bool newApzc = (apzc == nullptr);
+        // The APZC we get off the layer may have been destroyed previously if the layer was inactive
+        // or omitted from the layer tree for whatever reason from a layers update. If it later comes
+        // back it will have a reference to a destroyed APZC and so we need to throw that out and make
+        // a new one.
+        bool newApzc = (apzc == nullptr || apzc->IsDestroyed());
         if (newApzc) {
           apzc = new AsyncPanZoomController(aLayersId, this, state->mController,
                                             AsyncPanZoomController::USE_GESTURE_DETECTOR);
           apzc->SetCompositorParent(aCompositor);
         } else {
           // If there was already an APZC for the layer clear the tree pointers
           // so that it doesn't continue pointing to APZCs that should no longer
           // be in the tree. These pointers will get reset properly as we continue
--- a/gfx/layers/ipc/AsyncPanZoomController.cpp
+++ b/gfx/layers/ipc/AsyncPanZoomController.cpp
@@ -321,16 +321,22 @@ AsyncPanZoomController::Destroy()
     mGestureEventListener = nullptr;
   }
   mPrevSibling = nullptr;
   mLastChild = nullptr;
   mParent = nullptr;
   mTreeManager = nullptr;
 }
 
+bool
+AsyncPanZoomController::IsDestroyed()
+{
+  return mTreeManager == nullptr;
+}
+
 /* static */float
 AsyncPanZoomController::GetTouchStartTolerance()
 {
   return gTouchStartTolerance;
 }
 
 /* static */AsyncPanZoomController::AxisLockMode AsyncPanZoomController::GetAxisLockMode()
 {
--- a/gfx/layers/ipc/AsyncPanZoomController.h
+++ b/gfx/layers/ipc/AsyncPanZoomController.h
@@ -199,16 +199,21 @@ public:
 
   /**
    * Shut down the controller/UI thread state and prepare to be
    * deleted (which may happen from any thread).
    */
   void Destroy();
 
   /**
+   * Returns true if Destroy() has already been called on this APZC instance.
+   */
+  bool IsDestroyed();
+
+  /**
    * Returns the incremental transformation corresponding to the async pan/zoom
    * in progress. That is, when this transform is multiplied with the layer's
    * existing transform, it will make the layer appear with the desired pan/zoom
    * amount.
    */
   ViewTransform GetCurrentAsyncTransform();
 
   /**
--- a/ipc/dbus/DBusThread.cpp
+++ b/ipc/dbus/DBusThread.cpp
@@ -64,239 +64,425 @@
 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GonkDBus", args);
 #else
 #define BTDEBUG true
 #define LOG(args...) if (BTDEBUG) printf(args);
 #endif
 
 #define DEFAULT_INITIAL_POLLFD_COUNT 8
 
-// Functions for converting between unix events in the poll struct,
-// and their dbus definitions
-
-enum DBusEventTypes {
-  DBUS_EVENT_LOOP_EXIT = 1,
-  DBUS_EVENT_LOOP_ADD = 2,
-  DBUS_EVENT_LOOP_REMOVE = 3,
-  DBUS_EVENT_LOOP_WAKEUP = 4
-};
-
-static unsigned int UnixEventsToDBusFlags(short events)
-{
-  return (events & DBUS_WATCH_READABLE ? POLLIN : 0) |
-    (events & DBUS_WATCH_WRITABLE ? POLLOUT : 0) |
-    (events & DBUS_WATCH_ERROR ? POLLERR : 0) |
-    (events & DBUS_WATCH_HANGUP ? POLLHUP : 0);
-}
-
-static short DBusFlagsToUnixEvents(unsigned int flags)
-{
-  return (flags & POLLIN ? DBUS_WATCH_READABLE : 0) |
-    (flags & POLLOUT ? DBUS_WATCH_WRITABLE : 0) |
-    (flags & POLLERR ? DBUS_WATCH_ERROR : 0) |
-    (flags & POLLHUP ? DBUS_WATCH_HANGUP : 0);
-}
-
 namespace mozilla {
 namespace ipc {
 
-struct PollFdComparator {
-  bool Equals(const pollfd& a, const pollfd& b) const {
-    return ((a.fd == b.fd) &&
-            (a.events == b.events));
-  }
-  bool LessThan(const pollfd& a, const pollfd&b) const {
-    return false;
-  }
-};
+class DBusWatcher : public RawDBusConnection
+{
+public:
+  DBusWatcher()
+  { }
 
-// DBus Thread Class prototype
-
-struct DBusThread : public RawDBusConnection
-{
-  DBusThread();
-  ~DBusThread();
+  ~DBusWatcher()
+  { }
 
   bool Initialize();
   void CleanUp();
 
   void WakeUp();
+  bool Stop();
+
+  bool Poll();
+
+  bool AddWatch(DBusWatch* aWatch);
+  void RemoveWatch(DBusWatch* aWatch);
+
+  void HandleWatchAdd();
+  void HandleWatchRemove();
 
   // Information about the sockets we're polling. Socket counts
   // increase/decrease depending on how many add/remove watch signals
   // we're received via the control sockets.
   nsTArray<pollfd> mPollData;
   nsTArray<DBusWatch*> mWatchData;
 
   // Sockets for receiving dbus control information (watch
   // add/removes, loop shutdown, etc...)
   ScopedClose mControlFdR;
   ScopedClose mControlFdW;
 
-protected:
+private:
+  struct PollFdComparator {
+    bool Equals(const pollfd& a, const pollfd& b) const {
+      return ((a.fd == b.fd) && (a.events == b.events));
+    }
+    bool LessThan(const pollfd& a, const pollfd&b) const {
+      return false;
+    }
+  };
+
+  enum DBusEventTypes {
+    DBUS_EVENT_LOOP_EXIT = 1,
+    DBUS_EVENT_LOOP_ADD = 2,
+    DBUS_EVENT_LOOP_REMOVE = 3,
+    DBUS_EVENT_LOOP_WAKEUP = 4
+  };
+
+  static unsigned int UnixEventsToDBusFlags(short events);
+  static short        DBusFlagsToUnixEvents(unsigned int flags);
+
+  static dbus_bool_t AddWatchFunction(DBusWatch* aWatch, void* aData);
+  static void        RemoveWatchFunction(DBusWatch* aWatch, void* aData);
+  static void        ToggleWatchFunction(DBusWatch* aWatch, void* aData);
+  static void        DBusWakeupFunction(void* aData);
+
   bool SetUp();
 };
 
-// DBus utility functions
-// Free statics, as they're used as function pointers in dbus setup
+bool
+DBusWatcher::Initialize()
+{
+  if (!SetUp()) {
+    CleanUp();
+    return false;
+  }
+
+  return true;
+}
+
+void
+DBusWatcher::CleanUp()
+{
+  MOZ_ASSERT(!NS_IsMainThread());
 
-static dbus_bool_t
-AddWatch(DBusWatch *aWatch, void *aData)
-{
-  DBusThread *dbt = (DBusThread *)aData;
+  dbus_connection_set_wakeup_main_function(mConnection, nullptr,
+                                           nullptr, nullptr);
+  dbus_bool_t success = dbus_connection_set_watch_functions(mConnection,
+                                                            nullptr, nullptr,
+                                                            nullptr, nullptr,
+                                                            nullptr);
+  if (success != TRUE) {
+    NS_WARNING("dbus_connection_set_watch_functions failed");
+  }
+
+#ifdef DEBUG
+  LOG("Removing DBus Sockets\n");
+#endif
+  if (mControlFdW.get()) {
+    mControlFdW.dispose();
+  }
+  if (mControlFdR.get()) {
+    mControlFdR.dispose();
+  }
+  mPollData.Clear();
 
-  if (dbus_watch_get_enabled(aWatch)) {
-    // note that we can't just send the watch and inspect it later
-    // because we may get a removeWatch call before this data is reacted
-    // to by our eventloop and remove this watch..  reading the add first
-    // and then inspecting the recently deceased watch would be bad.
-    char control = DBUS_EVENT_LOOP_ADD;
-    if (write(dbt->mControlFdW.get(), &control, sizeof(char)) < 0) {
-      LOG("Cannot write DBus add watch control data to socket!\n");
-      return false;
-    }
+  // DBusWatch pointers are maintained by DBus, so we won't leak by
+  // clearing.
+  mWatchData.Clear();
+}
+
+void
+DBusWatcher::WakeUp()
+{
+  static const char control = DBUS_EVENT_LOOP_WAKEUP;
+
+  struct pollfd fds = {
+    mControlFdW.get(),
+    POLLOUT,
+    0
+  };
 
-    int fd = dbus_watch_get_unix_fd(aWatch);
-    if (write(dbt->mControlFdW.get(), &fd, sizeof(int)) < 0) {
-      LOG("Cannot write DBus add watch descriptor data to socket!\n");
-      return false;
-    }
+  int nfds = TEMP_FAILURE_RETRY(poll(&fds, 1, 0));
+  NS_ENSURE_TRUE_VOID(nfds == 1);
+  NS_ENSURE_TRUE_VOID(fds.revents == POLLOUT);
 
-    unsigned int flags = dbus_watch_get_flags(aWatch);
-    if (write(dbt->mControlFdW.get(), &flags, sizeof(unsigned int)) < 0) {
-      LOG("Cannot write DBus add watch flag data to socket!\n");
-      return false;
-    }
+  ssize_t res = TEMP_FAILURE_RETRY(
+    write(mControlFdW.get(), &control, sizeof(control)));
+  if (res < 0) {
+    NS_WARNING("Cannot write wakeup bit to DBus controller!");
+  }
+}
 
-    if (write(dbt->mControlFdW.get(), &aWatch, sizeof(DBusWatch*)) < 0) {
-      LOG("Cannot write DBus add watch struct data to socket!\n");
-      return false;
-    }
-  }
+bool
+DBusWatcher::Stop()
+{
+  static const char data = DBUS_EVENT_LOOP_EXIT;
+
+  ssize_t res =
+    TEMP_FAILURE_RETRY(write(mControlFdW.get(), &data, sizeof(data)));
+  NS_ENSURE_TRUE(res == 1, false);
+
   return true;
 }
 
-static void
-RemoveWatch(DBusWatch *aWatch, void *aData)
+bool
+DBusWatcher::Poll()
 {
-  DBusThread *dbt = (DBusThread *)aData;
+  int res = TEMP_FAILURE_RETRY(poll(mPollData.Elements(),
+                                    mPollData.Length(), -1));
+  NS_ENSURE_TRUE(res > 0, false);
+
+  bool continueThread = true;
+
+  nsTArray<pollfd>::size_type i = 0;
+
+  while (i < mPollData.Length()) {
+    if (mPollData[i].revents == POLLIN) {
+      if (mPollData[i].fd == mControlFdR.get()) {
+        char data;
+        res = TEMP_FAILURE_RETRY(read(mControlFdR.get(), &data, sizeof(data)));
+        NS_ENSURE_TRUE(res > 0, NS_OK);
+
+        switch (data) {
+          case DBUS_EVENT_LOOP_EXIT:
+            continueThread = false;
+            break;
+          case DBUS_EVENT_LOOP_ADD:
+            HandleWatchAdd();
+            break;
+          case DBUS_EVENT_LOOP_REMOVE:
+            HandleWatchRemove();
+            // don't increment i, or we'll skip one element
+            continue;
+          case DBUS_EVENT_LOOP_WAKEUP:
+            NS_ProcessPendingEvents(NS_GetCurrentThread(),
+                                    PR_INTERVAL_NO_TIMEOUT);
+            break;
+          default:
+#if DEBUG
+            nsCString warning("unknown command ");
+            warning.AppendInt(data);
+            NS_WARNING(warning.get());
+#endif
+            break;
+        }
+      } else {
+        short events = mPollData[i].revents;
+        unsigned int flags = UnixEventsToDBusFlags(events);
+        dbus_watch_handle(mWatchData[i], flags);
+        mPollData[i].revents = 0;
+        // Break at this point since we don't know if the operation
+        // was destructive
+        break;
+      }
+
+      DBusDispatchStatus dbusDispatchStatus;
+      do {
+        dbusDispatchStatus = dbus_connection_dispatch(GetConnection());
+      } while (dbusDispatchStatus == DBUS_DISPATCH_DATA_REMAINS);
+    }
 
-  char control = DBUS_EVENT_LOOP_REMOVE;
-  if (write(dbt->mControlFdW.get(), &control, sizeof(char)) < 0) {
+    ++i;
+  }
+
+  return continueThread;
+}
+
+bool
+DBusWatcher::AddWatch(DBusWatch* aWatch)
+{
+  static const char control = DBUS_EVENT_LOOP_ADD;
+
+  if (dbus_watch_get_enabled(aWatch) == FALSE) {
+    return true;
+  }
+
+  // note that we can't just send the watch and inspect it later
+  // because we may get a removeWatch call before this data is reacted
+  // to by our eventloop and remove this watch..  reading the add first
+  // and then inspecting the recently deceased watch would be bad.
+  ssize_t res =
+    TEMP_FAILURE_RETRY(write(mControlFdW.get(),&control, sizeof(control)));
+  if (res < 0) {
+    LOG("Cannot write DBus add watch control data to socket!\n");
+    return false;
+  }
+
+  int fd = dbus_watch_get_unix_fd(aWatch);
+  res = TEMP_FAILURE_RETRY(write(mControlFdW.get(), &fd, sizeof(fd)));
+  if (res < 0) {
+    LOG("Cannot write DBus add watch descriptor data to socket!\n");
+    return false;
+  }
+
+  unsigned int flags = dbus_watch_get_flags(aWatch);
+  res = TEMP_FAILURE_RETRY(write(mControlFdW.get(), &flags, sizeof(flags)));
+  if (res < 0) {
+    LOG("Cannot write DBus add watch flag data to socket!\n");
+    return false;
+  }
+
+  res = TEMP_FAILURE_RETRY(write(mControlFdW.get(), &aWatch, sizeof(aWatch)));
+  if (res < 0) {
+    LOG("Cannot write DBus add watch struct data to socket!\n");
+    return false;
+  }
+
+  return true;
+}
+
+void
+DBusWatcher::RemoveWatch(DBusWatch* aWatch)
+{
+  static const char control = DBUS_EVENT_LOOP_REMOVE;
+
+  ssize_t res =
+    TEMP_FAILURE_RETRY(write(mControlFdW.get(), &control, sizeof(control)));
+  if (res < 0) {
     LOG("Cannot write DBus remove watch control data to socket!\n");
     return;
   }
 
   int fd = dbus_watch_get_unix_fd(aWatch);
-  if (write(dbt->mControlFdW.get(), &fd, sizeof(int)) < 0) {
+  res = TEMP_FAILURE_RETRY(write(mControlFdW.get(), &fd, sizeof(fd)));
+  if (res < 0) {
     LOG("Cannot write DBus remove watch descriptor data to socket!\n");
     return;
   }
 
   unsigned int flags = dbus_watch_get_flags(aWatch);
-  if (write(dbt->mControlFdW.get(), &flags, sizeof(unsigned int)) < 0) {
+  res = TEMP_FAILURE_RETRY(write(mControlFdW.get(), &flags, sizeof(flags)));
+  if (res < 0) {
     LOG("Cannot write DBus remove watch flag data to socket!\n");
     return;
   }
 }
 
-static void
-ToggleWatch(DBusWatch *aWatch, void *aData)
+void
+DBusWatcher::HandleWatchAdd()
 {
-  if (dbus_watch_get_enabled(aWatch)) {
-    AddWatch(aWatch, aData);
-  } else {
-    RemoveWatch(aWatch, aData);
-  }
-}
-
-static void
-HandleWatchAdd(DBusThread* aDbt)
-{
-  DBusWatch *watch;
-  int newFD;
-  unsigned int flags;
-  if (read(aDbt->mControlFdR.get(), &newFD, sizeof(int)) < 0) {
+  int fd;
+  ssize_t res = TEMP_FAILURE_RETRY(read(mControlFdR.get(), &fd, sizeof(fd)));
+  if (res < 0) {
     LOG("Cannot read DBus watch add descriptor data from socket!\n");
     return;
   }
-  if (read(aDbt->mControlFdR.get(), &flags, sizeof(unsigned int)) < 0) {
+
+  unsigned int flags;
+  res = TEMP_FAILURE_RETRY(read(mControlFdR.get(), &flags, sizeof(flags)));
+  if (res < 0) {
     LOG("Cannot read DBus watch add flag data from socket!\n");
     return;
   }
-  if (read(aDbt->mControlFdR.get(), &watch, sizeof(DBusWatch *)) < 0) {
+
+  DBusWatch* watch;
+  res = TEMP_FAILURE_RETRY(read(mControlFdR.get(), &watch, sizeof(watch)));
+  if (res < 0) {
     LOG("Cannot read DBus watch add watch data from socket!\n");
     return;
   }
-  short events = DBusFlagsToUnixEvents(flags);
 
-  pollfd p;
-  p.fd = newFD;
-  p.revents = 0;
-  p.events = events;
-  if (aDbt->mPollData.Contains(p, PollFdComparator())) return;
-  aDbt->mPollData.AppendElement(p);
-  aDbt->mWatchData.AppendElement(watch);
+  struct pollfd p = {
+    fd, // .fd
+    DBusFlagsToUnixEvents(flags), // .events
+    0 // .revents
+  };
+  if (mPollData.Contains(p, PollFdComparator())) {
+    return;
+  }
+  mPollData.AppendElement(p);
+  mWatchData.AppendElement(watch);
 }
 
-static void
-HandleWatchRemove(DBusThread* aDbt)
+void
+DBusWatcher::HandleWatchRemove()
 {
-  int removeFD;
-  unsigned int flags;
-
-  if (read(aDbt->mControlFdR.get(), &removeFD, sizeof(int)) < 0) {
+  int fd;
+  ssize_t res = TEMP_FAILURE_RETRY(read(mControlFdR.get(), &fd, sizeof(fd)));
+  if (res < 0) {
     LOG("Cannot read DBus watch remove descriptor data from socket!\n");
     return;
   }
-  if (read(aDbt->mControlFdR.get(), &flags, sizeof(unsigned int)) < 0) {
+
+  unsigned int flags;
+  res = TEMP_FAILURE_RETRY(read(mControlFdR.get(), &flags, sizeof(flags)));
+  if (res < 0) {
     LOG("Cannot read DBus watch remove flag data from socket!\n");
     return;
   }
-  short events = DBusFlagsToUnixEvents(flags);
-  pollfd p;
-  p.fd = removeFD;
-  p.events = events;
-  int index = aDbt->mPollData.IndexOf(p, 0, PollFdComparator());
+
+  struct pollfd p = {
+    fd, // .fd
+    DBusFlagsToUnixEvents(flags), // .events
+    0 // .revents
+  };
+  int index = mPollData.IndexOf(p, 0, PollFdComparator());
   // There are times where removes can be requested for watches that
   // haven't been added (for example, whenever gecko comes up after
   // adapters have already been enabled), so check to make sure we're
   // using the watch in the first place
   if (index < 0) {
     LOG("DBus requested watch removal of non-existant socket, ignoring...");
     return;
   }
-  aDbt->mPollData.RemoveElementAt(index);
+  mPollData.RemoveElementAt(index);
 
   // DBusWatch pointers are maintained by DBus, so we won't leak by
   // removing.
-  aDbt->mWatchData.RemoveElementAt(index);
+  mWatchData.RemoveElementAt(index);
+}
+
+// Flag conversion
+
+unsigned int
+DBusWatcher::UnixEventsToDBusFlags(short events)
+{
+  return (events & DBUS_WATCH_READABLE ? POLLIN : 0) |
+         (events & DBUS_WATCH_WRITABLE ? POLLOUT : 0) |
+         (events & DBUS_WATCH_ERROR ? POLLERR : 0) |
+         (events & DBUS_WATCH_HANGUP ? POLLHUP : 0);
 }
 
-static
-void DBusWakeup(void* aData)
+short
+DBusWatcher::DBusFlagsToUnixEvents(unsigned int flags)
+{
+  return (flags & POLLIN ? DBUS_WATCH_READABLE : 0) |
+         (flags & POLLOUT ? DBUS_WATCH_WRITABLE : 0) |
+         (flags & POLLERR ? DBUS_WATCH_ERROR : 0) |
+         (flags & POLLHUP ? DBUS_WATCH_HANGUP : 0);
+}
+
+// DBus utility functions, used as function pointers in DBus setup
+
+dbus_bool_t
+DBusWatcher::AddWatchFunction(DBusWatch* aWatch, void* aData)
 {
   MOZ_ASSERT(aData);
-  DBusThread* dbusThread = static_cast<DBusThread*>(aData);
-  dbusThread->WakeUp();
+  DBusWatcher* dbusWatcher = static_cast<DBusWatcher*>(aData);
+  return dbusWatcher->AddWatch(aWatch);
+}
+
+void
+DBusWatcher::RemoveWatchFunction(DBusWatch* aWatch, void* aData)
+{
+  MOZ_ASSERT(aData);
+  DBusWatcher* dbusWatcher = static_cast<DBusWatcher*>(aData);
+  dbusWatcher->RemoveWatch(aWatch);
 }
 
-// DBus Thread Implementation
+void
+DBusWatcher::ToggleWatchFunction(DBusWatch* aWatch, void* aData)
+{
+  MOZ_ASSERT(aData);
+  DBusWatcher* dbusWatcher = static_cast<DBusWatcher*>(aData);
 
-DBusThread::DBusThread()
-{
+  if (dbus_watch_get_enabled(aWatch)) {
+    dbusWatcher->AddWatch(aWatch);
+  } else {
+    dbusWatcher->RemoveWatch(aWatch);
+  }
 }
 
-DBusThread::~DBusThread()
+void
+DBusWatcher::DBusWakeupFunction(void* aData)
 {
-
+  MOZ_ASSERT(aData);
+  DBusWatcher* dbusWatcher = static_cast<DBusWatcher*>(aData);
+  dbusWatcher->WakeUp();
 }
 
 bool
-DBusThread::SetUp()
+DBusWatcher::SetUp()
 {
   MOZ_ASSERT(!NS_IsMainThread());
 
   // If we already have a connection, exit
   if (mConnection) {
     return false;
   }
 
@@ -310,17 +496,17 @@ DBusThread::SetUp()
   int sockets[2];
   if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sockets) < 0) {
     return false;
   }
 
   mControlFdR.rwget() = sockets[0];
   mControlFdW.rwget() = sockets[1];
 
-  pollfd *p = mPollData.AppendElement();
+  pollfd* p = mPollData.AppendElement();
 
   p->fd = mControlFdR.get();
   p->events = POLLIN;
   p->revents = 0;
 
   // Due to the fact that mPollData and mWatchData have to match, we
   // push a null to the front of mWatchData since it has the control
   // fd in the first slot of mPollData.
@@ -330,247 +516,132 @@ DBusThread::SetUp()
   // If we can't establish a connection to dbus, nothing else will work
   nsresult rv = EstablishDBusConnection();
   if (NS_FAILED(rv)) {
     NS_WARNING("Cannot create DBus Connection for DBus Thread!");
     return false;
   }
 
   dbus_bool_t success =
-    dbus_connection_set_watch_functions(mConnection, AddWatch, RemoveWatch,
-                                        ToggleWatch, this, nullptr);
+    dbus_connection_set_watch_functions(mConnection, AddWatchFunction,
+                                        RemoveWatchFunction,
+                                        ToggleWatchFunction, this, nullptr);
   NS_ENSURE_TRUE(success == TRUE, false);
 
-  dbus_connection_set_wakeup_main_function(mConnection, DBusWakeup, this, nullptr);
-
-  return true;
-}
-
-bool
-DBusThread::Initialize()
-{
-  if (!SetUp()) {
-    CleanUp();
-    return false;
-  }
-
+  dbus_connection_set_wakeup_main_function(mConnection, DBusWakeupFunction,
+                                           this, nullptr);
   return true;
 }
 
-void
-DBusThread::CleanUp()
-{
-  MOZ_ASSERT(!NS_IsMainThread());
-
-  dbus_connection_set_wakeup_main_function(mConnection, nullptr, nullptr, nullptr);
-
-  dbus_bool_t success = dbus_connection_set_watch_functions(mConnection, nullptr,
-                                                            nullptr, nullptr,
-                                                            nullptr, nullptr);
-  if (success != TRUE) {
-    NS_WARNING("dbus_connection_set_watch_functions failed");
-  }
-
-#ifdef DEBUG
-  LOG("Removing DBus Sockets\n");
-#endif
-  if (mControlFdW.get()) {
-    mControlFdW.dispose();
-  }
-  if (mControlFdR.get()) {
-    mControlFdR.dispose();
-  }
-  mPollData.Clear();
-
-  // DBusWatch pointers are maintained by DBus, so we won't leak by
-  // clearing.
-  mWatchData.Clear();
-}
-
-void
-DBusThread::WakeUp()
-{
-  static const char control = DBUS_EVENT_LOOP_WAKEUP;
-
-  struct pollfd fds = {
-    mControlFdW.get(),
-    POLLOUT,
-    0
-  };
-
-  int nfds = TEMP_FAILURE_RETRY(poll(&fds, 1, 0));
-  NS_ENSURE_TRUE_VOID(nfds == 1);
-  NS_ENSURE_TRUE_VOID(fds.revents == POLLOUT);
-
-  ssize_t rv = TEMP_FAILURE_RETRY(write(mControlFdW.get(), &control, sizeof(control)));
-
-  if (rv < 0) {
-    NS_WARNING("Cannot write wakeup bit to DBus controller!");
-  }
-}
-
 // Main task for polling the DBus system
 
 class DBusPollTask : public nsRunnable
 {
 public:
-  DBusPollTask(DBusThread* aConnection)
-  : mConnection(aConnection)
+  DBusPollTask(DBusWatcher* aDBusWatcher)
+  : mDBusWatcher(aDBusWatcher)
   { }
 
   NS_IMETHOD Run()
   {
     MOZ_ASSERT(!NS_IsMainThread());
 
-    bool exitThread = false;
-
-    while (!exitThread) {
-
-      int res = TEMP_FAILURE_RETRY(poll(mConnection->mPollData.Elements(),
-                                        mConnection->mPollData.Length(),
-                                        -1));
-      NS_ENSURE_TRUE(res > 0, NS_OK);
+    bool continueThread;
 
-      nsTArray<pollfd>::size_type i = 0;
-
-      while (i < mConnection->mPollData.Length()) {
-        if (mConnection->mPollData[i].revents == POLLIN) {
+    do {
+      continueThread = mDBusWatcher->Poll();
+    } while (continueThread);
 
-          if (mConnection->mPollData[i].fd == mConnection->mControlFdR.get()) {
-            char data;
-            res = TEMP_FAILURE_RETRY(read(mConnection->mControlFdR.get(), &data, sizeof(data)));
-            NS_ENSURE_TRUE(res > 0, NS_OK);
+    mDBusWatcher->CleanUp();
 
-            switch (data) {
-            case DBUS_EVENT_LOOP_EXIT:
-              exitThread = true;
-              break;
-            case DBUS_EVENT_LOOP_ADD:
-              HandleWatchAdd(mConnection);
-              break;
-            case DBUS_EVENT_LOOP_REMOVE:
-              HandleWatchRemove(mConnection);
-              // don't increment i, or we'll skip one element
-              continue;
-            case DBUS_EVENT_LOOP_WAKEUP:
-              NS_ProcessPendingEvents(NS_GetCurrentThread(),
-                                      PR_INTERVAL_NO_TIMEOUT);
-              break;
-            default:
-#if DEBUG
-              nsCString warning("unknown command ");
-              warning.AppendInt(data);
-              NS_WARNING(warning.get());
-#endif
-              break;
-            }
-          } else {
-            short events = mConnection->mPollData[i].revents;
-            unsigned int flags = UnixEventsToDBusFlags(events);
-            dbus_watch_handle(mConnection->mWatchData[i], flags);
-            mConnection->mPollData[i].revents = 0;
-            // Break at this point since we don't know if the operation
-            // was destructive
-            break;
-          }
-          while (dbus_connection_dispatch(mConnection->GetConnection()) ==
-                 DBUS_DISPATCH_DATA_REMAINS)
-          {}
-        }
-        ++i;
-      }
-    }
+    nsIThread* thread;
+    nsresult rv = NS_GetCurrentThread(&thread);
+    NS_ENSURE_SUCCESS(rv, rv);
 
-    mConnection->CleanUp();
+    nsRefPtr<nsIRunnable> runnable =
+      NS_NewRunnableMethod(thread, &nsIThread::Shutdown);
+    rv = NS_DispatchToMainThread(runnable);
+    NS_ENSURE_SUCCESS(rv, rv);
 
     return NS_OK;
   }
 
 private:
-  nsRefPtr<DBusThread> mConnection;
+  nsRefPtr<DBusWatcher> mDBusWatcher;
 };
 
-static StaticRefPtr<DBusThread> gDBusThread;
-static StaticRefPtr<nsIThread>  gDBusServiceThread;
+static StaticRefPtr<DBusWatcher> gDBusWatcher;
+static StaticRefPtr<nsIThread>   gDBusServiceThread;
 
 // Startup/Shutdown utility functions
 
 bool
 StartDBus()
 {
   MOZ_ASSERT(!NS_IsMainThread());
-  NS_ENSURE_TRUE(!gDBusThread, true);
+  NS_ENSURE_TRUE(!gDBusWatcher, true);
 
-  nsRefPtr<DBusThread> dbusThread(new DBusThread());
+  nsRefPtr<DBusWatcher> dbusWatcher(new DBusWatcher());
 
-  bool eventLoopStarted = dbusThread->Initialize();
+  bool eventLoopStarted = dbusWatcher->Initialize();
   NS_ENSURE_TRUE(eventLoopStarted, false);
 
   nsresult rv;
 
   if (!gDBusServiceThread) {
     nsIThread* dbusServiceThread;
     rv = NS_NewNamedThread("DBus Thread", &dbusServiceThread);
     NS_ENSURE_SUCCESS(rv, false);
     gDBusServiceThread = dbusServiceThread;
   }
 
 #ifdef DEBUG
   LOG("DBus Thread Starting\n");
 #endif
 
-  nsRefPtr<nsIRunnable> pollTask(new DBusPollTask(dbusThread));
+  nsRefPtr<nsIRunnable> pollTask(new DBusPollTask(dbusWatcher));
   NS_ENSURE_TRUE(pollTask, false);
 
   rv = gDBusServiceThread->Dispatch(pollTask, NS_DISPATCH_NORMAL);
   NS_ENSURE_SUCCESS(rv, false);
 
-  gDBusThread = dbusThread;
+  gDBusWatcher = dbusWatcher;
 
   return true;
 }
 
 bool
 StopDBus()
 {
   MOZ_ASSERT(!NS_IsMainThread());
   NS_ENSURE_TRUE(gDBusServiceThread, true);
 
-  nsRefPtr<DBusThread> dbusThread(gDBusThread);
-  gDBusThread = nullptr;
+  nsRefPtr<DBusWatcher> dbusWatcher(gDBusWatcher);
+  gDBusWatcher = nullptr;
 
-  if (dbusThread) {
-    static const char data = DBUS_EVENT_LOOP_EXIT;
-    ssize_t wret = TEMP_FAILURE_RETRY(write(dbusThread->mControlFdW.get(),
-                                            &data, sizeof(data)));
-    NS_ENSURE_TRUE(wret == 1, false);
+  if (dbusWatcher && !dbusWatcher->Stop()) {
+    return false;
   }
 
-  nsRefPtr<nsIThread> dbusServiceThread(gDBusServiceThread);
   gDBusServiceThread = nullptr;
 
-  nsRefPtr<nsIRunnable> runnable =
-    NS_NewRunnableMethod(dbusServiceThread, &nsIThread::Shutdown);
-  nsresult rv = NS_DispatchToMainThread(runnable);
-  NS_ENSURE_SUCCESS(rv, false);
-
   return true;
 }
 
 nsresult
 DispatchToDBusThread(nsIRunnable* event)
 {
   nsRefPtr<nsIThread> dbusServiceThread(gDBusServiceThread);
-  nsRefPtr<DBusThread> dbusThread(gDBusThread);
+  nsRefPtr<DBusWatcher> dbusWatcher(gDBusWatcher);
 
-  NS_ENSURE_TRUE(dbusServiceThread.get() && dbusThread.get(),
+  NS_ENSURE_TRUE(dbusServiceThread.get() && dbusWatcher.get(),
                  NS_ERROR_NOT_INITIALIZED);
 
   nsresult rv = dbusServiceThread->Dispatch(event, NS_DISPATCH_NORMAL);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  dbusThread->WakeUp();
+  dbusWatcher->WakeUp();
 
   return NS_OK;
 }
 
 }
 }
--- a/tools/profiler/platform-linux.cc
+++ b/tools/profiler/platform-linux.cc
@@ -451,49 +451,103 @@ void Sampler::UnregisterCurrentThread()
 
   uwt__unregister_thread_for_profiling();
 }
 
 #ifdef ANDROID
 static struct sigaction old_sigstart_signal_handler;
 const int SIGSTART = SIGUSR2;
 
+static void freeArray(const char** array, int size) {
+  for (int i = 0; i < size; i++) {
+    free((void*) array[i]);
+  }
+}
+
+static uint32_t readCSVArray(char* csvList, const char** buffer) {
+  uint32_t count;
+  char* savePtr;
+  int newlinePos = strlen(csvList) - 1;
+  if (csvList[newlinePos] == '\n') {
+    csvList[newlinePos] = '\0';
+  }
+
+  char* item = strtok_r(csvList, ",", &savePtr);
+  for (count = 0; item; item = strtok_r(NULL, ",", &savePtr)) {
+    int length = strlen(item) + 1;  // Include \0
+    char* newBuf = (char*) malloc(sizeof(char) * length);
+    buffer[count] = newBuf;
+    strncpy(newBuf, item, length);
+    count++;
+  }
+
+  return count;
+}
+
+// Currently support only the env variables
+// reported in read_profiler_env
+static void ReadProfilerVars(const char* fileName, const char** features,
+                            uint32_t* featureCount, const char** threadNames, uint32_t* threadCount) {
+  FILE* file = fopen(fileName, "r");
+  const int bufferSize = 1024;
+  char line[bufferSize];
+  char* feature;
+  char* value;
+  char* savePtr;
+
+  if (file) {
+    while (fgets(line, bufferSize, file) != NULL) {
+      feature = strtok_r(line, "=", &savePtr);
+      value = strtok_r(NULL, "", &savePtr);
+
+      if (strncmp(feature, PROFILER_MODE, bufferSize) == 0) {
+        set_profiler_mode(value);
+      } else if (strncmp(feature, PROFILER_INTERVAL, bufferSize) == 0) {
+        set_profiler_interval(value);
+      } else if (strncmp(feature, PROFILER_ENTRIES, bufferSize) == 0) {
+        set_profiler_entries(value);
+      } else if (strncmp(feature, PROFILER_STACK, bufferSize) == 0) {
+        set_profiler_scan(value);
+      } else if (strncmp(feature, PROFILER_FEATURES, bufferSize) == 0) {
+        *featureCount = readCSVArray(value, features);
+      } else if (strncmp(feature, "threads", bufferSize) == 0) {
+        *threadCount = readCSVArray(value, threadNames);
+      }
+    }
+
+    fclose(file);
+  }
+}
+
+
 static void StartSignalHandler(int signal, siginfo_t* info, void* context) {
-
   // XXX: Everything we do here is NOT async signal safe. We risk nasty things
   // like deadlocks but we typically only do this once so it tends to be ok.
   // See bug 909403
-  const char* threadName = NULL;
+  uint32_t featureCount = 0;
   uint32_t threadCount = 0;
-  char thread[256];
 
-  // TODO support selecting features from profiler.options
-  const char* features[3] = {NULL, NULL, NULL};
-  uint32_t featureCount = 0;
-  features[0] = "leaf";
-  featureCount++;
-  features[1] = "js";
-  featureCount++;
-  const char* threadFeature = "threads";
+  // Just allocate 10 features for now
+  // FIXME: these don't really point to const chars*
+  // So we free them later, but we don't want to change the const char**
+  // declaration in profiler_start. Annoying but ok for now.
+  const char* threadNames[10];
+  const char* features[10];
+  const char* profilerConfigFile = "/data/local/tmp/profiler.options";
 
-  std::ifstream infile;
-  infile.open("/data/local/tmp/profiler.options");
-  if (infile.is_open()) {
-    infile.getline(thread, 256);
-    threadName = thread;
-    threadCount = 1;
-    features[featureCount] = threadFeature;
-    featureCount++;
-    printf_stderr("Profiling only %s\n", threadName);
-  }
-  infile.close();
+  ReadProfilerVars(profilerConfigFile, features, &featureCount, threadNames, &threadCount);
+  MOZ_ASSERT(featureCount < 10);
+  MOZ_ASSERT(threadCount < 10);
 
   profiler_start(PROFILE_DEFAULT_ENTRY, 1,
-                 features, featureCount,
-                 &threadName, threadCount);
+      features, featureCount,
+      threadNames, threadCount);
+
+  freeArray(threadNames, threadCount);
+  freeArray(features, featureCount);
 }
 
 void OS::RegisterStartHandler()
 {
   LOG("Registering start signal");
   struct sigaction sa;
   sa.sa_sigaction = StartSignalHandler;
   sigemptyset(&sa.sa_mask);
--- a/tools/profiler/platform.cpp
+++ b/tools/profiler/platform.cpp
@@ -41,16 +41,23 @@ bool stack_key_initialized;
 
 TimeStamp   sLastTracerEvent; // is raced on
 TimeStamp   sStartTime;
 int         sFrameNumber = 0;
 int         sLastFrameNumber = 0;
 int         sInitCount = 0; // Each init must have a matched shutdown.
 static bool sIsProfiling = false; // is raced on
 
+// env variables to control the profiler
+const char* PROFILER_MODE = "MOZ_PROFILER_MODE";
+const char* PROFILER_INTERVAL = "MOZ_PROFILER_INTERVAL";
+const char* PROFILER_ENTRIES = "MOZ_PROFILER_ENTRIES";
+const char* PROFILER_STACK = "MOZ_PROFILER_STACK_SCAN";
+const char* PROFILER_FEATURES = "MOZ_PROFILING_FEATURES";
+
 /* used to keep track of the last event that we sampled during */
 unsigned int sLastSampledEventGeneration = 0;
 
 /* a counter that's incremented everytime we get responsiveness event
  * note: it might also be worth trackplaing everytime we go around
  * the event loop */
 unsigned int sCurrentEventGeneration = 0;
 /* we don't need to worry about overflow because we only treat the
@@ -247,78 +254,122 @@ static inline const char* name_UnwMode(U
     case UnwINVALID:  return "invalid";
     case UnwNATIVE:   return "native";
     case UnwPSEUDO:   return "pseudo";
     case UnwCOMBINED: return "combined";
     default:          return "??name_UnwMode??";
   }
 }
 
+bool set_profiler_mode(const char* mode) {
+  if (mode) {
+    if (0 == strcmp(mode, "pseudo")) {
+      sUnwindMode = UnwPSEUDO;
+      return true;
+    }
+    else if (0 == strcmp(mode, "native") && is_native_unwinding_avail()) {
+      sUnwindMode = UnwNATIVE;
+      return true;
+    }
+    else if (0 == strcmp(mode, "combined") && is_native_unwinding_avail()) {
+      sUnwindMode = UnwCOMBINED;
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool set_profiler_interval(const char* interval) {
+  if (interval) {
+    errno = 0;
+    long int n = strtol(interval, (char**)NULL, 10);
+    if (errno == 0 && n >= 1 && n <= 1000) {
+      sUnwindInterval = n;
+      return true;
+    }
+    return false;
+  }
+
+  return true;
+}
+
+bool set_profiler_entries(const char* entries) {
+  if (entries) {
+    errno = 0;
+    long int n = strtol(entries, (char**)NULL, 10);
+    if (errno == 0 && n > 0) {
+      sProfileEntries = n;
+      return true;
+    }
+    return false;
+  }
+
+  return true;
+}
+
+bool set_profiler_scan(const char* scanCount) {
+  if (scanCount) {
+    errno = 0;
+    long int n = strtol(scanCount, (char**)NULL, 10);
+    if (errno == 0 && n >= 0 && n <= 100) {
+      sUnwindStackScan = n;
+      return true;
+    }
+    return false;
+  }
+
+  return true;
+}
+
+bool is_native_unwinding_avail() {
+# if defined(HAVE_NATIVE_UNWIND)
+  return true;
+#else
+  return false;
+#endif
+}
+
 // Read env vars at startup, so as to set sUnwindMode and sInterval.
 void read_profiler_env_vars()
 {
-  bool nativeAvail = false;
-# if defined(HAVE_NATIVE_UNWIND)
-  nativeAvail = true;
-# endif
-
-  MOZ_ASSERT(sUnwindMode     == UnwINVALID);
-  MOZ_ASSERT(sUnwindInterval == 0);
-  MOZ_ASSERT(sProfileEntries == 0);
+  bool nativeAvail = is_native_unwinding_avail();
 
   /* Set defaults */
   sUnwindMode     = nativeAvail ? UnwCOMBINED : UnwPSEUDO;
   sUnwindInterval = 0;  /* We'll have to look elsewhere */
   sProfileEntries = 0;
 
-  const char* strM = PR_GetEnv("MOZ_PROFILER_MODE");
-  const char* strI = PR_GetEnv("MOZ_PROFILER_INTERVAL");
-  const char* strE = PR_GetEnv("MOZ_PROFILER_ENTRIES");
-  const char* strF = PR_GetEnv("MOZ_PROFILER_STACK_SCAN");
+  const char* stackMode = PR_GetEnv(PROFILER_MODE);
+  const char* interval = PR_GetEnv(PROFILER_INTERVAL);
+  const char* entries = PR_GetEnv(PROFILER_ENTRIES);
+  const char* scanCount = PR_GetEnv(PROFILER_STACK);
 
-  if (strM) {
-    if (0 == strcmp(strM, "pseudo"))
-      sUnwindMode = UnwPSEUDO;
-    else if (0 == strcmp(strM, "native") && nativeAvail)
-      sUnwindMode = UnwNATIVE;
-    else if (0 == strcmp(strM, "combined") && nativeAvail)
-      sUnwindMode = UnwCOMBINED;
-    else goto usage;
-  }
-
-  if (strI) {
-    errno = 0;
-    long int n = strtol(strI, (char**)NULL, 10);
-    if (errno == 0 && n >= 1 && n <= 1000) {
-      sUnwindInterval = n;
-    }
-    else goto usage;
+  if (!set_profiler_mode(stackMode) ||
+      !set_profiler_interval(interval) ||
+      !set_profiler_entries(entries) ||
+      !set_profiler_scan(scanCount)) {
+      profiler_usage();
+  } else {
+    LOG( "SPS:");
+    LOGF("SPS: Unwind mode       = %s", name_UnwMode(sUnwindMode));
+    LOGF("SPS: Sampling interval = %d ms (zero means \"platform default\")",
+        (int)sUnwindInterval);
+    LOGF("SPS: Entry store size  = %d (zero means \"platform default\")",
+        (int)sProfileEntries);
+    LOGF("SPS: UnwindStackScan   = %d (max dubious frames per unwind).",
+        (int)sUnwindStackScan);
+    LOG( "SPS: Use env var MOZ_PROFILER_MODE=help for further information.");
+    LOG( "SPS:");
   }
-
-  if (strE) {
-    errno = 0;
-    long int n = strtol(strE, (char**)NULL, 10);
-    if (errno == 0 && n > 0) {
-      sProfileEntries = n;
-    }
-    else goto usage;
-  }
+}
 
-  if (strF) {
-    errno = 0;
-    long int n = strtol(strF, (char**)NULL, 10);
-    if (errno == 0 && n >= 0 && n <= 100) {
-      sUnwindStackScan = n;
-    }
-    else goto usage;
-  }
-
-  goto out;
-
- usage:
+void profiler_usage() {
   LOG( "SPS: ");
   LOG( "SPS: Environment variable usage:");
   LOG( "SPS: ");
   LOG( "SPS:   MOZ_PROFILER_MODE=native    for native unwind only");
   LOG( "SPS:   MOZ_PROFILER_MODE=pseudo    for pseudo unwind only");
   LOG( "SPS:   MOZ_PROFILER_MODE=combined  for combined native & pseudo unwind");
   LOG( "SPS:   If unset, default is 'combined' on native-capable");
   LOG( "SPS:     platforms, 'pseudo' on others.");
@@ -334,25 +385,25 @@ void read_profiler_env_vars()
   LOG( "SPS: ");
   LOG( "SPS:   MOZ_PROFILER_STACK_SCAN=<number>   (default is zero)");
   LOG( "SPS:   The number of dubious (stack-scanned) frames allowed");
   LOG( "SPS: ");
   LOG( "SPS:   MOZ_PROFILER_NEW");
   LOG( "SPS:   Needs to be set to use Breakpad-based unwinding.");
   LOG( "SPS: ");
   LOGF("SPS:   This platform %s native unwinding.",
-       nativeAvail ? "supports" : "does not support");
+       is_native_unwinding_avail() ? "supports" : "does not support");
   LOG( "SPS: ");
+
   /* Re-set defaults */
-  sUnwindMode       = nativeAvail ? UnwCOMBINED : UnwPSEUDO;
+  sUnwindMode       = is_native_unwinding_avail() ? UnwCOMBINED : UnwPSEUDO;
   sUnwindInterval   = 0;  /* We'll have to look elsewhere */
   sProfileEntries   = 0;
   sUnwindStackScan  = 0;
 
- out:
   LOG( "SPS:");
   LOGF("SPS: Unwind mode       = %s", name_UnwMode(sUnwindMode));
   LOGF("SPS: Sampling interval = %d ms (zero means \"platform default\")",
        (int)sUnwindInterval);
   LOGF("SPS: Entry store size  = %d (zero means \"platform default\")",
        (int)sProfileEntries);
   LOGF("SPS: UnwindStackScan   = %d (max dubious frames per unwind).",
        (int)sUnwindStackScan);
--- a/tools/profiler/platform.h
+++ b/tools/profiler/platform.h
@@ -235,17 +235,32 @@ class Thread {
         || defined(SPS_PLAT_x86_linux) \
         || defined(SPS_OS_windows) \
         || defined(SPS_OS_darwin))
 # define HAVE_NATIVE_UNWIND
 #endif
 
 /* Some values extracted at startup from environment variables, that
    control the behaviour of the breakpad unwinder. */
+extern const char* PROFILER_MODE;
+extern const char* PROFILER_INTERVAL;
+extern const char* PROFILER_ENTRIES;
+extern const char* PROFILER_STACK;
+extern const char* PROFILER_FEATURES;
+
 void read_profiler_env_vars();
+void profiler_usage();
+
+// Helper methods to expose modifying profiler behavior
+bool set_profiler_mode(const char*);
+bool set_profiler_interval(const char*);
+bool set_profiler_entries(const char*);
+bool set_profiler_scan(const char*);
+bool is_native_unwinding_avail();
+
 typedef  enum { UnwINVALID, UnwNATIVE, UnwPSEUDO, UnwCOMBINED }  UnwMode;
 extern UnwMode sUnwindMode;       /* what mode? */
 extern int     sUnwindInterval;   /* in milliseconds */
 extern int     sUnwindStackScan;  /* max # of dubious frames allowed */
 
 extern int     sProfileEntries;   /* how many entries do we store? */
 
 void set_tls_stack_top(void* stackTop);