• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 #include <errno.h>
18 #include <fcntl.h>
19 #include <pthread.h>
20 #include <semaphore.h>
21 #include <stddef.h>
22 #include <string.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26 
27 #define LOG_TAG "libsuspend"
28 #include <cutils/log.h>
29 
30 #include "autosuspend_ops.h"
31 
32 #define SYS_POWER_STATE "/sys/power/state"
33 #define SYS_POWER_WAKEUP_COUNT "/sys/power/wakeup_count"
34 
35 static int state_fd;
36 static int wakeup_count_fd;
37 static pthread_t suspend_thread;
38 static sem_t suspend_lockout;
39 static const char *sleep_state = "mem";
40 
suspend_thread_func(void * arg)41 static void *suspend_thread_func(void *arg __attribute__((unused)))
42 {
43     char buf[80];
44     char wakeup_count[20];
45     int wakeup_count_len;
46     int ret;
47 
48     while (1) {
49         usleep(100000);
50         ALOGV("%s: read wakeup_count\n", __func__);
51         lseek(wakeup_count_fd, 0, SEEK_SET);
52         wakeup_count_len = read(wakeup_count_fd, wakeup_count, sizeof(wakeup_count));
53         if (wakeup_count_len < 0) {
54             strerror_r(errno, buf, sizeof(buf));
55             ALOGE("Error reading from %s: %s\n", SYS_POWER_WAKEUP_COUNT, buf);
56             wakeup_count_len = 0;
57             continue;
58         }
59         if (!wakeup_count_len) {
60             ALOGE("Empty wakeup count\n");
61             continue;
62         }
63 
64         ALOGV("%s: wait\n", __func__);
65         ret = sem_wait(&suspend_lockout);
66         if (ret < 0) {
67             strerror_r(errno, buf, sizeof(buf));
68             ALOGE("Error waiting on semaphore: %s\n", buf);
69             continue;
70         }
71 
72         ALOGV("%s: write %*s to wakeup_count\n", __func__, wakeup_count_len, wakeup_count);
73         ret = write(wakeup_count_fd, wakeup_count, wakeup_count_len);
74         if (ret < 0) {
75             strerror_r(errno, buf, sizeof(buf));
76             ALOGE("Error writing to %s: %s\n", SYS_POWER_WAKEUP_COUNT, buf);
77         } else {
78             ALOGV("%s: write %s to %s\n", __func__, sleep_state, SYS_POWER_STATE);
79             ret = write(state_fd, sleep_state, strlen(sleep_state));
80             if (ret < 0) {
81                 strerror_r(errno, buf, sizeof(buf));
82                 ALOGE("Error writing to %s: %s\n", SYS_POWER_STATE, buf);
83             }
84         }
85 
86         ALOGV("%s: release sem\n", __func__);
87         ret = sem_post(&suspend_lockout);
88         if (ret < 0) {
89             strerror_r(errno, buf, sizeof(buf));
90             ALOGE("Error releasing semaphore: %s\n", buf);
91         }
92     }
93     return NULL;
94 }
95 
autosuspend_wakeup_count_enable(void)96 static int autosuspend_wakeup_count_enable(void)
97 {
98     char buf[80];
99     int ret;
100 
101     ALOGV("autosuspend_wakeup_count_enable\n");
102 
103     ret = sem_post(&suspend_lockout);
104 
105     if (ret < 0) {
106         strerror_r(errno, buf, sizeof(buf));
107         ALOGE("Error changing semaphore: %s\n", buf);
108     }
109 
110     ALOGV("autosuspend_wakeup_count_enable done\n");
111 
112     return ret;
113 }
114 
autosuspend_wakeup_count_disable(void)115 static int autosuspend_wakeup_count_disable(void)
116 {
117     char buf[80];
118     int ret;
119 
120     ALOGV("autosuspend_wakeup_count_disable\n");
121 
122     ret = sem_wait(&suspend_lockout);
123 
124     if (ret < 0) {
125         strerror_r(errno, buf, sizeof(buf));
126         ALOGE("Error changing semaphore: %s\n", buf);
127     }
128 
129     ALOGV("autosuspend_wakeup_count_disable done\n");
130 
131     return ret;
132 }
133 
134 struct autosuspend_ops autosuspend_wakeup_count_ops = {
135         .enable = autosuspend_wakeup_count_enable,
136         .disable = autosuspend_wakeup_count_disable,
137 };
138 
autosuspend_wakeup_count_init(void)139 struct autosuspend_ops *autosuspend_wakeup_count_init(void)
140 {
141     int ret;
142     char buf[80];
143 
144     state_fd = open(SYS_POWER_STATE, O_RDWR);
145     if (state_fd < 0) {
146         strerror_r(errno, buf, sizeof(buf));
147         ALOGE("Error opening %s: %s\n", SYS_POWER_STATE, buf);
148         goto err_open_state;
149     }
150 
151     wakeup_count_fd = open(SYS_POWER_WAKEUP_COUNT, O_RDWR);
152     if (wakeup_count_fd < 0) {
153         strerror_r(errno, buf, sizeof(buf));
154         ALOGE("Error opening %s: %s\n", SYS_POWER_WAKEUP_COUNT, buf);
155         goto err_open_wakeup_count;
156     }
157 
158     ret = sem_init(&suspend_lockout, 0, 0);
159     if (ret < 0) {
160         strerror_r(errno, buf, sizeof(buf));
161         ALOGE("Error creating semaphore: %s\n", buf);
162         goto err_sem_init;
163     }
164     ret = pthread_create(&suspend_thread, NULL, suspend_thread_func, NULL);
165     if (ret) {
166         strerror_r(ret, buf, sizeof(buf));
167         ALOGE("Error creating thread: %s\n", buf);
168         goto err_pthread_create;
169     }
170 
171     ALOGI("Selected wakeup count\n");
172     return &autosuspend_wakeup_count_ops;
173 
174 err_pthread_create:
175     sem_destroy(&suspend_lockout);
176 err_sem_init:
177     close(wakeup_count_fd);
178 err_open_wakeup_count:
179     close(state_fd);
180 err_open_state:
181     return NULL;
182 }
183