Go开发工程师:迎接上升风口,踏入蓝海行业-无酒无花锄作田

#1

download:Go开发工程师:迎接上升风口,踏入蓝海行业-无酒无花锄作田

Android功耗原理与飞本功耗治理
Android功耗统计原理
我们来看看安卓系统是怎么统计耗电量的。最准确的方法当然是用电流表统计耗电量,但手机硬件在正常情况下不支持。所以系统在统计功耗的时候,基本都是用模块功耗模块时间消耗的公式,只是不同的模块还是有一定的差异。这种统计方法不可能很准确,但基本能反映出每个应用的功耗。
模块功率
我们先来看看模块功率。每个模块的功耗是不同的。通过计算可以分为以下三类。

第一类是通用传感器或设备的模块,如照相机、手电筒和媒体播放器。它的工作功率与额定功率基本一致,所以模块功率的计算只需要统计模块的使用时间,再乘以额定功率即可。

第二类是Wifi、移动、蓝牙等数据模块。它的工作动力可以分为不同的档位。例如,当手机Wifi信号较弱时,Wifi模块必须工作在较高的功率档位,以维持数据链路。所以这类模块的电量计算有点类似于我们日常的电费计算,需要“阶梯计费”。

第三类是屏幕,CPU模块。模块除了每个CPU核需要像数据模块一样计算功耗外,每个CPU集群(一般一个集群包含一个或多个相同规格的核)也有额外功耗,整个CPU处理器芯片也有功耗。简单计算,CPU功耗= SUM(每个核的功耗)+每个集群的功耗+芯片的功耗。模块功耗的计算就更麻烦了,很难将屏幕功耗合理分配给各个App。所以Android系统只是简单的计算出App锁屏的保持时间,将App CPU的统计时间增加一个固定的系数,粗略的计算出屏幕功耗进入CPU。

每个模块的功耗位于framework的power_profile.xml文件中,由厂商自己提供,文件中规定了每个模块的功耗。以下是一加9测试器的power_profile文件。

由apktook反向求解的power_profile如下

文件中每个模块的对应描述可以在Google提供的文档中找到。
source.android.com/devices/tec…

模块耗时
知道了模块的强大,我们再来看看模块的耗时。当耗电模块改变工作或状态时,会通知batterystats这个服务,BatteryStatsService会调用BatteryStats对象进行耗时统计。每个模块的定时器都会在BatteryStats的构造函数中初始化,进行耗时统计,统计数据会保存在batterystats.bin文件中。
BatteryStatsImpl.java
从上面三个例子可以看出,BatteryStats是需要时间来统计模块的,主要是通过定时器来统计时间长度,比如WifiOnTimer,AudioOnTimer,ForegroundActivityTimer,根据是否有UID来决定是否统计UID对应的数据。系统在统计应用的功耗时,会根据UID下各个模块的统计数据来计算应用的功耗。
功耗计算
当我们知道了各个模块的时间消耗和功耗,就可以计算出各个模块的功耗。功耗的计算在BatteryStatsHelper类中。下面我们来详细看看在设置中功耗统计的实现。功耗统计在设置中的应用主要调用BatteryStatsHelper中的refreshStats()函数。

RefreshStats主要用processappUsage来计算应用的功耗,用memory processMiscUsage来计算杂项功耗,比如WIFI,电话等等。

计算app的威力

这里,以简单的模块CameraPowerCalculator来看看它是如何计算电量的。
CameraPowerCalculator.java

可以看到,里面简单用了totalTime * mCameraPowerOnAvg,mCameraPowerOnAvg是从power_profile.xml读取的其他老师负责CPU模块的计算,有兴趣的可以自己看看,这里就不说了。

计算杂项的功率
AlarmManager警报将推迟到下一个维护窗口响应时发出。

用setAndAllowWhileIdle或SetExactAndAllowWhileIdle设置闹钟不会受到Doze模式的影响。
setAlarmClock设置的报警在Doze模式下仍然有效,但系统会在报警生效前退出Doze。

系统不执行Wi-Fi/GPS扫描;
系统不允许同步适配器运行;
不允许运行JobScheduler
Deep Doze还提供了一个白名单。位于白名单中的应用程序可以:
继续使用网络并保持清醒
作业和同步仍然会被延迟。
不会触发常规AlarmManager警报。

轻微瞌睡
浅瞌睡的限制不如深瞌睡严格,主要有以下几点

不允许网络访问。
不允许运行同步适配器。
不允许运行JobScheduler
深度瞌睡和轻度瞌睡的对比总结如下:
深度瞌睡和浅瞌睡都需要满足一定条件才能进入,进入后会定期提供窗口期解除限制。
在这个过程中,检测是否有gps,是否有位置移动。如果有gps,会通过break跳出循环,进行30S的位置移动检测。如果没有gps,则转到案例为STATE_IDLE_MAINTENANCE的流程,将状态设置为STATE_IDLE。
进入STATE_IDLE后会申请wakelock,同时调用MSG_REPORT_IDLE_ON的handler任务限制耗电策略。这和轻瞌睡的空闲状态处理是同一个入口,所以MSG_REPORT_IDLE_ON会在下面的轻瞌睡中详细描述。
同时我们可以看到,进入STATE_IDLE后,一个时间会被设置为:
对于延迟的任务,IDLE_FACTOR是2,mNextIdleDelay的初始值是60分钟,MAX_IDLE_TIMEOUT是6小时,所以这个时间是1小时,2小时,4小时,最后稳定到6小时。
6.从状态空闲到状态空闲维护

从代码中可以看出,这些事情是在case为LIGHT_STATE_INACTIVE的处理逻辑中完成的。
设置当前状态为LIGHT_STATE_PRE_IDLE,
并发送3分钟闹钟,准备进入下一个状态。
后续状态都是由scheduleLightAlarmLocked设置的调度任务,然后在stepLightIdleStateLocked函数中处理状态转换和对应状态的逻辑。

这里,状态将被设置为LIGHT_STATE_IDLE,并且MnextlightIdleLay的一个定时任务将被设置为进入下一个状态。MnextlightIdleLay的初始值是5分钟。
这里我们可以看到LIGHT_STATE_PRE_IDLE和LIGHT_STATE_IDLE_MAINTENANCE是同一个案例处理逻辑,这两个状态的下一个状态是LIGHT_STATE_IDLE。
如果最后一个状态是灯状态空闲维护,那么
MnextlightIdleLay = math . min(m constants。LIGHT_MAX_IDLE_TIMEOUT,(long)(mnextlightIdleLay * m constants。LIGHT_IDLE_FACTOR),light _ max _ idle _ timeout为15分钟,light _ idle _ factor为2。
所以轻瞌睡的空闲时间是5分钟,10分钟,最后稳定在15分钟。
当状态变为IDLE时,这里会应用wakelock唤醒cpu,然后使用MSG_REPORT_IDLE_ON_LIGHT的处理程序任务进行逻辑处理,然后释放wakelock使cpu休眠。
剩下的状态函数转换都在上面的函数里注释了,我就不详细解释了。

大家可以看到,进入空闲状态后的深瞌睡和浅瞌睡的逻辑处理是在同一个地方。根据这里的不同模式,通知PowerServiceManager、NetworkPolicyManager、BatteryStats等。来制定不同的优化策略。这里要做的主要是这些事情。
调用mlocalpowermanager . setdeviceidlemode设置是否是Deep Doze的空闲状态。如果它是空闲的,这一步将设置应用程序忽略唤醒锁。
调用mlocalpowermanager . setlightdeviceidlemode设置是否为轻瞌睡的空闲状态。
调用mnetworkpolicymanager . setdeviceidlemode(true)通过添加防火墙规则来限制网络访问。
打电话给batterystats。改变状态和耗时的系统。
调用sendBroadcastAsUser发送广播,进入深睡或浅睡的空闲状态。
释放唤醒锁

瞌睡限制逻辑取消
进入MAINTENCANCE后,轻瞌睡和深瞌睡都会取消各种限制,取消的逻辑会在MSG_REPORT_IDLE_OFF的handler任务中处理。
案例消息_报告_空闲_关闭:{
//mactiveidwakelock在此时被保持
event log tags . writedeviceidloffstart(" unknown ");
final boolean deep changed = mlocalpowermanager . setdeviceidlemode(false);
final boolean light changed = mlocalpowermanager . setlightdeviceidlemode(false);
尝试{
mnetworkpolicymanager . setdeviceidlemode(false);
mbatterystats . notdeviceidlemode(battery stats。设备空闲模式关闭,
null,process . myuid());
} catch(远程异常e) {
}
如果(深度更改){
incactiveidloops();
getContext()。sendOrderedBroadcastAsUser(mid eintent,UserHandle。所有的,
null,mIdleStartedDoneReceiver,null,0,null,null);
}
如果(光线改变){
incactiveidloops();
getContext()。sendOrderedBroadcastAsUser(mlightidletent,UserHandle。所有的,
null,mIdleStartedDoneReceiver,null,0,null,null);
}
decactiveidloops();
}破;
复制代码
备用方式
Doze模式是针对整个系统的功耗优化模式,而Standby模式即应用组待机模式是针对单个应用的功耗优化模式。是Android7.0推出的,当应用空闲时,系统会根据应用的最新时间和频率将其设置到相应的组中。在不同的组下,作业、报警和网络的使用限制是不同的。
待机模式的进入和退出
当用户一段时间没有触摸应用程序时,系统将判断进入待机模式。以下条件不适用,否则将退出待机模式:

用户主动启动App

该应用程序当前有一个前台进程(或包含一个活动的前台服务,或被另一个活动或前台服务使用);

在锁定屏幕或通知栏中看到的通知
系统应用
充电状态
待机模式的优化策略
应用进入待机后,会根据应用的状态限制作业、告警、网络,应用的状态可以分为五个等级。
Activie:如果用户当前正在使用该应用程序,该应用程序将被归类为“atcitive”。

WORKING_SER:如果应用程序经常运行(在12到24小时内被使用过),但是它当前不是活动的,那么它将被分类到工作集组中。例如,用户大部分时间启动的社交媒体应用程序可能属于“工作集”组。如果应用程序被间接使用,它们也将被升级到工作集组。

频繁:如果该应用程序将定期使用,但不是每天使用(亮屏和使用的时间差超过1小时和24小时),它将被归入“常见”组。例如,用户在健身房运行的锻炼跟踪应用可以属于“公共”组。

稀有:如果应用不经常使用(亮屏和使用的时间差超过2小时和48小时),那么它就属于“很少使用”的群体。例如,用户仅在入住酒店期间运行的酒店应用程序可能属于“很少使用”组。如果应用程序属于“很少使用”组,系统将对其运行作业、触发警报和接收高优先级FCM消息的能力施加严格的限制。系统还会限制应用程序连接到网络的能力。

从不:已安装但从未运行的应用程序将被归类为“从未使用”组。系统将对这些应用施加严格的限制。

以下是五个等级的适用限制。
developer.android.com/topic/perfo…

待机模式的实现原理
待机模式的逻辑在AppStandbyController对象中实现,该对象为app行为变化的外部通知提供reportEvent。比如ams,NotificationManagerService等。将调用reportEvent通知应用程序行为变化并更新存储桶。
AppStandbyController.java
更新存储桶
ReportEvent将根据mEventType更新桶,并根据mEventType设置延迟任务。在这个延迟任务中,Bucket将根据应用程序的使用行为再次更新。通知类型消息的延迟时间为12小时,SYSTEM_INTERACTION为10分钟,其他mStrongUsageTimeoutMillis为1小时。
MSG_CHECK_PACKAGE_IDLE_STATE的处理程序消息主要是根据使用时长更新Bucket。
应用功耗分析
电池历史记录
Android官方提供了电池历史记录来分析电量使用情况,电池历史记录图表会显示一段时间内与电源相关的事件。
从上面可以看出,进入Doze后,BLE扫描、GPS等没有任何行为。,而cpu、wakelock等活动的频率也变低了。
我们还可以通过电池历史记录获得应用程序。

设备的估计功耗。
网络信息。
起床时间。

服务
msdtc
官方文件已经很详细了,这里就不细说了。
developer.android.com/topic/perfo…
鱼人守卫
与鱼人守卫电力相关的统计指标包括
当应用程序在前台时,提供电流作为功耗的指标。
通过收集app的cpu、流量、gps的使用情况,计算出一个加权和作为耗电指标。
电池温度,作为测量功耗的辅助参考

归因项目有
高cpu可以通过CPU菜单查看高消耗CPU的堆栈。
当超过规定的保持时间和频率时,gps(定位)、报警和唤醒锁的使用将被报告给采集堆栈。
鱼人守卫虽然上报了很多用电量相关指标,但目前只能作为整体用电量的参考,很多指标波动较大,无法帮助更细致的治理。
图书功耗管理
治理目标
消除主流手机的高耗电提醒。
建立完善的功耗监控和降级预防系统。
治理方案
前面我们已经知道功耗=模块功耗,所以治理的本质就是在不影响性能和功能的前提下,减少舒菲使用模块的时间消耗。我们还知道系统的功耗优化策略。在舒菲的用电治理中,我们同样可以参考相应的策略。
治理方案主要分为监控完善和功耗治理。
功耗管理
为了系统地管理功耗,有两类:管理功耗模块和执行状态。
模块化治理
模块的功耗管理主要体现在以下几个方面。

1.中央处理器
不必要的cpu消耗,比如死循环函数,高频函数,高耗时函数,无效函数等。,或者消费比较多的功能管理。
具有高cpu利用率和业务治理的场景

2.GPU和显示器
过度渲染,过度动画,不可见区域的动画等。废GPU场景管理。
主动降低屏幕亮度,使用深色UI等方案降低屏幕功耗。

3.网络
在不影响业务和性能的前提下,降低网络访问频率。
减少瞌睡状态下的无效网络请求

4.全球(卫星)定位系统
对于使用GPS的场景,比如小程序,降低精度,合理请求频率。

5.音频、摄像机、视频等
除了子模块治理,它还管理状态,主要状态如下。
次国家治理
1.前台状态
渲染场景优化
同等音视频场景优化
……

2.背景状态
任务频率降低或放弃
降低网络访问频率,适应瞌睡模式
减少消耗cpu的函数执行
降低功耗场景,如gps
完善用电分析和监控系统
为了更好的管理,完善的用电分析监控系统是必然的,否则就会出现漫无目的的状态。该区域的主要施工点有

1.完美的CPU消耗监控
高cpu消耗的后台场景监控,高cpu消耗的线程监控(slardar已经存在)
高频率任务、高耗时任务、后台任务监控(现有)
高消耗和耗时的功能监控

2.GPU和显示器消耗监控
场景、过画检测、视图级别检测、屏幕功耗监控等。

3.网络
Rust,OkHttp等网络请求场景,频率和消耗监控
后台网络访问监控

4.全球(卫星)定位系统
GPS使用场景、持续时间和功耗监控

5.音频、摄像头、视频
使用场景、持续时间和功耗监控

6.整体和现场用电量
用书的整体功耗和不同场景的功耗来衡量版本功耗的好坏。