PowerManagerService第四讲之亮屏

一.亮屏

​ 在上面讲解PSensor灭屏的时候其实已经有涉及到关于亮屏的相关知识。当灭屏之后WakeLock就不会被进程所持有,因此如果需要点亮屏幕,就需要去申请WakeLock。我们以最简单的按Power键亮屏来讲述

1.Power键亮屏

按下Power键的时候,down值为true,就会执行到interceptPowerKeyDown方法:

    private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
        // Hold a wake lock until the power key is released.
        // 申请唤醒锁
        if (!mPowerKeyWakeLock.isHeld()) {
            mPowerKeyWakeLock.acquire();
        }

        // Cancel multi-press detection timeout.
        if (mPowerKeyPressCounter != 0) {
            mHandler.removeMessages(MSG_POWER_DELAYED_PRESS);
        }

        mWindowManagerFuncs.onPowerKeyDown(interactive);

        // Latch power key state to detect screenshot chord.
        if (interactive && !mScreenshotChordPowerKeyTriggered
                && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
            mScreenshotChordPowerKeyTriggered = true;
            mScreenshotChordPowerKeyTime = event.getDownTime();
            interceptScreenshotChord();
            interceptRingerToggleChord();
        }

        // Stop ringing or end call if configured to do so when power is pressed.
        TelecomManager telecomManager = getTelecommService();
        boolean hungUp = false;
        if (telecomManager != null) {
            if (telecomManager.isRinging()) {
                // Pressing Power while there's a ringing incoming
                // call should silence the ringer.
                telecomManager.silenceRinger();
            } else if ((mIncallPowerBehavior
                    & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
                    && telecomManager.isInCall() && interactive) {
                // Otherwise, if "Power button ends call" is enabled,
                // the Power button will hang up any current active call.
                hungUp = telecomManager.endCall();
            }
        }

        GestureLauncherService gestureService = LocalServices.getService(
                GestureLauncherService.class);
        boolean gesturedServiceIntercepted = false;
        if (gestureService != null) {
            gesturedServiceIntercepted = gestureService.interceptPowerKeyDown(event, interactive,
                    mTmpBoolean);
            if (mTmpBoolean.value && mRequestedOrGoingToSleep) {
                mCameraGestureTriggeredDuringGoingToSleep = true;
            }
        }

        // Inform the StatusBar; but do not allow it to consume the event.
        sendSystemKeyToStatusBarAsync(event.getKeyCode());

        schedulePossibleVeryLongPressReboot();

        // If the power key has still not yet been handled, then detect short
        // press, long press, or multi press and decide what to do.
        mPowerKeyHandled = hungUp || mScreenshotChordVolumeDownKeyTriggered
                || mA11yShortcutChordVolumeUpKeyTriggered || gesturedServiceIntercepted;
        if (!mPowerKeyHandled) {
            if (interactive) {
                // When interactive, we're already awake.
                // Wait for a long press or for the button to be released to decide what to do.
                // 长按power键
                if (hasLongPressOnPowerBehavior()) {
                    if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
                        powerLongPress();
                    } else {
                        Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
                        msg.setAsynchronous(true);
                        if (hasVeryLongPressOnPowerBehavior()) {
                            Message longMsg = mHandler.obtainMessage(MSG_POWER_VERY_LONG_PRESS);
                            longMsg.setAsynchronous(true);
                            mHandler.sendMessageDelayed(longMsg, mVeryLongPressTimeout);
                        }
                    }
                }
            } else {
                // 亮屏处理
                wakeUpFromPowerKey(event.getDownTime());

                if (mSupportLongPressPowerWhenNonInteractive && hasLongPressOnPowerBehavior()) {
                    if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
                        powerLongPress();
                    } else {
                        Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
                        msg.setAsynchronous(true);
                        if (hasVeryLongPressOnPowerBehavior()) {
                            Message longMsg = mHandler.obtainMessage(MSG_POWER_VERY_LONG_PRESS);
                            longMsg.setAsynchronous(true);
                            mHandler.sendMessageDelayed(longMsg, mVeryLongPressTimeout);
                        }
                    }

                    mBeganFromNonInteractive = true;
                } else {
                    final int maxCount = getMaxMultiPressPowerCount();

                    if (maxCount <= 1) {
                        mPowerKeyHandled = true;
                    } else {
                        mBeganFromNonInteractive = true;
                    }
                }
            }
        }
    }来看wakeUpFromPowerKey方法:

可以看到会先去申请一个WakeLock锁,之后执行亮屏动作。调用wakeUpFromPowerKey方法:

    private void wakeUpFromPowerKey(long eventTime) {
        wakeUp(eventTime, mAllowTheaterModeWakeFromPowerKey,
                PowerManager.WAKE_REASON_POWER_BUTTON, "android.policy:POWER");
    }

接着看wakeUp的实现:

    private boolean wakeUp(long wakeTime, boolean wakeInTheaterMode, @WakeReason int reason,
            String details) {
        final boolean theaterModeEnabled = isTheaterModeEnabled();
        if (!wakeInTheaterMode && theaterModeEnabled) {
            return false;
        }

        if (theaterModeEnabled) {
            Settings.Global.putInt(mContext.getContentResolver(),
                    Settings.Global.THEATER_MODE_ON, 0);
        }

        mPowerManager.wakeUp(wakeTime, reason, details);
        return true;
    }

传入的第三个参数是亮屏的原因:WAKE_REASON_POWER_BUTTON(按Power键亮屏)。最终会走到PowerManager的wakeup方法(传三个参数的):

    public void wakeUp(long time, @WakeReason int reason, String details) {
        try {
            mService.wakeUp(time, reason, details, mContext.getOpPackageName());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

这时就会调用PowerManagerService的wakeUp方法:

        @Override // Binder call
        public void wakeUp(long eventTime, @WakeReason int reason, String details,
                String opPackageName) {
            if (eventTime > SystemClock.uptimeMillis()) {
                throw new IllegalArgumentException("event time must not be in the future");
            }

            // 判断DEVICE_POWER权限
            mContext.enforceCallingOrSelfPermission(
                    android.Manifest.permission.DEVICE_POWER, null);

            final int uid = Binder.getCallingUid();
            final long ident = Binder.clearCallingIdentity();
            try {
                wakeUpInternal(eventTime, reason, details, uid, opPackageName, uid);
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
        }

执行到wakeUpInternal方法:

    private void wakeUpInternal(long eventTime, @WakeReason int reason, String details, int uid,
            String opPackageName, int opUid) {
        synchronized (mLock) {
            if (wakeUpNoUpdateLocked(eventTime, reason, details, uid, opPackageName, opUid)) {
                updatePowerStateLocked();
            }
        }
    }

加锁后,先调用wakeUpNoUpdateLocked判断是否需要update,一般都是返回true。最终还是执行到PowerManagerService的关键方法updatePowerStateLocked上。

    private boolean wakeUpNoUpdateLocked(long eventTime, @WakeReason int reason, String details,
            int reasonUid, String opPackageName, int opUid) {
        if (DEBUG_SPEW) {
            Slog.d(TAG, "wakeUpNoUpdateLocked: eventTime=" + eventTime + ", uid=" + reasonUid);
        }

        if (eventTime < mLastSleepTime || mWakefulness == WAKEFULNESS_AWAKE
                || !mBootCompleted || !mSystemReady || mForceSuspendActive) {
            return false;
        }

        Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, 0);
        
        Trace.traceBegin(Trace.TRACE_TAG_POWER, "wakeUp");
        try {
            Slog.i(TAG, "Waking up from "
                    + PowerManagerInternal.wakefulnessToString(mWakefulness)
                    + " (uid=" + reasonUid
                    + ", reason=" + PowerManager.wakeReasonToString(reason)
                    + ", details=" + details
                    + ")...");
		   // 设置最后一次亮屏时间,即该次的时间
            mLastWakeTime = eventTime;
            // 设置最后一次亮屏的原因,即该次的原因
            mLastWakeReason = reason;
            // 设置wakefulness为WAKEFULNESS_AWAKE
            setWakefulnessLocked(WAKEFULNESS_AWAKE, reason, eventTime);

            // 通知BatteryStatsService统计亮屏
            mNotifier.onWakeUp(reason, details, reasonUid, opPackageName, opUid);
            // 更新用户活动时间
            userActivityNoUpdateLocked(
                    eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, reasonUid);
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_POWER);
        }
        return true;
    }

接着看setWakefulnessLocked方法的实现:

    void setWakefulnessLocked(int wakefulness, int reason, long eventTime) {
        if (mWakefulness != wakefulness) {
            mWakefulness = wakefulness;
            mWakefulnessChanging = true;
            mDirty |= DIRTY_WAKEFULNESS;
            if (mNotifier != null) {
                mNotifier.onWakefulnessChangeStarted(wakefulness, reason, eventTime);
            }
            mAttentionDetector.onWakefulnessChangeStarted(wakefulness);
        }
    }

这里会调用Notifier类的onWakefulnessChangeStarted方法,这个方法是用来通知设备正在更改唤醒状态:

    public void onWakefulnessChangeStarted(final int wakefulness, int reason, long eventTime) {
        final boolean interactive = PowerManagerInternal.isInteractive(wakefulness);
        if (DEBUG) {
            Slog.d(TAG, "onWakefulnessChangeStarted: wakefulness=" + wakefulness
                    + ", reason=" + reason + ", interactive=" + interactive);
        }

        // Tell the activity manager about changes in wakefulness, not just interactivity.
        // It needs more granularity than other components.
        // 唤醒ActivityManagerService
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                mActivityManagerInternal.onWakefulnessChanged(wakefulness);
            }
        });

        // Handle any early interactive state changes.
        // Finish pending incomplete ones from a previous cycle.
        if (mInteractive != interactive) {
            // Finish up late behaviors if needed.
            if (mInteractiveChanging) {
                // 结束后期的处理
                handleLateInteractiveChange();
            }

            // Start input as soon as we start waking up or going to sleep.
            // 启动Input
            mInputManagerInternal.setInteractive(interactive);
            mInputMethodManagerInternal.setInteractive(interactive);

            // Notify battery stats.
            // 通知电池状态
            try {
                mBatteryStats.noteInteractive(interactive);
            } catch (RemoteException ex) { }
            StatsLog.write(StatsLog.INTERACTIVE_STATE_CHANGED,
                    interactive ? StatsLog.INTERACTIVE_STATE_CHANGED__STATE__ON :
                            StatsLog.INTERACTIVE_STATE_CHANGED__STATE__OFF);

            // Handle early behaviors.
            // 处理前期行为
            mInteractive = interactive;
            mInteractiveChangeReason = reason;
            mInteractiveChangeStartTime = eventTime;
            mInteractiveChanging = true;
            handleEarlyInteractiveChange();
        }
    }

处理前期交互的handleEarlyInteractiveChange方法:

    private void handleEarlyInteractiveChange() {
        synchronized (mLock) {
            if (mInteractive) {
                // Waking up...
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        final int why = translateOnReason(mInteractiveChangeReason);
                        // 回调PhoneWindowManager
                        mPolicy.startedWakingUp(why);
                    }
                });

                // Send interactive broadcast.
                // 发送亮灭屏广播
                mPendingInteractiveState = INTERACTIVE_STATE_AWAKE;
                mPendingWakeUpBroadcast = true;
                updatePendingBroadcastLocked();
            } else {
                // Going to sleep...
                // Tell the policy that we started going to sleep.
                final int why = translateOffReason(mInteractiveChangeReason);
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        mPolicy.startedGoingToSleep(why);
                    }
                });
            }
        }
    }

调用堆栈信息如下:

12-09 03:31:37.397  1086  1192 I xw      :      at android.os.PowerManager.wakeUp(PowerManager.java:1208)
12-09 03:31:37.397  1086  1192 I xw      :      at com.android.server.policy.PhoneWindowManager.wakeUp(PhoneWindowManager.java:4981)
12-09 03:31:37.397  1086  1192 I xw      :      at com.android.server.policy.PhoneWindowManager.wakeUpFromPowerKey(PhoneWindowManager.java:4965)
12-09 03:31:37.397  1086  1192 I xw      :      at com.android.server.policy.PhoneWindowManager.interceptPowerKeyDown(PhoneWindowManager.java:1124)
12-09 03:31:37.397  1086  1192 I xw      :      at com.android.server.policy.PhoneWindowManager.interceptKeyBeforeQueueing(PhoneWindowManager.java:4283)
12-09 03:31:37.397  1086  1192 I xw      :      at com.android.server.wm.InputManagerCallback.interceptKeyBeforeQueueing(InputManagerCallback.java:164)
12-09 03:31:37.397  1086  1192 I xw      :      at com.android.server.input.InputManagerService.interceptKeyBeforeQueueing(InputManagerService.java:1827)

##二.总结

这里涉及的PowerManagerServices的一部分亮屏流程。整个唤醒流程是底层把power key传到上层 --> PowerManagerService处理 -->初始化keyguard/唤醒底层 --> 将亮度写到设备节点中。

PowerManagerService第四讲之亮屏PowerManagerService第四讲之亮屏 adroid_newbie 发布了18 篇原创文章 · 获赞 5 · 访问量 2万+ 私信 关注
上一篇:如何在python中结合Cmd和Matplotlib


下一篇:python-确保在交互式会话中释放资源