Android N DisplayManager服务解析(二)

本文涉及的产品
数据管理 DMS,安全协同 3个实例 3个月
推荐场景:
学生管理系统数据库
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 版权声明:转载请联系本人,感谢配合!本站地址:http://blog.csdn.net/nomasp https://blog.csdn.net/NoMasp/article/details/77430743 PowerManagerService:负责协调设备上电源管理功能的服务。
版权声明:转载请联系本人,感谢配合!本站地址:http://blog.csdn.net/nomasp https://blog.csdn.net/NoMasp/article/details/77430743

PowerManagerService:负责协调设备上电源管理功能的服务。

DisplayPowerController:控制屏幕显示相关的电源状态。处理距离传感器、光线传感器和屏幕关闭时的动画等。这个组件在其他电源管理服务中是独立的,也就是说它不会共享任何状态,而只是通过异步回调来通知其他电源管理模块某些状态已经改变。这个类在内部做的一切都是被序列化的,尽管它可能被来自外部的其他线程访问。

DisplayManagerService:它管理显示的整个生命周期,决定怎样基于当前的物理显示设备来配置逻辑显示,并且当状态改变时发生通知给系统和应用。为了发现和配置依附于系统的一系列物理显示设备,DMS依赖于一系列 DisplayAdapter 组件。根据设备的不同分为不同的显示适配器:一个显示适配器用于内置的本地显示器;one for simulated non-functional displays when the system is headless;one for simulated overlay displays used for development;一个用于WiFi显示。通过注册的 DisplayAdapter.Listener ,适配器来和 DMS 异步地交流显示设备的状态。这里有两个主要的原因。 首先它很好的封装了两个类的职责:显示适配器处理各个显示设备,显示管理服务处理全局状态。其次,它消除了异步的查找显示设备时导致的死锁。

DisplayPowerState:控制显示状态。当属性改变的时候,该组件以统一的顺序发生一个回调以应用这些改变。这个组件必须且只能被属于 DPC 的 Looper 线程来创建和访问。

在PMS的systemReady方法中,会初始化各种组件,其中就包括这里的DMI,也就是DisplayManagerInternal,它位于hardware包下,作为显示管理的本地服务借口,而DMS等处于server包下,LocalService就继承于它,而DMS本身继承于SystemService。这SS是运行在系统进程中的用于server的基础类,负责提供了相关的生命周期和回调。

回调到DisplayManagerService LocalService.initPowerManagement
DMS.requestGlobalDisplayStateInternal -> applyGlobalDisplayStateLocked -> updateDisplayStateLocked

LocalDisplayDevice.requestDisplayStateLocked

以下都是在requestDisplayStateLocked返回的Runnable中调用的:
SurfaceControl.setDisplayPowerMode 调到native层
mBacklight.setBrightness

DisplayPowerController

DPC控制屏幕显示相关的电源状态,包括距离传感器和光线传感器等。

这个类比较多庞大,我们逐步来看,首先是构造方法。在这里对它所持有的对象进行了初始化,包括以下内容:

mHandler,内部持有的DisplayControllerHandler,用于分发事件。
mCallbacks,
mBatteryStates,
mSensorManager
mWindowManagerPolicy
mBlanker

调节屏幕电源状态,这里指的是屏幕状态,之后会通过mHandler来发送一条异步的MSG_UPDATE_POWER_STATE消息。

    /**
     * Requests a new power state.
     * The controller makes a copy of the provided object and then
     * begins adjusting the power state to match what was requested.
     *
     * @param request The requested power state.
     * @param waitForNegativeProximity If true, issues a request to wait for
     * negative proximity before turning the screen back on, assuming the screen
     * was turned off by the proximity sensor.
     * @return True if display is ready, false if there are important changes that must
     * be made asynchronously (such as turning the screen on), in which case the caller
     * should grab a wake lock, watch for {@link DisplayPowerCallbacks#onStateChanged()}
     * then try the request again later until the state converges.
     */
    public boolean requestPowerState(DisplayPowerRequest request,
            boolean waitForNegativeProximity) {
        if (DEBUG) {
            Slog.d(TAG, "requestPowerState: "
                    + request + ", waitForNegativeProximity=" + waitForNegativeProximity);
        }

        synchronized (mLock) {
            boolean changed = false;

            if (waitForNegativeProximity
                    && !mPendingWaitForNegativeProximityLocked) {
                mPendingWaitForNegativeProximityLocked = true;
                changed = true;
            }

            if (mPendingRequestLocked == null) {
                mPendingRequestLocked = new DisplayPowerRequest(request);
                changed = true;
            } else if (!mPendingRequestLocked.equals(request)) {
                mPendingRequestLocked.copyFrom(request);
                changed = true;
            }

            if (changed) {
                mDisplayReadyLocked = false;
            }

            if (changed && !mPendingRequestChangedLocked) {
                mPendingRequestChangedLocked = true;
                sendUpdatePowerStateLocked();
            }

            return mDisplayReadyLocked;
        }
    }

接下来就看看对于MSG_UPDATE_POWER_STATE消息是如何处理的,在handler中直接调用了updatePowerState()方法。

initialize() 为默认显示设备初始化电源状态,包括根据屏幕状态和亮度反馈给电源Line 508

根据mPowerRequest.policy来设置state和brightness

对距离传感器做相应的操作

执行屏幕状态变化的动画

息屏时亮度设为BRIGHTNESS_OFF

判断和使用自动亮度

boost这个没有理解,再看看源码,

再分别对自动亮度和手动亮度调节做处理

如果低电量模式开启,在亮度的阀值之上,对亮度进行减半

在屏幕点亮状态或休眠时,animate屏幕亮度。如果是息屏、挂起,或者从VR状态转入转出时,跳过动画。

判断对于新的状态请求,显示设备是否就绪

通知policy屏幕已经点亮,真正执行时在mWindowManagerPolicy.screenTurnedOn()

获取锁、通知状态、释放锁


DisplayPowerState

该组件用于控制显示状态,当属性改变的时候,其以统一的顺序将这些改变回调出去。这个组件只能被DisplayPowerController的Looper线程来创建和访问。

DisplayPowerState主要负责设置屏幕状态和屏幕亮度等。这里的dozing也是一种屏幕状态,它是指在低电量模式下,屏幕的休眠状态,但是此时仍然是亮屏的,这是为了让屏幕在没有发生交互时而显示内容的一种优化(其中又分为DOZE和DOZE_SUSPEND两种状态,后者能够实现always-on等功能)。

    /**
     * Sets whether the screen is on, off, or dozing.
     */
    public void setScreenState(int state) {
        if (mScreenState != state) {
            if (DEBUG) {
                Slog.d(TAG, "setScreenState: state=" + state);
            }

            mScreenState = state;
            mScreenReady = false;
            scheduleScreenUpdate();
        }
    }

    /**
     * Sets the display brightness.
     *
     * @param brightness The brightness, ranges from 0 (minimum / off) to 255 (brightest).
     */
    public void setScreenBrightness(int brightness) {
        if (mScreenBrightness != brightness) {
            if (DEBUG) {
                Slog.d(TAG, "setScreenBrightness: brightness=" + brightness);
            }

            mScreenBrightness = brightness;
            if (mScreenState != Display.STATE_OFF) {
                mScreenReady = false;
                scheduleScreenUpdate();
            }
        }
    }

其中最重要的就是这个scheduleScreenUpdate方法,它会去在mPhotonicModulator中异步地设置屏幕状态和亮度。

    private final Runnable mScreenUpdateRunnable = new Runnable() {
        @Override
        public void run() {
            mScreenUpdatePending = false;

            int brightness = mScreenState != Display.STATE_OFF
                    && mColorFadeLevel > 0f ? mScreenBrightness : 0;
            if (mPhotonicModulator.setState(mScreenState, brightness)) {
                if (DEBUG) {
                    Slog.d(TAG, "Screen ready");
                }
                mScreenReady = true;
                invokeCleanListenerIfNeeded();
            } else {
                if (DEBUG) {
                    Slog.d(TAG, "Screen not ready");
                }
            }
        }
    };

这个PhotonicModulator线程在DPS的构造函数中就已经start了,始终在运行着。那么对于一次setState操作,这个现场里究竟会发生什么呢?

1.在setState之后,该方法就会获取到mLock,这样在run中只会走到for循环里,但不会进到synchronized里面的代码中。
2.在setState中,首先会判断屏幕状态和背光是否发生改变,如果是就继续往下走,将这两个值赋给现场内部的mPending*,这个会在run()中使用。
3.判断状态是否都在改变中,判断完后分别进行赋值,如果不在就调用mLock.notifyAll()通知现场可以进行修改了。然后setState方法返回false,因为还没有设置完毕。
4.此时就轮到run方法中获取mLock了,在这里首先state和backlight会获取到来自setState中存储到线程内的值,如果设置的状态和实际的状态不一样,就不会将InProgress的值设为false,因为现在正是要进行修改。
5.然后就会去调用mBlander去设置屏幕状态和背光。
6.在屏幕状态和背光都设置好之后,因为是run方法,for循环还得继续,此时因为值没有变化,不用修改,所以就会去wait。

        public boolean setState(int state, int backlight) {
            synchronized (mLock) {
                boolean stateChanged = state != mPendingState;
                boolean backlightChanged = backlight != mPendingBacklight;
                if (stateChanged || backlightChanged) {
                    if (DEBUG) {
                        Slog.d(TAG, "Requesting new screen state: state="
                                + Display.stateToString(state) + ", backlight=" + backlight);
                    }

                    mPendingState = state;
                    mPendingBacklight = backlight;

                    boolean changeInProgress = mStateChangeInProgress || mBacklightChangeInProgress;
                    mStateChangeInProgress = stateChanged;
                    mBacklightChangeInProgress = backlightChanged;

                    if (!changeInProgress) {
                        mLock.notifyAll();
                    }
                }
                return !mStateChangeInProgress;
            }
        }
        @Override
        public void run() {
            for (;;) {
                // Get pending change.
                final int state;
                final boolean stateChanged;
                final int backlight;
                final boolean backlightChanged;
                synchronized (mLock) {
                    state = mPendingState;
                    stateChanged = (state != mActualState);
                    backlight = mPendingBacklight;
                    backlightChanged = (backlight != mActualBacklight);
                    if (!stateChanged) {
                        // State changed applied, notify outer class.
                        postScreenUpdateThreadSafe();
                        mStateChangeInProgress = false;
                    }
                    if (!backlightChanged) {
                        mBacklightChangeInProgress = false;
                    }
                    if (!stateChanged && !backlightChanged) {
                        try {
                            mLock.wait();
                        } catch (InterruptedException ex) { }
                        continue;
                    }
                    mActualState = state;
                    mActualBacklight = backlight;
                }

                // Apply pending change.
                if (DEBUG) {
                    Slog.d(TAG, "Updating screen state: state="
                            + Display.stateToString(state) + ", backlight=" + backlight);
                }
                mBlanker.requestDisplayState(state, backlight);
            }
        }
相关实践学习
MySQL基础-学生管理系统数据库设计
本场景介绍如何使用DMS工具连接RDS,并使用DMS图形化工具创建数据库表。
目录
相关文章
|
1月前
|
存储 缓存 算法
分布式锁服务深度解析:以Apache Flink的Checkpointing机制为例
【10月更文挑战第7天】在分布式系统中,多个进程或节点可能需要同时访问和操作共享资源。为了确保数据的一致性和系统的稳定性,我们需要一种机制来协调这些进程或节点的访问,避免并发冲突和竞态条件。分布式锁服务正是为此而生的一种解决方案。它通过在网络环境中实现锁机制,确保同一时间只有一个进程或节点能够访问和操作共享资源。
68 3
|
18天前
|
域名解析 缓存 网络协议
浏览器中输入URL返回页面过程(超级详细)、DNS域名解析服务,TCP三次握手、四次挥手
浏览器中输入URL返回页面过程(超级详细)、DNS域名解析服务,TCP三次握手、四次挥手
|
18天前
|
安全 测试技术 数据安全/隐私保护
原生鸿蒙应用市场开发者服务的技术解析:从集成到应用发布的完整体验
原生鸿蒙应用市场开发者服务的技术解析:从集成到应用发布的完整体验
|
26天前
|
安全 Java 网络安全
Android远程连接和登录FTPS服务代码(commons.net库)
Android远程连接和登录FTPS服务代码(commons.net库)
22 1
|
1月前
|
开发工具 Android开发 iOS开发
深入解析安卓与iOS开发环境的优劣
【10月更文挑战第4天】 本文将深入探讨安卓和iOS两大主流移动操作系统的开发环境,从技术架构、开发工具、用户体验等方面进行详细比较。通过分析各自的优势和不足,帮助开发者更好地理解这两个平台的异同,从而为项目选择最合适的开发平台提供参考。
24 3
|
19天前
|
安全 5G Android开发
安卓与iOS的较量:技术深度解析
【10月更文挑战第24天】 在移动操作系统领域,安卓和iOS无疑是两大巨头。本文将深入探讨这两个系统的技术特点、优势和不足,以及它们在未来可能的发展方向。我们将通过对比分析,帮助读者更好地理解这两个系统的本质和内涵,从而引发对移动操作系统未来发展的深思。
34 0
|
1月前
|
安全 Android开发 iOS开发
深入解析:安卓与iOS的系统架构及其对应用开发的影响
本文旨在探讨安卓与iOS两大主流操作系统的架构差异,并分析这些差异如何影响应用开发的策略和实践。通过对比两者的设计哲学、安全机制、开发环境及性能优化等方面,本文揭示了各自的特点和优势,为开发者在选择平台和制定开发计划时提供参考依据。
52 4
|
1月前
|
网络安全 Docker 容器
【Bug修复】秒杀服务器异常,轻松恢复网站访问--从防火墙到Docker服务的全面解析
【Bug修复】秒杀服务器异常,轻松恢复网站访问--从防火墙到Docker服务的全面解析
26 0
|
1月前
|
安全 网络安全 Android开发
深度解析:利用Universal Links与Android App Links实现无缝网页至应用跳转的安全考量
【10月更文挑战第2天】在移动互联网时代,用户经常需要从网页无缝跳转到移动应用中。这种跳转不仅需要提供流畅的用户体验,还要确保安全性。本文将深入探讨如何利用Universal Links(仅限于iOS)和Android App Links技术实现这一目标,并分析其安全性。
224 0
|
4天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
16 2

推荐镜像

更多