Hublog随手记录一些东西

手机锁屏之后 Linux Deploy 休眠问题

我在安卓手机安装了 Linux deploy,为了使 Linux deploy中的 Linux 稳定运行,已经设置了取消电池优化,并且也锁定了 Linux deploy 的后台,但是在手机息屏一段时间以后还是会出现断网或者ssh连接缓慢的问题。

我设置了每分钟都会将当前时间输出到文件中的定时任务,但是在息屏后一段时间以后脚本中的数据就不正常了。后面每一分钟有三条,而是输出时间有比较明显的延后现象。

文件中数据如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
2023年 03月 07日 星期二 16:41:01 CST
2023年 03月 07日 星期二 16:42:01 CST
2023年 03月 07日 星期二 16:43:01 CST
2023年 03月 07日 星期二 16:44:01 CST
2023年 03月 07日 星期二 16:45:01 CST
2023年 03月 07日 星期二 16:46:01 CST
2023年 03月 07日 星期二 16:47:01 CST
2023年 03月 07日 星期二 16:48:01 CST
2023年 03月 07日 星期二 16:49:01 CST
2023年 03月 07日 星期二 16:50:01 CST
2023年 03月 07日 星期二 17:14:53 CST
2023年 03月 07日 星期二 17:15:48 CST
2023年 03月 07日 星期二 17:17:32 CST
2023年 03月 07日 星期二 17:17:32 CST
2023年 03月 07日 星期二 17:20:07 CST
2023年 03月 07日 星期二 17:20:07 CST
2023年 03月 07日 星期二 17:20:07 CST

解决办法

关闭 Doze 和 App Standby

adb shell dumpsys deviceidle disable

adb shell am set-inactive ru.meefik.linuxdeploy false

创建定时任务,让应用一直持有唤醒锁:

1
2
3
4
5
6
7
#!/bin/bash
# Wake Lock 数量,为0说明 linux deploy 的唤醒锁被释放了
flag=`adb shell dumpsys power | grep WakeLocks | awk -F= '{print $2}'`
if [ $flag -eq 0 ]; then
    # 唤醒应用
    adb shell am start ru.meefik.linuxdeploy/.Launcher
fi

应用被操作时,如果没有唤醒锁,就会申请一个60分钟的唤醒锁,60分钟以后唤醒锁会被释放,程序会进入睡眠状态,如果时间较久,应用进入深度睡眠,进程会被挂起,此时进入ssh会非常慢,linux deploy 源码的 MainActivity.java onResume() 中有以下代码:

1
2
3
4
5
6
        // Wake lock
        if (PrefStore.isWakeLock(this)) {
            if (!wakeLock.isHeld()) wakeLock.acquire(60 * 60 * 1000L /*60 minutes*/);
        } else {
            if (wakeLock.isHeld()) wakeLock.release();
        }

相关命令 adb 命令:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# linux deploy 包名
ru.meefik.linuxdeploy

# 打开 linux deploy 应用
adb shell am start ru.meefik.linuxdeploy/.Launcher
# 查看 Doze 状态
adb shell dumpsys deviceidle
# 查看 App Standby 状态
adb shell am get-inactive ru.meefik.linuxdeploy
# 查看 wake lock 数量
adb shell dumpsys power | grep WakeLocks


# 添加 Doze 白名单
adb shell dumpsys deviceidle whitelist +<package name>
# 移除 Doze 白名单
adb shell dumpsys deviceidle whitelist -<packageName>
# 显示白名单列表
adb shell dumpsys deviceidle whitelist


#进入睡眠(Doze 模式):
# 拔出电源
adb shell dumpsys battery unplug
adb shell dumpsys deviceidle enable
adb shell dumpsys deviceidle step
# 查看 Doze 状态
adb shell dumpsys deviceidle
# 一直执行上述第三步,直到打印出的信息是以 IDEL 开头的字符

# 解除睡眠(Doze 模式):
adb shell dumpsys deviceidle disable
# 重置电源电源状态
adb shell dumpsys battery reset

### App Standby 模式
# 查看连接列表
adb devices

# 获取待机(App Standby模式)状态
adb shell am get-inactive <packageName>

# 进入休眠(App Standby模式):
-> adb shell dumpsys battery unplug
-> adb shell am set-inactive <packageName> true

# 解除休眠(App Standby模式):
adb shell am set-inactive <packageName> false
# 重置电源电源状态
adb shell dumpsys battery reset

下面是对于 Doze 、App Standby 和 Wake Lock 的解释说明:

Doze 睡眠模式

从Android6.0开始,Android提供了两种省电延长电池寿命的功能:Doze和App Standby

表现形式:当设备没有连接到电源,设备进入Doze模式时,系统将通过延迟最近用户没有使用的应用程序的后台CPU运作及网络活动,让应用程序处于App Standby状态,以此来减少电池消耗。谷歌表示,在Nexus5和Nexus6上测试,当屏幕处于关闭状态,平均续航时间提高30%;

版本要求:Android6.0(API level 23)及其更高版本;

设备进入Doze睡眠模式时机(满足以下三个条件):

  • 设备未连接电源充电
  • 屏幕关闭
  • 用户不操作设备一段时间(首先进入浅度睡眠,设备静止约30分钟进入深度睡眠)

Doze模式下应用程序有什么变化:

1.网络访问被挂起

  1. Wake Locks被无视

  2. AlarmManager被推迟到下一个maintenance window窗口, 除非使用AlarmManager新方法:setAndAllowWhileIdle(),setExactAndAllowWhileIdle(),setAlarmClock()

  3. WiFi扫描被停止

  4. SyncAdapter同步工作被停止

  5. JobScheduler定时任务被停止

Doze模式的五种状态:

ACTIVE:手机设备处于激活活动状态

INACTIVE:屏幕关闭进入非活动状态

IDLE_PENDING:每隔30分钟让App进入等待空闲预备状态

IDLE:空闲状态

IDLE_MAINTENANCE:处理挂起任务

Doze期间提供间隔一小段时间(30s)供应用程序使用网络和处理挂起的活动。

系统进入Doze模式后,系统会隔一段时间处理正在挂起的任务,随着时间推移,后面间隔的时间会越来越长,以此来减少电量消耗

退出Doze模式(系统退出休眠,所有的应用程序恢复正常活动):

  • 用户唤醒装置移动,打开屏幕
  • 或者设备连接电源

阻止电池优化(白名单)

Android6.0及更高版本提供电池优化白名单,App加入白名单可逃脱Doze和App Standby限制, 处于白名单中的App也会受到一定限制: Jobs和Syncs以及常规Alarms也会被推迟;

用户手动设置App进入白名单: 设置>电池>电池优化白名单

App Standby 应用待机模式

当用户有一段时间未主动使用应用时,系统判定该应用处于空闲状态。以下情况除外:

  1. 用户显式启动应用。

  2. 应用当前有一个进程位于前台(表现为 Activity 或前台服务形式,或被另一 Activity 或前台服务占用)。

  3. 用户可在锁屏或通知栏中看到的通知。

  4. 系统应用。

当用户将设备插入电源时,系统将退出待机状态,从而让它们可以自由访问网络并执行任何待定作业和同步。 如果设备长时间处于空闲状态,系统将按每天大约一次的频率允许空闲应用访问网络。

具有前台服务(Foreground Service,通过startForeground启动的service)的应用,将不会进入待机模式。

可以看出,低电耗模式(Doze)是系统级别的,应用待机模式(App Standby)是应用级别的。

Doze和App Standby的区别:

Doze模式需要屏幕关闭(通常晚上睡觉或长时间屏幕关闭才会进入),而App Standby不需要屏幕关闭,App进入后台一段时间也会受到连接网络等限制。

Wake Lock 唤醒锁

不操作android设备一段时间后,Android设备就会进入休眠模式,Android系统的休眠分为浅度休眠和深度休眠。

首先进入的是浅度休眠,在这种模式下,lcd、tp等关闭用以节省电量。

一段时间后,若没有应用持有wake_lock的锁,进入深度睡眠模式,在深度休眠的过程中系统会首先冻结所有可以冻结的进程,然后依次挂起所有设备的电源,挂起顺序与设备注册的顺序相反,这样保证了设备之间电源的依赖性;直至最后进入省电模式,等待用户或者RTC唤醒;在唤醒过程中则会按照设备注册的顺序依次恢复每个设备的电源进入正常工作状态,解冻相关的进程,然后再进行浅度休眠的唤醒流程。

在深度睡眠模式下,是可以有消息push的,因为深度休眠下虽然AP会休眠,网络断开,但是BP是工作的,可以通过心跳机制,保持和服务器的长连接,当有消息来的时候,BP唤醒AP执行相应的操作。这里设置心跳机制应该是基于AlarmManager的,若是Timer则必须持有wakelock锁,这样会导致系统无法进入深度休眠,Alarm定时器是基于工作在BP的。

doze模式是不管你会不会持有wake_lock锁,只根据时间和传感器判断是否进入doze模式。在进入Doze模式之后,只有在白名单里面的应用可以正常使用,其他应用的网络,alarm都是被暂停的。

参考链接:

Android 的 doze mode 严重影响接收推送消息。 - V2EX

Android M新特性Doze and App Standby模式详解 - 知乎 (zhihu.com)

Android-电池优化Doze和Standby模式-AlarmManager失效_lioil.win的博客-CSDN博客

Android系统休眠机制和doze模式的关系_exstar的博客-CSDN博客

安卓 省电模式、低电耗(Doze)模式、应用待机(standby)模式、唤醒锁_android standby_神秘_博士的博客-CSDN博客

0%