当前位置:首页 > 计算机 > Android手机亮屏流程分析

Android手机亮屏流程分析

关键词:   发布时间:2019-07-10 08:00:01

极力推荐Android 开发大总结文章:欢迎收藏
程序员Android 力荐 ,Android 开发者需要的必备技能

注:文章转于网络,点击查看原文

PowerManagerService 之前系列文章请参考如下
1.PowerManagerService分析(一)之PMS启动
2.PowerManagerService分析(二)之updatePowerStateLocked()核心
3.PowerManagerService分析(三)之WakeLock机制

注: 本文转自网络,原文地址

本篇分析PMS中涉及到亮屏的部分,以及PMS相关的两个类:PowerManagerNotifier

1.亮屏流程

1.1.Power键亮屏

这里直接从PhoneWindowManager开始分析。按power键后,会触发PhoneWindowManagerinterceptKeyBeforeQueueing()方法:

@Override
    public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
           .......            case KeyEvent.KEYCODE_POWER: {
                cancelPendingAccessibilityShortcutAction();
                result &= ~ACTION_PASS_TO_USER;
                isWakeKey = false; // wake-up will be handled separately
                if (down) {
                    interceptPowerKeyDown(event, interactive);
                } else {
                    interceptPowerKeyUp(event, interactive, canceled);
                }                break;
            }
            .......

在这个方法中,对Power键的按下和抬起做了处理,按下时,调用interceptPowerKeyDown():

private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {    // Hold a wake lock until the power key is released.
    if (!mPowerKeyWakeLock.isHeld()) {       //1.申请一个唤醒锁,使CPU保持唤醒
        mPowerKeyWakeLock.acquire();
    }
   ......if (!mPowerKeyHandled) {       if (interactive) {
       ......
       } else {    //2.进行亮屏处理
        wakeUpFromPowerKey(event.getDownTime());
    ........
        }
    }
}

在这个方法中,首先是申请了一个唤醒锁,然后会对一些特定功能进行处理,如截屏、结束通话,等等,然后如果此时处于非交互状态(interactive=false),进行亮屏操作。该锁实例化如下:

mPowerKeyWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,            "PhoneWindowManager.mPowerKeyWakeLock");

申请锁流程在PowerManagerService分析第三篇PowerManagerService分析(三)之WakeLock机制已经分析过了。继续看wakeUpFromPowerKey()方法:

private void wakeUpFromPowerKey(long eventTime) {    //第三个参数为亮屏原因,因此如果是power键亮屏,则log中会出现android.policy:POWER
    wakeUp(eventTime, mAllowTheaterModeWakeFromPowerKey, "android.policy:POWER");
}private boolean wakeUp(long wakeTime, boolean wakeInTheaterMode, String reason) {    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);    return true;
}

在这个方法中,首先判断是否允许在剧院模式下点亮屏幕(这个模式不常用,未进行详细分析),之后通过PowerManagerPMS进行屏幕的唤醒,先来看看PowerManagerwakeup()方法:

public void wakeUp(long time) {    try {
        mService.wakeUp(time, "wakeUp", mContext.getOpPackageName());
    } catch (RemoteException e) {        throw e.rethrowFromSystemServer();
    }
}

现在到PMS中继续分析流程:

@Override // Binder callpublic void wakeUp(long eventTime, String reason, String opPackageName) {    if (eventTime > SystemClock.uptimeMillis()) {        throw new IllegalArgumentException("event time must not be in the future");
    }    //权限检查
    mContext.enforceCallingOrSelfPermission(
            android.Manifest.permission.DEVICE_POWER, null);    final int uid = Binder.getCallingUid();    //清除IPC标志
    final long ident = Binder.clearCallingIdentity();    try {        //调用内部方法
        wakeUpInternal(eventTime, reason, uid, opPackageName, uid);
    } finally {        //重置IPC标志
        Binder.restoreCallingIdentity(ident);
    }
}

PMS中暴露给Binder客户端的方法中,进行了权限的检查,然后调用wakeUpInternal()方法,该方法如下:

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

这里又调用了wakeUpNoUpdateLocked()方法,如果这个方法返回true,则会执行updatePowerStateLocked()方法,如果返回false,则整个过程结束。这个方法在我们分析wakelock申请时提到过,如果申请的wakelock锁带有唤醒屏幕的标志,也只执行这个方法,因此,这个方法是唤醒屏幕的主要方法之一,来看看这个方法:

private boolean wakeUpNoUpdateLocked(long eventTime, String reason, int reasonUid,
        String opPackageName, int opUid) {    if (eventTime < mLastSleepTime || mWakefulness == WAKEFULNESS_AWAKE
            || !mBootCompleted || !mSystemReady) {        return false;
    }    try {    //根据当前wakefulness状态打印log,这些log很有用
        switch (mWakefulness) {            case WAKEFULNESS_ASLEEP:
                Slog.i(TAG, "Waking up from sleep (uid " + reasonUid +")...");                break;            case WAKEFULNESS_DREAMING:
                Slog.i(TAG, "Waking up from dream (uid " + reasonUid +")...");                break;            case WAKEFULNESS_DOZING:
                Slog.i(TAG, "Waking up from dozing (uid " + reasonUid +")...");                break;
        }        //设置最后一次亮屏时间,即该次的时间
        mLastWakeTime = eventTime;        //设置wakefulness为WAKEFULNESS_AWAKE
        setWakefulnessLocked(WAKEFULNESS_AWAKE, 0);        //Notifier中通知BatteryStatsService统计亮屏
        mNotifier.onWakeUp(reason, reasonUid, opPackageName, opUid);        //更新用户活动时间
        userActivityNoUpdateLocked(
                eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, reasonUid);
    } finally {
    }    return true;
}

在这个方法中,Log中的reason需要注意一下:

  • Power键亮屏:
    则reason是PWM中传入的android.policy:POWER;

  • 来电亮屏:
    android.server.am:TURN_ON;

  • USB插拔时:
    android.server.power:POWER

所以不管是哪种亮屏方式,最终都会在这里汇合的。之后通过setWakefulnessLocked()方法设置wakefulness,再通过Notifier进行处理和通知其他系统服务wakefulness的改变,最后更新用户活动的时间,重置下次超时灭屏时间。继续看看setWakefulnessLocked():

void setWakefulnessLocked(int wakefulness, int reason) {       if (mWakefulness != wakefulness) {       //改变Wakefulness
        mWakefulness = wakefulness;
        mWakefulnessChanging = true;        //置位操作
        mDirty |= DIRTY_WAKEFULNESS;        if (mNotifier != null) {            //处理wakefulness改变前的操作
            mNotifier.onWakefulnessChangeStarted(wakefulness, reason);
        }
    }
}

首先,改变当前mWakefulness值,将mWakefulnessChanging标记为true,将mWakefulness值标志为DIRTY_WAKEFULNESS,然后通过Notifier进行改变wakefulness之前的一些处理,Notifier负责PMS和其他系统服务的交互。而Notifier中的onWakefulnessChangeStarted()方法,就是亮屏的主要方法之一,如发送亮屏或者灭屏的广播等。

为了不显得凌乱,将关于Notifier的具体细节的分析放在了3小节中。这里对其大概的进行下阐述。onWakefulnessChangeStarted()方法部分如下:

public void onWakefulnessChangeStarted(final int wakefulness, int reason) {        final boolean interactive = PowerManagerInternal.isInteractive(wakefulness);        if (DEBUG) {
            Slog.d(TAG, "onWakefulnessChangeStarted: wakefulness=" + wakefulness
                    + ", reason=" + reason + ", interactive=" + interactive);
        }        // 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();
            }            // Handle early behaviors.
            mInteractive = interactive;
            mInteractiveChangeReason = reason;
            mInteractiveChanging = true;            //做亮屏早期工作
            handleEarlyInteractiveChange();
        }
    }

亮屏操作,此时部分变量值为:
interactive为true; mInteractive为false; mInteractiveChanging = true;
因此会开始执行handleEarlyInteractiveChange()方法,做一些亮屏前期的工作,该方法亮屏部分如下:

private void handleEarlyInteractiveChange() {        synchronized (mLock) {            if (mInteractive) {                // Waking up...
                mHandler.post(new Runnable() {                    @Override
                    public void run() {                        //回调PhoneWindowManager
                        mPolicy.startedWakingUp();
                    }
                });                // Send interactive broadcast.
                mPendingInteractiveState = INTERACTIVE_STATE_AWAKE;
                mPendingWakeUpBroadcast = true;                //发送亮/灭屏广播
                updatePendingBroadcastLocked();
            } else {                // Going to sleep...
            }
        }
    }

首先,会回调

相关内容
分享 2019-07-10 08:00:01

0个评论

文明上网理性发言,请遵守新闻评论服务协议