blob: 30f8427381478690d441e7c6536d9306b3f05750 [file] [log] [blame]
Colin Crossa2582c22012-05-03 17:30:16 -07001/*
2 * Copyright (C) 2012 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
Mark Salyzyn66ce3e02016-09-28 10:07:20 -070017#define LOG_TAG "libsuspend"
18//#define LOG_NDEBUG 0
19
Colin Crossa2582c22012-05-03 17:30:16 -070020#include <errno.h>
21#include <fcntl.h>
22#include <pthread.h>
23#include <semaphore.h>
Ruchi Kandoid3027d82015-05-13 14:57:08 -070024#include <stdbool.h>
Steve Paikdb887742017-12-20 15:09:21 -080025#include <stddef.h>
Colin Crossa2582c22012-05-03 17:30:16 -070026#include <string.h>
Ajay Dudani0c5f7d82017-04-17 16:54:15 -070027#include <sys/param.h>
Colin Crossa2582c22012-05-03 17:30:16 -070028#include <sys/stat.h>
29#include <sys/types.h>
30#include <unistd.h>
31
Mark Salyzyn30f991f2017-01-10 13:19:54 -080032#include <log/log.h>
Colin Crossa2582c22012-05-03 17:30:16 -070033
34#include "autosuspend_ops.h"
35
36#define SYS_POWER_STATE "/sys/power/state"
37#define SYS_POWER_WAKEUP_COUNT "/sys/power/wakeup_count"
38
Ajay Dudani0c5f7d82017-04-17 16:54:15 -070039#define BASE_SLEEP_TIME 100000
40
Colin Crossa2582c22012-05-03 17:30:16 -070041static int state_fd;
42static int wakeup_count_fd;
43static pthread_t suspend_thread;
44static sem_t suspend_lockout;
Steve Paik2d441902017-12-15 13:26:28 -080045static const char* sleep_state = "mem";
Ruchi Kandoid3027d82015-05-13 14:57:08 -070046static void (*wakeup_func)(bool success) = NULL;
Ajay Dudani0c5f7d82017-04-17 16:54:15 -070047static int sleep_time = BASE_SLEEP_TIME;
48
49static void update_sleep_time(bool success) {
50 if (success) {
51 sleep_time = BASE_SLEEP_TIME;
52 return;
53 }
54 // double sleep time after each failure up to one minute
55 sleep_time = MIN(sleep_time * 2, 60000000);
56}
Colin Crossa2582c22012-05-03 17:30:16 -070057
Steve Paik2d441902017-12-15 13:26:28 -080058static void* suspend_thread_func(void* arg __attribute__((unused))) {
Colin Crossa2582c22012-05-03 17:30:16 -070059 char buf[80];
60 char wakeup_count[20];
61 int wakeup_count_len;
62 int ret;
Ajay Dudani0c5f7d82017-04-17 16:54:15 -070063 bool success = true;
Colin Crossa2582c22012-05-03 17:30:16 -070064
65 while (1) {
Ajay Dudani0c5f7d82017-04-17 16:54:15 -070066 update_sleep_time(success);
67 usleep(sleep_time);
68 success = false;
Steve Paikfea16e12017-12-14 17:31:58 -080069 ALOGV("%s: read wakeup_count", __func__);
Colin Crossa2582c22012-05-03 17:30:16 -070070 lseek(wakeup_count_fd, 0, SEEK_SET);
Steve Paikdb887742017-12-20 15:09:21 -080071 wakeup_count_len =
72 TEMP_FAILURE_RETRY(read(wakeup_count_fd, wakeup_count, sizeof(wakeup_count)));
Colin Crossa2582c22012-05-03 17:30:16 -070073 if (wakeup_count_len < 0) {
74 strerror_r(errno, buf, sizeof(buf));
Steve Paikfea16e12017-12-14 17:31:58 -080075 ALOGE("Error reading from %s: %s", SYS_POWER_WAKEUP_COUNT, buf);
Colin Crossa2582c22012-05-03 17:30:16 -070076 wakeup_count_len = 0;
77 continue;
78 }
79 if (!wakeup_count_len) {
Steve Paikfea16e12017-12-14 17:31:58 -080080 ALOGE("Empty wakeup count");
Colin Crossa2582c22012-05-03 17:30:16 -070081 continue;
82 }
83
Steve Paikfea16e12017-12-14 17:31:58 -080084 ALOGV("%s: wait", __func__);
Colin Crossa2582c22012-05-03 17:30:16 -070085 ret = sem_wait(&suspend_lockout);
86 if (ret < 0) {
87 strerror_r(errno, buf, sizeof(buf));
Steve Paikfea16e12017-12-14 17:31:58 -080088 ALOGE("Error waiting on semaphore: %s", buf);
Colin Crossa2582c22012-05-03 17:30:16 -070089 continue;
90 }
91
Steve Paikfea16e12017-12-14 17:31:58 -080092 ALOGV("%s: write %*s to wakeup_count", __func__, wakeup_count_len, wakeup_count);
Jeff Brown0446e162015-05-15 14:56:03 -070093 ret = TEMP_FAILURE_RETRY(write(wakeup_count_fd, wakeup_count, wakeup_count_len));
Colin Crossa2582c22012-05-03 17:30:16 -070094 if (ret < 0) {
95 strerror_r(errno, buf, sizeof(buf));
Steve Paikfea16e12017-12-14 17:31:58 -080096 ALOGE("Error writing to %s: %s", SYS_POWER_WAKEUP_COUNT, buf);
Colin Crossa2582c22012-05-03 17:30:16 -070097 } else {
Steve Paikfea16e12017-12-14 17:31:58 -080098 ALOGV("%s: write %s to %s", __func__, sleep_state, SYS_POWER_STATE);
Jeff Brown0446e162015-05-15 14:56:03 -070099 ret = TEMP_FAILURE_RETRY(write(state_fd, sleep_state, strlen(sleep_state)));
Ajay Dudani0c5f7d82017-04-17 16:54:15 -0700100 if (ret >= 0) {
101 success = true;
Ruchi Kandoid3027d82015-05-13 14:57:08 -0700102 }
103 void (*func)(bool success) = wakeup_func;
104 if (func != NULL) {
105 (*func)(success);
Colin Crossa2582c22012-05-03 17:30:16 -0700106 }
107 }
108
Steve Paikfea16e12017-12-14 17:31:58 -0800109 ALOGV("%s: release sem", __func__);
Colin Crossa2582c22012-05-03 17:30:16 -0700110 ret = sem_post(&suspend_lockout);
111 if (ret < 0) {
112 strerror_r(errno, buf, sizeof(buf));
Steve Paikfea16e12017-12-14 17:31:58 -0800113 ALOGE("Error releasing semaphore: %s", buf);
Colin Crossa2582c22012-05-03 17:30:16 -0700114 }
115 }
116 return NULL;
117}
118
Steve Paik2d441902017-12-15 13:26:28 -0800119static int autosuspend_wakeup_count_enable(void) {
Colin Crossa2582c22012-05-03 17:30:16 -0700120 char buf[80];
121 int ret;
122
Steve Paikfea16e12017-12-14 17:31:58 -0800123 ALOGV("autosuspend_wakeup_count_enable");
Colin Crossa2582c22012-05-03 17:30:16 -0700124
125 ret = sem_post(&suspend_lockout);
126
127 if (ret < 0) {
128 strerror_r(errno, buf, sizeof(buf));
Steve Paikfea16e12017-12-14 17:31:58 -0800129 ALOGE("Error changing semaphore: %s", buf);
Colin Crossa2582c22012-05-03 17:30:16 -0700130 }
131
Steve Paikfea16e12017-12-14 17:31:58 -0800132 ALOGV("autosuspend_wakeup_count_enable done");
Colin Crossa2582c22012-05-03 17:30:16 -0700133
134 return ret;
135}
136
Steve Paik2d441902017-12-15 13:26:28 -0800137static int autosuspend_wakeup_count_disable(void) {
Colin Crossa2582c22012-05-03 17:30:16 -0700138 char buf[80];
139 int ret;
140
Steve Paikfea16e12017-12-14 17:31:58 -0800141 ALOGV("autosuspend_wakeup_count_disable");
Colin Crossa2582c22012-05-03 17:30:16 -0700142
143 ret = sem_wait(&suspend_lockout);
144
145 if (ret < 0) {
146 strerror_r(errno, buf, sizeof(buf));
Steve Paikfea16e12017-12-14 17:31:58 -0800147 ALOGE("Error changing semaphore: %s", buf);
Colin Crossa2582c22012-05-03 17:30:16 -0700148 }
149
Steve Paikfea16e12017-12-14 17:31:58 -0800150 ALOGV("autosuspend_wakeup_count_disable done");
Colin Crossa2582c22012-05-03 17:30:16 -0700151
152 return ret;
153}
154
Steve Paik2d441902017-12-15 13:26:28 -0800155static void autosuspend_set_wakeup_callback(void (*func)(bool success)) {
Dianne Hackborn9552cdf2014-03-07 11:00:39 -0800156 if (wakeup_func != NULL) {
157 ALOGE("Duplicate wakeup callback applied, keeping original");
158 return;
159 }
160 wakeup_func = func;
161}
162
Colin Crossa2582c22012-05-03 17:30:16 -0700163struct autosuspend_ops autosuspend_wakeup_count_ops = {
Steve Paik2d441902017-12-15 13:26:28 -0800164 .enable = autosuspend_wakeup_count_enable,
165 .disable = autosuspend_wakeup_count_disable,
166 .set_wakeup_callback = autosuspend_set_wakeup_callback,
Colin Crossa2582c22012-05-03 17:30:16 -0700167};
168
Steve Paik2d441902017-12-15 13:26:28 -0800169struct autosuspend_ops* autosuspend_wakeup_count_init(void) {
Colin Crossa2582c22012-05-03 17:30:16 -0700170 int ret;
171 char buf[80];
172
Jeff Brown0446e162015-05-15 14:56:03 -0700173 state_fd = TEMP_FAILURE_RETRY(open(SYS_POWER_STATE, O_RDWR));
Colin Crossa2582c22012-05-03 17:30:16 -0700174 if (state_fd < 0) {
175 strerror_r(errno, buf, sizeof(buf));
Steve Paikfea16e12017-12-14 17:31:58 -0800176 ALOGE("Error opening %s: %s", SYS_POWER_STATE, buf);
Colin Crossa2582c22012-05-03 17:30:16 -0700177 goto err_open_state;
178 }
179
Jeff Brown0446e162015-05-15 14:56:03 -0700180 wakeup_count_fd = TEMP_FAILURE_RETRY(open(SYS_POWER_WAKEUP_COUNT, O_RDWR));
Colin Crossa2582c22012-05-03 17:30:16 -0700181 if (wakeup_count_fd < 0) {
182 strerror_r(errno, buf, sizeof(buf));
Steve Paikfea16e12017-12-14 17:31:58 -0800183 ALOGE("Error opening %s: %s", SYS_POWER_WAKEUP_COUNT, buf);
Colin Crossa2582c22012-05-03 17:30:16 -0700184 goto err_open_wakeup_count;
185 }
186
187 ret = sem_init(&suspend_lockout, 0, 0);
188 if (ret < 0) {
189 strerror_r(errno, buf, sizeof(buf));
Steve Paikfea16e12017-12-14 17:31:58 -0800190 ALOGE("Error creating semaphore: %s", buf);
Colin Crossa2582c22012-05-03 17:30:16 -0700191 goto err_sem_init;
192 }
193 ret = pthread_create(&suspend_thread, NULL, suspend_thread_func, NULL);
194 if (ret) {
195 strerror_r(ret, buf, sizeof(buf));
Steve Paikfea16e12017-12-14 17:31:58 -0800196 ALOGE("Error creating thread: %s", buf);
Colin Crossa2582c22012-05-03 17:30:16 -0700197 goto err_pthread_create;
198 }
199
Steve Paikfea16e12017-12-14 17:31:58 -0800200 ALOGI("Selected wakeup count");
Colin Crossa2582c22012-05-03 17:30:16 -0700201 return &autosuspend_wakeup_count_ops;
202
203err_pthread_create:
204 sem_destroy(&suspend_lockout);
205err_sem_init:
206 close(wakeup_count_fd);
207err_open_wakeup_count:
208 close(state_fd);
209err_open_state:
210 return NULL;
211}