android6.0系统 Doze模式(DeviceIdle)实现与控制逻辑

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

DeviceIdleController的实现逻辑


1.服务启动 2

1.1SystemServer.java启动阶段 2

1.2准备阶段 5

2. 进入Idle模式 6

2.1进入idle模式的流程 6

3. 状态变化的驱动因素 10

4.进入Idle模式后的处理 10

4.1对于PowerManager的限制 11

4.2对网络的限制 13

4.3 Alarm限制 13


1.服务启动

 Doze功能概述

当系统灭屏并长时间处于静止状态时,系统会进入Doze状态,此时

1)不在White list里的APP会被限制网络访问

2wake lock会被忽略

3)通过alarm manger设置的alarm 被推迟,除非设置了允许在idle状态也能工作的flag

5wifi scan被取消

6jobschedule sync被推迟


1.1SystemServer.java启动阶段

 

startOtherServices() 中有

mSystemServiceManager.startService(DeviceIdleController.class);这里启动DeviceIdleController的服务

 

首先调用到DeviceIdleController的构造函数:

    public DeviceIdleController(Context context) {

        super(context);

        mConfigFile = new AtomicFile(new File(getSystemDir(), "deviceidle.xml"));

        mHandler = new MyHandler(BackgroundThread.getHandler().getLooper());

}

构造函数仅仅做了两件事:1.创建一个保证原子操作的的mConfigFile的文件(系统/data/system/deviceidle.xml文件);2.创建一个handler线程执行idle的状态变化消息处理。

 

SystemServer的start的函数在执行了service的构造函数之后,会将该函数add到SystemService的list中,然后执行到Service的onStart函数中。

DeviceIdleController的onStart函数总共做了两件事:

 

   mEnabled = getContext().getResources().getBoolean(

                    com.Android.internal.R.bool.config_enableAutoPowerModes);

Idle模式中开关在frameworks/base/core/res/res/values/config.xml中配置。原生逻辑默认是关闭的,可以修改配置打开

 

 

  SystemConfig sysConfig = SystemConfig.getInstance();

  ArraySet<String> allowPowerExceptIdle =   sysConfig.getAllowInPowerSaveExceptIdle();

            for (int i=0; i<allowPowerExceptIdle.size(); i++) {

                String pkg = allowPowerExceptIdle.valueAt(i);

                try {

                    ApplicationInfo ai = pm.getApplicationInfo(pkg, 0);

                    if ((ai.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {

                        int appid = UserHandle.getAppId(ai.uid);

                        mPowerSaveWhitelistAppsExceptIdle.put(ai.packageNameappid);

                        mPowerSaveWhitelistSystemAppIdsExceptIdle.put(appidtrue);

                    }

将配置文件中配置系统应用白名单应用添加到mPowerSaveWhitelistAppsExceptIdle列表中,省电模式下这些应用即使不在前台也能有联网权限(除了在Idle状态下)

 

  ArraySet<String> allowPower = sysConfig.getAllowInPowerSave();

            for (int i=0; i<allowPower.size(); i++) {

                String pkg = allowPower.valueAt(i);

                try {

                    ApplicationInfo ai = pm.getApplicationInfo(pkg, 0);

                    if ((ai.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {

                        int appid = UserHandle.getAppId(ai.uid);

                        // These apps are on both the whitelist-except-idle as well

                        // as the full whitelist, so they apply in all cases.

                        mPowerSaveWhitelistAppsExceptIdle.put(ai.packageNameappid);

                        mPowerSaveWhitelistSystemAppIdsExceptIdle.put(appidtrue);

                        mPowerSaveWhitelistApps.put(ai.packageNameappid);

                        mPowerSaveWhitelistSystemAppIds.put(appidtrue);

                    }

将系统完整省电模式的白名单应用添加到mPowerSaveWhitelistApps,该应用列表中的应用在省电模式下的所有状态都有联网权限。

 

 

            mConstants = new Constants(mHandler, getContext().getContentResolver());

 

            readConfigFileLocked();

            updateWhitelistAppIdsLocked();

将系统中/data/system/deviceidle.xml配置的用户App读取到mPowerSaveWhitelistUserApps白名单列表中去,并更新所有的白名单应用列表。省电模式下出Idle模式不能工作的白名单应用列表:mPowerSaveWhitelistExceptIdleAppIdArray省电模式下在Idle状态下也能工作的完全白名单列表:mPowerSaveWhitelistAllAppIdArraymPowerSaveWhitelistAllAppIdArray设置到PowerManagerService中的白名单中

 

            mScreenOn = true;

            mCharging = true;

            mState = STATE_ACTIVE;

            mInactiveTimeout = mConstants.INACTIVE_TIMEOUT;

        }

 

        publishBinderService(Context.DEVICE_IDLE_CONTROLLERnew BinderService());

        publishLocalService(LocalService.classnew LocalService());

    }

 

2.将deviceidle注册到BinderService()中。将DeviceIdleController的内部类LocalService注册到本地服务中。

 

onStart的详细

mPowerSaveWhitelistAppsExceptIdle里读取的类似allow-in-power-save-except-idle,和allow-in-power-save的应用包名例如:

<allow-in-power-save-except-idle package="com.Android.providers.downloads" />

 

<allow-in-power-save package="com.google.android.gms" />

 

 

读取allow-in-power-save的应用,并将配置的应用添加到mPowerSaveWhitelistApps的List中。并且通过PackageManager通过包名获取到应用的appid。

并且将mPowerSaveWhitelistSystemAppIds.put(appidtrue);

 

以上两种通过配置文件里面读取的系统应用,将其将入到mPowerSaveWhitelistSystemAppIdsExceptIdle, mPowerSaveWhitelistSystemAppIds两个列表中。在加入到列表时会判断该应用是否为系统应用,所以这两个列表里装的都是系统应用。

 

readConfigFileLocked()函数将读取系统中/data/system/deviceidle.xml文件,并将其解析出来应用的包名,将其解析出来的包名,通过pm获取应用信息,将其加入到mPowerSaveWhitelistUserApps列表中。

 

updateWhitelistAppIdsLocked()函数中建立两个列表:

mPowerSaveWhitelistExceptIdleAppIdArray:除了Idle模式下,省电模式的完整白名单

mPowerSaveWhitelistAllAppIdArray:列表里保存的完整的省电模式(包括Idle)白名单的应用ID。

 

调用PowerManagerService的setDeviceIdleWhitelist函数:

 mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);

将完整的省电模式下应用白名单,设置到PowerManagerService的wakelock列表中。

 

在onStart中创建:

mConstants = new Constants(mHandler, getContext().getContentResolver());

注册ContentObserver的,监听Settings.Global.DEVICE_IDLE_CONSTANTS,在updateConstants中初始化各个阶段的时间

INACTIVE_TIMEOUT = 30min

SENSING_TIMEOUT = 4min

LOCATING_TIMEOUT = 30s

MOTION_INACTIVE_TIMEOUT = 10min

IDLE_AFTER_INACTIVE_TIMEOUT = 30min

IDLE_PENDING_TIMEOUT = 5min

MAX_IDLE_PENDING_TIMEOUT = 10min

IDLE_PENDING_FACTOR =2f

IDLE_TIMEOUT = 1h

MAX_IDLE_TIMEOUT = 6h

IDLE_FACTOR = 2f

MIN_TIME_TO_ALARM = 1h

这些参数在后面进入Idle模式的过程中都将用到

 

 

最后将设置设备状态: mState = STATE_ACTIVE;

 

大致流程图如下:

 

 

 

 

 

 

1.2准备阶段

作为一个系统服务,启动过程都需要走到onBootPhase(int phase),当系统服务准备好了,就可以执行该服务的准备工作。

准备工作:1.获取AlarmManager服务

2.获取BatteryService服务

3.获取网络NetworkPolicyManager服务

4.获取Display服务

5.获取SensorManager服务(mSigMotionSensor)

6.获取LocationManager服务

7.创建运动检测对象

8.创建AlarmIntent(ACTION_STEP_IDLE_STATE),广播Intent。

9.创建mSensingAlarmIntentACTION_STEP_IDLE_STATE,在Sensing和Locating的时候广播Intent。

10.并注册广播接收器mReceiver,若接收到Intent(ACTION_STEP_IDLE_STATE)执行进入idle模式流程函数stepIdleStateLocked();

11.注册DisplayManager的监听器mDisplayListener,监听屏幕显示状态变化

 

 

 

2.进入Idle模式

2.1进入idle模式的流程

1).INACTIVE

进入idle模式主要是在Step,在屏幕进入灭屏幕状态时,mDisplayListener会监听到屏幕显示状态的变化,继而会调用到updateDisplayLocked();更新屏幕状态,进入到灭屏时,会在becomeInactiveIfAppropriateLocked() 中将设备状态mState设置为 STATE_INACTIVE,然后发送延迟为INACTIVE_TIMEOUT的一个带有mAlarmIntentalarm,由于mAlarmIntent中含有ACTION_STEP_IDLE_STATE的消息广播,所以在INACTIVE_TIMEOUT(30min)后,mReceiver会收到Intent为ACTION_STEP_IDLE_STATE的广播,进入到stepIdleStateLocked()中;

函数开始首先判断,下一次能从Idle状态唤醒的Alarm距离现在的时间,如果小于MIN_TIME_TO_ALARM,则直接唤醒设备,知道下一次唤醒Alarm发送成功:

final long now = SystemClock.elapsedRealtime();

if ((now+mConstants.MIN_TIME_TO_ALARM) > mAlarmManager.getNextWakeFromIdleTime()) {

    if (mState != STATE_ACTIVE) {

        becomeActiveLocked("alarm", Process.myUid());

    }

    return;

}

 

 

2).STATE_IDLE_PENDING;

如果不满足则开始一步一步进入Idle模式

我们可知当屏幕灭屏时,mState的状态是INACTIVE_TIMEOUT,30min后发送广播,则执行:

case STATE_INACTIVE:

           // We have now been inactive long enough, it is time to start looking

           // for significant motion and sleep some more while doing so.

           startMonitoringSignificantMotion();

           scheduleAlarmLocked(mConstants.IDLE_AFTER_INACTIVE_TIMEOUTfalse);

           // Reset the upcoming idle delays.

           mNextIdlePendingDelay = mConstants.IDLE_PENDING_TIMEOUT;

           mNextIdleDelay = mConstants.IDLE_TIMEOUT;

           mState = STATE_IDLE_PENDING;

           if (DEBUG) Slog.d(TAG"Moved from STATE_INACTIVE to STATE_IDLE_PENDING.");

           EventLogTags.writeDeviceIdle(mState"step");

           break;

此时mState已经是STATE_IDLE_PENDING的状态,开始检查SignificantMotion(显著运动)了;然后重新设置下一次Alarm发送的时间为IDLE_AFTER_INACTIVE_TIMEOUT(30min)。并且在此初始化mNextIdlePendingDelay(自动退出Idle的间隙时间5min),和 mNextIdleDelay(Idle持续时间1h).

 

3).SENSING:

case STATE_IDLE_PENDING:

     mState = STATE_SENSING;

     if (DEBUG) Slog.d(TAG"Moved from STATE_IDLE_PENDING to STATE_SENSING.");

     EventLogTags.writeDeviceIdle(mState"step");

     scheduleSensingAlarmLocked(mConstants.SENSING_TIMEOUT);

     cancelLocatingLocked();

     mAnyMotionDetector.checkForAnyMotion();

     mNotMoving = false;

     mLocated = false;

     mLastGenericLocation = null;

     mLastGpsLocation = null;

当在STATE_IDLE_PENDING时,30分钟内没有检测到SignificantMotion(显著运动),就进入到下一个状态——STATE_SENSING,在这个状态下会重新设置该状态下发送alarm的时间SENSING_TIMEOUT(4min);并且不检测位置移动(因为位置移动下一个状态会去检查判断);检查设备是否处于一个静止状态;

并初始化几个参数。

 

4)LOCATIN

case STATE_SENSING:

    mState = STATE_LOCATING;

    if (DEBUG) Slog.d(TAG"Moved from STATE_SENSING to STATE_LOCATING.");

    EventLogTags.writeDeviceIdle(mState"step");

    scheduleSensingAlarmLocked(mConstants.LOCATING_TIMEOUT);

    mLocating = true;

    mLocationManager.requestLocationUpdates(mLocationRequestmGenericLocationListenermHandler.getLooper());

    if (mLocationManager.getProvider(LocationManager.GPS_PROVIDER) != null) {

          mHaveGps = true;                mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 5,

                            mGpsLocationListenermHandler.getLooper());

    } else {

           mHaveGps = false;

           }

   break;

mAnyMotionDetector检测为静止时,进入到STATE_LOCATING状态,并设置发送Alarm的超时时间为LOCATING_TIMEOUT(30s),并且检测位置移动。

 

5)IDLE

case STATE_IDLE_MAINTENANCE:

       scheduleAlarmLocked(mNextIdleDelaytrue);

       if (DEBUG) Slog.d(TAG"Moved to STATE_IDLE. Next alarm in " + mNextIdleDelay + " ms.");

       mNextIdleDelay = (long)(mNextIdleDelay * mConstants.IDLE_FACTOR);

       if (DEBUG) Slog.d(TAG"Setting mNextIdleDelay = " + mNextIdleDelay);

       mNextIdleDelay = Math.min(mNextIdleDelaymConstants.MAX_IDLE_TIMEOUT);

       mState = STATE_IDLE;

       EventLogTags.writeDeviceIdle(mState"step");

       mHandler.sendEmptyMessage(MSG_REPORT_IDLE_ON);

       break;

当位置定位满足精确标准时,停掉Alarm检测,位置检测,设备移动检测等,直接进入Idle模式,此时重置Idle的发送超时时间为mNextIdleDelay(1h),并且通过Handler发送消息MSG_REPORT_IDLE_ON,在handleMessage中去做idle模式下的各种限制。

 

case STATE_IDLE:

       // We have been idling long enough, now it is time to do some work.

       scheduleAlarmLocked(mNextIdlePendingDelayfalse);

       if (DEBUG) Slog.d(TAG"Moved from STATE_IDLE to STATE_IDLE_MAINTENANCE. " + "Next alarm in " + mNextIdlePendingDelay + " ms.");

       mNextIdlePendingDelay = Math.min(mConstants.MAX_IDLE_PENDING_TIMEOUT,

             (long)(mNextIdlePendingDelay * mConstants.IDLE_PENDING_FACTOR));

       mState = STATE_IDLE_MAINTENANCE;

       EventLogTags.writeDeviceIdle(mState"step");

       mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF);

       break;

当进入Idle模式后,每隔一段时间都会进入到STATE_IDLE_MAINTENANCE;的间隙状态去处理相应的一些网络同步,Alarm发送的功能,具体操作在handleMessage中去做。



 

其整个流程大致如下:

系统启动时设置初始状态为STATE_ACTIVE。之后根据屏幕状态/充电状态/传感器状态来进行状态转移。

(1)当screenoff 且non-charging时,进入STATE_INACTIVE。此时会设置INACTIVE_TIMEOUT,默认为30min

(2)当INACTIVE_TIMEOUT时,进入STATE_IDLE_PENDING,此时会开启SignificantMotion,并设置IDLE_AFTER_INACTIVE_TIMEOUT,默认为30min.

(3)当IDLE_AFTER_INACTIVE_TIMEOUT时,进入STATE_SENSING,此时启动AnyMotionDetetor

(4)当AnyMoTionDetetor检测为静止时,进入STATE_LOCATING,并设置LOCATING_TIMEOUT,默认为30s,并请求当前的Location状态。

(5)当Location状态显示当前位置达到设定的精确标准时,直接进入STATE_IDLE,否则等到LOCATING_TIMEOUT,进入STATE_IDLE.此时停止AnyMotionDetetor,通过AlarmManager.setIdleUntil 通只AlarmManager进入IDLE,直到指定的alarm到来(这里设置的alarm默认为60min);通知PowerManager/NetworkPolicy/BatteryStas 进入IDLE状态。

并发送broadcast: ACTION_DEVICE_IDLE_MODE_CHANGED.

(6)当(5)中设置的alarm唤醒时,进入STATE_IDLE_MAINTAINTENCE,此时设置一个默认为5min的timeout,同时通知PowerManager/NetworkPolicy/BatteryStas退出IDLE状态

(7)当(6)设置的timeout 到时,再次进入STATE_IDLE

(8)在状态STATE_SENSING和STATE_LOCATING,可能会因为AnyMoTionDetetor监测到移动或者SignificantMotion检测到有动作而重新进入STATE_INACTIVE

(9)在状态STATE_IDLE_PENDING,可能会因为SignificantMotion检测到有动作而重新进入STATE_INACTIVE

(10)当screenon 或者 charging 都会重新进入STATE_ACTIVE

 

 

 

 

 

3. 状态变化的驱动因素

1screen 状态

2)充电状态(charging)

3AnyMonitionDetetor 监测到的状态。其作用区间为进入STATE_SENSING开始到离开STATE_LOCATING

4SignificantMotionSensor监测到的状态,其作用区间为进入STATE_IDLE_PENDING开始,到重新进入ACTIVE或者INACTIVE状态

5)外部模块直接调用exitIdle

6)使用dumpsys force-idle

7)控制IDLE功能的总开关:

config.xmlconfig_enableAutoPowerModes,默认为false

8)当检测到线控耳机按钮事件(voice-search)时,会退出idle模式。

 

 

 

4.进入Idle模式后的处理

case MSG_REPORT_IDLE_ON: {

       EventLogTags.writeDeviceIdleOnStart();

       mLocalPowerManager.setDeviceIdleMode(true);

       try {

             mNetworkPolicyManager.setDeviceIdleMode(true);

             mBatteryStats.noteDeviceIdleMode(truenull, Process.myUid());

           } catch (RemoteException e) {

     }

      getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);

      EventLogTags.writeDeviceIdleOnComplete();

  } break;

 

可以直观的看到进入Idle模式后,对PowerManager,NetworkPolicy,有直接限制,而进入到Idle模式后BatteryStats统计电池电量使用信息,将其当成与Alarm,Audio等模块一样去计算。

4.1对于PowerManager的限制

在服务启动阶段,onBootPhase()函数中,有:

mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);

将Idle模式白名单应用设置到PowerManagerService中,所以调用到PowerManagerService中时,去更新wakelock函数updateWakeLockDisabledStatesLocked():

 private void updateWakeLockDisabledStatesLocked() {

 boolean changed = false;

        final int numWakeLocks = mWakeLocks.size();

        for (int i = 0; i < numWakeLocksi++) {

            final WakeLock wakeLock = mWakeLocks.get(i);

            if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)

                    == PowerManager.PARTIAL_WAKE_LOCK) {

                if (setWakeLockDisabledStateLocked(wakeLock)) {

                    changed = true;

                    if (wakeLock.mDisabled) {

                        // This wake lock is no longer being respected.

                        notifyWakeLockReleasedLocked(wakeLock);

                    } else {

                        notifyWakeLockAcquiredLocked(wakeLock);

                    }

                }

            }

        }

        if (changed) {

            mDirty |= DIRTY_WAKE_LOCKS;

            updatePowerStateLocked();

        }

}

 

进入到Idle模式后,会遍历mWakeLocks列表,将该列表将不在白名单应用的PARTIAL_WAKE_LOCK类型的wakelock设置mDisabled参数。

函数setWakeLockDisabledStateLocked:

if (mDeviceIdleMode) {

     final int appid = UserHandle.getAppId(wakeLock.mOwnerUid);

     // If we are in idle mode, we will ignore all partial wake locks that are

     // for application uids that are not whitelisted.

         if (appid >= Process.FIRST_APPLICATION_UID &&

             Arrays.binarySearch(mDeviceIdleWhitelistappid) < 0 &&

             Arrays.binarySearch(mDeviceIdleTempWhitelistappid) < 0 &&

             mUidState.get(wakeLock.mOwnerUid,

                                ActivityManager.PROCESS_STATE_CACHED_EMPTY)

              > ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {

                    disabled = true;

                }

            }

            if (wakeLock.mDisabled != disabled) {

                wakeLock.mDisabled = disabled;

                return true;

}

判断首先wakelock的appid需要大于Process.FIRST_APPLICATION_UID(10000:非系统应用Uid一般都是大于10000),appid不能在省电模式白名单以及零时白名单中,并且该uid的Service不能为一个前台服务。当满足这几个条件,该appid申请的wakelock会被disable掉,相当于release了,但是还在mWakelocks列表中,退出Idle状态时会重新生效。退出Idle时会重新走一遍setWakeLockDisabledStateLocked,将mWakeLocks列表中的所有wakelock的mDisbale参数置为false,所以退出Idle时,mWakeLocks列表中的所有wakelock会重新生效。

 

 

 

4.2对网络的限制

在NetworkPolicyManagerService中来控制idle状态下对网络访问的控制:

(1)监听ACTION_POWER_SAVE_WHITELIST_CHANGED来维护mPowerSaveWhitelistAppIds

(2)向DeviceIdleController注册mTempPowerSaveChangedCallback来维护 mPowerSaveTempWhitelistAppIds

(3)提供setDeviceIdleMode供DeviceIdleController 通知进入idle

 

当进入Idle模式后,便会通过NetworkPolicyManagerService通过updateRulesForGlobalChangeLocked全局去更新网络访问控制策略规则:

 void updateRulesForGlobalChangeLocked(boolean restrictedNetworksChanged) {

        final PackageManager pm = mContext.getPackageManager();

 

        updateRulesForDeviceIdleLocked();

        updateRulesForAppIdleLocked();

 

        // update rules for all installed applications

        final List<UserInfo> users = mUserManager.getUsers();

        final List<ApplicationInfo> apps = pm.getInstalledApplications(

                PackageManager.GET_UNINSTALLED_PACKAGES | PackageManager.GET_DISABLED_COMPONENTS);

 

        for (UserInfo user : users) {

            for (ApplicationInfo app : apps) {

                final int uid = UserHandle.getUid(user.idapp.uid);

                updateRulesForUidLocked(uid);

            }

        }

 

        // limit data usage for some internal system services

        updateRulesForUidLocked(android.os.Process.MEDIA_UID);

        updateRulesForUidLocked(android.os.Process.DRM_UID);

 

}

(1)将mPowerSaveWhitelistAppIds,和mPowerSaveTempWhitelistAppIds中的app设置rule为FIREWALL_RULE_ALLOW(允许网络访问),加入到FIREWALL_CHAIN_DOZABLE这个chain中。

(2)向UsageStatesService注册AppIdleStateChangeListener,当UsageStatesService检测到有app standby时候,此时NetworkPolicyManagerService将会限制该app访问网络。

(6)当不在White list的APP 在进入IDLE状态时,将无法再使用网络。(通过添加使能firewall的相关chain来实现)

 

 

 

4.3 Alarm限制

AlarmManagerService增加了一套新的标志,用来区分不同alarm在idle模式下的工作状态。同时新增了3个api接口,用来设置可在idle模式下执行的alarm。具体情况如下:

public static final int FLAG_STANDALONE = 1<<0;

这种Alarm是独立的Alarm,不会和其他Alarm合并到一个batch中。

 

public static final int FLAG_WAKE_FROM_IDLE = 1<<1;

这种Alarm可以从idle模式下将设备唤醒,(用于闹钟,日程)

 

public static final int FLAG_ALLOW_WHILE_IDLE = 1<<2;

这种Alarm在Idle状态下依旧可以被发送执行,它不会使设备推出Idle,仅仅让Alarm运行,

    

public static final int FLAG_IDLE_UNTIL = 1<<4;

这种Alarm是标记一个时间点来退出idle状态。

 

AlarmManager中新增了三个方法:

setAndAllowWhileIdle:设置可在idle模式下执行的alarm(flag: FLAG_ALLOW_WHILE_IDLE)

setExactAndAllowWhileIdl:同setExact(),设置可以在idle模式下执行的精确Alarm

setIdleUntil:设置idle-until alarm,这种Alarm(flag:FLAG_IDLE_UNTIL)将会使设备退出idle,进入idle-mataintence状态,只能由系统服务调用,在6.0系统中暂时只有DeviceIdleController在Idle状态和Idle-Matainence状态切换时候调用,

 

在Alarm中alarm manager进入idle模式,会将先前设置的普通alarm(不带FLAG_ALLOW_WHILE_IDLE/ FLAG_WAKE_FROM_IDLE标志)放到PendingList,同时新来的普通alarm也会被存到PendingList。PendingList中的alarm不会被设置到底层alarm设备,因此也就不会有唤醒动作。当idle-until alarm的触发时间到来,PendingList才会重新设置。idle-until alarm的触发时间是一个可设置的参数,默认值是15分钟,也就是说如果设备在idle模式下,每15分钟唤醒一次。类似于15分钟的心跳同步。

 

 

以上是google原生代码上对于idle状态的控制逻辑,由于进入Idle状态后,会对系统的wakelock,network,Alarm作限制,以保证最大的省电效率。可以看出原生逻辑对于进入DeviceIdle状态是有着非常严格苛刻的条件的,从进入开始进入Idle到完全进入Idle状态中间需要走五个状态流程,且需要判断位置,移动以及明显动作,这些外界因素一个不满足都会使设备进入Idle状态失败。所以Idle状态基本只能在晚上睡眠时间才能完全进入。

(原创)android6.0系统 Doze模式(DeviceIdle)实现控制逻辑 DeviceIdleController的实现逻辑 1.服务启动 2 1.1SystemServer.java启动阶段 2 1.2准备阶段 5 2. 进入Idle模式 6 2.1进入idle模式的流程 6 3. 状态变化的驱动因素 10 4.进入Idle模式后的处理 10 4.1对于PowerManager的限制 11 4.2对网络的限制 13 4.3 Alarm限制 阅读详情

相关推荐

电源管理-省电模式-基于android 9

插电状态下,不允许进入省电模式。拔电状态下,手动任意电量进入省电模式,会立即进入省电模式。充电会暂时打断,拔电后会再次进入省电模式,恢复用户的操作终态。拔电状态下,开启自动省电模式,电量低于设置值会自动进入省电模式。自动省电模式状态下,手动进入省电模式会因为重复设置被拦截;手动退出省电模式可以生效,会立即退出省电模式。注意,当重启设备或者充电到自动省电模式边界值以上,再次掉电到边界值以下,还是会自动进入省电模式

archie_7的博客 4187

Android 7.0 Doze模式分析

设置白名单 wakeLock白名单 在DeviceIdleController中我们调用PowerManagerService.java中的setDeviceIdleWhitelist设置白名单,这里的appids是uid @Override public void setDeviceIdleWhitelist(int[] appids) {

dk_work的博客 1万+

android8.1 应用程序添加白名单并添加grant权限

近日,将一个业务app导入系统,发现APP中功能界面在切入后台的时候,会受到影响,原来是白名单的存在导致的,先将framework层面添加的改动展示一下,后面再上原理层面的内容分析: diff --git a/data/etc/platform.xml b/data/etc/platform.xml index c243e311..948c2848 100755 --- a/da...

kevin's cache的专栏 2762

如何将非系统app预置到Doze的白名单中

按步骤1-4操作后,然后全编译。 1.在framework/base/data创建一个data目录 2.在framework/base/data/data下创建deviceidle.xml, 并把要放入白名单的应用按格式写入到该文件 deviceidle.xml # include $(CLEAR_VARS) LOCAL_MODULE := deviceidle.xml LOC...

LYJ的IT生活 1861

Android应用后台保活实战:从系统机制到合规方案全解析

Android开发中,后台进程管理是一个核心挑战,尤其涉及即时通讯、位置上报等场景时,应用常因系统限制而意外终止。理解其底层原理,如Low Memory Killer(LMK)进程回收机制和Doze模式,是设计有效策略的基础。这些机制旨在平衡功能设备续航,其技术价值在于保障关键服务的连续性。实践中,开发者需掌握前台服务、JobScheduler等合规方案,并巧妙结合厂商推送通道,以在即时通讯、运动健康等场景中实现可靠后台运行。本文聚焦Android应用保活,系统拆解了从机制原理到分场景选型的实战指南,帮

weixin_30700099的博客 426

Android后台任务管理:从保活到合规存活的现代实践

在移动应用开发中,后台任务管理是确保应用功能完整性和用户体验的关键技术领域。其核心原理在于平衡应用功能需求系统资源管理(如电池续航和内存优化)之间的矛盾。随着Android系统版本的演进,后台限制策略不断收紧,这使得传统的“保活”手段逐渐失效,技术价值转向如何在系统规则内实现任务的可靠执行。现代Android开发通过前台服务(Foreground Service)和WorkManager等官方框架,为后台任务提供了合规且高效的解决方案。前台服务适用于用户可感知的持续任务(如音乐播放或文件下载),并通过通知

cneo2012的博客 348

Android 7系统网络(六)Framework层()—NMS_NPMS_NSS三大服务

600 系列响应码是 netd 主动推送的异步事件通知, 200/400/500 系列的命令响应不同——NMS 通过。它是 NPMS 的"眼睛"——NPMS 需要流量数据来判断是否达到警告或限制阈值。:NPMS 是决策层(“限制谁”),NSS 是感知层(“用了多少”),NMS 是执行层(“怎么限制”),三者通过。协调——NMS 负责执行,NSS 负责统计,NPMS 负责决策,形成"执行-统计-决策"的闭环。在内核中为每个 Socket 创建唯一的 tag,所有数据包在协议栈中自动统计,无需用户态干预。

AfinalStone的专栏 349

电脑休眠睡眠功能详解:原理、配置常见问题排查

计算机电源管理是操作系统硬件协同工作的核心机制之一,旨在平衡性能能耗。其基本原理涉及ACPI标准,定义了系统从工作到休眠的不同状态。在技术实现上,睡眠模式通过保持内存供电实现快速恢复,而休眠模式则将内存数据完整转储至硬盘以实现零功耗保存。从技术价值看,合理的电源管理能有效延长硬件寿命、保障数据安全并提升能效。在应用场景上,无论是日常办公的短暂离开,还是移动设备的续航优化,都离不开对睡眠休眠模式的正确配置。本文聚焦于WindowsUbuntu系统,深入解析休眠睡眠的核心差异,并提供从BIOS设置、P

weixin_33816300的博客 385

OkHttp核心架构实战:从基础请求到高级拦截器应用

HTTP客户端是移动应用后端服务通信的核心组件,其设计直接影响着应用的性能稳定性。传统的HttpURLConnection等原生方案API繁琐、功能缺失,难以满足现代应用对高效网络通信的需求。OkHttp作为一款现代化的HTTP客户端库,通过连接复用、透明压缩、响应缓存等底层优化,以及拦截器链的灵活设计,为开发者提供了构建健壮网络层的有力工具。其核心价值在于将复杂的网络细节封装,让开发者能专注于业务逻辑,同时通过可定制的拦截器实现统一认证、日志记录、网络状态检查等高级功能。在Android开发中,结合协

weixin_34043301的博客 321

Android 功耗优化(4)---android 7.0低电耗Doze模式

android 7.0低电耗Doze模式Android 6.0(API 级别 23)开始,Android 引入了两个省电功能,可通过管理应用在设备未连接至电源时的行为方式为用户延长电池寿命。 低电耗(Doze)模式通过在设备长时间处于闲置状态时推迟应用的后台 CPU 和网络 Activity 来减少电池消耗。 应用待机(App Standby)模式可推迟用户近期未之交互的应用的后台网络 Ac...

zhangbijun1230的专栏 3523

深入Android 'M' Doze

Android ‘M’的诸多新的特性中,有一个特性被Google称作是“doze” – 通过这个机制,当你的设备在特定时间内没有被使用。应用就会被限制到有限的活动中。在这篇博文中,我们将会试图从系统层面上解密这个新特性是如何工作的。

licaomeng的专栏 6409

android8.1 添加 doze白名单

省电优化白名单和调试方式

xyb_2012的博客 2007

Android7.0 Doze模式分析 Doze介绍 & DeviceIdleController

参考:http://blog.csdn.net/gaugamela/article/details/52981984 在Android M中,Google就引入了Doze模式。它定义了一种全新的、低能耗的状态。 在该状态,后台只有部分任务被允许运行,其它任务都被强制停止。 在之前的博客中分析过Doze模式,就是device idle状态。可能有的地方分析的不是很详细,现在在android7

Perpetual1006的博客 1941

androidP Doze模式 添加 doze白名单 省电优化白名单

androidP Doze模式 androidP 添加 doze白名单 省电优化白名单 通过命令查找文件 grep allow-in-power-save frameworks/base/ --include=*.xml -Rn 配置文件路径 frameworks/base/data/etc/platform.xml 配置说明 allow-in-power-save :始终在省点白名单,即使在省电模式或者非前台应用。 allow-in-power-save-except-idle : 用于指定进程在省电模式

mowwwcom的专栏 2877

Doze模式adb shell命令集

一、adb 指令1.1 让设备进入未连接充电的模式进行doze模式命令模拟的话,需要先下发该命令,因为只要存在充电状态,是无法从Acitve状态切换到InActive状态的adb shell dumpsys battery unplugZ90:/ # dumpsys battery unplug dumpsys battery unplug1.2 退出Doze模式,让手机恢复正常需要复位充电模式不使

苏法迪的专栏 8340

Android6.0 设备Idle状态(一)DeviceIdleController

Android6.0上power改动比较大,粗略的看PowerManagerService的话感觉变动不大,只是在PowerManagerService的改动代码比较少,但是其实质改动较大,特别增加了这个DeviceIdleController,来控制设备的Idle状态。而当设备在idle状态时,它会忽略cpu的wakelock,Alarm等。 因此DeviceIdleController在po...

kc58236582的博客 1万+

DeviceIdle-低电耗模式和应用待机模式

    mLightEnabled = mDeepEnabled = getContext().getResources().getBoolean(                     com.android.internal.R.bool.config_enableAutoPowerModes)   ?hl=zh-Hans  

lei7143的专栏 1014
上一篇: 常见编译错误-ubuntu16.04
下一篇: android 如何通过包名杀死指定的进程
mmmccc000
博客等级 码龄16年 43粉丝 4原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值