summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libsuspend/autosuspend.c27
-rw-r--r--libsuspend/autosuspend_ops.h1
-rw-r--r--libsuspend/autosuspend_wakeup_count.cpp130
-rw-r--r--libsuspend/include/suspend/autosuspend.h11
4 files changed, 112 insertions, 57 deletions
diff --git a/libsuspend/autosuspend.c b/libsuspend/autosuspend.c
index 09fc0617e..b87f59cd6 100644
--- a/libsuspend/autosuspend.c
+++ b/libsuspend/autosuspend.c
@@ -24,28 +24,20 @@
24 24
25#include "autosuspend_ops.h" 25#include "autosuspend_ops.h"
26 26
27static struct autosuspend_ops *autosuspend_ops; 27static struct autosuspend_ops* autosuspend_ops = NULL;
28static bool autosuspend_enabled; 28static bool autosuspend_enabled;
29static bool autosuspend_inited;
30 29
31static int autosuspend_init(void) { 30static int autosuspend_init(void) {
32 if (autosuspend_inited) { 31 if (autosuspend_ops != NULL) {
33 return 0; 32 return 0;
34 } 33 }
35 34
36 autosuspend_ops = autosuspend_wakeup_count_init(); 35 autosuspend_ops = autosuspend_wakeup_count_init();
37 if (autosuspend_ops) { 36 if (autosuspend_ops == NULL) {
38 goto out;
39 }
40
41 if (!autosuspend_ops) {
42 ALOGE("failed to initialize autosuspend"); 37 ALOGE("failed to initialize autosuspend");
43 return -1; 38 return -1;
44 } 39 }
45 40
46out:
47 autosuspend_inited = true;
48
49 ALOGV("autosuspend initialized"); 41 ALOGV("autosuspend initialized");
50 return 0; 42 return 0;
51} 43}
@@ -96,6 +88,19 @@ int autosuspend_disable(void) {
96 return 0; 88 return 0;
97} 89}
98 90
91int autosuspend_force_suspend(int timeout_ms) {
92 int ret;
93
94 ret = autosuspend_init();
95 if (ret) {
96 return ret;
97 }
98
99 ALOGV("autosuspend_force_suspend");
100
101 return autosuspend_ops->force_suspend(timeout_ms);
102}
103
99void autosuspend_set_wakeup_callback(void (*func)(bool success)) { 104void autosuspend_set_wakeup_callback(void (*func)(bool success)) {
100 int ret; 105 int ret;
101 106
diff --git a/libsuspend/autosuspend_ops.h b/libsuspend/autosuspend_ops.h
index 357b82827..b0024c8bb 100644
--- a/libsuspend/autosuspend_ops.h
+++ b/libsuspend/autosuspend_ops.h
@@ -20,6 +20,7 @@
20struct autosuspend_ops { 20struct autosuspend_ops {
21 int (*enable)(void); 21 int (*enable)(void);
22 int (*disable)(void); 22 int (*disable)(void);
23 int (*force_suspend)(int timeout_ms);
23 void (*set_wakeup_callback)(void (*func)(bool success)); 24 void (*set_wakeup_callback)(void (*func)(bool success));
24}; 25};
25 26
diff --git a/libsuspend/autosuspend_wakeup_count.cpp b/libsuspend/autosuspend_wakeup_count.cpp
index cfca76521..27c862957 100644
--- a/libsuspend/autosuspend_wakeup_count.cpp
+++ b/libsuspend/autosuspend_wakeup_count.cpp
@@ -37,7 +37,7 @@
37#define BASE_SLEEP_TIME 100000 37#define BASE_SLEEP_TIME 100000
38#define MAX_SLEEP_TIME 60000000 38#define MAX_SLEEP_TIME 60000000
39 39
40static int state_fd; 40static int state_fd = -1;
41static int wakeup_count_fd; 41static int wakeup_count_fd;
42 42
43using android::base::ReadFdToString; 43using android::base::ReadFdToString;
@@ -46,11 +46,12 @@ using android::base::WriteStringToFd;
46 46
47static pthread_t suspend_thread; 47static pthread_t suspend_thread;
48static sem_t suspend_lockout; 48static sem_t suspend_lockout;
49static const char* sleep_state = "mem"; 49static constexpr char sleep_state[] = "mem";
50static void (*wakeup_func)(bool success) = NULL; 50static void (*wakeup_func)(bool success) = NULL;
51static int sleep_time = BASE_SLEEP_TIME; 51static int sleep_time = BASE_SLEEP_TIME;
52static constexpr char sys_power_state[] = "/sys/power/state"; 52static constexpr char sys_power_state[] = "/sys/power/state";
53static constexpr char sys_power_wakeup_count[] = "/sys/power/wakeup_count"; 53static constexpr char sys_power_wakeup_count[] = "/sys/power/wakeup_count";
54static bool autosuspend_is_init = false;
54 55
55static void update_sleep_time(bool success) { 56static void update_sleep_time(bool success) {
56 if (success) { 57 if (success) {
@@ -62,10 +63,9 @@ static void update_sleep_time(bool success) {
62} 63}
63 64
64static void* suspend_thread_func(void* arg __attribute__((unused))) { 65static void* suspend_thread_func(void* arg __attribute__((unused))) {
65 int ret;
66 bool success = true; 66 bool success = true;
67 67
68 while (1) { 68 while (true) {
69 update_sleep_time(success); 69 update_sleep_time(success);
70 usleep(sleep_time); 70 usleep(sleep_time);
71 success = false; 71 success = false;
@@ -84,7 +84,7 @@ static void* suspend_thread_func(void* arg __attribute__((unused))) {
84 } 84 }
85 85
86 LOG(VERBOSE) << "wait"; 86 LOG(VERBOSE) << "wait";
87 ret = sem_wait(&suspend_lockout); 87 int ret = sem_wait(&suspend_lockout);
88 if (ret < 0) { 88 if (ret < 0) {
89 PLOG(ERROR) << "error waiting on semaphore"; 89 PLOG(ERROR) << "error waiting on semaphore";
90 continue; 90 continue;
@@ -112,13 +112,72 @@ static void* suspend_thread_func(void* arg __attribute__((unused))) {
112 return NULL; 112 return NULL;
113} 113}
114 114
115static int autosuspend_wakeup_count_enable(void) { 115static int init_state_fd(void) {
116 int ret; 116 if (state_fd >= 0) {
117 return 0;
118 }
119
120 int fd = TEMP_FAILURE_RETRY(open(sys_power_state, O_CLOEXEC | O_RDWR));
121 if (fd < 0) {
122 PLOG(ERROR) << "error opening " << sys_power_state;
123 return -1;
124 }
125
126 state_fd = fd;
127 LOG(INFO) << "init_state_fd success";
128 return 0;
129}
130
131static int autosuspend_init(void) {
132 if (autosuspend_is_init) {
133 return 0;
134 }
135
136 int ret = init_state_fd();
137 if (ret < 0) {
138 return -1;
139 }
140
141 wakeup_count_fd = TEMP_FAILURE_RETRY(open(sys_power_wakeup_count, O_CLOEXEC | O_RDWR));
142 if (wakeup_count_fd < 0) {
143 PLOG(ERROR) << "error opening " << sys_power_wakeup_count;
144 goto err_open_wakeup_count;
145 }
146
147 ret = sem_init(&suspend_lockout, 0, 0);
148 if (ret < 0) {
149 PLOG(ERROR) << "error creating suspend_lockout semaphore";
150 goto err_sem_init;
151 }
152
153 ret = pthread_create(&suspend_thread, NULL, suspend_thread_func, NULL);
154 if (ret) {
155 LOG(ERROR) << "error creating thread: " << strerror(ret);
156 goto err_pthread_create;
157 }
158
159 LOG(VERBOSE) << "autosuspend_init success";
160 autosuspend_is_init = true;
161 return 0;
117 162
163err_pthread_create:
164 sem_destroy(&suspend_lockout);
165err_sem_init:
166 close(wakeup_count_fd);
167err_open_wakeup_count:
168 return -1;
169}
170
171static int autosuspend_wakeup_count_enable(void) {
118 LOG(VERBOSE) << "autosuspend_wakeup_count_enable"; 172 LOG(VERBOSE) << "autosuspend_wakeup_count_enable";
119 173
120 ret = sem_post(&suspend_lockout); 174 int ret = autosuspend_init();
175 if (ret < 0) {
176 LOG(ERROR) << "autosuspend_init failed";
177 return ret;
178 }
121 179
180 ret = sem_post(&suspend_lockout);
122 if (ret < 0) { 181 if (ret < 0) {
123 PLOG(ERROR) << "error changing semaphore"; 182 PLOG(ERROR) << "error changing semaphore";
124 } 183 }
@@ -129,11 +188,13 @@ static int autosuspend_wakeup_count_enable(void) {
129} 188}
130 189
131static int autosuspend_wakeup_count_disable(void) { 190static int autosuspend_wakeup_count_disable(void) {
132 int ret;
133
134 LOG(VERBOSE) << "autosuspend_wakeup_count_disable"; 191 LOG(VERBOSE) << "autosuspend_wakeup_count_disable";
135 192
136 ret = sem_wait(&suspend_lockout); 193 if (!autosuspend_is_init) {
194 return 0; // always successful if no thread is running yet
195 }
196
197 int ret = sem_wait(&suspend_lockout);
137 198
138 if (ret < 0) { 199 if (ret < 0) {
139 PLOG(ERROR) << "error changing semaphore"; 200 PLOG(ERROR) << "error changing semaphore";
@@ -144,6 +205,17 @@ static int autosuspend_wakeup_count_disable(void) {
144 return ret; 205 return ret;
145} 206}
146 207
208static int force_suspend(int timeout_ms) {
209 LOG(VERBOSE) << "force_suspend called with timeout: " << timeout_ms;
210
211 int ret = init_state_fd();
212 if (ret < 0) {
213 return ret;
214 }
215
216 return WriteStringToFd(sleep_state, state_fd) ? 0 : -1;
217}
218
147static void autosuspend_set_wakeup_callback(void (*func)(bool success)) { 219static void autosuspend_set_wakeup_callback(void (*func)(bool success)) {
148 if (wakeup_func != NULL) { 220 if (wakeup_func != NULL) {
149 LOG(ERROR) << "duplicate wakeup callback applied, keeping original"; 221 LOG(ERROR) << "duplicate wakeup callback applied, keeping original";
@@ -155,44 +227,10 @@ static void autosuspend_set_wakeup_callback(void (*func)(bool success)) {
155struct autosuspend_ops autosuspend_wakeup_count_ops = { 227struct autosuspend_ops autosuspend_wakeup_count_ops = {
156 .enable = autosuspend_wakeup_count_enable, 228 .enable = autosuspend_wakeup_count_enable,
157 .disable = autosuspend_wakeup_count_disable, 229 .disable = autosuspend_wakeup_count_disable,
230 .force_suspend = force_suspend,
158 .set_wakeup_callback = autosuspend_set_wakeup_callback, 231 .set_wakeup_callback = autosuspend_set_wakeup_callback,
159}; 232};
160 233
161struct autosuspend_ops* autosuspend_wakeup_count_init(void) { 234struct autosuspend_ops* autosuspend_wakeup_count_init(void) {
162 int ret;
163
164 state_fd = TEMP_FAILURE_RETRY(open(sys_power_state, O_RDWR));
165 if (state_fd < 0) {
166 PLOG(ERROR) << "error opening " << sys_power_state;
167 goto err_open_state;
168 }
169
170 wakeup_count_fd = TEMP_FAILURE_RETRY(open(sys_power_wakeup_count, O_RDWR));
171 if (wakeup_count_fd < 0) {
172 PLOG(ERROR) << "error opening " << sys_power_wakeup_count;
173 goto err_open_wakeup_count;
174 }
175
176 ret = sem_init(&suspend_lockout, 0, 0);
177 if (ret < 0) {
178 PLOG(ERROR) << "error creating semaphore";
179 goto err_sem_init;
180 }
181 ret = pthread_create(&suspend_thread, NULL, suspend_thread_func, NULL);
182 if (ret) {
183 LOG(ERROR) << "error creating thread: " << strerror(ret);
184 goto err_pthread_create;
185 }
186
187 LOG(INFO) << "selected wakeup count";
188 return &autosuspend_wakeup_count_ops; 235 return &autosuspend_wakeup_count_ops;
189
190err_pthread_create:
191 sem_destroy(&suspend_lockout);
192err_sem_init:
193 close(wakeup_count_fd);
194err_open_wakeup_count:
195 close(state_fd);
196err_open_state:
197 return NULL;
198} 236}
diff --git a/libsuspend/include/suspend/autosuspend.h b/libsuspend/include/suspend/autosuspend.h
index e130ca3df..21f4d61bf 100644
--- a/libsuspend/include/suspend/autosuspend.h
+++ b/libsuspend/include/suspend/autosuspend.h
@@ -45,6 +45,17 @@ int autosuspend_enable(void);
45int autosuspend_disable(void); 45int autosuspend_disable(void);
46 46
47/* 47/*
48 * force_suspend
49 *
50 * Forces suspend to happen. timeout_ms is used to give system a chance to suspend gracefully.
51 * When timeout expires, suspend will be forced via mem --> /sys/power/state. timeout_ms of 0
52 * will force suspend immediately.
53 *
54 * Returns 0 if system suspended, -1 if suspend did not occur.
55 */
56int autosuspend_force_suspend(int timeout_ms);
57
58/*
48 * set_wakeup_callback 59 * set_wakeup_callback
49 * 60 *
50 * Set a function to be called each time the device returns from suspend. 61 * Set a function to be called each time the device returns from suspend.