【FW】DisplayManagerService相关

一、DisplayManagerService 核心职责

1. 系统服务定位

// Java 层入口
frameworks/base/services/core/java/com/android/server/display/DisplayManagerService.java
  • 核心功能
    • 监控显示设备(主屏/副屏/HDMI)的 热插拔事件
    • 维护 DisplayDevice 列表(设备创建/销毁)
    • 提供 DisplayManager API 给 App 使用
    • 管理显示模式(HDR/刷新率/DPI)

2. 启动流程概览

public class SystemServer {
    private void startOtherServices() {
        // Step1: 初始化 DisplayManagerService
        mSystemServiceManager.startService(DisplayManagerService.class);
        
        // Step2: 注册 Binder 接口
        ServiceManager.addService(Context.DISPLAY_SERVICE, service);
        
        // Step3: 发送 INIT_READY 消息
        sendBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
    }
}

二、DisplayDevice 生命周期全解析

1. 设备类型分类

类型来源示例
Internal系统内置手机主屏
External热插拔HDMI/Virtual Display
WifiMiracast 投屏无线显示设备

2. 生命周期阶段详解

(1) 设备添加阶段
// frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
void SurfaceFlinger::onHotplugReceived(int dispId, bool connected) {
    // Step1: 通过 Binder 通知 DMS
    mEventControlThread->post([this, dispId, connected] {
        mDisplayEventReceiver.sendDisplayEvent(dispId, connected ? 
            DisplayEventReceiver::DISPLAY_CONNECTED : 
            DisplayEventReceiver::DISPLAY_DISCONNECTED);
    });
}
// frameworks/base/services/core/java/com/android/server/display/DisplayManagerService.java
private final class DisplayEventReceiver extends Handler {
    @Override
    public void onMessageReceived(Message msg) {
        switch (msg.what) {
            case MSG_HANDLE_DISPLAY_EVENT:
                if (connected) {
                    // Step2: 创建 DisplayDevice 实例
                    createDisplayDeviceLocked(displayId);
                } else {
                    // Step3: 移除 DisplayDevice
                    removeDisplayDeviceLocked(displayId);
                }
        }
    }
}
(2) DisplayDevice 初始化
// frameworks/base/services/core/java/com/android/server/display/DisplayDevice.java
public DisplayDevice(...) {
    // Step1: 获取显示设备信息
    mInfo = new DisplayDeviceInfo();
    
    // Step2: 初始化显示参数(分辨率/DPI)
    configureDisplayLocked();
    
    // Step3: 注册监听器(如刷新率变化)
    registerDisplayListener();
}

// 关键数据结构
public final class DisplayDeviceInfo implements Parcelable {
    public int width;          // 宽度(像素)
    public int height;         // 高度
    public float refreshRate;  // 刷新率(如 60Hz)
    public int densityDpi;     // DPI(如 480)
    public boolean secure;     // 是否安全(防止截屏)
}
(3) 显示模式变更
// 修改刷新率示例(需系统签名)
WindowManager.LayoutParams params = getWindow().getAttributes();
params.preferredDisplayModeId = getMatchingDisplayModeId(90); // 设置为 90Hz
getWindow().setAttributes(params);
(4) 设备移除清理
private void removeDisplayDeviceLocked(int displayId) {
    // Step1: 通知所有注册的 listener
    for (DisplayDevice device : mDevices) {
        device.mCallback.onDisplayDeviceRemoved(device);
    }
    
    // Step2: 清理关联资源
    releaseResourcesLocked(displayId);
    
    // Step3: 广播 Intent
    sendDisplayRemovedBroadcast(displayId);
}

三、关键协作组件

1. DisplayAdapter

  • 职责:适配不同显示类型的协议(如 LocalDisplayAdapter 处理主屏)
// frameworks/base/services/core/java/com/android/server/display/LocalDisplayAdapter.java
protected void processDisplayDeviceInfoLocked(DisplayDeviceInfo info) {
    // Step1: 创建 DisplayDevice 实例
    DisplayDevice device = new DisplayDevice(this, info, false);
    
    // Step2: 添加到 DMS 管理列表
    mGlobal.registerDisplayDeviceLocked(device);
}

2. DisplayPowerController

  • 职能:管理屏幕亮灭状态(与 PowerManager 协作)
// frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
private void updateDisplayPowerStateLocked() {
    if (mDisplayReadyCondition != Display.STATE_ON) {
        // 请求关闭屏幕
        mDisplayPowerController.setScreenState(Display.STATE_OFF);
    }
}

四、实战调试技巧

1. ADB 命令监控

# 查看当前显示设备信息
adb shell dumpsys display

# 强制刷新率(需 root)
adb shell setprop debug.sf.use_phase_clock 1

# 模拟 HDMI 插拔事件
adb shell sendevent /dev/input/eventX 1 330 1 # 连接
adb shell sendevent /dev/input/eventX 1 330 0 # 断开

2. 日志分析

# 过滤 DMS 日志
adb logcat -s DisplayManagerService

# 查看 VSync 状态
adb shell dumpsys SurfaceFlinger --latency

3. 开发者选项调试

  • 强制 GPU 渲染开发者选项 → GPU 渲染模式分析
  • 窗口动画缩放设置 → 开发者选项 → 动画持续时间调整

五、典型问题排查案例

场景:副屏连接后黑屏

排查路径
  1. 检查 DMS 是否收到连接事件:
    adb logcat -s DisplayManagerService | grep "Display connected"
    
  2. 查看 SF 是否创建 Layer:
    adb shell dumpsys SurfaceFlinger | grep "Layer name=.*display"
    
  3. 检查 DisplayDevice 参数:
    adb shell dumpsys display | grep "DisplayDeviceInfo"
    
修复方向
  • secure=true 导致无法渲染,检查 DRM 权限配置
  • width/height=0,需修复厂商驱动返回的显示参数

六、推荐动手实验

实验1:监听显示设备变化

// 在 Activity 中注册监听
DisplayManager dm = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE);
dm.registerDisplayListener(new DisplayManager.DisplayListener() {
    @Override
    public void onDisplayAdded(int displayId) {
        Log.d("Display", "新增设备 ID:" + displayId);
    }

    @Override
    public void onDisplayRemoved(int displayId) {
        Log.d("Display", "移除设备 ID:" + displayId);
    }

    @Override
    public void onDisplayChanged(int displayId) {
        Log.d("Display", "设备变更 ID:" + displayId);
    }
}, null);

实验2:创建虚拟显示器

// 需要权限 <uses-permission android:name="android.permission.CREATE_MULTIPLE_USERS"/>
DisplayManager dm = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE);
VirtualDisplay vd = dm.createVirtualDisplay(...);

// 将 Camera Preview 输出到虚拟显示器
Surface surface = new Surface.Builder(vd.getDisplay())
    .setFormat(PixelFormat.RGBA_8888)
    .build();
camera.setPreviewDisplay(surface);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值