summaryrefslogtreecommitdiffstats
path: root/hal/gonk/SystemService.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'hal/gonk/SystemService.cpp')
-rw-r--r--hal/gonk/SystemService.cpp131
1 files changed, 131 insertions, 0 deletions
diff --git a/hal/gonk/SystemService.cpp b/hal/gonk/SystemService.cpp
new file mode 100644
index 000000000..2b98f5fdd
--- /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];
+ Unused << 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