OSDN Git Service

Migrating suspend functionality to SuspendControlService
authorSantos Cordon <santoscordon@google.com>
Wed, 9 Jan 2019 16:48:25 +0000 (16:48 +0000)
committerSantos Cordon <santoscordon@google.com>
Tue, 5 Feb 2019 11:39:59 +0000 (11:39 +0000)
Move most API methods (other than acquireWakeLock) from SystemSuspend to
SuspendControlService for interactions that happend solely between
suspend HAL and the system server. This allows us to tighten security
SEPolicy around methods that only system-server should be using.

Bug: 121210355
Test: SystemSuspendV1_0UnitTest
Change-Id: Ia92c42ecf069d606916854430e81f2e232d788c7

12 files changed:
suspend/1.0/Android.bp
suspend/1.0/ISystemSuspend.hal
suspend/1.0/default/Android.bp
suspend/1.0/default/SuspendControlService.cpp [new file with mode: 0644]
suspend/1.0/default/SuspendControlService.h [new file with mode: 0644]
suspend/1.0/default/SystemSuspend.cpp
suspend/1.0/default/SystemSuspend.h
suspend/1.0/default/SystemSuspendUnitTest.cpp
suspend/1.0/default/main.cpp
suspend/aidl/Android.bp [new file with mode: 0644]
suspend/aidl/android/system/suspend/ISuspendCallback.aidl [moved from suspend/1.0/ISystemSuspendCallback.hal with 66% similarity]
suspend/aidl/android/system/suspend/ISuspendControlService.aidl [new file with mode: 0644]

index cdf4435..9dfaa68 100644 (file)
@@ -6,7 +6,6 @@ hidl_interface {
     },
     srcs: [
         "ISystemSuspend.hal",
-        "ISystemSuspendCallback.hal",
         "IWakeLock.hal",
     ],
     interfaces: [
@@ -14,4 +13,3 @@ hidl_interface {
     ],
     gen_java: false,
 }
-
index 6c24c64..949f205 100644 (file)
 
 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().
index 86d25b8..0453f8a 100644 (file)
@@ -16,6 +16,7 @@ cc_defaults {
     name: "system_suspend_defaults",
     shared_libs: [
         "libbase",
+        "libbinder",
         "libcutils",
         "libhidlbase",
         "libhidltransport",
@@ -68,11 +69,15 @@ cc_binary {
     ],
     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",
     ],
 }
 
@@ -86,9 +91,11 @@ cc_test {
     ],
     static_libs: [
         "android.system.suspend@1.0",
+        "suspend_control_aidl_interface-cpp",
         "libgmock",
     ],
     srcs: [
+        "SuspendControlService.cpp",
         "SystemSuspend.cpp",
         "SystemSuspendUnitTest.cpp"
     ],
diff --git a/suspend/1.0/default/SuspendControlService.cpp b/suspend/1.0/default/SuspendControlService.cpp
new file mode 100644 (file)
index 0000000..7601f17
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * 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
diff --git a/suspend/1.0/default/SuspendControlService.h b/suspend/1.0/default/SuspendControlService.h
new file mode 100644 (file)
index 0000000..454ad4c
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * 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
index d0f5944..1cbce94 100644 (file)
@@ -33,7 +33,6 @@
 
 using ::android::base::ReadFdToString;
 using ::android::base::WriteStringToFd;
-using ::android::hardware::IPCThreadState;
 using ::android::hardware::Void;
 using ::std::string;
 
@@ -55,7 +54,7 @@ string readFd(int fd) {
 }
 
 static inline int getCallingPid() {
-    return IPCThreadState::self()->getCallingPid();
+    return ::android::hardware::IPCThreadState::self()->getCallingPid();
 }
 
 static inline WakeLockIdType getWakeLockId(int pid, const string& name) {
@@ -90,15 +89,19 @@ void WakeLock::releaseOnce() {
 }
 
 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.";
@@ -138,28 +141,6 @@ Return<sp<IWakeLock>> SystemSuspend::acquireWakeLock(WakeLockType /* type */,
     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) {
@@ -231,16 +212,8 @@ void SystemSuspend::initAutosuspend() {
                 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);
         }
     });
index 9817b97..313b234 100644 (file)
 #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>
 
@@ -65,18 +66,17 @@ class WakeLock : public IWakeLock {
     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();
@@ -99,19 +99,13 @@ class SystemSuspend : public ISystemSuspend, public hidl_death_recipient {
     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
index 90c0266..c5e07cd 100644 (file)
  * 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>
@@ -44,11 +49,13 @@ using android::hardware::configureRpcThreadpool;
 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;
@@ -56,6 +63,7 @@ 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 {
@@ -81,13 +89,26 @@ class SystemSuspendTestEnvironment : public ::testing::Environment {
     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();
@@ -98,7 +119,16 @@ class SystemSuspendTestEnvironment : public ::testing::Environment {
         ::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];
@@ -112,6 +142,11 @@ class SystemSuspendTest : public ::testing::Test {
         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];
@@ -175,13 +210,16 @@ class SystemSuspendTest : public ::testing::Test {
     }
 
     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) {
@@ -319,13 +357,15 @@ TEST_F(SystemSuspendTest, WakeLockStressTest) {
 // 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; }
@@ -337,7 +377,9 @@ class MockCallback : public ISystemSuspendCallback {
 
 // 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.
@@ -349,7 +391,9 @@ TEST_F(SystemSuspendTest, CallbackNotifyWakeup) {
     // 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();
 }
@@ -359,7 +403,9 @@ TEST_F(SystemSuspendTest, DeadCallback) {
     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), "");
@@ -370,24 +416,27 @@ TEST_F(SystemSuspendTest, DeadCallback) {
 }
 
 // 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);
 }
 
index 3070e42..e37c576 100644 (file)
@@ -1,8 +1,29 @@
+/*
+ * 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>
@@ -18,6 +39,7 @@ using android::base::unique_fd;
 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;
 
@@ -45,13 +67,26 @@ int main() {
     }
 
     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 */
 }
diff --git a/suspend/aidl/Android.bp b/suspend/aidl/Android.bp
new file mode 100644 (file)
index 0000000..2917bfc
--- /dev/null
@@ -0,0 +1,9 @@
+aidl_interface {
+    name: "suspend_control_aidl_interface",
+    local_include_dir: ".",
+    srcs: [
+        "android/system/suspend/ISuspendControlService.aidl",
+        "android/system/suspend/ISuspendCallback.aidl",
+    ],
+}
+
@@ -1,5 +1,5 @@
 /*
- * 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);
+}
diff --git a/suspend/aidl/android/system/suspend/ISuspendControlService.aidl b/suspend/aidl/android/system/suspend/ISuspendControlService.aidl
new file mode 100644 (file)
index 0000000..cf64153
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * 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);
+}