最近修复一个遗留的bug,定时检测,超过多长时间则弹出一个Tip,在debug跟进这个bug的时候,并没有发现问题,Timer和TimerTask实现的定时任务,但是在实际使用的时候,产品等很多人都遇到不弹Tip的问题。回过神来一想,应该是掉进了Android休眠机制的坑里了。趁此机会对Android的休眠机制进行一个总结。

Linux的休眠机制


       Android是基于Linux的,要理解Android的休眠机制,那就需要先了解Linux系统的电源状态。Linux系统的电源状态可以分为四种:On,Standby,Suspend-to-RAM,Suspend-to-disk.

  • On:表示处于工作状态(working),CPU、RAM等设备都处于工作状态。

  • Standby:CPU、RAM等设备依然处于通电状态,但是并没有进行工作,此时还是需要损耗小部分电。

  • Suspend-to-RAM:挂起到内存,简称待机。计算机将目前的运行状态等数据存放在内存,关闭硬 盘、外设等设备,进入等待状态。此时内存仍然需要电力维持其数据,但整机耗电很少;恢复时计算机从内存读出数据,回到挂起前的状态,恢复速度较快。

  • Suspend-to-disk:挂起到硬盘,简称休眠。把运行状态等数据存放在硬盘上某个文件或者某个特定的区域,关闭硬盘、外设等设备,进入关机状态。此时计算机完全关闭,不耗电。恢复时计算机从休眠文件/分区中读出数据,回到休眠前的状态,恢复速度较慢。

Linux支持的电源状态都记录在/sys/power/state中,Root的手机可以通过ADB进行查看,我的手机没有Root,只能看到目录,无法看到里面的内容。


AutoSleep


       Android系统包含AP和BP两个处理器,应用程序等都运行在AP处理器中,因此下面所说的Android休眠指的是AP。
       Android系统虽然是基于Linux的,但是它的AutoSleep并不支持上述所有的四种电源状态。首先,On 肯定是需要支持的,因为我们使用手机的时候正是出于On的电源状态,同时还支持Suspend-to-RAM的电源状态,Android系统休眠就是处于Suspend-to-RAM电源状态,根据上面的介绍,从Suspend-to-RAM恢复数据比Suspend-to-disk快,而耗电有点Standby少。

early_suspend与late_resume

       当我们的手机从亮屏到灭屏时,此时我们的应用还需要处于活跃的状态,但是为了节省电量,触摸屏、LCD等设备此时可以关闭了。而当我们的手机处于休眠状态时收到网络数据,需要应用程序处理时我们不希望触摸屏、LCD等设备开启;因此Android引入了early_suspend和late_resume.

  • early_suspend:当灭屏时,LCD、触摸屏等设备就会通过对应驱动,使其进入suspend状态,减少电量的损耗。

  • late_resume:对应early_suspend关闭的设备。系统休眠时,当应用收到网络数据,进行处理时,不会执行late_resume。

wake_lock 与 wake_unlock

       某些情况下,我们应用在后台需要处理一些数据,在处理数据的时候,不希望系统进入休眠,当处理完数据之后才能进入休眠状态。因此引入了wake_lock与wake_unlock机制。wake_lock机制一开始并不是Linux所支持的,而是由Android层实现的,后面由于Android的普及,Linux才进行支持。

  • wake_lock:当应用有数据需要处理,不希望系统马上进入休眠时,可以通过wake_lock,当有应用持有wake_lock时,系统不会进入休眠。当应用申请一个XXX的wake_lock时,会将XXX写入wake_lock文件中,,并标记为active。

  • wake_unlock:当应用处理完数据后,需要释放其所有持有的wake_lock,不然无法使系统进入休眠状态,耗费大量的电。当应用释放一个XXX的wake_lock时,会在wake_unlock中写入XXX,并将其标记的deactive.

AutoSleep流程



AlarmManager


       回到文章开头的那个bug,在系统休眠的时候,CPU已经停止工作了,应用的代码也没法被执行,如何定时弹出Tip呢。第一种方式就是在回到应用的时候再次判断时间,当超过时间就弹出Tip继续及时,采用这种方法解决了问题。但是当IM等即时通讯时,在系统休眠的情况下也需要及时通知消息,此时就需要采用另外的方式解决问题了。
       通过AlarmManager定时解决问题,前面提到在Android系统中,有两个处理器AP与BP,系统休眠中的CPU停止指的是AP处理器,而BP处理器处于正常工作的状态,当接受到网络数据等时,BP处理器会唤醒AP处理器来进行处理,而AlarmManager也是同理,定时通过BP处理器唤醒AP处理器,从而让AP处理器进行定时操作,然后AP处理器会在满足条件的情况下再次休眠。

Doze


       在Android 6.0时,引入了Doze模式。如果用户设备未插接电源、处于静止状态一段时间且屏幕关闭,设备会进入低电耗模式。 在低电耗模式下,系统会尝试通过限制应用对网络和 CPU 密集型服务的访问来节省电量。 这还可以阻止应用访问网络并推迟其作业、同步和标准闹铃。系统会定期退出低电耗模式一会儿,好让应用完成其已推迟的 Activity。在此维护时段内,系统会运行所有待定同步、作业和闹铃并允许应用访问网络。

在每个维护时段结束后,系统会再次进入低电耗模式,暂停网络访问并推迟作业、同步和闹铃。 随着时间的推移,系统安排维护时段的次数越来越少,这有助于在设备未连接至充电器的情况下长期处于不活动状态时降低电池消耗。一旦用户通过移动设备、打开屏幕或连接到充电器唤醒设备,系统就会立即退出低电耗模式,并且所有应用都将返回到正常 Activity。

在低电耗模式下,您的应用会受到以下限制:

  • 暂停访问网络

  • 系统将忽略 wake locks

  • 标准 AlarmManager 闹铃(包括 setExact() 和 setWindow())推迟到下一维护时段。如果您需要设置在低电耗模式下触发的闹铃,请使用setAndAllowWhileIdle() 或 setExactAndAllowWhileIdle(),触发闹铃的时间间隔都不能超过 9 分钟。一般情况下,使用 setAlarmClock() 设置的闹铃将继续触发,但系统会在这些闹铃触发之前不久退出低电耗模式。

  • 系统不执行 Wi-Fi 扫描

  • 系统不允许运行同步适配器

  • 系统不允许运行 JobScheduler

注意AlarmManager标准的闹铃也会被推迟,在定时执行任务不是均匀的执行,而是间隔时间越来越久。例如定时心跳推荐用setAndAllowWhileIdle() 或 setExactAndAllowWhileIdle()。

总结


  1. Android包含AP和BP两个处理器,系统休眠时AP停止运行,但BP依旧执行

  2. 定时任务推荐用AlarmManager

  3. Doze模式下,标准的Alarm会被推迟,推荐使用setAndAllowWhileIdle() 或 setExactAndAllowWhileIdle()

  4. Android系统浅休眠指early_suspend,此时AP处理器并没有停止,应用可以执行;Android系统深度休眠指标准的Linux Suspend-to-RAM,系统的状态保存在RAM中,AP处理器停止工作,应用也停止执行。

更多相关文章

  1. Android(安卓)如何自己定义控件的样式 Shape
  2. Android面试系列文章2018之Android部分之自定义View篇
  3. android 自定义SeekBar
  4. Android沉浸式状态栏、导航栏
  5. android中实现带图片和checkbox的listview
  6. Android(安卓)Battery 架构
  7. android 状态栏 时间 错误 adb连接
  8. Android状态机
  9. Android通讯:通话

随机推荐

  1. Android常用Manager
  2. Android(安卓)游戏与应用开发最佳学习路
  3. android 使用gdb调试的方式
  4. Android(安卓)软键盘问题总结
  5. Android(安卓)获取网络时间
  6. [置顶] Android4.2.2自增物理按键(framewo
  7. 关于cocos2dx的eclipse的"serializing cd
  8. PullToRefresh的简单使用
  9. android使用全局变量的两种方法
  10. android之实现底部TabHost