diff options
Diffstat (limited to 'hal/gonk/SystemService.cpp')
-rw-r--r-- | hal/gonk/SystemService.cpp | 131 |
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 |