diff options
-rw-r--r-- | libsuspend/autosuspend.c | 27 | ||||
-rw-r--r-- | libsuspend/autosuspend_ops.h | 1 | ||||
-rw-r--r-- | libsuspend/autosuspend_wakeup_count.cpp | 130 | ||||
-rw-r--r-- | libsuspend/include/suspend/autosuspend.h | 11 |
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 | ||
27 | static struct autosuspend_ops *autosuspend_ops; | 27 | static struct autosuspend_ops* autosuspend_ops = NULL; |
28 | static bool autosuspend_enabled; | 28 | static bool autosuspend_enabled; |
29 | static bool autosuspend_inited; | ||
30 | 29 | ||
31 | static int autosuspend_init(void) { | 30 | static 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 | ||
46 | out: | ||
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 | ||
91 | int 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 | |||
99 | void autosuspend_set_wakeup_callback(void (*func)(bool success)) { | 104 | void 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 @@ | |||
20 | struct autosuspend_ops { | 20 | struct 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 | ||
40 | static int state_fd; | 40 | static int state_fd = -1; |
41 | static int wakeup_count_fd; | 41 | static int wakeup_count_fd; |
42 | 42 | ||
43 | using android::base::ReadFdToString; | 43 | using android::base::ReadFdToString; |
@@ -46,11 +46,12 @@ using android::base::WriteStringToFd; | |||
46 | 46 | ||
47 | static pthread_t suspend_thread; | 47 | static pthread_t suspend_thread; |
48 | static sem_t suspend_lockout; | 48 | static sem_t suspend_lockout; |
49 | static const char* sleep_state = "mem"; | 49 | static constexpr char sleep_state[] = "mem"; |
50 | static void (*wakeup_func)(bool success) = NULL; | 50 | static void (*wakeup_func)(bool success) = NULL; |
51 | static int sleep_time = BASE_SLEEP_TIME; | 51 | static int sleep_time = BASE_SLEEP_TIME; |
52 | static constexpr char sys_power_state[] = "/sys/power/state"; | 52 | static constexpr char sys_power_state[] = "/sys/power/state"; |
53 | static constexpr char sys_power_wakeup_count[] = "/sys/power/wakeup_count"; | 53 | static constexpr char sys_power_wakeup_count[] = "/sys/power/wakeup_count"; |
54 | static bool autosuspend_is_init = false; | ||
54 | 55 | ||
55 | static void update_sleep_time(bool success) { | 56 | static 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 | ||
64 | static void* suspend_thread_func(void* arg __attribute__((unused))) { | 65 | static 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 | ||
115 | static int autosuspend_wakeup_count_enable(void) { | 115 | static 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 | |||
131 | static 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 | ||
163 | err_pthread_create: | ||
164 | sem_destroy(&suspend_lockout); | ||
165 | err_sem_init: | ||
166 | close(wakeup_count_fd); | ||
167 | err_open_wakeup_count: | ||
168 | return -1; | ||
169 | } | ||
170 | |||
171 | static 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 | ||
131 | static int autosuspend_wakeup_count_disable(void) { | 190 | static 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 | ||
208 | static 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 | |||
147 | static void autosuspend_set_wakeup_callback(void (*func)(bool success)) { | 219 | static 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)) { | |||
155 | struct autosuspend_ops autosuspend_wakeup_count_ops = { | 227 | struct 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 | ||
161 | struct autosuspend_ops* autosuspend_wakeup_count_init(void) { | 234 | struct 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 | |||
190 | err_pthread_create: | ||
191 | sem_destroy(&suspend_lockout); | ||
192 | err_sem_init: | ||
193 | close(wakeup_count_fd); | ||
194 | err_open_wakeup_count: | ||
195 | close(state_fd); | ||
196 | err_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); | |||
45 | int autosuspend_disable(void); | 45 | int 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 | */ | ||
56 | int 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. |