},
srcs: [
"ISystemSuspend.hal",
- "ISystemSuspendCallback.hal",
"IWakeLock.hal",
],
interfaces: [
],
gen_java: false,
}
-
package android.system.suspend@1.0;
-import ISystemSuspendCallback;
import IWakeLock;
interface ISystemSuspend {
/**
- * Registers a callback for system suspend events. ISystemSuspend must keep
- * track of all registered callbacks unless the client process that
- * registered the callback dies.
- *
- * @param callback the callback to register.
- * @return status true on success, false otherwise.
- */
- registerCallback(ISystemSuspendCallback callback) generates (bool success);
-
- /**
- * Starts automatic system suspension.
- *
- * @return status true on success, false otherwise.
- */
- enableAutosuspend() generates (bool success);
-
- /**
* Acquires an IWakeLock instance. Any allocated IWakeLock must block the
* device from suspending. This method must be able to be called
* independently of enableAutosuspend().
name: "system_suspend_defaults",
shared_libs: [
"libbase",
+ "libbinder",
"libcutils",
"libhidlbase",
"libhidltransport",
],
init_rc: ["android.system.suspend@1.0-service.rc"],
vintf_fragments: ["android.system.suspend@1.0-service.xml"],
- shared_libs: ["android.system.suspend@1.0"],
+ shared_libs: [
+ "android.system.suspend@1.0",
+ "suspend_control_aidl_interface-cpp",
+ ],
static_libs: ["SystemSuspendStatsProto"],
srcs: [
- "SystemSuspend.cpp",
"main.cpp",
+ "SuspendControlService.cpp",
+ "SystemSuspend.cpp",
],
}
],
static_libs: [
"android.system.suspend@1.0",
+ "suspend_control_aidl_interface-cpp",
"libgmock",
],
srcs: [
+ "SuspendControlService.cpp",
"SystemSuspend.cpp",
"SystemSuspendUnitTest.cpp"
],
--- /dev/null
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SuspendControlService.h"
+
+#include "SystemSuspend.h"
+
+#include <android-base/logging.h>
+
+namespace android {
+namespace system {
+namespace suspend {
+namespace V1_0 {
+
+template <typename T>
+binder::Status retOk(const T& value, T* ret_val) {
+ *ret_val = value;
+ return binder::Status::ok();
+}
+
+void SuspendControlService::setSuspendService(const wp<SystemSuspend>& suspend) {
+ mSuspend = suspend;
+}
+
+binder::Status SuspendControlService::enableAutosuspend(bool* _aidl_return) {
+ const auto suspendService = mSuspend.promote();
+ return retOk(suspendService != nullptr && suspendService->enableAutosuspend(), _aidl_return);
+}
+
+binder::Status SuspendControlService::registerCallback(const sp<ISuspendCallback>& callback,
+ bool* _aidl_return) {
+ if (!callback) {
+ return retOk(false, _aidl_return);
+ }
+
+ auto l = std::lock_guard(mCallbackLock);
+ sp<IBinder> cb = IInterface::asBinder(callback);
+ // Only remote binders can be linked to death
+ if (cb->remoteBinder() != nullptr) {
+ if (findCb(cb) == mCallbacks.end()) {
+ auto status = cb->linkToDeath(this);
+ if (status != NO_ERROR) {
+ LOG(ERROR) << __func__ << " Cannot link to death: " << status;
+ return retOk(false, _aidl_return);
+ }
+ }
+ }
+ mCallbacks.push_back(callback);
+ return retOk(true, _aidl_return);
+}
+
+void SuspendControlService::binderDied(const wp<IBinder>& who) {
+ auto l = std::lock_guard(mCallbackLock);
+ mCallbacks.erase(findCb(who));
+}
+
+void SuspendControlService::notifyWakeup(bool success) {
+ // A callback could potentially modify mCallbacks (e.g., via registerCallback). That must not
+ // result in a deadlock. To that end, we make a copy of mCallbacks and release mCallbackLock
+ // before calling the copied callbacks.
+ auto callbackLock = std::unique_lock(mCallbackLock);
+ auto callbacksCopy = mCallbacks;
+ callbackLock.unlock();
+
+ for (const auto& callback : callbacksCopy) {
+ callback->notifyWakeup(success).isOk(); // ignore errors
+ }
+}
+
+} // namespace V1_0
+} // namespace suspend
+} // namespace system
+} // namespace android
--- /dev/null
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SYSTEM_SYSTEM_SUSPEND_CONTROL_SERVICE_H
+#define ANDROID_SYSTEM_SYSTEM_SUSPEND_CONTROL_SERVICE_H
+
+#include <android/system/suspend/BnSuspendControlService.h>
+
+using ::android::system::suspend::BnSuspendControlService;
+using ::android::system::suspend::ISuspendCallback;
+
+namespace android {
+namespace system {
+namespace suspend {
+namespace V1_0 {
+
+class SystemSuspend;
+
+class SuspendControlService : public BnSuspendControlService,
+ public virtual IBinder::DeathRecipient {
+ public:
+ SuspendControlService() = default;
+ ~SuspendControlService() override = default;
+
+ binder::Status enableAutosuspend(bool* _aidl_return) override;
+ binder::Status registerCallback(const sp<ISuspendCallback>& callback,
+ bool* _aidl_return) override;
+ void binderDied(const wp<IBinder>& who) override;
+
+ void setSuspendService(const wp<SystemSuspend>& suspend);
+ void notifyWakeup(bool success);
+
+ private:
+ wp<SystemSuspend> mSuspend;
+
+ std::mutex mCallbackLock;
+ std::vector<sp<ISuspendCallback> > mCallbacks;
+ std::vector<sp<ISuspendCallback> >::iterator findCb(const wp<IBinder>& cb) {
+ return std::find_if(
+ mCallbacks.begin(), mCallbacks.end(),
+ [&cb](const sp<ISuspendCallback> i) { return cb == IInterface::asBinder(i); });
+ }
+};
+
+} // namespace V1_0
+} // namespace suspend
+} // namespace system
+} // namespace android
+
+#endif // ANDROID_SYSTEM_SYSTEM_SUSPEND_CONTROL_SERVICE_H
using ::android::base::ReadFdToString;
using ::android::base::WriteStringToFd;
-using ::android::hardware::IPCThreadState;
using ::android::hardware::Void;
using ::std::string;
}
static inline int getCallingPid() {
- return IPCThreadState::self()->getCallingPid();
+ return ::android::hardware::IPCThreadState::self()->getCallingPid();
}
static inline WakeLockIdType getWakeLockId(int pid, const string& name) {
}
SystemSuspend::SystemSuspend(unique_fd wakeupCountFd, unique_fd stateFd, size_t maxStatsEntries,
- std::chrono::milliseconds baseSleepTime)
+ std::chrono::milliseconds baseSleepTime,
+ const sp<SuspendControlService>& controlService)
: mSuspendCounter(0),
mWakeupCountFd(std::move(wakeupCountFd)),
mStateFd(std::move(stateFd)),
mMaxStatsEntries(maxStatsEntries),
mBaseSleepTime(baseSleepTime),
- mSleepTime(baseSleepTime) {}
+ mSleepTime(baseSleepTime),
+ mControlService(controlService) {
+ mControlService->setSuspendService(this);
+}
-Return<bool> SystemSuspend::enableAutosuspend() {
+bool SystemSuspend::enableAutosuspend() {
static bool initialized = false;
if (initialized) {
LOG(ERROR) << "Autosuspend already started.";
return wl;
}
-Return<bool> SystemSuspend::registerCallback(const sp<ISystemSuspendCallback>& cb) {
- if (!cb) {
- return false;
- }
- auto l = std::lock_guard(mCallbackLock);
- if (findCb(cb) == mCallbacks.end()) {
- auto linkRet = cb->linkToDeath(this, 0 /* cookie */);
- if (!linkRet.withDefault(false)) {
- LOG(ERROR) << __func__ << "Cannot link to death: "
- << (linkRet.isOk() ? "linkToDeath returns false" : linkRet.description());
- return false;
- }
- mCallbacks.push_back(cb);
- }
- return true;
-}
-
-void SystemSuspend::serviceDied(uint64_t, const wp<IBase>& service) {
- auto l = std::lock_guard(mCallbackLock);
- mCallbacks.erase(findCb(service.promote()));
-}
-
Return<void> SystemSuspend::debug(const hidl_handle& handle,
const hidl_vec<hidl_string>& /* options */) {
if (handle == nullptr || handle->numFds < 1 || handle->data[0] < 0) {
PLOG(VERBOSE) << "error writing to /sys/power/state";
}
- // A callback could potentially modify mCallbacks (e.g. via registerCallback). That must
- // not result in a deadlock. To that end, we make a copy of mCallbacks and release
- // mCallbackLock before calling the copied callbacks.
- auto callbackLock = std::unique_lock(mCallbackLock);
- auto callbacksCopy = mCallbacks;
- callbackLock.unlock();
+ mControlService->notifyWakeup(success);
- for (const auto& callback : callbacksCopy) {
- callback->notifyWakeup(success).isOk(); // ignore errors
- }
updateSleepTime(success);
}
});
#ifndef ANDROID_SYSTEM_SYSTEM_SUSPEND_V1_0_H
#define ANDROID_SYSTEM_SYSTEM_SUSPEND_V1_0_H
+#include "SuspendControlService.h"
+
#include <android-base/unique_fd.h>
#include <android/system/suspend/1.0/ISystemSuspend.h>
-#include <android/system/suspend/1.0/ISystemSuspendCallback.h>
#include <hidl/HidlTransportSupport.h>
#include <system/hardware/interfaces/suspend/1.0/default/SystemSuspendStats.pb.h>
WakeLockIdType mId;
};
-class SystemSuspend : public ISystemSuspend, public hidl_death_recipient {
+class SystemSuspend : public ISystemSuspend {
public:
SystemSuspend(unique_fd wakeupCountFd, unique_fd stateFd, size_t maxStatsEntries,
- std::chrono::milliseconds baseSleepTime);
- Return<bool> enableAutosuspend() override;
+ std::chrono::milliseconds baseSleepTime,
+ const sp<SuspendControlService>& controlService);
Return<sp<IWakeLock>> acquireWakeLock(WakeLockType type, const hidl_string& name) override;
- Return<bool> registerCallback(const sp<ISystemSuspendCallback>& cb) override;
Return<void> debug(const hidl_handle& handle, const hidl_vec<hidl_string>& options) override;
- void serviceDied(uint64_t /* cookie */, const wp<IBase>& service);
void incSuspendCounter();
void decSuspendCounter();
void deleteWakeLockStatsEntry(WakeLockIdType id);
+ bool enableAutosuspend();
private:
void initAutosuspend();
std::map<TimestampType, WakeLockIdType> mLruWakeLockId;
SystemSuspendStats mStats;
- using CbType = sp<ISystemSuspendCallback>;
- std::mutex mCallbackLock;
- std::vector<CbType> mCallbacks;
- std::vector<CbType>::iterator findCb(const sp<IBase>& cb) {
- return std::find_if(mCallbacks.begin(), mCallbacks.end(),
- [&cb](const CbType& i) { return interfacesEqual(i, cb); });
- }
-
// Amount of sleep time between consecutive iterations of the suspend loop.
std::chrono::milliseconds mBaseSleepTime;
std::chrono::milliseconds mSleepTime;
// Updates sleep time depending on the result of suspend attempt.
void updateSleepTime(bool success);
+
+ sp<SuspendControlService> mControlService;
};
} // namespace V1_0
* limitations under the License.
*/
+#include "SuspendControlService.h"
#include "SystemSuspend.h"
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
+#include <android/system/suspend/BnSuspendCallback.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
#include <cutils/native_handle.h>
#include <gmock/gmock.h>
#include <google/protobuf/text_format.h>
using android::hardware::joinRpcThreadpool;
using android::hardware::Return;
using android::hardware::Void;
+using android::system::suspend::BnSuspendCallback;
+using android::system::suspend::ISuspendControlService;
using android::system::suspend::V1_0::getEpochTimeNow;
using android::system::suspend::V1_0::ISystemSuspend;
-using android::system::suspend::V1_0::ISystemSuspendCallback;
using android::system::suspend::V1_0::IWakeLock;
using android::system::suspend::V1_0::readFd;
+using android::system::suspend::V1_0::SuspendControlService;
using android::system::suspend::V1_0::SystemSuspend;
using android::system::suspend::V1_0::WakeLockType;
using namespace std::chrono_literals;
namespace android {
static constexpr char kServiceName[] = "TestService";
+static constexpr char kControlServiceName[] = "TestControlService";
static bool isReadBlocked(int fd) {
struct pollfd pfd {
void registerTestService() {
std::thread testService([this] {
configureRpcThreadpool(1, true /* callerWillJoin */);
+
+ sp<SuspendControlService> suspendControl = new SuspendControlService();
+ auto controlStatus = ::android::defaultServiceManager()->addService(
+ android::String16(kControlServiceName), suspendControl);
+ if (android::OK != controlStatus) {
+ LOG(FATAL) << "Unable to register service " << kControlServiceName << controlStatus;
+ }
+
+ // Create non-HW binder threadpool for SuspendControlService.
+ sp<android::ProcessState> ps{android::ProcessState::self()};
+ ps->startThreadPool();
+
sp<ISystemSuspend> suspend =
new SystemSuspend(std::move(wakeupCountFds[1]), std::move(stateFds[1]),
- 1 /* maxStatsEntries */, 0ms /* baseSleepTime */);
+ 1 /* maxStatsEntries */, 0ms /* baseSleepTime */, suspendControl);
status_t status = suspend->registerAsService(kServiceName);
if (android::OK != status) {
LOG(FATAL) << "Unable to register service: " << status;
}
+
joinRpcThreadpool();
});
testService.detach();
::android::hardware::details::waitForHwService(ISystemSuspend::descriptor, kServiceName);
sp<ISystemSuspend> suspendService = ISystemSuspend::getService(kServiceName);
ASSERT_NE(suspendService, nullptr) << "failed to get suspend service";
- ASSERT_EQ(suspendService->enableAutosuspend(), true) << "failed to start autosuspend";
+
+ sp<IBinder> control =
+ android::defaultServiceManager()->getService(android::String16(kControlServiceName));
+ ASSERT_NE(control, nullptr) << "failed to get the suspend control service";
+ sp<ISuspendControlService> controlService = interface_cast<ISuspendControlService>(control);
+
+ // Start auto-suspend.
+ bool enabled = false;
+ controlService->enableAutosuspend(&enabled);
+ ASSERT_EQ(enabled, true) << "failed to start autosuspend";
}
unique_fd wakeupCountFds[2];
suspendService = ISystemSuspend::getService(kServiceName);
ASSERT_NE(suspendService, nullptr) << "failed to get suspend service";
+ sp<IBinder> control =
+ android::defaultServiceManager()->getService(android::String16(kControlServiceName));
+ ASSERT_NE(control, nullptr) << "failed to get the suspend control service";
+ controlService = interface_cast<ISuspendControlService>(control);
+
auto* environment = SystemSuspendTestEnvironment::Instance();
wakeupCountFd = environment->wakeupCountFds[0];
stateFd = environment->stateFds[0];
}
sp<ISystemSuspend> suspendService;
+ sp<ISuspendControlService> controlService;
int stateFd;
int wakeupCountFd;
};
// Tests that autosuspend thread can only be enabled once.
TEST_F(SystemSuspendTest, OnlyOneEnableAutosuspend) {
- ASSERT_EQ(suspendService->enableAutosuspend(), false);
+ bool enabled = false;
+ controlService->enableAutosuspend(&enabled);
+ ASSERT_EQ(enabled, false);
}
TEST_F(SystemSuspendTest, AutosuspendLoop) {
// MockCallbackImpl can be destroyed independently of its wrapper MockCallback which is passed to
// SystemSuspend.
struct MockCallbackImpl {
- MOCK_METHOD1(notifyWakeup, Return<void>(bool));
+ MOCK_METHOD1(notifyWakeup, binder::Status(bool));
};
-class MockCallback : public ISystemSuspendCallback {
+class MockCallback : public BnSuspendCallback {
public:
MockCallback(MockCallbackImpl* impl) : mImpl(impl), mDisabled(false) {}
- Return<void> notifyWakeup(bool x) { return mDisabled ? Void() : mImpl->notifyWakeup(x); }
+ binder::Status notifyWakeup(bool x) {
+ return mDisabled ? binder::Status::ok() : mImpl->notifyWakeup(x);
+ }
// In case we pull the rug from under MockCallback, but SystemSuspend still has an sp<> to the
// object.
void disable() { mDisabled = true; }
// Tests that nullptr can't be registered as callbacks.
TEST_F(SystemSuspendTest, RegisterInvalidCallback) {
- ASSERT_FALSE(suspendService->registerCallback(nullptr));
+ bool retval = false;
+ controlService->registerCallback(nullptr, &retval);
+ ASSERT_FALSE(retval);
}
// Tests that SystemSuspend HAL correctly notifies wakeup events.
// finished by the time last notification completes.
EXPECT_CALL(impl, notifyWakeup).Times(testing::AtLeast(numWakeups));
sp<MockCallback> cb = new MockCallback(&impl);
- ASSERT_TRUE(suspendService->registerCallback(cb));
+ bool retval = false;
+ controlService->registerCallback(cb, &retval);
+ ASSERT_TRUE(retval);
checkLoop(numWakeups + 1);
cb->disable();
}
ASSERT_EXIT(
{
sp<MockCallback> cb = new MockCallback(nullptr);
- ASSERT_TRUE(suspendService->registerCallback(cb));
+ bool retval = false;
+ controlService->registerCallback(cb, &retval);
+ ASSERT_TRUE(retval);
std::exit(0);
},
::testing::ExitedWithCode(0), "");
}
// Callback that registers another callback.
-class CbRegisteringCb : public ISystemSuspendCallback {
+class CbRegisteringCb : public BnSuspendCallback {
public:
- CbRegisteringCb(sp<ISystemSuspend> suspendService) : mSuspendService(suspendService) {}
- Return<void> notifyWakeup(bool x) {
+ CbRegisteringCb(sp<ISuspendControlService> controlService) : mControlService(controlService) {}
+ binder::Status notifyWakeup(bool x) {
sp<MockCallback> cb = new MockCallback(nullptr);
cb->disable();
- mSuspendService->registerCallback(cb);
- return Void();
+ bool retval = false;
+ mControlService->registerCallback(cb, &retval);
+ return binder::Status::ok();
}
private:
- sp<ISystemSuspend> mSuspendService;
+ sp<ISuspendControlService> mControlService;
};
// Tests that callback registering another callback doesn't result in a deadlock.
TEST_F(SystemSuspendTest, CallbackRegisterCallbackNoDeadlock) {
- sp<CbRegisteringCb> cb = new CbRegisteringCb(suspendService);
- ASSERT_TRUE(suspendService->registerCallback(cb));
+ sp<CbRegisteringCb> cb = new CbRegisteringCb(controlService);
+ bool retval = false;
+ controlService->registerCallback(cb, &retval);
+ ASSERT_TRUE(retval);
checkLoop(3);
}
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SuspendControlService.h"
#include "SystemSuspend.h"
#include <android-base/logging.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
#include <cutils/native_handle.h>
#include <hidl/HidlTransportSupport.h>
+#include <hwbinder/ProcessState.h>
#include <sys/socket.h>
#include <sys/stat.h>
using android::hardware::configureRpcThreadpool;
using android::hardware::joinRpcThreadpool;
using android::system::suspend::V1_0::ISystemSuspend;
+using android::system::suspend::V1_0::SuspendControlService;
using android::system::suspend::V1_0::SystemSuspend;
using namespace std::chrono_literals;
}
configureRpcThreadpool(1, true /* callerWillJoin */);
- sp<ISystemSuspend> suspend =
+
+ sp<SuspendControlService> suspendControl = new SuspendControlService();
+ auto controlStatus = android::defaultServiceManager()->addService(
+ android::String16("suspend_control"), suspendControl);
+ if (controlStatus != android::OK) {
+ LOG(FATAL) << "Unable to register suspend_control service: " << controlStatus;
+ }
+
+ // Create non-HW binder threadpool for SuspendControlService.
+ sp<android::ProcessState> ps{android::ProcessState::self()};
+ ps->startThreadPool();
+
+ sp<SystemSuspend> suspend =
new SystemSuspend(std::move(wakeupCountFd), std::move(stateFd), 100 /* maxStatsEntries */,
- 100ms /* baseSleepTime */);
+ 100ms /* baseSleepTime */, suspendControl);
status_t status = suspend->registerAsService();
if (android::OK != status) {
- LOG(FATAL) << "Unable to register service: " << status;
+ LOG(FATAL) << "Unable to register system-suspend service: " << status;
}
+
joinRpcThreadpool();
std::abort(); /* unreachable */
}
--- /dev/null
+aidl_interface {
+ name: "suspend_control_aidl_interface",
+ local_include_dir: ".",
+ srcs: [
+ "android/system/suspend/ISuspendControlService.aidl",
+ "android/system/suspend/ISuspendCallback.aidl",
+ ],
+}
+
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* limitations under the License.
*/
-package android.system.suspend@1.0;
+package android.system.suspend;
-interface ISystemSuspendCallback {
+/**
+ * Callback interface for monitoring system-suspend events.
+ * @hide
+ */
+interface ISuspendCallback
+{
/**
- * An implementation of ISystemSuspend must call notifyWakeup after every
- * system wakeup.
+ * An implementation of ISuspendControlService must call notifyWakeup after every system wakeup.
*
* @param success whether previous system suspend attempt was successful.
*/
- notifyWakeup(bool success);
-};
+ void notifyWakeup(boolean success);
+}
--- /dev/null
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.system.suspend;
+
+import android.system.suspend.ISuspendCallback;
+
+/**
+ * Interface exposed by the suspend hal that allows framework to toggle the suspend loop and
+ * monitor native wakelocks.
+ * @hide
+ */
+interface ISuspendControlService
+{
+ /**
+ * Starts automatic system suspendion.
+ *
+ * @return true on success, false otherwise.
+ */
+ boolean enableAutosuspend();
+
+ /**
+ * Registers a callback for suspend events. ISuspendControlService must keep track of all
+ * registered callbacks unless the client process that registered the callback dies.
+ *
+ * @param callback the callback to register.
+ * @return true on success, false otherwise.
+ */
+ boolean registerCallback(ISuspendCallback callback);
+}