summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorColin Cross2012-05-03 19:30:16 -0500
committerColin Cross2012-05-07 17:33:34 -0500
commita2582c2c4d20684b21aaf50913a27239789bf5eb (patch)
treee55a928fad07633045e5574e84f3cee782300a05 /libsuspend
parentf82e74116314c4def32013495337c038f6c6ee6c (diff)
downloadplatform-system-core-a2582c2c4d20684b21aaf50913a27239789bf5eb.tar.gz
platform-system-core-a2582c2c4d20684b21aaf50913a27239789bf5eb.tar.xz
platform-system-core-a2582c2c4d20684b21aaf50913a27239789bf5eb.zip
libsuspend: create new library to handle triggering suspend
libsuspend provides functions autosuspend_enable() and autosuspend_disable() to trigger suspend on a variety of different kernels. Change-Id: I5dc28fb51532fa7c514330f1cfde7698d31d734c
Diffstat (limited to 'libsuspend')
-rw-r--r--libsuspend/Android.mk23
-rw-r--r--libsuspend/autosuspend.c109
-rw-r--r--libsuspend/autosuspend_autosleep.c99
-rw-r--r--libsuspend/autosuspend_earlysuspend.c113
-rw-r--r--libsuspend/autosuspend_ops.h29
-rw-r--r--libsuspend/autosuspend_wakeup_count.c182
-rw-r--r--libsuspend/include/suspend/autosuspend.h48
7 files changed, 603 insertions, 0 deletions
diff --git a/libsuspend/Android.mk b/libsuspend/Android.mk
new file mode 100644
index 000000000..45cb70116
--- /dev/null
+++ b/libsuspend/Android.mk
@@ -0,0 +1,23 @@
1# Copyright 2012 The Android Open Source Project
2
3LOCAL_PATH:= $(call my-dir)
4
5libsuspend_src_files := \
6 autosuspend.c \
7 autosuspend_autosleep.c \
8 autosuspend_earlysuspend.c \
9 autosuspend_wakeup_count.c \
10
11libsuspend_libraries := \
12 liblog libcutils
13
14include $(CLEAR_VARS)
15
16LOCAL_SRC_FILES := $(libsuspend_src_files)
17LOCAL_MODULE := libsuspend
18LOCAL_MODULE_TAGS := optional
19LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
20LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
21LOCAL_SHARED_LIBRARIES := $(libsuspend_libraries)
22#LOCAL_CFLAGS += -DLOG_NDEBUG=0
23include $(BUILD_SHARED_LIBRARY)
diff --git a/libsuspend/autosuspend.c b/libsuspend/autosuspend.c
new file mode 100644
index 000000000..7d1d97333
--- /dev/null
+++ b/libsuspend/autosuspend.c
@@ -0,0 +1,109 @@
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 <stdbool.h>
18
19#define LOG_TAG "libsuspend"
20#include <cutils/log.h>
21
22#include <suspend/autosuspend.h>
23
24#include "autosuspend_ops.h"
25
26static struct autosuspend_ops *autosuspend_ops;
27static bool autosuspend_enabled;
28static bool autosuspend_inited;
29
30static int autosuspend_init(void)
31{
32 if (autosuspend_inited) {
33 return 0;
34 }
35
36 autosuspend_inited = true;
37
38 autosuspend_ops = autosuspend_earlysuspend_init();
39 if (autosuspend_ops) {
40 goto out;
41 }
42
43 autosuspend_ops = autosuspend_autosleep_init();
44 if (autosuspend_ops) {
45 goto out;
46 }
47
48 autosuspend_ops = autosuspend_wakeup_count_init();
49 if (autosuspend_ops) {
50 goto out;
51 }
52
53 if (!autosuspend_ops) {
54 ALOGE("failed to initialize autosuspend\n");
55 return -1;
56 }
57
58out:
59 ALOGV("autosuspend initialized\n");
60 return 0;
61}
62
63int autosuspend_enable(void)
64{
65 int ret;
66
67 ret = autosuspend_init();
68 if (ret) {
69 return ret;
70 }
71
72 ALOGV("autosuspend_enable\n");
73
74 if (autosuspend_enabled) {
75 return 0;
76 }
77
78 ret = autosuspend_ops->enable();
79 if (ret) {
80 return ret;
81 }
82
83 autosuspend_enabled = true;
84 return 0;
85}
86
87int autosuspend_disable(void)
88{
89 int ret;
90
91 ret = autosuspend_init();
92 if (ret) {
93 return ret;
94 }
95
96 ALOGV("autosuspend_disable\n");
97
98 if (!autosuspend_enabled) {
99 return 0;
100 }
101
102 ret = autosuspend_ops->disable();
103 if (ret) {
104 return ret;
105 }
106
107 autosuspend_enabled = false;
108 return 0;
109}
diff --git a/libsuspend/autosuspend_autosleep.c b/libsuspend/autosuspend_autosleep.c
new file mode 100644
index 000000000..dd0dfefe7
--- /dev/null
+++ b/libsuspend/autosuspend_autosleep.c
@@ -0,0 +1,99 @@
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/stat.h>
22#include <sys/types.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 SYS_POWER_AUTOSLEEP "/sys/power/autosleep"
31
32static int autosleep_fd;
33static const char *sleep_state = "mem";
34static const char *on_state = "off";
35
36static int autosuspend_autosleep_enable(void)
37{
38 char buf[80];
39 int ret;
40
41 ALOGV("autosuspend_autosleep_enable\n");
42
43 ret = write(autosleep_fd, sleep_state, strlen(sleep_state));
44 if (ret < 0) {
45 strerror_r(errno, buf, sizeof(buf));
46 ALOGE("Error writing to %s: %s\n", SYS_POWER_AUTOSLEEP, buf);
47 goto err;
48 }
49
50 ALOGV("autosuspend_autosleep_enable done\n");
51
52 return 0;
53
54err:
55 return ret;
56}
57
58static int autosuspend_autosleep_disable(void)
59{
60 char buf[80];
61 int ret;
62
63 ALOGV("autosuspend_autosleep_disable\n");
64
65 ret = write(autosleep_fd, on_state, strlen(on_state));
66 if (ret < 0) {
67 strerror_r(errno, buf, sizeof(buf));
68 ALOGE("Error writing to %s: %s\n", SYS_POWER_AUTOSLEEP, buf);
69 goto err;
70 }
71
72 ALOGV("autosuspend_autosleep_disable done\n");
73
74 return 0;
75
76err:
77 return ret;
78}
79
80struct autosuspend_ops autosuspend_autosleep_ops = {
81 .enable = autosuspend_autosleep_enable,
82 .disable = autosuspend_autosleep_disable,
83};
84
85struct autosuspend_ops *autosuspend_autosleep_init(void)
86{
87 int ret;
88 char buf[80];
89
90 autosleep_fd = open(SYS_POWER_AUTOSLEEP, O_WRONLY);
91 if (autosleep_fd < 0) {
92 strerror_r(errno, buf, sizeof(buf));
93 ALOGE("Error opening %s: %s\n", SYS_POWER_AUTOSLEEP, buf);
94 return NULL;
95 }
96
97 ALOGI("Selected autosleep\n");
98 return &autosuspend_autosleep_ops;
99}
diff --git a/libsuspend/autosuspend_earlysuspend.c b/libsuspend/autosuspend_earlysuspend.c
new file mode 100644
index 000000000..2c2aa3661
--- /dev/null
+++ b/libsuspend/autosuspend_earlysuspend.c
@@ -0,0 +1,113 @@
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";
38
39static int autosuspend_earlysuspend_enable(void)
40{
41 char buf[80];
42 int ret;
43
44 ALOGV("autosuspend_earlysuspend_enable\n");
45
46 ret = write(sPowerStatefd, pwr_state_mem, strlen(pwr_state_mem));
47 if (ret < 0) {
48 strerror_r(errno, buf, sizeof(buf));
49 ALOGE("Error writing to %s: %s\n", EARLYSUSPEND_SYS_POWER_STATE, buf);
50 goto err;
51 }
52
53 ALOGV("autosuspend_earlysuspend_enable done\n");
54
55 return 0;
56
57err:
58 return ret;
59}
60
61static int autosuspend_earlysuspend_disable(void)
62{
63 char buf[80];
64 int ret;
65
66 ALOGV("autosuspend_earlysuspend_disable\n");
67
68 ret = write(sPowerStatefd, pwr_state_on, strlen(pwr_state_on));
69 if (ret < 0) {
70 strerror_r(errno, buf, sizeof(buf));
71 ALOGE("Error writing to %s: %s\n", EARLYSUSPEND_SYS_POWER_STATE, buf);
72 goto err;
73 }
74
75 ALOGV("autosuspend_earlysuspend_disable done\n");
76
77 return 0;
78
79err:
80 return ret;
81}
82
83struct autosuspend_ops autosuspend_earlysuspend_ops = {
84 .enable = autosuspend_earlysuspend_enable,
85 .disable = autosuspend_earlysuspend_disable,
86};
87
88struct autosuspend_ops *autosuspend_earlysuspend_init(void)
89{
90 char buf[80];
91 int ret;
92
93 ret = access(EARLYSUSPEND_WAIT_FOR_FB_SLEEP, F_OK);
94 if (ret < 0) {
95 return NULL;
96 }
97
98 ret = access(EARLYSUSPEND_WAIT_FOR_FB_WAKE, F_OK);
99 if (ret < 0) {
100 return NULL;
101 }
102
103 sPowerStatefd = open(EARLYSUSPEND_SYS_POWER_STATE, O_RDWR);
104
105 if (sPowerStatefd < 0) {
106 strerror_r(errno, buf, sizeof(buf));
107 ALOGE("Error opening %s: %s\n", EARLYSUSPEND_SYS_POWER_STATE, buf);
108 return NULL;
109 }
110
111 ALOGI("Selected early suspend\n");
112 return &autosuspend_earlysuspend_ops;
113}
diff --git a/libsuspend/autosuspend_ops.h b/libsuspend/autosuspend_ops.h
new file mode 100644
index 000000000..698e25be8
--- /dev/null
+++ b/libsuspend/autosuspend_ops.h
@@ -0,0 +1,29 @@
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#ifndef _LIBSUSPEND_AUTOSUSPEND_OPS_H_
18#define _LIBSUSPEND_AUTOSUSPEND_OPS_H_
19
20struct autosuspend_ops {
21 int (*enable)(void);
22 int (*disable)(void);
23};
24
25struct autosuspend_ops *autosuspend_autosleep_init(void);
26struct autosuspend_ops *autosuspend_earlysuspend_init(void);
27struct autosuspend_ops *autosuspend_wakeup_count_init(void);
28
29#endif
diff --git a/libsuspend/autosuspend_wakeup_count.c b/libsuspend/autosuspend_wakeup_count.c
new file mode 100644
index 000000000..b038e20f5
--- /dev/null
+++ b/libsuspend/autosuspend_wakeup_count.c
@@ -0,0 +1,182 @@
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
35static int state_fd;
36static int wakeup_count_fd;
37static pthread_t suspend_thread;
38static sem_t suspend_lockout;
39static const char *sleep_state = "mem";
40
41static void *suspend_thread_func(void *arg)
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
96static 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
115static 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
134struct autosuspend_ops autosuspend_wakeup_count_ops = {
135 .enable = autosuspend_wakeup_count_enable,
136 .disable = autosuspend_wakeup_count_disable,
137};
138
139struct 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
174err_pthread_create:
175 sem_destroy(&suspend_lockout);
176err_sem_init:
177 close(wakeup_count_fd);
178err_open_wakeup_count:
179 close(state_fd);
180err_open_state:
181 return NULL;
182}
diff --git a/libsuspend/include/suspend/autosuspend.h b/libsuspend/include/suspend/autosuspend.h
new file mode 100644
index 000000000..f56fc6acb
--- /dev/null
+++ b/libsuspend/include/suspend/autosuspend.h
@@ -0,0 +1,48 @@
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#ifndef _LIBSUSPEND_AUTOSUSPEND_H_
18#define _LIBSUSPEND_AUTOSUSPEND_H_
19
20#include <sys/cdefs.h>
21
22__BEGIN_DECLS
23
24/*
25 * autosuspend_enable
26 *
27 * Turn on autosuspend in the kernel, allowing it to enter suspend if no
28 * wakelocks/wakeup_sources are held.
29 *
30 *
31 *
32 * Returns 0 on success, -1 if autosuspend was not enabled.
33 */
34int autosuspend_enable(void);
35
36/*
37 * autosuspend_disable
38 *
39 * Turn off autosuspend in the kernel, preventing suspend and synchronizing
40 * with any in-progress resume.
41 *
42 * Returns 0 on success, -1 if autosuspend was not disabled.
43 */
44int autosuspend_disable(void);
45
46__END_DECLS
47
48#endif