• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
No Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

system/hardware/interfaces


Commit MetaInfo

Revisionec036db0798299bd6bf9d38dfaf48d0736ce0f50 (tree)
Time2018-08-17 12:30:43
AuthorTri Vo <trong@goog...>
Commiterandroid-build-merger

Log Message

System suspend HAL implementation. am: 180813bea6
am: b5cfa06fbd

Change-Id: Id33e2dde5ac8b482c04608434f83f592033e3ad6

Change Summary

Incremental Difference

--- /dev/null
+++ b/suspend/1.0/default/Android.bp
@@ -0,0 +1,59 @@
1+// Copyright (C) 2018 The Android Open Source Project
2+//
3+// Licensed under the Apache License, Version 2.0 (the "License");
4+// you may not use this file except in compliance with the License.
5+// You may obtain a copy of the License at
6+//
7+// http://www.apache.org/licenses/LICENSE-2.0
8+//
9+// Unless required by applicable law or agreed to in writing, software
10+// distributed under the License is distributed on an "AS IS" BASIS,
11+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+// See the License for the specific language governing permissions and
13+// limitations under the License.
14+
15+cc_defaults {
16+ name: "system_suspend_defaults",
17+ shared_libs: [
18+ "libbase",
19+ "libcutils",
20+ "libhidlbase",
21+ "libhidltransport",
22+ "libhwbinder",
23+ "liblog",
24+ "libutils",
25+ ],
26+ cflags: [
27+ "-Wall",
28+ "-Werror",
29+ ],
30+ cpp_std: "c++17",
31+}
32+
33+cc_binary {
34+ name: "android.system.suspend@1.0-service",
35+ relative_install_path: "hw",
36+ defaults: [
37+ "system_suspend_defaults",
38+ ],
39+ init_rc: ["android.system.suspend@1.0-service.rc"],
40+ vintf_fragments: ["android.system.suspend@1.0-service.xml"],
41+ shared_libs: ["android.system.suspend@1.0"],
42+ srcs: [
43+ "SystemSuspend.cpp",
44+ "main.cpp",
45+ ],
46+}
47+
48+// Unit tests for ISystemSuspend implementation.
49+// Do *NOT* use for compliance with *TS.
50+cc_test {
51+ name: "SystemSuspendV1_0UnitTest",
52+ defaults: ["system_suspend_defaults"],
53+ static_libs: ["android.system.suspend@1.0"],
54+ srcs: [
55+ "SystemSuspend.cpp",
56+ "SystemSuspendUnitTest.cpp"
57+ ],
58+}
59+
--- /dev/null
+++ b/suspend/1.0/default/SystemSuspend.cpp
@@ -0,0 +1,140 @@
1+/*
2+ * Copyright 2018 The Android Open Source Project
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * http://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ */
16+
17+#include "SystemSuspend.h"
18+
19+#include <android-base/file.h>
20+#include <android-base/logging.h>
21+#include <android-base/strings.h>
22+#include <hidl/Status.h>
23+
24+#include <sys/stat.h>
25+#include <sys/types.h>
26+
27+#include <fcntl.h>
28+#include <string>
29+#include <thread>
30+
31+using ::android::base::ReadFdToString;
32+using ::android::base::WriteStringToFd;
33+using ::android::hardware::Void;
34+using ::std::string;
35+
36+namespace android {
37+namespace system {
38+namespace suspend {
39+namespace V1_0 {
40+
41+static const char kSleepState[] = "mem";
42+
43+// This function assumes that data in fd is small enough that it can be read in one go.
44+// We use this function instead of the ones available in libbase because it doesn't block
45+// indefinitely when reading from socket streams which are used for testing.
46+string readFd(int fd) {
47+ char buf[BUFSIZ];
48+ ssize_t n = TEMP_FAILURE_RETRY(read(fd, &buf[0], sizeof(buf)));
49+ if (n < 0) return "";
50+ return string{buf, static_cast<size_t>(n)};
51+}
52+
53+WakeLock::WakeLock(SystemSuspend* systemSuspend) : mSystemSuspend(systemSuspend) {
54+ mSystemSuspend->incSuspendCounter();
55+}
56+
57+WakeLock::~WakeLock() {
58+ mSystemSuspend->decSuspendCounter();
59+}
60+
61+SystemSuspend::SystemSuspend(unique_fd wakeupCountFd, unique_fd stateFd)
62+ : mCounterLock(),
63+ mCounterCondVar(),
64+ mSuspendCounter(0),
65+ mWakeupCountFd(std::move(wakeupCountFd)),
66+ mStateFd(std::move(stateFd)) {}
67+
68+Return<bool> SystemSuspend::enableAutosuspend() {
69+ static bool initialized = false;
70+ if (initialized) {
71+ LOG(ERROR) << "Autosuspend already started.";
72+ return false;
73+ }
74+
75+ initAutosuspend();
76+ initialized = true;
77+ return true;
78+}
79+
80+Return<sp<IWakeLock>> SystemSuspend::acquireWakeLock() {
81+ return new WakeLock{this};
82+}
83+
84+Return<void> SystemSuspend::debug(const hidl_handle& handle,
85+ const hidl_vec<hidl_string>& /* options */) {
86+ if (handle == nullptr || handle->numFds < 1 || handle->data[0] < 0) {
87+ LOG(ERROR) << "no valid fd";
88+ return Void();
89+ }
90+ int fd = handle->data[0];
91+ WriteStringToFd(std::to_string(mSuspendCounter) + "\n", fd);
92+ fsync(fd);
93+ return Void();
94+}
95+
96+void SystemSuspend::incSuspendCounter() {
97+ auto l = std::lock_guard(mCounterLock);
98+ mSuspendCounter++;
99+}
100+
101+void SystemSuspend::decSuspendCounter() {
102+ auto l = std::lock_guard(mCounterLock);
103+ if (--mSuspendCounter == 0) {
104+ mCounterCondVar.notify_one();
105+ }
106+}
107+
108+void SystemSuspend::initAutosuspend() {
109+ std::thread autosuspendThread([this] {
110+ while (true) {
111+ lseek(mWakeupCountFd, 0, SEEK_SET);
112+ const string wakeupCount = readFd(mWakeupCountFd);
113+ if (wakeupCount.empty()) {
114+ PLOG(ERROR) << "error reading from /sys/power/wakeup_count";
115+ continue;
116+ }
117+
118+ auto l = std::unique_lock(mCounterLock);
119+ mCounterCondVar.wait(l, [this] { return mSuspendCounter == 0; });
120+ // The mutex is locked and *MUST* remain locked until the end of the scope. Otherwise,
121+ // a WakeLock might be acquired after we check mSuspendCounter and before we write to
122+ // /sys/power/state.
123+
124+ if (!WriteStringToFd(wakeupCount, mWakeupCountFd)) {
125+ PLOG(VERBOSE) << "error writing from /sys/power/wakeup_count";
126+ continue;
127+ }
128+ if (!WriteStringToFd(kSleepState, mStateFd)) {
129+ PLOG(VERBOSE) << "error writing to /sys/power/state";
130+ }
131+ }
132+ });
133+ autosuspendThread.detach();
134+ LOG(INFO) << "automatic system suspend enabled";
135+}
136+
137+} // namespace V1_0
138+} // namespace suspend
139+} // namespace system
140+} // namespace android
--- /dev/null
+++ b/suspend/1.0/default/SystemSuspend.h
@@ -0,0 +1,75 @@
1+/*
2+ * Copyright 2018 The Android Open Source Project
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * http://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ */
16+
17+#ifndef ANDROID_SYSTEM_SYSTEM_SUSPEND_V1_0_H
18+#define ANDROID_SYSTEM_SYSTEM_SUSPEND_V1_0_H
19+
20+#include <android-base/unique_fd.h>
21+#include <android/system/suspend/1.0/ISystemSuspend.h>
22+
23+#include <condition_variable>
24+#include <mutex>
25+#include <string>
26+
27+namespace android {
28+namespace system {
29+namespace suspend {
30+namespace V1_0 {
31+
32+using ::android::base::unique_fd;
33+using ::android::hardware::hidl_handle;
34+using ::android::hardware::hidl_string;
35+using ::android::hardware::hidl_vec;
36+using ::android::hardware::Return;
37+
38+class SystemSuspend;
39+
40+std::string readFd(int fd);
41+
42+class WakeLock : public IWakeLock {
43+ public:
44+ WakeLock(SystemSuspend* systemSuspend);
45+ ~WakeLock();
46+
47+ private:
48+ SystemSuspend* mSystemSuspend;
49+};
50+
51+class SystemSuspend : public ISystemSuspend {
52+ public:
53+ SystemSuspend(unique_fd wakeupCountFd, unique_fd stateFd);
54+ Return<bool> enableAutosuspend() override;
55+ Return<sp<IWakeLock>> acquireWakeLock() override;
56+ Return<void> debug(const hidl_handle& handle, const hidl_vec<hidl_string>& options) override;
57+ void incSuspendCounter();
58+ void decSuspendCounter();
59+
60+ private:
61+ void initAutosuspend();
62+
63+ std::mutex mCounterLock;
64+ std::condition_variable mCounterCondVar;
65+ uint32_t mSuspendCounter;
66+ unique_fd mWakeupCountFd;
67+ unique_fd mStateFd;
68+};
69+
70+} // namespace V1_0
71+} // namespace suspend
72+} // namespace system
73+} // namespace android
74+
75+#endif // ANDROID_SYSTEM_SYSTEM_SUSPEND_V1_0_H
--- /dev/null
+++ b/suspend/1.0/default/SystemSuspendUnitTest.cpp
@@ -0,0 +1,214 @@
1+/*
2+ * Copyright 2018 The Android Open Source Project
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * http://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ */
16+
17+#include "SystemSuspend.h"
18+
19+#include <android-base/file.h>
20+#include <android-base/logging.h>
21+#include <android-base/unique_fd.h>
22+#include <cutils/native_handle.h>
23+#include <gtest/gtest.h>
24+#include <hidl/HidlTransportSupport.h>
25+
26+#include <sys/poll.h>
27+#include <sys/socket.h>
28+#include <sys/types.h>
29+
30+#include <chrono>
31+#include <csignal>
32+#include <cstdlib>
33+#include <future>
34+#include <string>
35+#include <thread>
36+
37+using android::sp;
38+using android::base::Socketpair;
39+using android::base::unique_fd;
40+using android::base::WriteStringToFd;
41+using android::hardware::configureRpcThreadpool;
42+using android::hardware::joinRpcThreadpool;
43+using android::hardware::Return;
44+using android::hardware::Void;
45+using android::system::suspend::V1_0::ISystemSuspend;
46+using android::system::suspend::V1_0::IWakeLock;
47+using android::system::suspend::V1_0::readFd;
48+using android::system::suspend::V1_0::SystemSuspend;
49+
50+namespace android {
51+
52+static constexpr char kServiceName[] = "TestService";
53+
54+static bool isReadBlocked(int fd) {
55+ struct pollfd pfd {
56+ .fd = fd, .events = POLLIN,
57+ };
58+ int timeout_ms = 20;
59+ return poll(&pfd, 1, timeout_ms) == 0;
60+}
61+
62+class SystemSuspendTestEnvironment : public ::testing::Environment {
63+ public:
64+ using Env = SystemSuspendTestEnvironment;
65+ static Env* Instance() {
66+ static Env* instance = new Env{};
67+ return instance;
68+ }
69+
70+ SystemSuspendTestEnvironment() {
71+ Socketpair(SOCK_STREAM, &wakeupCountFds[0], &wakeupCountFds[1]);
72+ Socketpair(SOCK_STREAM, &stateFds[0], &stateFds[1]);
73+ }
74+
75+ void registerTestService() {
76+ std::thread testService([this] {
77+ configureRpcThreadpool(1, true /* callerWillJoin */);
78+ sp<ISystemSuspend> suspend =
79+ new SystemSuspend(std::move(wakeupCountFds[1]), std::move(stateFds[1]));
80+ status_t status = suspend->registerAsService(kServiceName);
81+ if (android::OK != status) {
82+ LOG(FATAL) << "Unable to register service: " << status;
83+ }
84+ joinRpcThreadpool();
85+ });
86+ testService.detach();
87+ }
88+
89+ virtual void SetUp() {
90+ registerTestService();
91+ ::android::hardware::details::waitForHwService(ISystemSuspend::descriptor, kServiceName);
92+ sp<ISystemSuspend> suspendService = ISystemSuspend::getService(kServiceName);
93+ ASSERT_NE(suspendService, nullptr) << "failed to get suspend service";
94+ ASSERT_EQ(suspendService->enableAutosuspend(), true) << "failed to start autosuspend";
95+ }
96+
97+ unique_fd wakeupCountFds[2];
98+ unique_fd stateFds[2];
99+};
100+
101+class SystemSuspendTest : public ::testing::Test {
102+ public:
103+ virtual void SetUp() override {
104+ ::android::hardware::details::waitForHwService(ISystemSuspend::descriptor, kServiceName);
105+ suspendService = ISystemSuspend::getService(kServiceName);
106+ ASSERT_NE(suspendService, nullptr) << "failed to get suspend service";
107+
108+ auto* environment = SystemSuspendTestEnvironment::Instance();
109+ wakeupCountFd = environment->wakeupCountFds[0];
110+ stateFd = environment->stateFds[0];
111+
112+ // SystemSuspend HAL should not have written back to wakeupCountFd or stateFd yet.
113+ ASSERT_TRUE(isReadBlocked(wakeupCountFd));
114+ ASSERT_TRUE(isReadBlocked(stateFd));
115+ }
116+
117+ virtual void TearDown() override {
118+ if (!isReadBlocked(wakeupCountFd)) readFd(wakeupCountFd);
119+ if (!isReadBlocked(stateFd)) readFd(stateFd).empty();
120+ ASSERT_TRUE(isReadBlocked(wakeupCountFd));
121+ ASSERT_TRUE(isReadBlocked(stateFd));
122+ }
123+
124+ void unblockSystemSuspendFromWakeupCount() {
125+ std::string wakeupCount = std::to_string(rand());
126+ ASSERT_TRUE(WriteStringToFd(wakeupCount, wakeupCountFd));
127+ }
128+
129+ bool isSystemSuspendBlocked() { return isReadBlocked(stateFd); }
130+
131+ sp<ISystemSuspend> suspendService;
132+ int stateFd;
133+ int wakeupCountFd;
134+};
135+
136+// Tests that autosuspend thread can only be enabled once.
137+TEST_F(SystemSuspendTest, OnlyOneEnableAutosuspend) {
138+ ASSERT_EQ(suspendService->enableAutosuspend(), false);
139+}
140+
141+TEST_F(SystemSuspendTest, AutosuspendLoop) {
142+ for (int i = 0; i < 2; i++) {
143+ // Mock value for /sys/power/wakeup_count.
144+ std::string wakeupCount = std::to_string(rand());
145+ ASSERT_TRUE(WriteStringToFd(wakeupCount, wakeupCountFd));
146+ ASSERT_EQ(readFd(wakeupCountFd), wakeupCount)
147+ << "wakeup count value written by SystemSuspend is not equal to value given to it";
148+ ASSERT_EQ(readFd(stateFd), "mem") << "SystemSuspend failed to write correct sleep state.";
149+ }
150+}
151+
152+// Tests that upon WakeLock destruction SystemSuspend HAL is unblocked.
153+TEST_F(SystemSuspendTest, WakeLockDestructor) {
154+ {
155+ sp<IWakeLock> wl = suspendService->acquireWakeLock();
156+ ASSERT_NE(wl, nullptr);
157+ unblockSystemSuspendFromWakeupCount();
158+ ASSERT_TRUE(isSystemSuspendBlocked());
159+ }
160+ ASSERT_FALSE(isSystemSuspendBlocked());
161+}
162+
163+// Tests that multiple WakeLocks correctly block SystemSuspend HAL.
164+TEST_F(SystemSuspendTest, MultipleWakeLocks) {
165+ {
166+ sp<IWakeLock> wl1 = suspendService->acquireWakeLock();
167+ ASSERT_NE(wl1, nullptr);
168+ ASSERT_TRUE(isSystemSuspendBlocked());
169+ unblockSystemSuspendFromWakeupCount();
170+ {
171+ sp<IWakeLock> wl2 = suspendService->acquireWakeLock();
172+ ASSERT_NE(wl2, nullptr);
173+ ASSERT_TRUE(isSystemSuspendBlocked());
174+ }
175+ ASSERT_TRUE(isSystemSuspendBlocked());
176+ }
177+ ASSERT_FALSE(isSystemSuspendBlocked());
178+}
179+
180+// Tests that upon thread deallocation WakeLock is destructed and SystemSuspend HAL is unblocked.
181+TEST_F(SystemSuspendTest, ThreadCleanup) {
182+ std::thread clientThread([this] {
183+ sp<IWakeLock> wl = suspendService->acquireWakeLock();
184+ ASSERT_NE(wl, nullptr);
185+ unblockSystemSuspendFromWakeupCount();
186+ ASSERT_TRUE(isSystemSuspendBlocked());
187+ });
188+ clientThread.join();
189+ ASSERT_FALSE(isSystemSuspendBlocked());
190+}
191+
192+// Test that binder driver correctly deallocates acquired WakeLocks, even if the client processs
193+// is terminated without ability to do clean up.
194+TEST_F(SystemSuspendTest, CleanupOnAbort) {
195+ ASSERT_EXIT(
196+ {
197+ sp<IWakeLock> wl = suspendService->acquireWakeLock();
198+ ASSERT_NE(wl, nullptr);
199+ std::abort();
200+ },
201+ ::testing::KilledBySignal(SIGABRT), "");
202+ ASSERT_TRUE(isSystemSuspendBlocked());
203+ unblockSystemSuspendFromWakeupCount();
204+ ASSERT_FALSE(isSystemSuspendBlocked());
205+}
206+
207+} // namespace android
208+
209+int main(int argc, char** argv) {
210+ setenv("TREBLE_TESTING_OVERRIDE", "true", true);
211+ ::testing::AddGlobalTestEnvironment(android::SystemSuspendTestEnvironment::Instance());
212+ ::testing::InitGoogleTest(&argc, argv);
213+ return RUN_ALL_TESTS();
214+}
--- /dev/null
+++ b/suspend/1.0/default/android.system.suspend@1.0-service.rc
@@ -0,0 +1,4 @@
1+service system_suspend /system/bin/hw/android.system.suspend@1.0-service
2+ class hal
3+ user system
4+ group system
--- /dev/null
+++ b/suspend/1.0/default/android.system.suspend@1.0-service.xml
@@ -0,0 +1,11 @@
1+<manifest version="1.0" type="framework">
2+ <hal>
3+ <name>android.system.suspend</name>
4+ <transport>hwbinder</transport>
5+ <version>1.0</version>
6+ <interface>
7+ <name>ISystemSuspend</name>
8+ <instance>default</instance>
9+ </interface>
10+ </hal>
11+</manifest>
--- /dev/null
+++ b/suspend/1.0/default/main.cpp
@@ -0,0 +1,44 @@
1+#include "SystemSuspend.h"
2+
3+#include <android-base/logging.h>
4+#include <cutils/native_handle.h>
5+#include <hidl/HidlTransportSupport.h>
6+
7+#include <sys/stat.h>
8+#include <sys/types.h>
9+
10+#include <fcntl.h>
11+#include <unistd.h>
12+
13+using android::sp;
14+using android::status_t;
15+using android::base::unique_fd;
16+using android::hardware::configureRpcThreadpool;
17+using android::hardware::joinRpcThreadpool;
18+using android::system::suspend::V1_0::ISystemSuspend;
19+using android::system::suspend::V1_0::SystemSuspend;
20+
21+static constexpr char kSysPowerWakeupCount[] = "/sys/power/wakeup_count";
22+static constexpr char kSysPowerState[] = "/sys/power/state";
23+
24+int main() {
25+ unique_fd wakeupCountFd{TEMP_FAILURE_RETRY(open(kSysPowerWakeupCount, O_CLOEXEC | O_RDWR))};
26+ if (wakeupCountFd < 0) {
27+ PLOG(ERROR) << "error opening " << kSysPowerWakeupCount;
28+ return 1;
29+ }
30+ unique_fd stateFd{TEMP_FAILURE_RETRY(open(kSysPowerState, O_CLOEXEC | O_RDWR))};
31+ if (stateFd < 0) {
32+ PLOG(ERROR) << "error opening " << kSysPowerState;
33+ return 1;
34+ }
35+
36+ configureRpcThreadpool(1, true /* callerWillJoin */);
37+ sp<ISystemSuspend> suspend = new SystemSuspend(std::move(wakeupCountFd), std::move(stateFd));
38+ status_t status = suspend->registerAsService();
39+ if (android::OK != status) {
40+ LOG(FATAL) << "Unable to register service: " << status;
41+ }
42+ joinRpcThreadpool();
43+ std::abort(); /* unreachable */
44+}