但是 C program (大部分是 daemon, service),要知道 suspend/wakeup 的時機,好像就沒有 signal 之類的方法。
在
base/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
看到一個方法。
就是去讀 /sys/power/wait_for_fb_sleep, 和 wait_for_fb_wake
這兩個 sysfs 的 node 是 kernel/power/fbearlysuspend.c 提供的:
static ssize_t wait_for_fb_sleep_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
char *s = buf;
int ret;
ret = wait_event_interruptible(fb_state_wq,
fb_state != FB_STATE_DRAWING_OK);
if (ret && fb_state == FB_STATE_DRAWING_OK)
return ret;
else
s += sprintf(buf, "sleeping");
return s - buf;
}
其中有 wait_event_interruptible( ),
所以在 read /sys/power/wait_for_fb_sleep 時,會被 block 住,直到 fb_state != FB_STATE_DRAWING_OK 時,才會 恢復執行 。
看看 surfaceblinger 的 code:
static char const * kSleepFileName = "/sys/power/wait_for_fb_sleep";
...
...
fd = open(kSleepFileName, O_RDONLY, 0);
do {
err = read(fd, &buf, 1);
} while (err < 0 && errno == EINTR);
close(fd);
LOGW_IF(err<0, "ANDROID_WAIT_FOR_FB_SLEEP failed (%s)", strerror(errno));
if (err >= 0) {
sp<urfaceFlinger> flinger = mFlinger.promote();
LOGD("About to give-up screen, flinger = %p", flinger.get());
if (flinger != 0) {
mBarrier.close();
flinger->screenReleased(0);
mBarrier.wait();
}
}
在 read( wait_for_fb_sleep ) 時,會被 block 住,直到 kernel run 到earlysuspend 後,才會繼續,earlysuspend 的時機是在 call driver suspend 之前,所以在 logcat 可以看到:
InputManager-JNI 在 call android_server_PowerManagerService_goToSleep 後,會有:
libharware jni code, set_screen_state 0
然後就是
/D/SurfaceFlinger(2401): About to give-up screen, flinger = 0x8c830對照上面的 code,就是 read( ) 之後。
SurfaceFlinger 在做完 suspend 要作的事後,就要等 wakeup 了,
所以接著的 code 就是:
static char const * kWakeFileName = "/sys/power/wait_for_fb_wake";
...
...
fd = open(kWakeFileName, O_RDONLY, 0);
do {
err = read(fd, &buf, 1);
} while (err < 0 && errno == EINTR);
close(fd);
LOGW_IF(err<0, "ANDROID_WAIT_FOR_FB_WAKE failed (%s)", strerror(errno));
if (err >= 0) {
sp<SurfaceFlinger> flinger = mFlinger.promote();
LOGD("Screen about to return, flinger = %p", flinger.get());
if (flinger != 0)
flinger->screenAcquired(0);
}
return true;
馬上 read ( wait_for_fb_wake )
在 kernel 中,這個 attrib 是:
ret = wait_event_interruptible(fb_state_wq,
fb_state == FB_STATE_DRAWING_OK);
if (ret && fb_state != FB_STATE_DRAWING_OK)
return ret;
else
s += sprintf(buf, "awake");
return s - buf;
一樣,是等 fb_state == FB_STATE_DRAWING_OK
所以在 system logcat,libhardware power jni 設完 set_screen_state 1 後,
就是
D/SurfaceFlinger (2401): Screen about to return, flinger = 0x8c830
仿照 Surfaceflinger 的 code,這樣就可以得到 suspend/ wakeup 的時間:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <fcntl.h> | |
#include <errno.h> | |
int main(int argc, char* argv[]) | |
{ | |
int fd; | |
int err; | |
char buf; | |
printf("start!!\n"); | |
while(1) { | |
fd = open("/sys/power/wait_for_fb_sleep",O_RDONLY,0); | |
printf("wait_for_fb_sleep\n"); | |
do { | |
err = read(fd,&buf,1); | |
} while (err < 0 && errno == EINTR); | |
close(fd); | |
printf("suspend\n"); | |
fd = open("/sys/power/wait_for_fb_wake",O_RDONLY,0); | |
printf("wait_for_fb_wake\n"); | |
do { | |
err = read(fd, &buf,1); | |
} while (err < 0 && errno == EINTR); | |
close(fd); | |
printf("wakeup\n"); | |
} | |
printf("Over\n"); | |
return 0; | |
} |
沒有留言:
張貼留言