zoukankan      html  css  js  c++  java
  • PowerManagerService流程分析

    一、PowerManagerService简介

      PowerManagerService主要服务Android系统电源管理工作,这样讲比较笼统,就具体细节上大致可以认为PowerManagerService集中处理用户活动(如点击屏幕,按电源键等)、电量变化、用户设置(如在Setting中设置省电模式,飞行模式)、插拔充电器(无线冲,有线冲)等。当发生以上事件时,PowerManagerService都要进行各种状态的更新,以下把PMS作为PowerManagerService的简称

    二、PowerManagerService启动流程

    2.1、PMS启动

            // Power manager needs to be started early because other services need it.
            // Native daemons may be watching for it to be registered so it must be ready
            // to handle incoming binder calls immediately (including being able to verify
            // the permissions for those calls).
            mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
        .
        .
        .
            try {
                // TODO: use boot phase
                mPowerManagerService.systemReady(mActivityManagerService.getAppOpsService());
            } catch (Throwable e) {
                reportWtf("making Power Manager Service ready", e);
            }

    2.2、SystemServiceManager.startService()

     1     public <T extends SystemService> T startService(Class<T> serviceClass) {
     2         final String name = serviceClass.getName();
     3         Slog.i(TAG, "Starting " + name);
     4 
     5         // Create the service.
     6         if (!SystemService.class.isAssignableFrom(serviceClass)) {
     7             throw new RuntimeException("Failed to create " + name
     8                     + ": service must extend " + SystemService.class.getName());
     9         }
    10         final T service;
    11         try {
    12             Constructor<T> constructor = serviceClass.getConstructor(Context.class);
    13             service = constructor.newInstance(mContext);
    14         } catch (InstantiationException ex) {
    15             throw new RuntimeException("Failed to create service " + name
    16                     + ": service could not be instantiated", ex);
    17         } catch (IllegalAccessException ex) {
    18             throw new RuntimeException("Failed to create service " + name
    19                     + ": service must have a public constructor with a Context argument", ex);
    20         } catch (NoSuchMethodException ex) {
    21             throw new RuntimeException("Failed to create service " + name
    22                     + ": service must have a public constructor with a Context argument", ex);
    23         } catch (InvocationTargetException ex) {
    24             throw new RuntimeException("Failed to create service " + name
    25                     + ": service constructor threw an exception", ex);
    26         }
    27 
    28         // Register it.
    29         mServices.add(service);
    30 
    31         // Start it.
    32         try {
    33             service.onStart();
    34         } catch (RuntimeException ex) {
    35             throw new RuntimeException("Failed to start service " + name
    36                     + ": onStart threw an exception", ex);
    37         }
    38         return service;
    39     }

     在Android5.0以后SystemServer启动服务的方式发生了改变,在Android4.4以前SystemServer通过new方法创建服务的对象,并把服务注册到SystemManager中;Android5.0以后SystemServer通过SystemServiceManager.startService来启动服务,主要通过反射的方式获取服务的构造方法,并创建服务对象;最后调用服务重写的onStart()方法。

    说明:Android5.0以后所有服务都实现SystemService接口,这样方法服务的统一管理。

    2.3 、PMS构造方法

     public PowerManagerService(Context context) {
            super(context);
            mContext = context;
            //启动一个线程,创建一个handler,handler发送的消息由该线程来处理
            mHandlerThread = new ServiceThread(TAG,
                    Process.THREAD_PRIORITY_DISPLAY, false /*allowIo*/);
            mHandlerThread.start();
            mHandler = new PowerManagerHandler(mHandlerThread.getLooper());
    
            synchronized (mLock) {
                //创建两个suspendBlocker对象,获取suspendblocker防止cpu进去休眠
                mWakeLockSuspendBlocker = createSuspendBlockerLocked("PowerManagerService.WakeLocks");
                mDisplaySuspendBlocker = createSuspendBlockerLocked("PowerManagerService.Display");
                mDisplaySuspendBlocker.acquire();
                mHoldingDisplaySuspendBlocker = true;
                mHalAutoSuspendModeEnabled = false;
                mHalInteractiveModeEnabled = true;
    
                mWakefulness = WAKEFULNESS_AWAKE;
                //初始化电源相关设置,这些方法通过jni调动native方法
                nativeInit();
                nativeSetAutoSuspend(false);
                nativeSetInteractive(true);
                nativeSetFeature(POWER_FEATURE_DOUBLE_TAP_TO_WAKE, 0);
            }
        }

    2.4、OnStart()方法

     1     @Override
     2     public void onStart() {
     3         //BinderService继承IPowerManager.Stub,其实就是PowerManager的服务端
     4         //这里其实就是把BinderService对象注册到ServiceManager中
     5         publishBinderService(Context.POWER_SERVICE, new BinderService());
     6         publishLocalService(PowerManagerInternal.class, new LocalService());
     7 
     8         //加入Watchdog监听
     9         Watchdog.getInstance().addMonitor(this);
    10         Watchdog.getInstance().addThread(mHandler);
    11     }

    2.5、systemReady()方法

        public void systemReady(IAppOpsService appOps) {
            synchronized (mLock) {
                mSystemReady = true;
                mAppOps = appOps;
                mDreamManager = getLocalService(DreamManagerInternal.class);
                mDisplayManagerInternal = getLocalService(DisplayManagerInternal.class);
                mPolicy = getLocalService(WindowManagerPolicy.class);
                mBatteryManagerInternal = getLocalService(BatteryManagerInternal.class);
    
                PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
                //最大、最小、默认的屏幕亮超时时间
                mScreenBrightnessSettingMinimum = pm.getMinimumScreenBrightnessSetting();
                mScreenBrightnessSettingMaximum = pm.getMaximumScreenBrightnessSetting();
                mScreenBrightnessSettingDefault = pm.getDefaultScreenBrightnessSetting();
                //传感器相关,传感器检查到外部事件可以通过发送消息到mHandler的消息队列中处理
                SensorManager sensorManager = new SystemSensorManager(mContext, mHandler.getLooper());
    
                // The notifier runs on the system server's main looper so as not to interfere
                // with the animations and other critical functions of the power manager.
                mBatteryStats = BatteryStatsService.getService();
                
                //注意上面的注释,notifier运行在system server的主线程中,并且参数中传入了一个SuspendBlocker对象,应该发送通知的时候需要点亮屏幕
                mNotifier = new Notifier(Looper.getMainLooper(), mContext, mBatteryStats,
                        mAppOps, createSuspendBlockerLocked("PowerManagerService.Broadcasts"),
                        mPolicy);
                //无线充电器相关,参数中传入了sensorManager,并且参数中传入了一个SuspendBlocker对象,也是为了有外部事件发生时点亮屏幕
                mWirelessChargerDetector = new WirelessChargerDetector(sensorManager,
                        createSuspendBlockerLocked("PowerManagerService.WirelessChargerDetector"),
                        mHandler);
                //ContentObserver对象,用来监听电源相关设置的改变
                mSettingsObserver = new SettingsObserver(mHandler);
    
                mLightsManager = getLocalService(LightsManager.class);
                mAttentionLight = mLightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
    
                // Initialize display power management.
                mDisplayManagerInternal.initPowerManagement(
                        mDisplayPowerCallbacks, mHandler, sensorManager);
    
                // Register for broadcasts from other components of the system.
    
                //注册一些广播监听器,如电量变化、用户切换(多用户模式,一般手机就是单用户)
                IntentFilter filter = new IntentFilter();
                filter.addAction(Intent.ACTION_BATTERY_CHANGED);
                filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
                mContext.registerReceiver(new BatteryReceiver(), filter, null, mHandler);
    
                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);
    
                filter = new IntentFilter();
                filter.addAction(Intent.ACTION_DOCK_EVENT);
                mContext.registerReceiver(new DockReceiver(), filter, null, mHandler);
    
                // Register for settings changes.
                //监听系统中对电源的设置,如开启省电模式、默认休眠超时时间、屏幕亮度、充电是否亮屏等等
                final ContentResolver resolver = mContext.getContentResolver();
                resolver.registerContentObserver(Settings.Secure.getUriFor(
                        Settings.Secure.SCREENSAVER_ENABLED),
                        false, mSettingsObserver, UserHandle.USER_ALL);
                .......
                .......
                .......
                // Go.
                //读取资源文件中电源相关设置
                readConfigurationLocked();
                //更新设置中对电源的相关设置
                updateSettingsLocked();
                mDirty |= DIRTY_BATTERY_STATE;
                //更新电源状态,这里统一处理了所有的状态更新,该方法会被频繁调用
                updatePowerStateLocked();
            }
        }

    2.6、updatePowerStateLocked()方法

     1     private void updatePowerStateLocked() {
     2         if (!mSystemReady || mDirty == 0) {
     3             return;
     4         }
     5         if (!Thread.holdsLock(mLock)) {
     6             Slog.wtf(TAG, "Power manager lock was not held when calling updatePowerStateLocked");
     7         }
     8 
     9         Trace.traceBegin(Trace.TRACE_TAG_POWER, "updatePowerState");
    10         try {
    11             // Phase 0: Basic state updates.
    12             updateIsPoweredLocked(mDirty);
    13             //设置DIRTY_STAY_ON标志位
    14             updateStayOnLocked(mDirty);
    15             updateScreenBrightnessBoostLocked(mDirty);
    16 
    17             // Phase 1: Update wakefulness.
    18             // Loop because the wake lock and user activity computations are influenced
    19             // by changes in wakefulness.
    20             final long now = SystemClock.uptimeMillis();
    21             int dirtyPhase2 = 0;
    22             for (;;) {
    23                 int dirtyPhase1 = mDirty;
    24                 dirtyPhase2 |= dirtyPhase1;
    25                 mDirty = 0;
    26 
    27                 updateWakeLockSummaryLocked(dirtyPhase1);
    28                 updateUserActivitySummaryLocked(now, dirtyPhase1);
    29                 if (!updateWakefulnessLocked(dirtyPhase1)) {
    30                     break;
    31                 }
    32             }
    33 
    34             // Phase 2: Update display power state.
    35             boolean displayBecameReady = updateDisplayPowerStateLocked(dirtyPhase2);
    36 
    37             // Phase 3: Update dream state (depends on display ready signal).
    38             updateDreamLocked(dirtyPhase2, displayBecameReady);
    39 
    40             // Phase 4: Send notifications, if needed.
    41             finishWakefulnessChangeIfNeededLocked();
    42 
    43             // Phase 5: Update suspend blocker.
    44             // Because we might release the last suspend blocker here, we need to make sure
    45             // we finished everything else first!
    46             updateSuspendBlockerLocked();
    47         } finally {
    48             Trace.traceEnd(Trace.TRACE_TAG_POWER);
    49         }
    50     }

    这里还是需要把代码贴出来比较好,可以直观看到updatePowerStateLocked()有6个阶段

    第0阶段:基本状态更新:

    2.6.1、updateIsPoweredLocked()

     1     private void updateIsPoweredLocked(int dirty) {
     2         if ((dirty & DIRTY_BATTERY_STATE) != 0) {
     3             final boolean wasPowered = mIsPowered;
     4             final int oldPlugType = mPlugType;
     5             final boolean oldLevelLow = mBatteryLevelLow;
     6             //获取充电标志位、充电器类型、电量百分比、低电量标志位
     7             mIsPowered = mBatteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);
     8             mPlugType = mBatteryManagerInternal.getPlugType();
     9             mBatteryLevel = mBatteryManagerInternal.getBatteryLevel();
    10             mBatteryLevelLow = mBatteryManagerInternal.getBatteryLevelLow();
    11 
    12             if (DEBUG_SPEW) {
    13                 Slog.d(TAG, "updateIsPoweredLocked: wasPowered=" + wasPowered
    14                         + ", mIsPowered=" + mIsPowered
    15                         + ", oldPlugType=" + oldPlugType
    16                         + ", mPlugType=" + mPlugType
    17                         + ", mBatteryLevel=" + mBatteryLevel);
    18             }
    19             //充电器插拔时间发生、或者充电器类型更变则设置DIRTY_IS_POWERED标志位
    20             if (wasPowered != mIsPowered || oldPlugType != mPlugType) {
    21                 mDirty |= DIRTY_IS_POWERED;
    22 
    23                 // Update wireless dock detection state.
    24                 //判断是否进行无线充电
    25                 final boolean dockedOnWirelessCharger = mWirelessChargerDetector.update(
    26                         mIsPowered, mPlugType, mBatteryLevel);
    27 
    28                 // Treat plugging and unplugging the devices as a user activity.
    29                 // Users find it disconcerting when they plug or unplug the device
    30                 // and it shuts off right away.
    31                 // Some devices also wake the device when plugged or unplugged because
    32                 // they don't have a charging LED.
    33                 //上面的注释意思是说插拔充电器可以看做是用户行为,当插拔充电器时如果设备没有给出提示则用户会比较疑惑
    34                 //特别是在设备没有充电指示灯的时,所以一般插拔充电器时会唤醒设备
    35                 final long now = SystemClock.uptimeMillis();
    36                 if (shouldWakeUpWhenPluggedOrUnpluggedLocked(wasPowered, oldPlugType,
    37                         dockedOnWirelessCharger)) {
    38                     //如果设置了插拔充电器时候需要唤醒设备,则在这里唤醒设备
    39                     wakeUpNoUpdateLocked(now, "android.server.power:POWER", Process.SYSTEM_UID,
    40                             mContext.getOpPackageName(), Process.SYSTEM_UID);
    41                 }
    42                 userActivityNoUpdateLocked(
    43                         now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
    44 
    45                 // Tell the notifier whether wireless charging has started so that
    46                 // it can provide feedback to the user.
    47                 //当无线充电器开始充电时给出提示音,在mNotifier中进行处理,播放一个ogg音频文件,我的三星设备是在/system/media/audio/ui/WirelessChargingStarted.ogg
    48                 //该路径下有不少ogg文件,有兴趣的可以看看都是在什么情况下播的
    49                 if (dockedOnWirelessCharger) {
    50                     mNotifier.onWirelessChargingStarted();
    51                 }
    52             }
    53             //如果电源插拔时间发生、或者是低电量标志位发生变化
    54             if (wasPowered != mIsPowered || oldLevelLow != mBatteryLevelLow) {
    55                 if (oldLevelLow != mBatteryLevelLow && !mBatteryLevelLow) {
    56                     //当设备从低电量切换为非低电量,则设置自动打盹标志为false(因为已经不是低电量了)
    57                     if (DEBUG_SPEW) {
    58                         Slog.d(TAG, "updateIsPoweredLocked: resetting low power snooze");
    59                     }
    60                     mAutoLowPowerModeSnoozing = false;
    61                 }
    62                 //发送广播ACTION_POWER_SAVE_MODE_CHANGED,该广播在系统多处进行处理,在SystemUI中进行处理,如果低电量则给出提示
    63                 updateLowPowerModeLocked();
    64             }
    65         }
    66     }

    2.6.2、updateScreenBrightnessBoostLocked()

     1     private void updateScreenBrightnessBoostLocked(int dirty) {
     2         if ((dirty & DIRTY_SCREEN_BRIGHTNESS_BOOST) != 0) {
     3             if (mScreenBrightnessBoostInProgress) {
     4                 final long now = SystemClock.uptimeMillis();
     5                 //删除屏幕亮度提升超时广播
     6                 mHandler.removeMessages(MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT);
     7                 if (mLastScreenBrightnessBoostTime > mLastSleepTime) {
     8                     final long boostTimeout = mLastScreenBrightnessBoostTime +
     9                             SCREEN_BRIGHTNESS_BOOST_TIMEOUT;
    10                     //如果超时还没有发生,则重新发送广播(定时广播)
    11                     if (boostTimeout > now) {
    12                         Message msg = mHandler.obtainMessage(MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT);
    13                         msg.setAsynchronous(true);
    14                         mHandler.sendMessageAtTime(msg, boostTimeout);
    15                         return;
    16                     }
    17                 }
    18                 //运行到这里有2个条件
    19                 //mLastScreenBrightnessBoostTime <= mLastSleepTime 说明还在睡眠中
    20                 //boostTimeout <= now 说明屏幕提升超时发生
    21                 mScreenBrightnessBoostInProgress = false;
    22                 mNotifier.onScreenBrightnessBoostChanged();
    23                 userActivityNoUpdateLocked(now,
    24                         PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
    25             }
    26         }
    27     }

    第1阶段:基本状态更新: 

    2.6.3、updateWakeLockSummaryLocked()

     1  @SuppressWarnings("deprecation")
     2     private void updateWakeLockSummaryLocked(int dirty) {
     3         if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_WAKEFULNESS)) != 0) {
     4             mWakeLockSummary = 0;
     5             //mWakeLocks保存了用户创建的所有wakelock
     6             final int numWakeLocks = mWakeLocks.size();
     7             for (int i = 0; i < numWakeLocks; i++) {
     8                 final WakeLock wakeLock = mWakeLocks.get(i);
     9                 switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
    10                     case PowerManager.PARTIAL_WAKE_LOCK:
    11                         if (!wakeLock.mDisabled) {
    12                             // We only respect this if the wake lock is not disabled.
    13                             if(!wakeLock.mPackageName.equals("com.google.android.gms")){
    14                                 mWakeLockSummary |= WAKE_LOCK_CPU;
    15                             }
    16                         }
    17                         break;
    18                     case PowerManager.FULL_WAKE_LOCK:
    19                         mWakeLockSummary |= WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_BUTTON_BRIGHT;
    20                         break;
    21                     case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
    22                         mWakeLockSummary |= WAKE_LOCK_SCREEN_BRIGHT;
    23                         break;
    24                     case PowerManager.SCREEN_DIM_WAKE_LOCK:
    25                         mWakeLockSummary |= WAKE_LOCK_SCREEN_DIM;
    26                         break;
    27                     case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
    28                         mWakeLockSummary |= WAKE_LOCK_PROXIMITY_SCREEN_OFF;
    29                         break;
    30                     case PowerManager.DOZE_WAKE_LOCK:
    31                         mWakeLockSummary |= WAKE_LOCK_DOZE;
    32                         break;
    33                     case PowerManager.DRAW_WAKE_LOCK:
    34                         mWakeLockSummary |= WAKE_LOCK_DRAW;
    35                         break;
    36                 }
    37             }
    38             /**
    39                 根据mWakefullness的状态取消某些锁的作用,意思就是说在系统处于特定状态时,有些锁是没有意义的,需要取消mWakeLockSummary中相应的标志位
    40             */
    41             // Cancel wake locks that make no sense based on the current state.
    42             if (mWakefulness != WAKEFULNESS_DOZING) {
    43                 mWakeLockSummary &= ~(WAKE_LOCK_DOZE | WAKE_LOCK_DRAW);
    44             }
    45             /**
    46                 注意这里,当mWakefulless状态为asleep时,WAKE_LOCK_SCREEN_BRIGHT、WAKE_LOCK_SCREEN_DIM、WAKE_LOCK_BUTTON_BRIGHT、WAKE_LOCK_PROXIMITY_SCREEN_OFF
    47                 这几种WakeLock的标志位都会被清空,标志位被清空作用就是类似系统释放了这些锁;仔细看唯独WAKE_LOCK_CPU标志位不变,说明PARTIAL_WAKE_LOCK在系统休眠的
    48                 时候是不是会自动清空的,如果系统中存在PARTIAL_WAKE_LOCK,那么除非手动释放,不然系统将没办法进入休眠
    49                 如果第三方的应用获取了PARTIAL_WAKE_LOCK,但是在系统休眠时又不是释放该怎么办呢?在后面调试经验中会给出答案。
    50             */
    51             if (mWakefulness == WAKEFULNESS_ASLEEP
    52                     || (mWakeLockSummary & WAKE_LOCK_DOZE) != 0) {
    53                 mWakeLockSummary &= ~(WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM
    54                         | WAKE_LOCK_BUTTON_BRIGHT);
    55                 if (mWakefulness == WAKEFULNESS_ASLEEP) {
    56                     mWakeLockSummary &= ~WAKE_LOCK_PROXIMITY_SCREEN_OFF;
    57                 }
    58             }
    59             /**
    60                 根据mWakefullness的状态增加某些锁的作用,就是说当系统处于特定状态时,需要某些锁来保持系统的状态,比如WAKEFULNESS_AWAKE状态肯定是要保持CPU运行的,所以
    61                 需要添加WAKE_LOCK_CPU标志位以确保cpu处于运行状态
    62             */
    63             // Infer implied wake locks where necessary based on the current state.
    64             if ((mWakeLockSummary & (WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM)) != 0) {
    65                 if (mWakefulness == WAKEFULNESS_AWAKE) {
    66                     mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_STAY_AWAKE;
    67                 } else if (mWakefulness == WAKEFULNESS_DREAMING) {
    68                     mWakeLockSummary |= WAKE_LOCK_CPU;
    69                 }
    70             }
    71             if ((mWakeLockSummary & WAKE_LOCK_DRAW) != 0) {
    72                 mWakeLockSummary |= WAKE_LOCK_CPU;
    73             }
    74 
    75             if (DEBUG_SPEW) {
    76                 Slog.d(TAG, "updateWakeLockSummaryLocked: mWakefulness="
    77                         + PowerManagerInternal.wakefulnessToString(mWakefulness)
    78                         + ", mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary));
    79             }
    80         }
    81     }

     2.6.4、updateUserActivitySummaryLocked()

      这个方法只是更新mUserActivitySummary的值,内容比较简单,这里不再贴代码分析了,读者自行分析吧

    2.6.5、updateWakefulnessLocked()

     1     private boolean updateWakefulnessLocked(int dirty) {
     2         boolean changed = false;
     3         if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_BOOT_COMPLETED
     4                 | DIRTY_WAKEFULNESS | DIRTY_STAY_ON | DIRTY_PROXIMITY_POSITIVE
     5                 | DIRTY_DOCK_STATE)) != 0) {
     6                 //注意这里会改变mWakefullness的值,但是mWakefullness的值会影响锁的有效性,因此阶段2的处理在一个for循环中
     7             if (mWakefulness == WAKEFULNESS_AWAKE && isItBedTimeYetLocked()) {
     8                 if (DEBUG_SPEW) {
     9                     Slog.d(TAG, "updateWakefulnessLocked: Bed time...");
    10                 }
    11                 final long time = SystemClock.uptimeMillis();
    12                 if (shouldNapAtBedTimeLocked()) {
    13                     changed = napNoUpdateLocked(time, Process.SYSTEM_UID);
    14                 } else {
    15                     changed = goToSleepNoUpdateLocked(time,
    16                             PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, Process.SYSTEM_UID);
    17                 }
    18             }
    19         }
    20         return changed;
    21     }

    第2、3、4、5代码比较简单,这里就不分析了,读者自行分析,下面我们来关注第6阶段

    阶段6:

    2.6.6、updateSuspendBlockerLocked()

     1     private void updateSuspendBlockerLocked() {
     2         final boolean needWakeLockSuspendBlocker = ((mWakeLockSummary & WAKE_LOCK_CPU) != 0);
     3         final boolean needDisplaySuspendBlocker = needDisplaySuspendBlockerLocked();
     4         final boolean autoSuspend = !needDisplaySuspendBlocker;
     5         final boolean interactive = mDisplayPowerRequest.isBrightOrDim();
     6 
     7         // Disable auto-suspend if needed.
     8         // FIXME We should consider just leaving auto-suspend enabled forever since
     9         // we already hold the necessary wakelocks.
    10         if (!autoSuspend && mDecoupleHalAutoSuspendModeFromDisplayConfig) {
    11             setHalAutoSuspendModeLocked(false);
    12         }
    13         /**
    14             从上面我们知道有WAKE_LOCK_CPU标志的话就获取一个suspendblocker,这才是正真会阻止cpu待机的东西
    15         */
    16         // First acquire suspend blockers if needed.
    17         if (needWakeLockSuspendBlocker && !mHoldingWakeLockSuspendBlocker) {
    18             mWakeLockSuspendBlocker.acquire();
    19             mHoldingWakeLockSuspendBlocker = true;
    20         }
    21         /*
    22             只有屏幕亮的时候才需要display suspendblocker,当屏幕灭或者doz的时候这里不会获取suspendblocker
    23         */
    24         if (needDisplaySuspendBlocker && !mHoldingDisplaySuspendBlocker) {
    25             mDisplaySuspendBlocker.acquire();
    26             mHoldingDisplaySuspendBlocker = true;
    27         }
    28 
    29         /*
    30             设置设备为可交互模式
    31         */
    32         // Inform the power HAL about interactive mode.
    33         // Although we could set interactive strictly based on the wakefulness
    34         // as reported by isInteractive(), it is actually more desirable to track
    35         // the display policy state instead so that the interactive state observed
    36         // by the HAL more accurately tracks transitions between AWAKE and DOZING.
    37         // Refer to getDesiredScreenPolicyLocked() for details.
    38         if (mDecoupleHalInteractiveModeFromDisplayConfig) {
    39             // When becoming non-interactive, we want to defer sending this signal
    40             // until the display is actually ready so that all transitions have
    41             // completed.  This is probably a good sign that things have gotten
    42             // too tangled over here...
    43             if (interactive || mDisplayReady) {
    44                 setHalInteractiveModeLocked(interactive);
    45             }
    46         }
    47         /*
    48             注意这里needWakeLockSuspendBlocker为ture的话是不会释放mWakeLockSuspendBlocker的,所以系统会无法待机
    49             这样就能解释的通为什么PARTIAL_WAKE_LOCK级别的锁会导致不能待机了:
    50             app-->newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,flag) --->PMS设置mWakeLockSummary的WAKE_LOCK_CPU标志位
    51             --->PMS 因为WAKE_LOCK_CPU标志位存在mWakeLockSuspendBlocker.acquire()-->待机失败
    52         */
    53         // Then release suspend blockers if needed.
    54         if (!needWakeLockSuspendBlocker && mHoldingWakeLockSuspendBlocker) {
    55             mWakeLockSuspendBlocker.release();
    56             mHoldingWakeLockSuspendBlocker = false;
    57         }
    58         if (!needDisplaySuspendBlocker && mHoldingDisplaySuspendBlocker) {
    59             mDisplaySuspendBlocker.release();
    60             mHoldingDisplaySuspendBlocker = false;
    61         }
    62 
    63         //如果条件成立的话设置自动待机模式
    64         // Enable auto-suspend if needed.
    65         if (autoSuspend && mDecoupleHalAutoSuspendModeFromDisplayConfig) {
    66             setHalAutoSuspendModeLocked(true);
    67         }
    68     }

    三、PowerManager用法

     

    PowerManager的用法很简单,我们主要看下PowerManager创建锁这部分:

    newWakeLock(int levelAndFlags, String tag)

    levelAndFlags: 就是上边表格中的几个flag,可以看到不同的flag对系统的影响并不一样

    PARTIAL_WAKE_LOCK: 保持cpu运转状态,屏幕键盘灭,按power键该锁不会被系统自动释放,所以系统无法进去待机休眠

    SCREEN_DIM_WAKE_LOCK: 保持cpu处于运行状态,屏幕微亮、键盘灭,但是按power键进入待机休眠时会自动释放

    SCREEN_BRIGHT_WAKE_LOCK: 保持cpu处于运行状态,屏幕亮、键盘灭,但是按power键进入待机休眠时会自动释放

    FULL_WAKE_LOCK: 保持cpu处于运行状态,屏幕、键盘亮,但是按power键进入待机休眠时会自动释放

     

    注意:官方的文档介绍尽量不要使用WAKE_LOCK,用FLAG_KEEP_SCREEN_ON标志位代替WAKE_LOCK,用如下方式:

    1 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

    当然该方法只是针对当前Activity,如果要整个应用都保持屏幕亮,则可以写了BaseActivity并设置该标志位,其他Activity继承BaseActivity即可。

    四、PowerManagerService调试

    PMS中最容易出现的问题就是待机待不下去,原因就是上面说的PARTIAL_WAKE_LOCK级别的锁没有释放,按道理说这种锁的释放应该由应用自身来作的,但是一些第三方的应用(Google的一些应用就很多这种锁)没有释放的话该怎么办呢?

    下面介绍两种办法:

    1、强制不给设置WAKE_LOCK_CPU标志位

     1     private void updateWakeLockSummaryLocked(int dirty) {
     2         if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_WAKEFULNESS)) != 0) {
     3             mWakeLockSummary = 0;
     4             //mWakeLocks保存了用户创建的所有wakelock
     5             final int numWakeLocks = mWakeLocks.size();
     6             for (int i = 0; i < numWakeLocks; i++) {
     7                 final WakeLock wakeLock = mWakeLocks.get(i);
     8                 switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
     9                     case PowerManager.PARTIAL_WAKE_LOCK:
    10                         if (!wakeLock.mDisabled) {
    11                             // We only respect this if the wake lock is not disabled.
    12                             //com.google.android.gms获取了PARTIAL_WAKE_LOCK,但是不给设置WAKE_LOCK_CPU标志位
    13                             if(!wakeLock.mPackageName.equals("com.google.android.gms")){
    14                                 mWakeLockSummary |= WAKE_LOCK_CPU;
    15                             }else{
    16                                 mWakeLockSummary |= WAKE_LOCK_SCREEN_BRIGHT;
    17                             }
    18                         }

     2、让系统自动清楚WAKE_LOCK_CPU标志

    1             if (mWakefulness == WAKEFULNESS_ASLEEP
    2                     || (mWakeLockSummary & WAKE_LOCK_DOZE) != 0) {
    3                 mWakeLockSummary &= ~(WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM
    4                         | WAKE_LOCK_BUTTON_BRIGHT |WAKE_LOCK_CPU); //待机休眠时清楚 WAKE_LOCK_CPU
    5                 if (mWakefulness == WAKEFULNESS_ASLEEP) {
    6                     mWakeLockSummary &= ~WAKE_LOCK_PROXIMITY_SCREEN_OFF;
    7                 }
    8             }

     dumpsysy power可打印PMS中锁信息:

    五、总结

    总的来说PMS的流程并不复杂,不过需要静下心来分析代码仍然不是一件很容易的事情,本人水平有限,有不足之处请指出,后续我会持续更新修改。

    放弃很容易,但是坚持真的很酷,静享此刻,强风吹拂
  • 相关阅读:
    flash 自定义右键功能
    本地和VMware虚拟主机之间的网络访问
    java: org.luaj.vm2.LuaError:XXX module not found lua脚本初始化出错
    火狐 提示“此连接是不受信任的” 可能是因为开启了其它抓包代理软件导致的
    批量导入数据库
    引用Interop.SQLDMO.dll后的注意事项。
    c# Invoke和BeginInvoke 区别
    闭包的7种形式
    C#使用ICSharpCode.SharpZipLib压缩后进行web批量下载文件
    C# Socket编程笔记
  • 原文地址:https://www.cnblogs.com/joker8/p/7087321.html
Copyright © 2011-2022 走看看