两个处理器
Application Processor (AP):
AP是ARM架构的处理器,用于运行Linux+Android系统。
Baseband Processpr (BP):
BP用于运行实时操作系统(RTOS),运行手机射频通信控制软件。
非通话时间BP能耗很低;而AP由于需要运行操作系统、用户界面和应用程序,只要处于非休眠状态能耗相对BP要高出很多,执行图形运算会更高。
让系统保持“清醒”
当手机灭屏状态下保持一段时间后,系统会进入休眠,一些后台任务比如网络下载,播放音乐会得不到正常的执行。WakeLock API可以确保应用程序中关键代码的正确执行,使应用程序有能力控制AP的休眠状态。
一种锁机制
当应用申请了WakeLock,WakeLock会阻止AP挂起,系统无法进入休眠,即使在灭屏的状态下,应用要执行的任务依然不会被打断。当所有WakeLock被释放(解锁/超时),系统会挂起启动休眠机制进入休眠。
使用WakeLock
<!--WakeLock需要的权限-->
<uses-permission android:name="android.permission.WAKE_LOCK"/>
PowerManager pm= (PowerManager) this.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wakeLock=pm.newWakeLock(PowerManager.ON_AFTER_RELEASE|PowerManager.PARTIAL_WAKE_LOCK,"Tag");
//申请WakeLock
wakeLock.acquire();
//... do work...
//释放wakeLock
//当使用wakeLock.acquire(timeout)的方式时系统会自动释放
wakeLock.release();
WakeLock的分类和Flag
分类
- PARTIAL_WAKE_LOCK: 灭屏,关闭键盘背光的情况下,CPU依然保持运行。
- PROXIMITY_SCREEN_OFF_WAKE_LOCK: 基于距离感应器熄灭屏幕。最典型的运用场景是我们贴近耳朵打电话时,屏幕会自动熄灭。
- SCREEN_DIM_WAKE_LOCK
SCREEN_BRIGHT_WAKE_LOCK
FULL_WAKE_LOCK
三种过时方法,它们的目的是保持屏幕常亮。
官方建议使用:
//不需要申请WakeLock和权限
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- DOZE_WAKE_LOCK/DRAW_WAKE_LOCK: 隐藏的分类,系统级别才会用到。
Flag
- ACQUIRE_CAUSES_WAKEUP: 点亮屏幕,比如应用接收到通知后,屏幕亮起。
- ON_AFTER_RELEASE: 释放WakeLock后,屏幕不马上熄灭。
- UNIMPORTANT_FOR_LOGGING: 隐藏的flag,系统级别才会用到。
其他方法
//判断是否已经获取WakeLock
wakeLock.isHeld();
//是否引用计数器
wakeLock.setReferenceCounted(false);
默认true开启引用计数器,如果一个WakeLock acquire了多次也必须release多次才能释放掉。但是如果释放次数比acquire多则会抛出RuntimeException(Tag)异常。
false关闭引用计数器时,无论 acquire() 了多少次,只要通过一次 release()即可解锁。
PS:PowerManager.WakeLock 的计数机制并只是对同一把锁被申请/释放的次数进行了统计再正去操作。
简单的debug方法
测试代码
/**
* @Author: 吃茶泡饭丶
* @CreateDate: 2018/9/3
*/
public class WakeLockActivity extends BaseActivity {
private PowerManager.WakeLock wakeLock;
@Override
protected void onResume() {
PowerManager pm = (PowerManager) this.getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.ON_AFTER_RELEASE
| PowerManager.PARTIAL_WAKE_LOCK, "Tag");
//申请WakeLock
wakeLock.acquire();
super.onResume();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_wake_lock);
//... do work...
}
@Override
protected void onPause() {
//释放wakeLock
//当使用wakeLock.acquire(timeout)的方式时系统会自动释放
wakeLock.release();
super.onPause();
}
}
通过adb 命令
adb shell dumpsys "power|grep -i wake"
and
$ adb shell dumpsys power|grep -i wake
进入onResume申请WakeLock,dumpsys的信息
no_cached_wake_locks=true
mWakefulness=Awake
mWakefulnessChanging=false
mWakeLockSummary=0x1
mLastWakeTime=509144080 (30113 ms ago)
mHoldingWakeLockSuspendBlocker=true
mWakeUpWhenPluggedOrUnpluggedConfig=true
mWakeUpWhenPluggedOrUnpluggedInTheaterModeConfig=false
mDoubleTapWakeEnabled=false
Wake Locks: size=1
mLock:176961948 PARTIAL_WAKE_LOCK 'Tag' ON_AFTER_RELEASE ACQ=-2s581ms (uid=10155 pid=26429)
PowerManagerService.WakeLocks: ref count=1
Proxyed WakeLocks State
进入onPause释放WakeLock,dumpsys的信息
no_cached_wake_locks=true
mWakefulness=Awake
mWakefulnessChanging=false
mWakeLockSummary=0x0
mLastWakeTime=509144080 (271089 ms ago)
mHoldingWakeLockSuspendBlocker=false
mWakeUpWhenPluggedOrUnpluggedConfig=true
mWakeUpWhenPluggedOrUnpluggedInTheaterModeConfig=false
mDoubleTapWakeEnabled=false
Wake Locks: size=0
PowerManagerService.WakeLocks: ref count=0
Proxyed WakeLocks State
准确的debug方法
使用battery historian 工具,在应用运行一段时间后抓取bugreport查看wakelock申请情况。
https://github.com/google/battery-historian 需要搭建GO语言环境