autosuspend_earlysuspend.c revision 2146b7f2d7f8e9320d8ec5581c61e14f243ee97c
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 <stddef.h>
20#include <string.h>
21#include <sys/types.h>
22#include <sys/stat.h>
23#include <unistd.h>
24
25#define LOG_TAG "libsuspend"
26#include <cutils/log.h>
27
28#include "autosuspend_ops.h"
29
30#define EARLYSUSPEND_SYS_POWER_STATE "/sys/power/state"
31#define EARLYSUSPEND_WAIT_FOR_FB_SLEEP "/sys/power/wait_for_fb_sleep"
32#define EARLYSUSPEND_WAIT_FOR_FB_WAKE "/sys/power/wait_for_fb_wake"
33
34
35static int sPowerStatefd;
36static const char *pwr_state_mem = "mem";
37static const char *pwr_state_on = "on";
38static pthread_t earlysuspend_thread;
39
40int wait_for_fb_wake(void)
41{
42    int err = 0;
43    char buf;
44    int fd = open(EARLYSUSPEND_WAIT_FOR_FB_WAKE, O_RDONLY, 0);
45    // if the file doesn't exist, the error will be caught in read() below
46    do {
47        err = read(fd, &buf, 1);
48    } while (err < 0 && errno == EINTR);
49    ALOGE_IF(err < 0,
50            "*** ANDROID_WAIT_FOR_FB_WAKE failed (%s)", strerror(errno));
51    close(fd);
52    return err < 0 ? err : 0;
53}
54
55static int wait_for_fb_sleep(void)
56{
57    int err = 0;
58    char buf;
59    int fd = open(EARLYSUSPEND_WAIT_FOR_FB_SLEEP, O_RDONLY, 0);
60    // if the file doesn't exist, the error will be caught in read() below
61    do {
62        err = read(fd, &buf, 1);
63    } while (err < 0 && errno == EINTR);
64    ALOGE_IF(err < 0,
65            "*** ANDROID_WAIT_FOR_FB_SLEEP failed (%s)", strerror(errno));
66    close(fd);
67    return err < 0 ? err : 0;
68}
69
70static void *earlysuspend_thread_func(void *arg)
71{
72    char buf[80];
73    char wakeup_count[20];
74    int wakeup_count_len;
75    int ret;
76
77    while (1) {
78        if (wait_for_fb_sleep()) {
79            ALOGE("Failed reading wait_for_fb_sleep, exiting earlysuspend thread\n");
80            return NULL;
81        }
82        if (wait_for_fb_wake()) {
83            ALOGE("Failed reading wait_for_fb_wake, exiting earlysuspend thread\n");
84            return NULL;
85        }
86    }
87}
88static int autosuspend_earlysuspend_enable(void)
89{
90    char buf[80];
91    int ret;
92
93    ALOGV("autosuspend_earlysuspend_enable\n");
94
95    ret = write(sPowerStatefd, pwr_state_mem, strlen(pwr_state_mem));
96    if (ret < 0) {
97        strerror_r(errno, buf, sizeof(buf));
98        ALOGE("Error writing to %s: %s\n", EARLYSUSPEND_SYS_POWER_STATE, buf);
99        goto err;
100    }
101
102    ALOGV("autosuspend_earlysuspend_enable done\n");
103
104    return 0;
105
106err:
107    return ret;
108}
109
110static int autosuspend_earlysuspend_disable(void)
111{
112    char buf[80];
113    int ret;
114
115    ALOGV("autosuspend_earlysuspend_disable\n");
116
117    ret = write(sPowerStatefd, pwr_state_on, strlen(pwr_state_on));
118    if (ret < 0) {
119        strerror_r(errno, buf, sizeof(buf));
120        ALOGE("Error writing to %s: %s\n", EARLYSUSPEND_SYS_POWER_STATE, buf);
121        goto err;
122    }
123
124    ALOGV("autosuspend_earlysuspend_disable done\n");
125
126    return 0;
127
128err:
129    return ret;
130}
131
132struct autosuspend_ops autosuspend_earlysuspend_ops = {
133        .enable = autosuspend_earlysuspend_enable,
134        .disable = autosuspend_earlysuspend_disable,
135};
136
137void start_earlysuspend_thread(void)
138{
139    char buf[80];
140    int ret;
141
142    ret = access(EARLYSUSPEND_WAIT_FOR_FB_SLEEP, F_OK);
143    if (ret < 0) {
144        return;
145    }
146
147    ret = access(EARLYSUSPEND_WAIT_FOR_FB_WAKE, F_OK);
148    if (ret < 0) {
149        return;
150    }
151
152    ALOGI("Starting early suspend unblocker thread\n");
153    ret = pthread_create(&earlysuspend_thread, NULL, earlysuspend_thread_func, NULL);
154    if (ret) {
155        strerror_r(ret, buf, sizeof(buf));
156        ALOGE("Error creating thread: %s\n", buf);
157    }
158}
159
160struct autosuspend_ops *autosuspend_earlysuspend_init(void)
161{
162    char buf[80];
163    int ret;
164
165    sPowerStatefd = open(EARLYSUSPEND_SYS_POWER_STATE, O_RDWR);
166
167    if (sPowerStatefd < 0) {
168        strerror_r(errno, buf, sizeof(buf));
169        ALOGW("Error opening %s: %s\n", EARLYSUSPEND_SYS_POWER_STATE, buf);
170        return NULL;
171    }
172
173    ret = write(sPowerStatefd, "on", 2);
174    if (ret < 0) {
175        strerror_r(errno, buf, sizeof(buf));
176        ALOGW("Error writing 'on' to %s: %s\n", EARLYSUSPEND_SYS_POWER_STATE, buf);
177        goto err_write;
178    }
179
180    ALOGI("Selected early suspend\n");
181
182    start_earlysuspend_thread();
183
184    return &autosuspend_earlysuspend_ops;
185
186err_write:
187    close(sPowerStatefd);
188    return NULL;
189}
190