文章一:
power按键事件上报给android系统,最终由windownmanager接收到,当有按键事件时判断是否需要休眠后唤醒系统,然后调用powermanager系统服务去写/sys/power/state节点.
此节点的写函数里判断收到的内容,来执行android的休眠early_suspend/唤醒late_resume流程.
private int setScreenStateLocked(boolean on) 电源管理服务: frameworks/base/services/java/com/android/server/PowerManagerService.java
int err = Power.setScreenState(on);
在文件frameworks/base/core/java/android/os/Power.java定义
79 public static native int setScreenState(boolean on);
具体实现在:frameworks/base/core/jni/android_os_Power.cpp
static int setScreenState(JNIEnv *env, jobject clazz, jboolean on);
set_screen_state(on); 在文件hardware/libhardware_legacy/power/power.c中定义并实现
write(g_fds[REQUEST_STATE], buf, len); 写/sys/power/state节点
向节点写内容会调用kernel/power/main.c的写函数:
static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,const char *buf, size_t n)
request_suspend_state(state); 调用此函数: 具体实现在./kernel/power/earlysuspend.c中
state: 为休眠则调用early_suspend_work android early_suspen工作队列
为唤醒则调用late_resume_work android late_resume_work工作队列
drivers/video/samsung/s3cfb_main.c中早已经注册屏幕开关
register_early_suspend(&fbdev[i]->early_suspend);
所以
为休眠则调用early_suspend_work中的屏幕休眠函数:
s3cfb_early_suspend()
backlight_on()---->s3cfb_backlight_on() 在文件arch/arm/plat-s5p/dev-fimd-s5p.c中定义 npd->backlight_on = s3cfb_backlight_on;
s3cfb_backlight_on中直接操作用来控制lcd的gpio关闭屏幕 arch/arm/mach-exynos/setup-fb-s5p.c
为唤醒时调用late_resume_work中的屏幕唤醒函数:
s3cfb_late_resume()
backlight_off()---->s3cfb_backlight_off() 在文件arch/arm/plat-s5p/dev-fimd-s5p.c中定义 npd->backlight_off = s3cfb_backlight_off;
s3cfb_backlight_off中直接操作用来控制lcd的gpio使能屏幕
执行完所有的early_suspend后执行解锁main_wake_lock,以便休眠.
wake_unlock(&main_wake_lock);
mod_timer(&expire_timer, jiffies + has_lock); 在文件/kernel/power/wakelock.c中
此函数将启用expire_timer定时器,定时器内容即expire_wake_locks
340 static DEFINE_TIMER(expire_timer, expire_wake_locks, 0, 0);
有四种方式可以引起休眠
①在wake_unlock()中, 如果发现解锁以后没有任何其他的wake lock了, 就开始休眠
②在定时器到时间以后, 定时器的回调函数会查看是否有其他的wake lock, 如果没有, 就在这里让系统进入睡眠
③在wake_lock() 中, 对一个wake lock加锁以后, 会再次检查一下有没有锁, 刚加上锁,为什么要检查,有用吗????
④按power键,调用earlysuspend.使系统或应用程序释放锁.从而调用上述三个函数进入休眠
if(has_lock ==0)
queue_work(suspend_work_queue,&suspend_work); 由DECLARE_WORK(suspend_work, suspend);知道,队列中的内容即suspend函数.
suspend(); kernel/power/wakelock.c
pm_suspend(requested_suspend_state);
enter_state(state); kernel/power/suspend.c
suspend_devices_and_enter(state);
suspend_enter(state);
suspend_ops->enter(state); -->调用平台相关的休眠函数,定义在中arch/arm/plat-samsung/pm.c:379:static const struct platform_suspend_ops s3c_pm_ops
即s3c_pm_enter
s3c_pm_arch_stop_clocks() --> 休眠时执行的的最后一个函数.系统停在此处,等待中断或rtc等唤醒源唤醒.
从此处开始唤醒流程
enable_nonboot_cpus();
suspend_test_start(); ---------->kernel已经被唤醒,当按键或中断来临后可以执行中断函数,上报唤醒事件.对于外部中断来说,上报power按键事件.
pm_restore_gfp_mask(); kernel/power/suspend.c
enter_state(state);
pm_suspend(suspend_state_t state);
suspend(); kernel/power/wakelock.c
文章二:
Android系统关机或重启的几种实现方式:
(1)发送广播方式
(2)通过init.rc启动系统服务来运行sh文件
(3)Runtime调用Linux-shell
(4)PowerManager reboot以及反射调用PowerManagerService shutdown
具体说明:一. 发送广播方式
Broadcast是Android的四大基本组件之一,也就是我们常说的广播。Android系统本身就包含了许多广播,时时刻刻在监听着系统中注册的每一个广播并随时准备响应操作。其中,就有关于关机或重启的广播:Intent.ACTION_REQUEST_SHUTDOWN和Intent.ACTION_REBOOT,通过发送这两个广播,Android就能自动接收广播,并响应关机或重启的操作。ACTION_REQUEST和ACTION_REBOOT是Intent.java是声明的两个字符串常量
public static final String ACTION_REBOOT =
"android.intent.action.REBOOT";
public static final String ACTION_REQUEST_SHUTDOWN = "android.intent.action.ACTION_REQUEST_SHUTDOWN";
//广播方式关机重启
case R.id.shutdown_btn1:
Log.v(TAG, "broadcast->shutdown");
Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
//其中false换成true,会弹出是否关机的确认窗口
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
break;
case R.id.reboot_btn1:
Log.v(TAG, "broadcast->reboot");
Intent intent2 = new Intent(Intent.ACTION_REBOOT);
intent2.putExtra("nowait", 1);
intent2.putExtra("interval", 1);
intent2.putExtra("window", 0);
sendBroadcast(intent2);
break;
需要注意的几点是:
第一,如前面所说,需要将APP提升至系统权限,具体做法是在AndroidMenifest.xml中添加如下代码
android:sharedUserId="android.uid.system"
第四,由于需要在源码中编译项目,所以需要为项目编写mk文件,在项目根目录下添加Android.mk文件,内容如下所示:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := PowerActionDemo
LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE)
最后,将编译生成的apk文件,通过adb push到机器上就可以验证功能了。
二. 通过init.rc启动系统服务来运行sh文件
Android启动文件系统后调用的会调用第一个应用程序是/init,此文件一个很重要的内容就是解析了init.rc和init.xxx.rc,然后执行解析出来的任务。而init.rc,可以在系统的初始化过程中进行一些简单的初始化操作。利用这一点,可以编写简单的关机或重启的sh脚本文件,通过系统init解析,执行相应的关机或重启操作。
1.首先,编写关机和重启的sh脚本。比如,新建
重启脚本 system_reboot.sh,内容如下:
#!/system/bin/sh
reboot
关机脚本 system_shutdown.sh
#!/system/bin/sh
reboot -p
2. 编写Android.mk编译脚本,目的是在源码编译的时候,将这两个sh文件一起编译到/system/bin目录下
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_PREBUILT_EXECUTABLES := system_shutdown.sh system_reboot.sh
LOCAL_MODULE_TAGS := optional
include $(BUILD_MULTI_PREBUILT)
service system_shutdown /system/bin/system_shutdown.sh
oneshot
disabled
service system_reboot /system/bin/system_reboot.sh
oneshot
disabled
disabled 表示禁用服务,此服务开机时不会自动启动,但是可以在应用程序中手动启动它。
4.新建一个目录,比如poweraction, 将以上的Android.mk , system_shutdown.sh, system_reboot.sh放在这个目录下,然后将poweraction这个目录拷贝到Android系统中,比如device路径下面。然后,编译Android源码,源码编译完成后, 查看生成的out/.../system/bin下面是不是包含system_shutdown.sh, system_reboot.sh两个sh文件,如果有,则说明编译成功。
5.最后,启动系统服务,进行关机或重启。
//启动系统服务进行关机或重启
case R.id.shutdown_btn2:
Log.v(TAG, "system service->shutdown");
SystemProperties.set("ctl.start", "system_shutdwon");
break;
case R.id.reboot_btn2:
Log.v(TAG, "system service->reboot");
SystemProperties.set("ctl.start", "system_reboot");
break;
三. Runtime调用Linux-shell
我们知道,Runtime这个Java类是可以用来调用并执行shell命令的,而Android虚拟机是支持Linux-shell语言的,基于这一点,可以利用Runtime来执行 关机或重启的shell命令,这一点和上面介绍的方式二原理上大致相同。功能代码如下:
//Runtime执行linux-shell
case R.id.shutdown_btn3:
try{
Log.v(TAG, "root Runtime->shutdown");
//Process proc =Runtime.getRuntime().exec(new String[]{"su","-c","shutdown"}); //关机
Process proc =Runtime.getRuntime().exec(new String[]{"su","-c","reboot -p"}); //关机
proc.waitFor();
}catch(Exception e){
e.printStackTrace();
}
break;
case R.id.reboot_btn3:
try {
Log.v(TAG, "root Runtime->reboot");
Process proc =Runtime.getRuntime().exec(new String[]{"su","-c","reboot "}); //关机
proc.waitFor();
}catch (Exception ex){
ex.printStackTrace();
}
break;
Runtime.getRuntime().exec(new String[]{"su","-c","shutdown"})
Runtime.getRuntime().exec(new String[]{"su","-c","reboot -p"});
四 . PowerManager reboot以及反射调用PowerManagerService shutdown
1. PowerManager提供了reboot等接口,因此,利用PowerManager实现重启,就比较简单。
PowerManager pManager=(PowerManager) getSystemService(Context.POWER_SERVICE); //重启到fastboot模式
pManager.reboot("");
framework/base/core/java/android/os/IPowerManage.aidl
try {
//获得ServiceManager类
Class> ServiceManager = Class
.forName("android.os.ServiceManager");
//获得ServiceManager的getService方法
Method getService = ServiceManager.getMethod("getService", java.lang.String.class);
//调用getService获取RemoteService
Object oRemoteService = getService.invoke(null,Context.POWER_SERVICE);
//获得IPowerManager.Stub类
Class> cStub = Class
.forName("android.os.IPowerManager$Stub");
//获得asInterface方法
Method asInterface = cStub.getMethod("asInterface", android.os.IBinder.class);
//调用asInterface方法获取IPowerManager对象
Object oIPowerManager = asInterface.invoke(null, oRemoteService);
//获得shutdown()方法
Method shutdown = oIPowerManager.getClass().getMethod("shutdown",boolean.class,boolean.class);
//调用shutdown()方法
shutdown.invoke(oIPowerManager,false,true);
} catch (Exception e) {
Log.e(TAG, e.toString(), e);
}
文章三:
文章四:
linux下休眠/待机命令
if you
# cat /sys/power/state
mem disk
you can
echo “mem” > /sys/power/state 这相当于待机
echo “disk” > /sys/power/state 这相当于休眠
from http://Linux.chinaunix.NET/bbs/viewthread.PHP?tid=1057578
命令行中执行如下:
[root@fsc feng]# file /sys/power/state
/sys/power/state: ASCII text
[root@fsc feng]# cat /sys/power/state
standby mem disk
[root@fsc feng]# echo “mem”>/sys/power/state
/sys/power/state是个文本文档,一个”mem”的导向就能使系统挂起到内存(待机)或硬盘(休眠),实在太神奇了,一定要深入学习了解一下其中原因!
—————————————–
from http://www.xxlinux.com/linux/article/accidence/technique/20080303/14073.html
在作之前,先检查一下你的内核能支持哪些方式:
# cat /sys/power/state
standby disk
在实际项目中我执行后的结果为:
# cat /sys/power/state
freeze mem
1. 睡眠 (sleep)
睡眠可能有两种方式:mem和standby,这两种方式都是suspend to RAM,简称STR,只是standby耗电更多一些,返回到正常工作方式时间更短一些而已。
只需要
# echo standby > /sys/power/state
就可以了。
2. 休眠 (hibernation)
休眠也有两种方式:shutdown和platform。shutdown是通常的方式,比较可靠一些。如果你的系统上ACPI支持非常好,那就有机会支持platform方式。激活的方式稍有不同:
# echo platform > /sys/power/disk; echo disk > /sys/power/state
or
# echo shutdown > /sys/power/disk; echo disk > /sys/power/state
注意休眠有一个前提,就是在系统启动时需要指定resume设备,也就是休眠的镜像需要保存的分区。一般都用swap分区来做。
指定方式是:
kernel /boot/vmlinuz root=/dev/sda1 resume=/dev/sda2 vga=0×314 …
这样在系统启动时,内核会检查resume中的内容,如果存在上次休眠的镜像,那内核便会将镜像读入内存,恢复正常工作状态。
文章五
系统挂起(Suspend)是电源管理(APM&ACPI)的一个特性,给用户带来了很大的方便。Linux在2.6系列核心中对电源管理有了较好的支持,下面就谈谈linux对系统挂起的支持情况。
Linux对系统挂起的支持
Linux同时提供了对APM和ACPI的支持,当时两者是不兼容的,同一时刻只能有一种机制工作。由于ACPI的优越性,所以现在Linux将ACPI设为缺省的电源管理方案。对于一些比较旧的主板,如果其BIOS中ACPI的实现在2000年以前,那么Linux自动启用APM(可以通过核心命令行参数acpi=force来强制启用ACPI)。如果你下主板BIOS中对ACPI的支持有些问题导致Linux工作不正常,那么还可以使用核心命令行参数acpi=off来强制禁用ACPI,这样Linux会自动启用APM电源管理。
Linux现在主要支持三种ACPI的节电方式:
S1:Stopgrant,即待机(standby)模式。显示屏自动断电,只是主机通电。这时敲任意键即可恢复原来状态。待机模式
S2 S3:STR(Suspend To Ram),即挂起到内存。系统把当前信息储存在内存中,只有内存等几个关键部件通电,这时计算机处在高度节电状态。此时系统不能从键盘唤醒。手工唤醒的方法只能是按前面板上的电源按钮。唤醒后,计算机从内存中读取信息很快恢复到原来状态。
睡眠可能有两种方式:mem和standby,这两种方式都是suspend to RAM,简称STR,只是standby耗电更多一些,返回到正常工作方式时间更短一些而已。
S4:STD(Suspend To Disk),即挂起到硬盘,也即休眠。计算机自动关机,关机前将当前数据存储在硬盘上,用户下次按开关键开机时计算机将无须启动操作系统,直接从硬盘读取数据,恢复原来状态。休眠模式
在Linux下查看核心支持ACPI情况的方法如下:
2.4核心下:
# cat /proc/acpi/sleep
S0 S1 S3 S4 S5
2.6核心下:
# cat /sys/power/state
standby mem disk
在实际项目中我执行后的结果为:
# cat /sys/power/state
freeze mem上面的输出可知,我们系统中核心同时支持三种节电模式。
在/sys/power目录下还有一个文件:disk,文件的内容可以如下:
shutdown: 将系统状态保存到磁盘,让BIOS关闭计算机;
platform: 将系统状态保存到磁盘,让BIOS关闭计算机,并且点亮挂起指示灯;
firmware: 让BIOS自己将系统状态保存,并且关闭计算机,需要BIOS自己有挂起磁盘。大部分工作都由BIOS完成,对操作系统是透明的;
进入这三种节电模式的方法如下:
#echo standby > /sys/power/state ---->挂起(S1)
#echo mem > /sys/power/state ---->挂起到内存(S3)
#echo shutdown > /sys/power/disk; echo disk > /sys/power/state ---->挂起到磁盘(S4)#echo platform > /sys/power/disk; echo disk > /sys/power/state
Linux下的磁盘挂起(STD)是通过swsusp机制实现的:将系统当前状态保存的内存后,再把内存内容写入交换分区(swap)。这里要求交换分区容量最好大于内存容量。系统挂起到磁盘后,下次启动的时候需要向核心传递命令行参数resume=/dev/hdaX(/dev/hdaX是系统中的交换分区),这样系统就能够很快恢复到关机时的状态。
还有一个非正式的核心补丁可以实现STD:Software Suspend 2。该项目是一个快速发展的项目,设计上教swsusp有一些优势,但是还没有集成到核心正式发布中,实现方式与swsusp基本相同。
虽然Linux提供了系统挂起的机制,但是执行上面的挂起操作不一定能够成功。一方面,这些操作除了需要BIOS支持以外,还需要外围硬件设备能够兼容,即设备支持节电状态,支持从节电状态或断电状态恢复;另一方面,这些设备驱动必须能够接收电源管理指令。目前,系统挂起的主要障碍就是那些还不太完善的驱动程序,如USB、显卡、声卡驱动等。
当然,现在Linux核心对系统挂起的支持还有待改进,主要表现在:
1 不支持SMP系统。
2 不支持大内存(>4G)。
3 核心中许多模块需要增加电源管理的支持。
4 缺少上层配置程序。
不过以放心,所有的问题内核黑客们都能够解决!
http://www.tuicool.com/articles/MvUf6v
http://www.wowotech.net/linux_kenrel/std_str_func.html