Android9.0 应用待机群组

一、概述

 Android 9 引入了一项新的电池管理功能,即应用待机群组。应用待机群组可以基于应用最近使用时间和使用频率,帮助系统排定应用请求资源的优先级。 根据使用模式,每个应用都会归类到五个优先级群组之一中。 系统将根据应用所属的群组限制每个应用可以访问的设备资源。

五个群组按照以下特性将应用分组:

活跃

如果用户当前正在使用应用,应用将被归到“活跃”群组中,例如:

  • 应用已启动一个 Activity
  • 应用正在运行前台服务
  • 应用的同步适配器与某个前台应用使用的 content provider 关联
  • 用户在应用中点击了某个通知

如果应用处于“活跃”群组,系统不会对应用的作业、报警或 FCM 消息施加任何限制。

工作集

如果应用经常运行,但当前未处于活跃状态,它将被归到“工作集”群组中。 例如,用户在大部分时间都启动的某个社交媒体应用可能就属于“工作集”群组。 如果应用被间接使用,它们也会被升级到“工作集”群组中 。

如果应用处于“工作集”群组,系统会对它运行作业和触发报警的能力施加轻度限制。 如需了解详细信息,请参阅电源管理限制

常用

如果应用会定期使用,但不是每天都必须使用,它将被归到“常用”群组中。 例如,用户在健身房运行的某个锻炼跟踪应用可能就属于“常用”群组。

如果应用处于“常用”群组,系统将对它运行作业和触发报警的能力施加较强的限制,也会对高优先级 FCM 消息的数量设定限制。 

极少使用

如果应用不经常使用,那么它属于“极少使用”群组。 例如,用户仅在入住酒店期间运行的酒店应用就可能属于“极少使用”群组。

如果应用处于“极少使用”群组,系统将对它运行作业、触发警报和接收高优先级 FCM 消息的能力施加严格限制。系统还会限制应用连接到网络的能力。 

从未使用

安装但是从未运行过的应用会被归到“从未使用”群组中。 系统会对这些应用施加极强的限制。

系统设置各个app的bucket无非是为了限制各个app的资源,已达到节省功耗的目的。我们来看看这个流程的大致功能图:

二、实现

这一节我们主要讲述了系统设置app的bucket,获取bucket,以及系统何时去检查app bucket的状态。我们先看下时序图:

2.1 设置bucket

这个功能的实现是在UsageStatsService中实现的,在这个service的onstart函数中创建了AppStandbyController对象,而且对于各个app设置自己属于哪个群组的对外接口是reportEvent函数。这个接口会在AMS以及NotificationManagerService中调用UsageStatsService的reportEvent,这个函数会调用AppStandbyController的reportEvent函数,我们来看下这个函数主要还是调用了AppUsageHistory的reportUsage函数。但是我们要注意其两个时间的参数不一样。这里后面有一个延迟消息很重要,主要就是多一段时间再来检测这个app的idle状态。我们来看这个延迟消息,当是Notification类型的消息的延迟时间为12小时,SYSTEM_INTERACTION为10分钟(这种主要是调用startInstrumentation函数),其他的mStrongUsageTimeoutMillis为1小时(正常应用启动)。

    void reportEvent(UsageEvents.Event event, long elapsedRealtime, int userId) {
        if (!mAppIdleEnabled) return;//mAppIdleEnabled必须使能
        synchronized (mAppIdleLock) {
            // TODO: Ideally this should call isAppIdleFiltered() to avoid calling back
            // about apps that are on some kind of whitelist anyway.
            final boolean previouslyIdle = mAppIdleHistory.isIdle(
                    event.mPackage, userId, elapsedRealtime);
            // Inform listeners if necessary
            if ((event.mEventType == UsageEvents.Event.MOVE_TO_FOREGROUND
                    || event.mEventType == UsageEvents.Event.MOVE_TO_BACKGROUND
                    || event.mEventType == UsageEvents.Event.SYSTEM_INTERACTION
                    || event.mEventType == UsageEvents.Event.USER_INTERACTION
                    || event.mEventType == UsageEvents.Event.NOTIFICATION_SEEN
                    || event.mEventType == UsageEvents.Event.SLICE_PINNED
                    || event.mEventType == UsageEvents.Event.SLICE_PINNED_PRIV)) {

                final AppUsageHistory appHistory = mAppIdleHistory.getAppUsageHistory(
                        event.mPackage, userId, elapsedRealtime);
                final int prevBucket = appHistory.currentBucket;
                final int prevBucketReason = appHistory.bucketingReason;
                final long nextCheckTime;
                final int subReason = usageEventToSubReason(event.mEventType);
                final int reason = REASON_MAIN_USAGE | subReason;
                if (event.mEventType == UsageEvents.Event.NOTIFICATION_SEEN
                        || event.mEventType == UsageEvents.Event.SLICE_PINNED) {
                    // Mild usage elevates to WORKING_SET but doesn't change usage time.
                    mAppIdleHistory.reportUsage(appHistory, event.mPackage,
                            STANDBY_BUCKET_WORKING_SET, subReason,
                            0, elapsedRealtime + mNotificationSeenTimeoutMillis);
                    nextCheckTime = mNotificationSeenTimeoutMillis;//12小时
                } else if (event.mEventType == UsageEvents.Event.SYSTEM_INTERACTION) {
                    mAppIdleHistory.reportUsage(appHistory, event.mPackage,
                            STANDBY_BUCKET_ACTIVE, subReason,
                            0, elapsedRealtime + mSystemInteractionTimeoutMillis);
                    nextCheckTime = mSystemInteractionTimeoutMillis;//10分钟
                } else {
                    mAppIdleHistory.reportUsage(appHistory, event.mPackage,
                            STANDBY_BUCKET_ACTIVE, subReason,
                            elapsedRealtime, elapsedRealtime + mStrongUsageTimeoutMillis);
                    nextCheckTime = mStrongUsageTimeoutMillis;//1小时
                }
                mHandler.sendMessageDelayed(mHandler.obtainMessage
                        (MSG_CHECK_PACKAGE_IDLE_STATE, userId, -1, event.mPackage),
               
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值