对应用中Alarm优化

针对华为应用市场反馈的Alarm唤醒次数过多问题,进行了应用内的Alarm优化。通过查找和分析代码,调整了频繁唤醒设备的Alarm,将每小时唤醒次数从71次和62次降低到19-23次。然而,仍有一个未知来源的Alarm每小时唤醒15-20次,未达到华为标准的20次以内,目前正进一步排查可能通过JNI在底层设置的Alarm。
摘要由CSDN通过智能技术生成

起因:华为应用市场反馈Alarm唤醒次数过多,需要优化。
未优化之前通过华为的DevEco进行功耗测试,在Mate 9上每小时唤醒71次,在p10上每小时唤醒62,妥妥的手机没办法进入休眠状态,而他们的标准是每个应用每小时唤醒不超过20次。
未优化

查找使用Alarm的代码
  1. Alarm的使用需要AlarmManager,而AlarmManager的获取是通过getSystemService(ALARM_SERVICE)获取到的,找到了某个类中中的doMyJob方法,其中每隔5分钟唤醒一次设备。其他的Alarm服务间隔时间比较长,有的是一天唤醒一次,有的是定时上午九点唤醒,这些闹钟全部加起来一小时也不会超过15次。
  2. 使用 adb shell dumpsys alarm | grep “包名” 查看系统中的存在哪些Alarm并通过项目包名过滤掉不是自己工程的Alarm,发现了 *walarm*:包名.service_alive_alarm_filter,查看相关代码发现每隔十分钟唤醒一次设备,一方面是为了保活,一方面是为了检查计步传感器是否开启,因为有些设备在息屏之后会关闭计步传感器,这时候我们需要切换到自己的计步算法,通过加速度传感器来计算运动步数。
  3. 调整这两个Alarm的唤醒频率, 提交到DevEco进行测试,结果如下:
    第一次优化
查找三方使用的Alarm
  1. 仔细查看使用adb shell找到的alarm,发现了这货 *walarm*:AlarmNioTaskSchedule.包名,如果是我们自己在工程里面设置的Alarm,一般是以自己的项目包名命名的,接着查dump出来的信息,找到了两个唤醒间隔时间非常短的Alarm,粗略估计每个的唤醒间隔在4分钟半。下面日志中when就是alarm唤醒的时间点
ELAPSED_WAKEUP #0: Alarm{a359f35 type 2 when 1911290944 包名}
      operation=PendingIntent{7551fca: PendingIntentRecord{eb70106 包名 startService}}
ELAPSED_WAKEUP #1: Alarm{80150f type 2 when 1911660925 包名}
      operation=PendingIntent{58db99c: PendingIntentRecord{35972a0 包名 broadcastIntent}}

通过PendingIntent和PendingIntentRecord的编号,结合 adb shell dumpsys activity intents | grep “包名”
找到设置该Alarm的包名:

#4: PendingIntentRecord{eb70106 包名 startService}
      uid=10415 packageName=包名 type=startService flags=0x0
      requestIntent=act=com.qiyukf.desk.ACTION.KEEP_ALIVE cmp=包名/com.qiyukf.nimlib.service.NimService (has extras)
 
#8: PendingIntentRecord{35972a0 包名 broadcastIntent}
      uid=10415 packageName=包名 type=broadcastIntent flags=0x0
      requestIntent=act=com.qiyukf.nim.ACTION.ALARM.REPEATING cmp=包名/com.qiyukf.nimlib.service.NimReceiver

由于是三方的包,没办法修改代码来完成,只能用其他方法。
翻看设置Alarm的源码发现:由于设置Alarm的时候需要调用set或者setRepeating方法,最终都会调用setImpl方法,最后通过进程间通信,调IAlarmManager的set方法。
IAlarmManager的实现类是AlarmManagerService,只需要替换掉这个类的实例,在调用它的set方法时,替换掉alarm的时间间隔
就可以减少一部分alarm的唤醒。
由于hook的时间越早越好,于是选在Application初始化的时候进行hook,在Application的onCreate方法中:

//替换IAlarmService
try {
   
    AlarmManager alarm = (AlarmManager) getSystemService(ALARM_SERVICE);
    Class<?> alarmManagerClass = alarm.getClass();
    Field mService = alarmManagerClass.getDeclaredField("mService"
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值