ubuntu 在 R40e 上 還有 Debian 在 Sempron 2600 上

2012年12月19日 星期三

android : get suspend wakeup event in C code

在 android framework, app 中要知道 suspend/wakeup 的 時機,就收 SCREEN_OFF,SCREEN_OFF 這兩個 broadcast intent 就可以。

但是 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 的時間:

沒有留言:

標籤

網誌存檔