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