Bug 1232687: Add system-service interface to HAL, r=gsvelto
authorThomas Zimmermann <tdz@users.sourceforge.net>
Mon, 04 Jan 2016 16:08:21 +0100
changeset 315281 7670432d8866bfe462989853eaa6c75f62a6d625
parent 315280 20360de81e53172b93f95b82cad6a5151ba6ea99
child 315282 ee9973fdfffde07fc89c7101a73b239c55b3a636
push id1079
push userjlund@mozilla.com
push dateFri, 15 Apr 2016 21:02:33 +0000
treeherdermozilla-release@575fbf6786d5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgsvelto
bugs1232687
milestone46.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 1232687: Add system-service interface to HAL, r=gsvelto The new HAL interface allows for starting, stopping, and querying the status of system services. How these operations are performed depends on the underlying system. The current implementation for Gonk already contains a workaround from Bluetooth, where quickly restarted system services require a cool-down time between retrys.
hal/Hal.cpp
hal/Hal.h
hal/fallback/FallbackSystemService.cpp
hal/gonk/SystemService.cpp
hal/moz.build
hal/sandbox/SandboxHal.cpp
--- a/hal/Hal.cpp
+++ b/hal/Hal.cpp
@@ -143,17 +143,17 @@ Vibrate(const nsTArray<uint32_t>& patter
 
   if (!InSandbox()) {
     if (!gLastIDToVibrate) {
       InitLastIDToVibrate();
     }
     *gLastIDToVibrate = id.AsArray();
   }
 
-  // Don't forward our ID if we are not in the sandbox, because hal_impl 
+  // Don't forward our ID if we are not in the sandbox, because hal_impl
   // doesn't need it, and we don't want it to be tempted to read it.  The
   // empty identifier will assert if it's used.
   PROXY_IF_SANDBOXED(Vibrate(pattern, InSandbox() ? id : WindowIdentifier()));
 }
 
 void
 CancelVibrate(nsIDOMWindow* window)
 {
@@ -178,17 +178,17 @@ CancelVibrate(const WindowIdentifier &id
   // want this window's cancellation request to cancel that window's
   // actively-playing vibration!
   //
   // To solve this problem, we keep track of the id of the last window
   // to start a vibration, and only accepts cancellation requests from
   // the same window.  All other cancellation requests are ignored.
 
   if (InSandbox() || (gLastIDToVibrate && *gLastIDToVibrate == id.AsArray())) {
-    // Don't forward our ID if we are not in the sandbox, because hal_impl 
+    // Don't forward our ID if we are not in the sandbox, because hal_impl
     // doesn't need it, and we don't want it to be tempted to read it.  The
     // empty identifier will assert if it's used.
     PROXY_IF_SANDBOXED(CancelVibrate(InSandbox() ? id : WindowIdentifier()));
   }
 }
 
 template <class InfoType>
 class ObserversManager
@@ -491,24 +491,24 @@ UnregisterSystemTimezoneChangeObserver(S
 
 void
 NotifySystemTimezoneChange(const SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo)
 {
   nsJSUtils::ResetTimeZone();
   sSystemTimezoneChangeObservers.BroadcastInformation(aSystemTimezoneChangeInfo);
 }
 
-void 
+void
 AdjustSystemClock(int64_t aDeltaMilliseconds)
 {
   AssertMainThread();
   PROXY_IF_SANDBOXED(AdjustSystemClock(aDeltaMilliseconds));
 }
 
-void 
+void
 SetTimezone(const nsCString& aTimezoneSpec)
 {
   AssertMainThread();
   PROXY_IF_SANDBOXED(SetTimezone(aTimezoneSpec));
 }
 
 int32_t
 GetTimezoneOffset()
@@ -537,29 +537,29 @@ DisableSensorNotifications(SensorType aS
 }
 
 typedef mozilla::ObserverList<SensorData> SensorObserverList;
 static SensorObserverList* gSensorObservers = nullptr;
 
 static SensorObserverList &
 GetSensorObservers(SensorType sensor_type) {
   MOZ_ASSERT(sensor_type < NUM_SENSOR_TYPE);
-  
+
   if(!gSensorObservers) {
     gSensorObservers = new SensorObserverList[NUM_SENSOR_TYPE];
   }
   return gSensorObservers[sensor_type];
 }
 
 void
 RegisterSensorObserver(SensorType aSensor, ISensorObserver *aObserver) {
   SensorObserverList &observers = GetSensorObservers(aSensor);
 
   AssertMainThread();
-  
+
   observers.AddObserver(aObserver);
   if(observers.Length() == 1) {
     EnableSensorNotifications(aSensor);
   }
 }
 
 void
 UnregisterSensorObserver(SensorType aSensor, ISensorObserver *aObserver) {
@@ -585,17 +585,17 @@ UnregisterSensorObserver(SensorType aSen
   gSensorObservers = nullptr;
 }
 
 void
 NotifySensorChange(const SensorData &aSensorData) {
   SensorObserverList &observers = GetSensorObservers(aSensorData.sensor());
 
   AssertMainThread();
-  
+
   observers.Broadcast(aSensorData);
 }
 
 void
 RegisterNetworkObserver(NetworkObserver* aObserver)
 {
   AssertMainThread();
   sNetworkObservers.AddObserver(aObserver);
@@ -755,17 +755,17 @@ void NotifySwitchStateFromInputDevice(Sw
 }
 
 typedef mozilla::ObserverList<SwitchEvent> SwitchObserverList;
 
 static SwitchObserverList *sSwitchObserverLists = nullptr;
 
 static SwitchObserverList&
 GetSwitchObserverList(SwitchDevice aDevice) {
-  MOZ_ASSERT(0 <= aDevice && aDevice < NUM_SWITCH_DEVICE); 
+  MOZ_ASSERT(0 <= aDevice && aDevice < NUM_SWITCH_DEVICE);
   if (sSwitchObserverLists == nullptr) {
     sSwitchObserverLists = new SwitchObserverList[NUM_SWITCH_DEVICE];
   }
   return sSwitchObserverLists[aDevice];
 }
 
 static void
 ReleaseObserversIfNeeded() {
@@ -1189,10 +1189,28 @@ GetTotalSystemMemoryLevel()
 }
 
 bool IsHeadphoneEventFromInputDev()
 {
   AssertMainThread();
   RETURN_PROXY_IF_SANDBOXED(IsHeadphoneEventFromInputDev(), false);
 }
 
+nsresult StartSystemService(const char* aSvcName, const char* aArgs)
+{
+  AssertMainThread();
+  RETURN_PROXY_IF_SANDBOXED(StartSystemService(aSvcName, aArgs), NS_ERROR_FAILURE);
+}
+
+void StopSystemService(const char* aSvcName)
+{
+  AssertMainThread();
+  PROXY_IF_SANDBOXED(StopSystemService(aSvcName));
+}
+
+bool SystemServiceIsRunning(const char* aSvcName)
+{
+  AssertMainThread();
+  RETURN_PROXY_IF_SANDBOXED(SystemServiceIsRunning(aSvcName), false);
+}
+
 } // namespace hal
 } // namespace mozilla
--- a/hal/Hal.h
+++ b/hal/Hal.h
@@ -635,16 +635,31 @@ uint32_t GetTotalSystemMemory();
  */
 uint32_t GetTotalSystemMemoryLevel();
 
 /**
  * Determine whether the headphone switch event is from input device
  */
 bool IsHeadphoneEventFromInputDev();
 
+/**
+ * Start the system service with the specified name and arguments.
+ */
+nsresult StartSystemService(const char* aSvcName, const char* aArgs);
+
+/**
+ * Stop the system service with the specified name.
+ */
+void StopSystemService(const char* aSvcName);
+
+/**
+ * Determine whether the system service with the specified name is running.
+ */
+bool SystemServiceIsRunning(const char* aSvcName);
+
 } // namespace MOZ_HAL_NAMESPACE
 } // namespace mozilla
 
 #ifdef MOZ_DEFINED_HAL_NAMESPACE
 # undef MOZ_DEFINED_HAL_NAMESPACE
 # undef MOZ_HAL_NAMESPACE
 #endif
 
new file mode 100644
--- /dev/null
+++ b/hal/fallback/FallbackSystemService.cpp
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et ft=cpp : */
+/* 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 "Hal.h"
+
+namespace mozilla {
+namespace hal_impl {
+
+nsresult
+StartSystemService(const char* aSvcName, const char* aArgs)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+void
+StopSystemService(const char* aSvcName)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+}
+
+bool
+SystemServiceIsRunning(const char* aSvcName)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  return false;
+}
+
+} // namespace hal_impl
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/hal/gonk/SystemService.cpp
@@ -0,0 +1,131 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et ft=cpp : */
+/* 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 "Hal.h"
+
+#include <cutils/properties.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "HalLog.h"
+#include "nsITimer.h"
+#include "mozilla/unused.h"
+
+namespace mozilla {
+namespace hal_impl {
+
+static const int sRetryInterval = 100; // ms
+
+bool
+SystemServiceIsRunning(const char* aSvcName)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  char key[PROPERTY_KEY_MAX];
+  auto res = snprintf(key, sizeof(key), "init.svc.%s", aSvcName);
+
+  if (res < 0) {
+    HAL_ERR("snprintf: %s", strerror(errno));
+    return false;
+  } else if (static_cast<size_t>(res) >= sizeof(key)) {
+    HAL_ERR("snprintf: trunctated service name %s", aSvcName);
+    return false;
+  }
+
+  char value[PROPERTY_VALUE_MAX];
+  NS_WARN_IF(property_get(key, value, "") < 0);
+
+  return !strcmp(value, "running");
+}
+
+class StartSystemServiceTimerCallback final : public nsITimerCallback
+{
+  NS_DECL_THREADSAFE_ISUPPORTS;
+
+public:
+  StartSystemServiceTimerCallback(const char* aSvcName, const char* aArgs)
+    : mSvcName(aSvcName)
+    , mArgs(aArgs)
+  {
+    MOZ_COUNT_CTOR_INHERITED(StartSystemServiceTimerCallback,
+                             nsITimerCallback);
+  }
+
+  NS_IMETHOD Notify(nsITimer* aTimer) override
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    return StartSystemService(mSvcName.get(), mArgs.get());
+  }
+
+protected:
+  ~StartSystemServiceTimerCallback()
+  {
+    MOZ_COUNT_DTOR_INHERITED(StartSystemServiceTimerCallback,
+                             nsITimerCallback);
+  }
+
+private:
+  nsCString mSvcName;
+  nsCString mArgs;
+};
+
+NS_IMPL_ISUPPORTS0(StartSystemServiceTimerCallback);
+
+nsresult
+StartSystemService(const char* aSvcName, const char* aArgs)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  char value[PROPERTY_VALUE_MAX];
+  auto res = snprintf(value, sizeof(value), "%s:%s", aSvcName, aArgs);
+
+  if (res < 0) {
+    HAL_ERR("snprintf: %s", strerror(errno));
+    return NS_ERROR_FAILURE;
+  } else if (static_cast<size_t>(res) >= sizeof(value)) {
+    HAL_ERR("snprintf: trunctated service name %s", aSvcName);
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  if (NS_WARN_IF(property_set("ctl.start", value) < 0)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  /* If the system service is not running, re-try later to start it.
+   *
+   * This condition happens when we restart a service immediately
+   * after it crashed, as the service state remains 'stopping'
+   * instead of 'stopped'. Due to the limitation of property service,
+   * hereby add delay. See Bug 1143925 Comment 41.
+   */
+  if (!SystemServiceIsRunning(aSvcName)) {
+    nsCOMPtr<nsITimer> timer = do_CreateInstance("@mozilla.org/timer;1");
+    if (!timer) {
+      return NS_ERROR_FAILURE;
+    }
+
+    RefPtr<StartSystemServiceTimerCallback> timerCallback =
+      new StartSystemServiceTimerCallback(aSvcName, aArgs);
+
+    timer->InitWithCallback(timerCallback,
+                            sRetryInterval,
+                            nsITimer::TYPE_ONE_SHOT);
+  }
+
+  return NS_OK;
+}
+
+void
+StopSystemService(const char* aSvcName)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  Unused << NS_WARN_IF(property_set("ctl.stop", aSvcName));
+}
+
+} // namespace hal_impl
+} // namespace mozilla
--- a/hal/moz.build
+++ b/hal/moz.build
@@ -47,16 +47,17 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'andr
         'android/AndroidHal.cpp',
     ]
 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
     UNIFIED_SOURCES += [
         'gonk/GonkDiskSpaceWatcher.cpp',
         'gonk/GonkFMRadio.cpp',
         'gonk/GonkSensor.cpp',
         'gonk/GonkSwitch.cpp',
+        'gonk/SystemService.cpp',
         'gonk/UeventPoller.cpp',
         'linux/LinuxMemory.cpp',
         'linux/LinuxPower.cpp',
     ]
     # GonkHal.cpp cannot be built in unified mode because it relies on HalImpl.h.
     SOURCES += [
         'gonk/GonkHal.cpp',
     ]
@@ -131,16 +132,17 @@ else:
 if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk':
     UNIFIED_SOURCES += [
         'fallback/FallbackDiskSpaceWatcher.cpp',
         'fallback/FallbackFactoryReset.cpp',
         'fallback/FallbackFMRadio.cpp',
         'fallback/FallbackProcessPriority.cpp',
         'fallback/FallbackScreenPower.cpp',
         'fallback/FallbackSwitch.cpp',
+        'fallback/FallbackSystemService.cpp',
         'fallback/FallbackThreadPriority.cpp',
         'fallback/FallbackTime.cpp',
         'fallback/FallbackWakeLocks.cpp',
     ]
 
 # Fallbacks for backends implemented on Android only.
 if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'android':
     UNIFIED_SOURCES += [
--- a/hal/sandbox/SandboxHal.cpp
+++ b/hal/sandbox/SandboxHal.cpp
@@ -186,27 +186,27 @@ GetScreenBrightness()
 }
 
 void
 SetScreenBrightness(double aBrightness)
 {
   Hal()->SendSetScreenBrightness(aBrightness);
 }
 
-void 
+void
 AdjustSystemClock(int64_t aDeltaMilliseconds)
 {
   Hal()->SendAdjustSystemClock(aDeltaMilliseconds);
 }
 
 void
 SetTimezone(const nsCString& aTimezoneSpec)
 {
   Hal()->SendSetTimezone(nsCString(aTimezoneSpec));
-} 
+}
 
 nsCString
 GetTimezone()
 {
   nsCString timezone;
   Hal()->SendGetTimezone(&timezone);
   return timezone;
 }
@@ -461,16 +461,33 @@ StopDiskSpaceWatcher()
 }
 
 bool IsHeadphoneEventFromInputDev()
 {
   NS_RUNTIMEABORT("IsHeadphoneEventFromInputDev() cannot be called from sandboxed contexts.");
   return false;
 }
 
+nsresult StartSystemService(const char* aSvcName, const char* aArgs)
+{
+  NS_RUNTIMEABORT("System services cannot be controlled from sandboxed contexts.");
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+void StopSystemService(const char* aSvcName)
+{
+  NS_RUNTIMEABORT("System services cannot be controlled from sandboxed contexts.");
+}
+
+bool SystemServiceIsRunning(const char* aSvcName)
+{
+  NS_RUNTIMEABORT("System services cannot be controlled from sandboxed contexts.");
+  return false;
+}
+
 class HalParent : public PHalParent
                 , public BatteryObserver
                 , public NetworkObserver
                 , public ISensorObserver
                 , public WakeLockObserver
                 , public ScreenConfigurationObserver
                 , public SwitchObserver
                 , public SystemClockChangeObserver
@@ -698,24 +715,24 @@ public:
   {
     if (!AssertAppProcessPermission(this, "time")) {
       return false;
     }
     hal::AdjustSystemClock(aDeltaMilliseconds);
     return true;
   }
 
-  virtual bool 
+  virtual bool
   RecvSetTimezone(const nsCString& aTimezoneSpec) override
   {
     if (!AssertAppProcessPermission(this, "time")) {
       return false;
     }
     hal::SetTimezone(aTimezoneSpec);
-    return true;  
+    return true;
   }
 
   virtual bool
   RecvGetTimezone(nsCString *aTimezoneSpec) override
   {
     if (!AssertAppProcessPermission(this, "time")) {
       return false;
     }
@@ -763,23 +780,23 @@ public:
 
   virtual bool
   RecvEnableSensorNotifications(const SensorType &aSensor) override {
     // We currently allow any content to register device-sensor
     // listeners.
     hal::RegisterSensorObserver(aSensor, this);
     return true;
   }
-   
+
   virtual bool
   RecvDisableSensorNotifications(const SensorType &aSensor) override {
     hal::UnregisterSensorObserver(aSensor, this);
     return true;
   }
-  
+
   void Notify(const SensorData& aSensorData) override {
     Unused << SendNotifySensorChange(aSensorData);
   }
 
   virtual bool
   RecvModifyWakeLock(const nsString& aTopic,
                      const WakeLockControl& aLockAdjust,
                      const WakeLockControl& aHiddenAdjust,
@@ -794,31 +811,31 @@ public:
 
   virtual bool
   RecvEnableWakeLockNotifications() override
   {
     // We allow arbitrary content to use wake locks.
     hal::RegisterWakeLockObserver(this);
     return true;
   }
-   
+
   virtual bool
   RecvDisableWakeLockNotifications() override
   {
     hal::UnregisterWakeLockObserver(this);
     return true;
   }
 
   virtual bool
   RecvGetWakeLockInfo(const nsString &aTopic, WakeLockInformation *aWakeLockInfo) override
   {
     hal::GetWakeLockInfo(aTopic, aWakeLockInfo);
     return true;
   }
-  
+
   void Notify(const WakeLockInformation& aWakeLockInfo) override
   {
     Unused << SendNotifyWakeLockChange(aWakeLockInfo);
   }
 
   virtual bool
   RecvEnableSwitchNotifications(const SwitchDevice& aDevice) override
   {
@@ -946,17 +963,17 @@ public:
     hal::NotifySystemTimezoneChange(aSystemTimezoneChangeInfo);
     return true;
   }
 };
 
 bool
 HalChild::RecvNotifySensorChange(const hal::SensorData &aSensorData) {
   hal::NotifySensorChange(aSensorData);
-  
+
   return true;
 }
 
 PHalChild* CreateHalChild() {
   return new HalChild();
 }
 
 PHalParent* CreateHalParent() {