需求:Android待机的时候,网络延时关闭,即屏幕可以自己黑屏,但是WiFi/eth/ppoe要延时关闭。
以下先记录几个点:
1、ACTION_SCREEN_OFF这个anction标示待机,我都是跟这个action的
2、ppoe和eth的关闭可以使用wakelock来让系统无法待机,等待延时做完工作后,在释放wakelock。
wakelock在系统还持有一个wakelock时,系统是无法待机的,使用方法如下:
{@samplecode
* PowerManager pm = (PowerManager)mContext.getSystemService(
* Context.POWER_SERVICE);
* PowerManager.WakeLock wl = pm.newWakeLock(
* PowerManager.SCREEN_DIM_WAKE_LOCK
* | PowerManager.ON_AFTER_RELEASE,
* TAG);
* wl.acquire();
* // ... do work...
* wl.release();
* }
3、
在WifiController中,我们可以看到对于CMD_SCREEN_OFF这个消息的处理处,有以下注释
/*
* Set a timer to put Wi-Fi to sleep, but only if the screen is off
* AND the "stay on while plugged in" setting doesn't match the
* current power conditions (i.e, not plugged in, plugged in to USB,
* or plugged in to AC).
*/
WiFi的关闭有几种情况的,貌似在原生的Android WiFi的高级设置选项中,就有选择WiFi休眠策略:一般就是从不休眠和默认用的比较多,
当选择从不休眠时,其实就算进入待机模式,只要WiFi是连着的,WiFi也不会断掉。
当选择默认的话,就是要延时一段时间:默认是15mins,这个时间值也可以从provider获取:
<strong> private void readWifiIdleTime() {
mIdleMillis = Settings.Global.getLong(mContext.getContentResolver(),
Settings.Global.WIFI_IDLE_MS, DEFAULT_IDLE_MS);
}</strong>
跟去frameworks\base\core\java\android\provider\Settings.java可以看到相关策略的介绍
/**
* The policy for deciding when Wi-Fi should go to sleep (which will in
* turn switch to using the mobile data as an Internet connection).
* <p>
* Set to one of {@link #WIFI_SLEEP_POLICY_DEFAULT},
* {@link #WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED}, or
* {@link #WIFI_SLEEP_POLICY_NEVER}.
*/
public static final String WIFI_SLEEP_POLICY = "wifi_sleep_policy";
/**
* Value for {@link #WIFI_SLEEP_POLICY} to use the default Wi-Fi sleep
* policy, which is to sleep shortly after the turning off
* according to the {@link #STAY_ON_WHILE_PLUGGED_IN} setting.
*/
public static final int WIFI_SLEEP_POLICY_DEFAULT = 0;
/**
* Value for {@link #WIFI_SLEEP_POLICY} to use the default policy when
* the device is on battery, and never go to sleep when the device is
* plugged in.
*/
public static final int WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED = 1;
/**
* Value for {@link #WIFI_SLEEP_POLICY} to never go to sleep.
*/
public static final int WIFI_SLEEP_POLICY_NEVER = 2;
要注意的是,我跟的两个Android 4.4版本的代码,WiFi休眠策略默认都是选择从不休眠的。在frameworks\base\packages\SettingsProvider\res\values\default.xml中可以修改。这里0对应的是要休眠,2是一直开着。
<!-- 0 == never, 1 == only when plugged in, 2 == always -->
<integer name="def_wifi_sleep_policy">2</integer>
会在wificontroller中去获取这个值,可以看到现在默认也是设置为never
private void readWifiSleepPolicy() {
mSleepPolicy = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.WIFI_SLEEP_POLICY,
Settings.Global.WIFI_SLEEP_POLICY_NEVER);
}
以下再分享一篇关于Android待机流程的文章,来源处 http://blog.sina.com.cn/s/blog_759dc36b0100stax.html
睡眠/唤醒是嵌入式Linux非常重要的组成部分,因为优秀的睡眠唤醒机制可以是嵌入式设备尽可能的进入休眠状态,来延长电池的续航时间(这在移动终端消费类电子设备中是非常重要和有意义的!!)。但标准的Linux睡眠唤醒机制有其自身的一些缺陷(所有模块必须同时睡下或者唤醒),在某些情况下,这会导致能耗的白白浪费。因此Android在标准Linux睡眠唤醒的机制上作了新的改动(wake_lock唤醒、early_suspend和late_resume机制),从而很好的解决上面的问题。本文将以Android2.3.1版本为例,详细介绍标准Linux睡眠/唤醒是如何工作的,
比如:
当然还有其它的状态操作,在下面的内容中将有介绍。
Android在Linux内核原有的睡眠唤醒模块上基础上,主要增加了下面三个机制:
Early
Late
其基本原理如下:当启动一个应用程序的时候,它都可以申请一个wake_lock唤醒锁,每当申请成功之后都会在内核中注册一下(通知系统内核,现在已经有锁被申请),当应用程序在某种情况下释放wake_lock的时候,会注销之前所申请的wake_lock。特别要注意的是:只要是系统中有一个wake_lock的时候,系统此时都不能进行睡眠。但此时各个模块可以进行early_suspend。当系统中所有的wake_lock都被释放之后,系统就会进入真正的kernel的睡眠状态。在系统启动的时候会创建一个主唤醒锁main_wake_lock,该锁是内核初始化并持有的一个WAKE_LOCK_SUSPEND属性的非限时唤醒锁。因此,系统正常工作时,将始终因为该锁被内核持有而无法进入睡眠状态。也就是说在不添加新锁的情况下,只需将main_wake_lock
android/frameworks/base/core/java/android/os/PowerManager.java
android/frameworks/base/services/java/com/android/server/PowerManagerService.java
android/frameworks/base/core/java/android/os/
android/frameworks/base/core/jni/android_os_Power.cpp
android/hardware/libhardware_legacy/power/power.c
android/kernel/kernel/power/main.c
android/kernel/kernel/power/earlysuspend.c
android/kernel/kernel/power/suspend.c
android/kernel/kernel/power/wakelock.c
android/kernel/kernel/power/userwakelock.c
其余涉及到的都是内核kernel中的文件,它们的作用将在下面给予介绍。
下面我将分别以两条路线(第一:获得wakelock唤醒锁。第二:系统进入睡眠。)来分别说明各自的流程,让读者对android睡眠唤醒机制有更深入的理解!
android/os/PowerManager类中的public
public
}
而
public
}
我们可以看到在acquireWakeLockLocked
static
{
}
int
{
//
}
到现在为止,我们的代码流程已经走了一大半了,我们一开始介绍的android的上面几层Framework层、JNI层、HAL层都已经介绍了就剩下Kernel层了。下面就应该是和kernel层进行交互了。
我们先看一下android/kernel/kernel/power/main.c中的一段代码,我将会做简单的分析,之后你就会明白刚才上面所产生的疑问了。
#ifdef
power_attr(wake_lock);
power_attr(wake_unlock);
#endif
static
&state_attr.attr,
#ifdef
&pm_trace_attr.attr,
#endif
#ifdef
&pm_async_attr.attr,
#ifdef
&pm_test_attr.attr,
#endif
#ifdef
&wake_lock_attr.attr,
&wake_unlock_attr.attr,
#endif
#endif
NULL,
};
static
.attrs
};
#ifdef
struct
EXPORT_SYMBOL_GPL(pm_wq);
static
{
pm_wq
return
}
#else
static
#endif
static
{
int
if
return
power_kobj
if
return
return
}
core_initcall(pm_init);
这段代码虽然简短,但看起来是不是还是比较费劲,没关系,我们倒过来看就比较清楚了。上面代码中的sysfs_create_group(power_kobj,
#define
static
.attr =
.name
.mode
}, \
.show =
.store =
}
在该函数中##的作用通俗点讲就是“连接”的意思,比如power_attr(wake_lock),
.attr =
.name
.mode
}, \
.show =
.store =
}
函数wake_lock_store和wake_lock_show就定义在android/kernel/kernel/power/userwakelock.c
中。因此当我们对/sys/power/wake_lock进行操作的时候就会调用到userwakelock.c中定义的
wake_lock_store()函数。
int
{
//
}
initialize_fds(void)
{
}
其实这个函数中最和新的步骤就是open_file_descriptors(NEW_PATHS)
const
};
ssize_t
{
bad_name:
}
static
{
int
unsigned
long
spin_lock_irqsave(&list_lock,
type
BUG_ON(type
BUG_ON(!(lock->flags
#ifdef
if
if
pr_info("wakeup
wait_for_wakeup
lock->stat.wakeup_count++;
}
if
wake_unlock_stat_locked(lock,
lock->stat.last_time
}
#endif
if
lock->flags
#ifdef
lock->stat.last_time
#endif
}
list_del(&lock->link);
if
if
pr_info("wake_lock:
lock->name,
(timeout
lock->expires
lock->flags
list_add_tail(&lock->link,
}
if
pr_info("wake_lock:
lock->expires
lock->flags
list_add(&lock->link,
}
if
current_event_num++;
#ifdef
if
update_sleep_wait_stats_locked(1);
else
update_sleep_wait_stats_locked(0);
#endif
if
expire_in
else
expire_in
if
if
pr_info("wake_lock:
"%ld\n",
mod_timer(&expire_timer,
}
if
if
pr_info("wake_lock:
lock->name);
if
queue_work(suspend_work_queue,
}
}
spin_unlock_irqrestore(&list_lock,
}
有了上面第一部分的学习,再看第二部分的话,会容易很多。假如现在我们按了PAD上的power睡眠键,经过一些列的事件处理后,它会调用到PowerManager类中的
而该函数会调用到PowerManagerService类中的public
{
当我们在sys/power/state(android/hardware/libhardware_legacy/power/power.c)进行读写操作的时候,(linux/kernel/power/main.c)中的state_store()函数会被调用,在该函数中会分成两个分支:
static
{
#ifdef
#ifdef
#else
#endif
#endif
#ifdef
#ifdef
#else
#endif
#endif
Exit:
}
Android特有的earlysuspend:
Linux标准的suspend:
注意:如果CONFIG_EARLYSUSPEND宏开的话,kernel会先走earlysuspend,反之则直接走suspend;从这里开始就要分两个分支了,如果支持earlysuspend的话就进入
这两个函数分别在两个文件中kernel/kernel/power/earlysuspend.c和suspend.c。现在再回过头来看的话,感觉整个android中睡眠唤醒机制还是很清晰的。这两个函数体里又做了什么,在这里就不再做具体分析,大家可以自己对照代码或者上网查资料,因为本文的主旨是带读者从最上层应用层一直到最底层kernel层,把整个android的睡眠唤醒机制给走通。
PowerManager.java
PowerManagerService.java
PowerManagerService.java
PowerManagerService.java
PowerManagerService.java
Power.java
android_os_Power.cpp
power.c
main.c