Android P PowerManagerService分析(一)

2023-11-16

1、概述

     PowerManagerService是负责管理、协调设备电源管理的系统服务之一,设备常见功能如亮灭屏、亮度调节、低电量模式、保持CPU唤醒等,都会通过PMS的协调和处理。其继承自SystemService,因此具有SystemService子类的共性:具有生命周期方法,由SystemServer启动、注册到系统服务中,通过Binder和其他组件进行交互等。
其生命周期方法如下:
     构造方法:通过反射调用,获取实例;
     onstart()方法:开启对应的SystemService;
     onBootPhase()方法:在SystemService服务的启动过程中指定服务的启动阶段,每个阶段指定特定的工作;
由于是系统服务,不仅需要掌握其启动流程,还要了解和其他服务之间的交互,下面就PMS的流程和功能进行具体的分析。
在这里插入图片描述

2、PMS的启动

     和SystemService的其他子类一样,PMS由SystemServer通过反射的方式启动,首先,在SystemServer的main()方法中,调用了自身的run()方法,并在run()方法中启动三类服务:引导服务、核心服务和其他服务,引导服务中启动的是一些依赖性比较强的服务,其中就包括了PMS,具体如下:

在SystemServer的main()中:

//The main entry point from zygote.
public static void main(String[] args) {
    new SystemServer().run();
}

在SystemServer的run()中:

private void run() {
    //......
    try {
        startBootstrapServices();//启动引导服务
        startCoreServices();//启动核心服务
        startOtherServices();//启动其他服务
    } catch (Throwable ex) {
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
    }
    ......
}

     所谓引导服务是指一些具有高度相互依赖性的服务,在启动引导服务时,启动了PMS,以下代码是PMS的启动以及和其他服务的依赖关系:

private void startBootstrapServices() {
 	//通过SystemManagerService启动PMS服务
    mPowerManagerService = mSystemServiceManager.
                startService(PowerManagerService.class);
    //AMS中初始化PowerManager
    mActivityManagerService.initPowerManagement();
}

     逐步分析,首先看PMS的启动,调用了SystemServiceManager的startService()方法进行了启动,在startService()中,首先通过了传入的类名获取了Class对象,然后使用反射机制,通过Class对象获取了PMS的构造函数,从而获得了一个PMS对象:

public SystemService startService(String className) {
    final Class<SystemService> serviceClass;
    serviceClass = (Class<SystemService>)Class.forName(className);
    return startService(serviceClass);
}
public <T extends SystemService> T startService(Class<T> serviceClass) {
    try {
        final T service;
        try {
        	//获取实例
            Constructor<T> constructor = 
                  serviceClass.getConstructor(Context.class);
            service = constructor.newInstance(mContext);
        } catch (InstantiationException ex) {
        }
        mServices.add(service);//添加到List中,进行生命周期管理
        try {
            service.onStart();//启动服务
        } catch (RuntimeException ex) {
        }
        return service;
    }
}

     在获取了PMS的实例后,添加到了一个ArrayList中,只有在该ArrayList中的SystemService才能接收到生命周期方法回调;然后调用了onStart()方法.因此,对于PMS,先执行了PMS的构造方法,接着执行了onStart()方法。首先来看其构造方法:

public PowerManagerService(Context context) {
     super(context);
     mContext = context;
     //获取一个系统级别的HandlerThread,继承于Thread
     mHandlerThread = new ServiceThread(TAG,
             Process.THREAD_PRIORITY_DISPLAY, false /*allowIo*/);
     mHandlerThread.start();//开启线程
     //根据Looper实例化一个Handler
     mHandler = new PowerManagerHandler(mHandlerThread.getLooper());
     mConstants = new Constants(mHandler);
     mAmbientDisplayConfiguration = new AmbientDisplayConfiguration(mContext);
	//电池监测相关
     mBatterySavingStats = new BatterySavingStats(mLock);
     mBatterySaverPolicy = new BatterySaverPolicy(mLock, mContext, mBatterySavingStats);
     mBatterySaverController = new BatterySaverController(mLock, mContext,
             BackgroundThread.get().getLooper(), mBatterySaverPolicy, mBatterySavingStats);
     mBatterySaverStateMachine = new BatterySaverStateMachine(
             mLock, mContext, mBatterySaverController);

     synchronized (mLock) {
    	 //获取当应用申请wakelock后让CUP保持激活状态的Suspendlocker实例
         mWakeLockSuspendBlocker = createSuspendBlockerLocked("PowerManagerService.WakeLocks");
         //获取当显示屏开启、显示屏准备就绪或者有用户活动后让CPU保持激活状态的Suspendlocker
         mDisplaySuspendBlocker = createSuspendBlockerLocked("PowerManagerService.Display");
         //申请PowerManagerService.Display类型的suspendBloker锁
         mDisplaySuspendBlocker.acquire();
         //持有Display锁的bool值
         mHoldingDisplaySuspendBlocker = true;
         //AutoSuspend模式是否开启
         mHalAutoSuspendModeEnabled = false;
         //是否处于交互模式
         mHalInteractiveModeEnabled = true;
		//设置wakefulness表示亮屏状态
         mWakefulness = WAKEFULNESS_AWAKE;

         sQuiescent = SystemProperties.get(SYSTEM_PROPERTY_QUIESCENT, "0").equals("1");

         nativeInit();//初始化
         nativeSetAutoSuspend(false);//设置是否开启anto suspend模式
         nativeSetInteractive(true);//设置是否处于交互模式
         nativeSetFeature(POWER_FEATURE_DOUBLE_TAP_TO_WAKE, 0);
     }
 }

     在PMS构造方法中,首先获取了一个HandlerThread,然后使用该HandlerThread的Looper实例化PowerManagerHandler,如果不指定looper,则使用当前线程默认Looper,因此PowerManagerHandler会根据HandlerThread中的Looper,在HandlerThread中进行异步的操作;其次获取了两个Suspend锁,SuspendBlocker是一种锁机制,只用于系统内部,上层申请的wakelock锁在PMS中都会反映为SuspendBlocker锁。这里获取的两个Suspend锁在申请wakelock时会用到,这块在wakelock申请时会进行详细分析;最后,调用了本地方法,这几个方法会通过JNI层调用到HAL层。
     构造方法执行完毕后,执行onStart()方法:

@Override
public void onStart() {
    //发布到系统服务中
    publishBinderService(Context.POWER_SERVICE, new BinderService());
    //发布到本地服务
    publishLocalService(PowerManagerInternal.class, new LocalService());
	//设置Watchdog监听
    Watchdog.getInstance().addMonitor(this);
    Watchdog.getInstance().addThread(mHandler);
}

     在该方法中,首先对该服务进行Binder注册和本地注册,当进行Binder注册后,在其他模块中就可以通过Binder机制获取其实例,同理,当进行本地注册后,只有在System进程才能获取到其实例;最后设置Watchdog的监听。
     对服务进行远程注册,是通过Binder机制实现的,实际上,从代码中可以出,注册的并不是PMS本身,而是其内部类——BinderService,BinderService继承自IPowerManager.Stub,IPowerManager.Stub继承自Binder并且实现了IPowerManager,因此可以知道,BinderService作为Binder的服务端,可以和客户端进行交互;注册的过程在ServiceManager中进行的,如下:

public static void addService(String name, IBinder service, boolean allowIsolated) {
    try {
        getIServiceManager().addService(name, service, allowIsolated);
    } catch (RemoteException e) {
        Log.e(TAG, "error in addService", e);
    }
}

     当通过ServiceManager注册后,就可以根据Context.POWER_SERVICE在其他服务中获取对应的IBinder了,以PMS为例,当从其他应用中获取了PMS服务后,就可以调用PMS.BinderService中的方法。所以,PMS中的BinderService相当于服务端,其中的方法可以供其他应用进行调用,从而完成和PMS的交互。
     通过Binder进行注册是为了供其他应用或系统服务和PMS进行交互,那么本地注册则表示只能在System进程内部调用,和BinderService一样,本地注册也并非注册的是PMS,而是另一个内部类——LocalService,LocalService继承自PowerManagerInternal(带有Internal的类一般都在System进程内使用);Binder注册是在SystemManager中进行注册的,本地注册则是在LocalServices中进行注册,其注册方法如下:

public static <T> void addService(Class<T> type, T service) {
    synchronized (sLocalServiceObjects) {
        if (sLocalServiceObjects.containsKey(type)) {
            throw new IllegalStateException("Overriding service registration");
        }
        sLocalServiceObjects.put(type, service);
    }
}

     注册完成之后,就可以在System进程内,通过PowerManagerInternal.class获取PMS.LocalService对象,从而完成交互了。在远程注册和本地注册都完成以后,给PMS设置了watchDog监听,onStart()方法调用完毕。此时,继续回到SytemServer中,startBootstrapServices()方法中启动PMS部分执行完成了,然后根据SystemService的生命周期,会开始执行onBootPhase(),这个方法的功能是为所有的已启动的服务指定启动阶段,从而可以在指定的启动阶段来做指定的工作。源代码如下:

public void startBootPhase(final int phase) {
    if (phase <= mCurrentPhase) {
        throw new IllegalArgumentException("Next phase must be larger than previous");
    }
    mCurrentPhase = phase;
    try {
        final int serviceLen = mServices.size();
        for (int i = 0; i < serviceLen; i++) {
            final SystemService service = mServices.get(i);
            try {
                service.onBootPhase(mCurrentPhase);
            } catch (Exception ex) {
            }
        }
    }
}

     在SystemServiceManager的startBootPhase()中,调用SystemService的onBootPhase(int)方法,此时每个SystemService都会执行其对应的onBootPhase()方法。通过在SystemServiceManager中传入不同的形参,回调所有SystemService的onBootPhase(),根据形参的不同,在方法实现中完成不同的工作,在SystemService中定义了五个阶段:

  • SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY:这是一个依赖项,只有DisplayManagerService中进行了对应处理;
  • SystemService.PHASE_LOCK_SETTINGS_READY:经过这个引导阶段后,服务才可以接收到wakelock相关设置数据;
  • SystemService.PHASE_SYSTEM_SERVICES_READY:经过这个引导阶段 后,服务才可以安全地使用核心系统服务
  • SystemService.PHASE_ACTIVITY_MANAGER_READY:经过这个引导阶 段后,服务可以发送广播
  • SystemService.PHASE_THIRD_PARTY_APPS_CAN_START:经过这个引导阶段后,服务可以启动第三方应用,第三方应用也可以通过Binder来调 用服务。
  • SystemService.PHASE_BOOT_COMPLETED:经过这个引导阶段后,说明服务启动完成,这时用户就可以和设备进行交互。
         因此,只要在其他模块中调用了SystemServiceManager.startBootPhase(),都会触发各自的onBootPhase()。PMS的onBootPhase()方法只对引导阶段的2个阶段做了处理,具体代码如下:
public void onBootPhase(int phase) {
      synchronized (mLock) {
          if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
          //统计启动的apk个数
              incrementBootCount();

          } else if (phase == PHASE_BOOT_COMPLETED) {
              final long now = SystemClock.uptimeMillis();
              mBootCompleted = true;
              //mDirty置位
              mDirty |= DIRTY_BOOT_COMPLETED;

              mBatterySaverStateMachine.onBootCompleted();
              //更新用户活动时间
              userActivityNoUpdateLocked(
                      now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
              //更新电源状态信息
              updatePowerStateLocked();

              if (!ArrayUtils.isEmpty(mBootCompletedRunnables)) {
                  Slog.d(TAG, "Posting " + mBootCompletedRunnables.length + " delayed runnables");
                  for (Runnable r : mBootCompletedRunnables) {
                      BackgroundThread.getHandler().post(r);
                  }
              }
              mBootCompletedRunnables = null;
          }
      }
  }

     在这个方法中,mDirty是一个二进制的标记位,用来表示电源状态哪一部分发生了改变,通过对其进行置位(|操作)、清零(~操作),得到二进制数各个位的值(0或1),进行不同的处理 ,此外,这个方法中调用到了updatePowerStateLocked()方法,这是整个PMS中最重要的方法,这块会在下文中进行详细分析。此时,SystemServer.startBootstrapServices()执行完毕,生命周期方法也执行完毕。对于PMS,在SystemServer.startOtherServices()中还进行了一步操作:
mPowerManagerService.systemReady(mActivityManagerService.getAppOpsService());
     因此,当PMS依次执行完构造方法、onStart()、onBootPhase()(会调用多次)方法后,执行的下一个方法是systemReady()方法,这个方法中主要有以下5个功能:
1.获取各类本地服务和远程服务,如屏保(DreamMangerService)、窗口(PhoneWindowManager)、电池状态监听服务(BatteryService)等服务,用于进行交互:

synchronized (mLock) {
mSystemReady = true;
mAppOps = appOps;
//和DreamManagerService交互
mDreamManager = getLocalService(DreamManagerInternal.class);
//和DisplayManagerService交互
mDisplayManagerInternal = getLocalService(DisplayManagerInternal.class);
//和WindowManagerService交互
mPolicy = getLocalService(WindowManagerPolicy.class);
//和BatteryService交互
mBatteryManagerInternal = getLocalService(BatteryManagerInternal.class);
//获取屏幕亮度
PowerManager pm = (PowerManager)
mContext.getSystemService(Context.POWER_SERVICE);
mScreenBrightnessSettingMinimum = pm.getMinimumScreenBrightnessSetting();
mScreenBrightnessSettingMaximum = pm.getMaximumScreenBrightnessSetting();
mScreenBrightnessSettingDefault = pm.getDefaultScreenBrightnessSetting();
mScreenBrightnessForVrSettingDefault =
pm.getDefaultScreenBrightnessForVrSetting();
SensorManager sensorManager = new SystemSensorManager(mContext,
mHandler.getLooper());
//获取BatteryStatsService
mBatteryStats = BatteryStatsService.getService();
//mNotifier用于PMS和其他系统服务间的交互,以及广播的发送
mNotifier = new Notifier(Looper.getMainLooper(), mContext, mBatteryStats,
mAppOps,
createSuspendBlockerLocked(“PowerManagerService.Broadcasts”),
mPolicy);
//无线充电相关
mWirelessChargerDetector = new WirelessChargerDetector(sensorManager,
createSuspendBlockerLocked
(“PowerManagerService.WirelessChargerDetector”),
mHandler);
//监听Stetings中值的变化
mSettingsObserver = new SettingsObserver(mHandler);
//和LightsManager交互
mLightsManager = getLocalService(LightsManager.class);
mAttentionLight =
mLightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
//mDisplayPowerCallbacks提供PMS和Display的接口,当
//DisplayPowerController发生改变,通过该接口回调PMS中的实现
//initPowerManagement()方法中实例化了DisplayPowerController,
//DPC是和显示有关,如亮灭屏、背光调节
mDisplayManagerInternal.initPowerManagement(
mDisplayPowerCallbacks, mHandler, sensorManager);
2.注册用于和其他Sytem交互的广播,如:

// Register for broadcasts from other components of the system.
//注册BatteryService中ACTION_BATTERY_CHANGED广播
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
mContext.registerReceiver(new BatteryReceiver(), filter, null, mHandler);
//Dream相关
filter = new IntentFilter();
filter.addAction(Intent.ACTION_DREAMING_STARTED);
filter.addAction(Intent.ACTION_DREAMING_STOPPED); 
mContext.registerReceiver(new DreamReceiver(), filter, null, mHandler);
//??
filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_SWITCHED);
mContext.registerReceiver(new UserSwitchedReceiver(), filter, null, mHandler);
//Dock相关
filter = new IntentFilter();
filter.addAction(Intent.ACTION_DOCK_EVENT);
mContext.registerReceiver(new DockReceiver(), filter, null, mHandler);

3.调用updateSettingsLocked()方法更新Settings中值的变化:

private void updateSettingsLocked() {
final ContentResolver resolver = mContext.getContentResolver();
//屏保是否支持
mDreamsEnabledSetting = (Settings.Secure.getIntForUser(resolver,
Settings.Secure.SCREENSAVER_ENABLED,
mDreamsEnabledByDefaultConfig ? 1 : 0,
UserHandle.USER_CURRENT) != 0);
//休眠时是否启用屏保
mDreamsActivateOnSleepSetting = (Settings.Secure.getIntForUser(resolver,
Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP,
mDreamsActivatedOnSleepByDefaultConfig ? 1 : 0,
UserHandle.USER_CURRENT) != 0);
//插入基座时屏保是否激活
mDreamsActivateOnDockSetting = (Settings.Secure.getIntForUser(resolver,
Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
mDreamsActivatedOnDockByDefaultConfig ? 1 : 0,
UserHandle.USER_CURRENT) != 0);
//设备在一段时间不活动后进入休眠或者屏保状态的时间,15*1000ms
mScreenOffTimeoutSetting = Settings.System.getIntForUser(resolver,
Settings.System.SCREEN_OFF_TIMEOUT,
DEFAULT_SCREEN_OFF_TIMEOUT,
UserHandle.USER_CURRENT);
/设备在一段时间不活动后完全进入休眠状态之前的超时时间,
该值必须大于SCREEN_OFF_TIMEOUT,否则设置了屏保后来不及显示屏保就sleep
/
mSleepTimeoutSetting = Settings.Secure.getIntForUser(resolver,
Settings.Secure.SLEEP_TIMEOUT, DEFAULT_SLEEP_TIMEOUT,
UserHandle.USER_CURRENT);
//充电时屏幕一直开启
mStayOnWhilePluggedInSetting = Settings.Global.getInt(resolver,
Settings.Global.STAY_ON_WHILE_PLUGGED_IN,
BatteryManager.BATTERY_PLUGGED_AC);
//是否支持剧院模式
mTheaterModeEnabled = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.THEATER_MODE_ON, 0) == 1;
//屏幕保持常亮
mAlwaysOnEnabled = mAmbientDisplayConfiguration.
alwaysOnEnabled(UserHandle.USER_CURRENT);
//双击唤醒屏幕设置
if (mSupportsDoubleTapWakeConfig) {
boolean doubleTapWakeEnabled = Settings.Secure.getIntForUser(resolver,
Settings.Secure.DOUBLE_TAP_TO_WAKE,
DEFAULT_DOUBLE_TAP_TO_WAKE,
UserHandle.USER_CURRENT) != 0;
if (doubleTapWakeEnabled != mDoubleTapWakeEnabled) {
mDoubleTapWakeEnabled = doubleTapWakeEnabled;
nativeSetFeature(POWER_FEATURE_DOUBLE_TAP_TO_WAKE,
mDoubleTapWakeEnabled ? 1 : 0);
}
}
final String retailDemoValue = UserManager.isDeviceInDemoMode(mContext) ?
“1” : “0”;

//屏幕亮度
mScreenBrightnessSetting = Settings.System.getIntForUser(resolver,
Settings.System.SCREEN_BRIGHTNESS, mScreenBrightnessSettingDefault,
UserHandle.USER_CURRENT);
//自动调节亮度值(>0.0 <1.0)
final float oldScreenAutoBrightnessAdjustmentSetting =
mScreenAutoBrightnessAdjustmentSetting;
mScreenAutoBrightnessAdjustmentSetting =
Settings.System.getFloatForUser(resolver,
Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0.0f,
UserHandle.USER_CURRENT);
//重置临时亮度值
if (oldScreenBrightnessSetting != getCurrentBrightnessSettingLocked()) {
mTemporaryScreenBrightnessSettingOverride = -1;
}
if (oldScreenAutoBrightnessAdjustmentSetting !=
mScreenAutoBrightnessAdjustmentSetting) {
mTemporaryScreenAutoBrightnessAdjustmentSettingOverride = Float.NaN;
}
//亮度调节模式,自动1,正常0
mScreenBrightnessModeSetting = Settings.System.getIntForUser(resolver,
Settings.System.SCREEN_BRIGHTNESS_MODE,
Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL,
UserHandle.USER_CURRENT);
//低电量模式是否可用,1表示true
final boolean lowPowerModeEnabled = Settings.Global.getInt(resolver,
Settings.Global.LOW_POWER_MODE, 0) != 0;
if (lowPowerModeEnabled != mLowPowerModeSetting
|| autoLowPowerModeConfigured != mAutoLowPowerModeConfigured) {
mLowPowerModeSetting = lowPowerModeEnabled;
mAutoLowPowerModeConfigured = autoLowPowerModeConfigured;
//更新低电量模式
updateLowPowerModeLocked();
}
//标志位置位
mDirty |= DIRTY_SETTINGS;
}
这里需要注意这两个值:mTemporaryScreenBrightnessSettingOverride和mTemporaryScerrnAutoBrightnessAdjustmentSettingsOverride,这两个值分别表示一个临时亮度值和临时自动亮度调节比例,和亮度的调节有关。之所以是临时亮度值,是因为在自动调节亮度关闭时,从Settings中或者SystemUI中拉进度条时,首先会通过Binder调用setTemporaryScreenBrightnessSettingOverride()方法将亮度值赋给它,如果调节完毕手指抬起,此时Settings.Global等里面亮度值发生变化,则在PMS中会回调SettingsObserver中的onChange()方法,又会回调updateSettingsLocked()方法,又置为-1和NaN,也就是上面这段方法。

4.调用readConfigurationLocked()方法读取配置文件中的默认值:

private void readConfigurationLocked() {
final Resources resources = mContext.getResources();
/**
* auto_suspend模式是否和display分离
* 如果为false,则在亮屏前调用autosuspend_disable(),灭屏后调用
* autosuspend_enable();
* 如果为ture,则调用autosuspend_display()和autosuspend_enable()独立于display
* on/off.
/
mDecoupleHalAutoSuspendModeFromDisplayConfig = resources.getBoolean(
com.android.internal.R.bool.
config_powerDecoupleAutoSuspendModeFromDisplay);
/
*
* interactive模式是否和display分离
* 如果为false,则在亮屏前调用setInteractive(…, true),灭屏后调用
* setInteractive(…,false);
* 如果为ture,则调用setInteractive(…)独立于display on/off.
*/
mDecoupleHalInteractiveModeFromDisplayConfig = resources.getBoolean(
com.android.internal.R.bool
.config_powerDecoupleInteractiveModeFromDisplay);
//插拔USB是否亮屏
mWakeUpWhenPluggedOrUnpluggedConfig = resources.getBoolean(
com.android.internal.R.bool.config_unplugTurnsOnScreen);
//设备处于剧院模式时,插拔USB是否亮屏
mWakeUpWhenPluggedOrUnpluggedInTheaterModeConfig = resources.getBoolean(
com.android.internal.R.bool.config_allowTheaterModeWakeFromUnplug);
//是否允许设备由于接近传感器而关闭屏幕时CPU挂起,进入suspend状态
mSuspendWhenScreenOffDueToProximityConfig = resources.getBoolean(
com.android.internal.R.bool.
config_suspendWhenScreenOffDueToProximity);
//是否支持屏保
mDreamsSupportedConfig = resources.getBoolean(
com.android.internal.R.bool.config_dreamsSupported);
//是否屏保默认打开–false
mDreamsEnabledByDefaultConfig = resources.getBoolean(
com.android.internal.R.bool.config_dreamsEnabledByDefault);
//充电和睡眠时屏保是否激活
mDreamsActivatedOnSleepByDefaultConfig = resources.getBoolean(
com.android.internal.R.bool.config_dreamsActivatedOnSleepByDefault);
//Dock时屏保是否激活
mDreamsActivatedOnDockByDefaultConfig = resources.getBoolean(
com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault);
//放电时是否允许进入屏保
mDreamsEnabledOnBatteryConfig = resources.getBoolean(
com.android.internal.R.bool.config_dreamsEnabledOnBattery);
//充电时允许屏保的最低电量,使用-1禁用此功能
mDreamsBatteryLevelMinimumWhenPoweredConfig = resources.getInteger(
com.android.internal.R.integer.
config_dreamsBatteryLevelMinimumWhenPowered);
//放电时允许屏保的最低电量,使用-1禁用此功能,默认15
mDreamsBatteryLevelMinimumWhenNotPoweredConfig = resources.getInteger(
com.android.internal.R.integer.
config_dreamsBatteryLevelMinimumWhenNotPowered);
//电亮下降到该百分点,当用户活动超时后不进入屏保,默认5
mDreamsBatteryLevelDrainCutoffConfig = resources.getInteger(
com.android.internal.R.integer.config_dreamsBatteryLevelDrainCutoff);
//如果为true,则直到关闭屏幕并执行屏幕关闭动画之后,才开始Doze,默认false
mDozeAfterScreenOffConfig = resources.getBoolean(
com.android.internal.R.bool.config_dozeAfterScreenOff);
//用户活动超时的最小时间,默认10000ms,必须大于0
mMinimumScreenOffTimeoutConfig = resources.getInteger(
com.android.internal.R.integer.config_minimumScreenOffTimeout);
//用户活动超时进入且关闭屏幕前屏幕变暗的最大时间,默认7000ms,必须大于0
mMaximumScreenDimDurationConfig = resources.getInteger(
com.android.internal.R.integer.config_maximumScreenDimDuration);
//屏幕变暗的时长比例,如果用于超时时间过短,则在7000ms的基础上按还比例减少,默认20%
mMaximumScreenDimRatioConfig = resources.getFraction(
com.android.internal.R.fraction.config_maximumScreenDimRatio, 1, 1);
//是否支持双击唤醒屏幕
mSupportsDoubleTapWakeConfig = resources.getBoolean(
com.android.internal.R.bool.config_supportDoubleTapWake);
}
5.注册SettingsObserver监听:

// Register for settings changes.
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.SCREENSAVER_ENABLED),
false, mSettingsObserver, UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP),
false, mSettingsObserver, UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK),
false, mSettingsObserver, UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.SCREEN_OFF_TIMEOUT),

至此,systemReady()方法中分析完毕。执行完这个方法后,PMS的启动过程分析完毕。在下文中进行核心方法的分析。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android P PowerManagerService分析(一) 的相关文章

  • 为什么 cordova.file.documentsDirectory 为空?

    我正在尝试使用 cordova plugin file transfer 在http ngcordova com docs plugins fileTransfer http ngcordova com docs plugins fileT
  • BLE 外设支持 Android-L 示例 [关闭]

    Closed 这个问题需要调试细节 help minimal reproducible example 目前不接受答案 我希望有一个适用于 Android L 的 BLE 外设模式的示例 我的代码给了我奇怪的错误 即广告商太多 这没有任何意
  • 意图?如何注册以获得传入电子邮件提醒?

    这里是极限 Android 开发新手 好吧 Android 开发新手 而不是一般开发 我想编写一个应用程序 当电子邮件进入设备时会收到通知 并根据电子邮件中的数据 主题 发件人 收件人等 采取各种操作 我认为我要做的是创建一个带有 Inte
  • Android自定义控件命名空间问题

    我一直在为 Android 开发自定义控件 尽管我尝试按照建议进行操作here https stackoverflow com questions 4495511 how to pass custom component parameter
  • 如何从一个活动中完成一系列开放的子活动?

    我正在尝试为我的应用程序制作一个退出按钮 无论如何 我能够跟踪我的应用程序中的所有活动实例 然后完成它们 但在某些情况下 仍有一些活动仍然存在 不知道怎么办 有没有什么方法可以杀死android中的特定应用程序 或者我可以通过任何其他方式退
  • OPENGL ES 不工作:无当前上下文

    我尝试了 OpenGL ES2 for Android 一书中所示的程序 但它不起作用 我已经在Odroid E 三星s3 三星y 三星star上进行了测试 the gl version suported returns 2 but i g
  • ListView:防止视图回收

    我有一个使用回收视图的 ListView 我试图阻止视图被回收 所以我使用 setHasTransientState android support v4 view ViewCompatJB setHasTransientState Vie
  • 我的 Android 设备需要安装哪个驱动程序才能运行我的应用程序?

    我购买了 intex mobile 来在真实设备中测试我的 Android 应用程序 然而 该设备不存在于 OEM USB 驱动程序列表中 android 提供的设备列表中 我检查了 intex 官方网站 但不确定到底需要安装哪个驱动程序
  • 在后台服务中持续获取位置更新

    我正在开发需要在后台服务中持续获取位置更新的应用程序 我已经使用了它正在使用的后台粘性服务 但是 即使我添加了启动广播并在那里启动了服务 启动完成后服务也没有启动 服务启动并立即被杀死 另外 这不适用于奥利奥 服务在应用程序关闭几分钟后停止
  • 无法在云控制台中启用 Maps SDK for Android

    我在云控制台中启用适用于 Android 的 Maps SDK 时遇到此问题 https console cloud google com https console cloud google com 它会抛出以下错误 附截图 我收到错误消
  • Android - 多次实例化一个片段?

    我正在创建一个在 ListView 中显示数据的应用程序 数据分为两种类型 热门 收藏夹 我有一个活动和两个片段 片段根据类别显示项目列表 我为此使用了 ListView 然后我有两个fragment layouts 它们在设计上完全相同
  • 收到“无法解析上传的APK的AndroidManifest.xml。它是否正确编译?”启用 Google 应用签名后出现错误

    启用后谷歌应用程序签名 https support google com googleplay android developer answer 7384423 hl en 每次我尝试将签名版本 APK 上传到 Play 商店时 都会收到一
  • 如何在Android网格视图中设置单元格大小?

    我正在尝试为应用程序制作一个带有大图标的网格视图 但我找不到任何有关修改 Android 上网格布局上的单元格大小的教程 有人可以给我一个例子或相关链接吗 Thanks 就像另一个一样适配器视图 http developer android
  • Android Drawable 绘图性能?

    在我看来 我有一个简单的 ARGB 可绘制对象 大约需要 2 毫秒才能绘制 但我可以在 0 5 毫秒内绘制与位图相同的文件 只是一些快速代码 我真的不能认为它是一个选项 优化可绘制对象的绘制速度的最佳方法是什么 这取决于可绘制的数量以及每个
  • 在 android 中,第一次单击时按钮侦听器未注册

    因为我是 Android 新手 所以我遇到了按钮监听器的问题 我正在使用 OnClickListener 来处理胸像 但它第一次点击后不执行一旦我单击多个 它就会表现良好 但如何使其在第一次单击时成为可能 这是我的代码 public cla
  • BitmapFactory.decodeResource() 忽略 jpg 图像的 inPreferredConfig 选项

    我尝试将jpeg资源图像加载到ARGB 8888格式的位图 BitmapFactory Options opts new BitmapFactory Options opts inPreferredConfig Bitmap Config
  • 如何在 kotlin 中检查 lambda 空值

    在 Kotlin 中如何检查 lambda 是否为空 例如 我有这样的签名 onError Throwable gt Unit 我如何区分它的默认值是应用于主体还是应用于此函数的值 您无法测试 lambda 的主体是否为空 因此它不包含源代
  • 从Android客户端登录appengine

    我正在尝试登录应用程序引擎并访问应用程序引擎中的用户服务API 基本上我希望能够看到谁登录了我的 servlet 我正在使用从 android 获取 authtoken 然后从应用程序引擎获取 ASID 或 SACID cookie 的身份
  • Android 4.2 - Environment.getExternalStorageDirectory().getPath() 行为

    我一直在开发一个android应用程序 在上次更新到4 2之前 我使用 Environment getExternalStorageDirectory getPath 它返回了我 storage sdcard0 但自从更新后我现在得到了 s
  • 动态创建 JSON 对象

    我正在尝试使用以下格式创建 JSON 对象 tableID 1 price 53 payment cash quantity 3 products ID 1 quantity 1 ID 3 quantity 2 我知道如何使用 JSONOb

随机推荐

  • element-ui —Cascader 级联选择器(选中方式处理)

    目前Vue Element的 el cascader 级联选择器 多选或者选择任意一级 需要点击左侧的checkbox才能选中 目标 点击label选中 已选中状态再次点击label取消选中 有两种方式实现 通过添加点击事件 通过css样式
  • 企业微信第三方应用Demo源码

    第三方应用Demo源码 qywx third java qywx third java企业微信开发指南https github com liyuexi qywx guide企业微信开发第三方应用开发视频 https mp weixin qq
  • vue实现滚动监听,锚点定位,导航高亮

  • matlab双立方插值法_双三次插值(bicubic interpolation)原理及MATLAB源码实现

    双三次插值具体实现 clc clear fff imread E Documents BUPT DIP 图片 lena bmp ff rgb2gray fff 转化为灰度图像 mm nn size ff 将图像隔行隔列抽取元素 得到缩小的图
  • pikachu靶场记录之暴力破解-包括带token的密码猜解

    说明 pikachu是一个免费的php靶场 类似于dvwa 从github下载对应的项目 解压缩并放到phpstudy的www目录下即可 在phpstudy软件中开启apache mysql 访问首页 192 168 10 150 pika
  • Gitee在大数据中心的使用

    在本地主机或者可以VSCode直接连接可视化的服务器上 1 首先在gitee新建一个带有develop分支的仓库 2 在自己的主机 e g server 1 3 上git clone下来 例如 git clone git gitee com
  • Flutter ListView详解

    ListView详解 ListView常用构造 ListView ListView 默认构建 效果 ListView ListTile ListTile 属性 ListTile 使用 效果 ListView builder builder属
  • C# combobox绑定数据源(datasource)

    1 绑定数据源 1 1数据源为dataTable DataTable dt new DataTable 显示的数据 ComBox1 DisplayMemeber name name为DataTable的字段名 隐藏的数据 对于多个数据 可以
  • 左连接(LEFT JOIN)无法返回主表所有行的解决方法

    需求 在业务员管理客户页面 需要展示所有客户信息 并且按客户的最近下单次数进行排序 第一次写的代码如下
  • Vue 2 升级Vue3 ,并且使用vsCode 搭建Vue3 开发环境

    Vue 2 升级Vue 3 版本详细步骤 第一 使用快捷键win R 打开cmd 命令窗口 第二 查看当前电脑运行的vue 版本 请使用如下指令 vue V vue Version 卸载目前vue版本 输入如下指令 npm uninstal
  • JAVA常用的七种设计模式

    学习设计模式之前 我们先要了解一下设计模式的怎么来的 对于设计人员 特别是开发人员吗 往往受限于眼界或经验不能够体会到设计原则的实用性 或者在处理具体问题时 不知道如何把设计原则应用到到设计和代码 因此产生了 模式 随着参与的项目越来越多
  • 数据结构练习题-算法设计题-线性表

    算法设计题 1 将两个递增的有序链表合并为一个递增的有序链表 要求结果链表仍使用原来两个链表的存储空间 不另外占用其它的存储空间 表中不允许有重复的数据 题目分析 合并后的新表使用头指针Lc指向 pa和pb分别是链表La和Lb的工作指针 初
  • vue项目中封装手动上传单个图片并支持修改和移除

    现有的组件库无法满足手动上传文件到服务器 并支持通过按钮修改和移除文件的操作 所以我利用原生input进行封装 如有需要请拿走 1 页面部分 div class upload picture div class uploadItem div
  • 通信原理及系统系列38——图解过采样和欠采样

  • 【华为OD机试真题 JS】关联子串

    标题 关联子串 时间限制 1秒 内存限制 262144K 语言限制 不限 给定两个字符串str1和str2 如果字符串str1中的字符 经过排列组合后的字符串中 只要有一个字符串是str2的子串 则认为str1是str2的关联子串 若str
  • uni-app左右平分九宫格样式

    效果图 1 template 布局
  • 对区块链技术的一些思考

    作者 朱金灿 来源 clever101的专栏 为什么大多数人学不会人工智能编程 gt gt gt 缘起 本想把标题起为有些扯淡的区块链 但想想咱们还是别标题党了 实在一些吧 前段时间有个朋友向我介绍区块链技术 提到区块链技术如何牛逼 说到
  • OSI七层模型与TCP/IP五层模型

    一 OSI参考模型 1 OSI的来源 OSI Open System Interconnect 即开放式系统互联 一般都叫OSI参考模型 是ISO 国际标准化组织 组织在1985年研究的网络互连模型 ISO为了更好的使网络应用更为普及 推出
  • python—test2021.11.2

    1 filter 函数的语法格式如下 newIter filter function iterable 正因为该函数是根据自定义的过滤函数进行过滤操作 所以支持更加灵活的过滤规格 其中 各个参数的含义如下 function 可传递一个用于判
  • Android P PowerManagerService分析(一)

    1 概述 PowerManagerService是负责管理 协调设备电源管理的系统服务之一 设备常见功能如亮灭屏 亮度调节 低电量模式 保持CPU唤醒等 都会通过PMS的协调和处理 其继承自SystemService 因此具有SystemS