fw面试折叠屏不会?一起来调研荣耀手机折叠屏原理

背景

近期有学员朋友参加framework面试相关面试时候,有的面试官问到了折叠屏相关的一些问题,对于折叠屏这块的知识其实整个网络都属于比较空缺的,可能是因为主流程度不够,折叠屏的出现上市时间有限,折叠屏太贵市场接受度比较差,相关的官方资料比较少等。

那么马哥今天麻烦了一个学员朋友用他的折叠屏手机来进行一些dump从而调研出折叠屏的一些实现原理。
dump情况:
dumpsys activity containers
dumpsys adisplay

输出去如下:

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

从 dumpsys display 入手调研看懂活跃/非活跃

1 折叠态 (display1.txt)

dumpsys display 关键字段:

  Viewports:
    Display 0: isActive=true,  physicalPort=148, logicalFrame=1080×2420   ← 活跃!
    Display 1: isActive=false, physicalPort=147, logicalFrame=2172×2352   ← 不活跃

  Display States:
    Display 0: ON          ← 亮屏
    Display 1: OFF         ← 灭屏

  Display Devices:
    port=148 (外屏): state=ON,  layerStack=0           ← 活跃!
    port=147 (内屏): state=OFF, layerStack=-1          ← 不活跃

2 展开态 (display2.txt)

dumpsys display 关键字段:

  Viewports:
    Display 0: isActive=true,  physicalPort=147, logicalFrame=2172×2352  ← 活跃!
    Display 1: isActive=false, physicalPort=148, logicalFrame=1080×2420  ← 不活跃

  Display States:
    Display 0: ON          ← 亮屏
    Display 1: OFF         ← 灭屏

  Display Devices:
    port=147 (内屏): state=ON,  layerStack=0           ← 活跃!
    port=148 (外屏): state=OFF, layerStack=-1          ← 不活跃

3 看懂"活跃"的四个信号

同一个面板是否活跃,在 dump 中可以从四个层面交叉验证:

层面活跃时的值不活跃时的值含义
Viewport.isActivetruefalse是否当前使用的显示区域
Display StateONOFF显示电源状态
Device stateONOFF物理面板供电状态
device.layerStack0-1是否连接 SurfaceFlinger(-1 = 无内容)

四个信号同时变化——因为它们来自同一条控制链路。

对比关键字段(折叠→展开的变化):

折叠态:                                  展开态:
  Viewport[0].physicalPort = 148          Viewport[0].physicalPort = 147    ← 换了!
  Viewport[0].uniqueId = ...137790        Viewport[0].uniqueId = ...406847  ← 换了!
  port=148 device state = ON              port=148 device state = OFF       ← 外屏灭了
  port=148 device layerStack = 0          port=148 device layerStack = -1   ← 断开SF
  port=147 device state = OFF             port=147 device state = ON        ← 内屏亮了
  port=147 device layerStack = -1         port=147 device layerStack = 0    ← 接入SF

结论:活跃的面板 → state=ON + layerStack=0;不活跃的面板 → state=OFF + layerStack=-1。layerStack=-1 是关键——这面物理屏上什么都不显示。


从 dumpsys activity containers 看窗口归属

containers dump 展示的是逻辑层面——所有窗口都挂在 LogicDisplay 上,而不是物理面板上。

折叠态 (containers1.txt)

ROOT bounds=[0,0][1080,2420]                 ← 当前有效尺寸=外屏

Display 0 bounds=[0,0][1080,2420]           ← 所有应用在这里
  └─ DefaultTaskDisplayArea
       ├─ Task=8171 小红书   bounds=[0,0][1080,2420]
       ├─ Task=1    桌面     bounds=[0,0][1080,2420]
       ├─ Task=8112 微信     bounds=[0,0][1080,2420]
       └─ ...

Display 1 bounds=[0,0][2172,2352]           ← 尺寸是内屏的,但没有Task
  └─ DefaultTaskDisplayArea                 ← 空的,无应用

展开态 (containers2.txt)

ROOT bounds=[0,0][2172,2352]               ← 尺寸=内屏

Display 0 bounds=[0,0][2172,2352]          ← 窗口全部迁移到这里
  └─ DefaultTaskDisplayArea
       ├─ Task=8171 小红书   bounds=[0,0][2172,2352]   ← 尺寸变了
       ├─ Task=1    桌面     bounds=[0,0][2172,2352]
       ├─ Task=8112 微信     bounds=[0,0][2172,2352]
       └─ ...

Display 1 bounds=[0,0][1080,2420]          ← 尺寸变成外屏,空的
  └─ DefaultTaskDisplayArea               ← 空

关键理解:Display ID 0 和 1 是逻辑编号,不是物理面板。展开时,物理内屏"换到"Display 0 下面,所有窗口跟着 Display 0 走——所以应用不需要知道自己跑在哪块物理面板上。但 bounds 变了(1080→2172),所以每个 Task 的尺寸都要重算。


活跃/非活跃是如何设置的

核心链路只有三步:

第一步:layout 配置文件说了算

/vendor/etc/displayconfig/display_layout_configuration.xml 定义了每个设备状态下,哪块面板 enabled、哪块 disabled

<!-- 折叠态 -->
<device-state name="FOLDED">
  <layout>
    <display address="port:148" logicalDisplayId="0" enabled="true"/>   <!-- 外屏活跃 -->
    <display address="port:147" logicalDisplayId="1" enabled="false"/>  <!-- 内屏休眠 -->
  </layout>
</device-state>

<!-- 展开态 -->
<device-state name="OPEN">
  <layout>
    <display address="port:147" logicalDisplayId="0" enabled="true"/>   <!-- 内屏活跃 -->
    <display address="port:148" logicalDisplayId="1" enabled="false"/>  <!-- 外屏休眠 -->
  </layout>
</device-state>

enabled="true/false" 就是活跃与否的源头。

总结

  1. 硬件层面:两块独立的物理面板(port=147 和 port=148)
  2. 逻辑层面:Display ID 0/1 是固定编号,窗口和应用挂在逻辑 Display 上不动
  3. 切换本质:物理面板在两个逻辑 Display 之间"交换",每次只有一个被设为 enabled
  4. 活跃的标志(dump 里看这四个字段):Viewport.isActive=true + DisplayState=ON + DeviceState=ON + layerStack=0
  5. 不活跃的标志isActive=false + DisplayState=OFF + DeviceState=OFF + layerStack=-1
  6. 控制源头display_layout_configuration.xml 中的 enabled 属性 → setEnabledLocked() → 设置 layerStack + 开关设备
  7. App 感知:通过 Activity.onConfigurationChanged() 收到新的屏幕尺寸/density/挖孔信息,触发重绘

更多折叠屏相关深入原理后续马哥将继续分析,有成果了分享到vip群内,学员们敬请期待。

原文地址:
https://mp.weixin.qq.com/s/pH5reyADvZRnQ28tpAQjSw

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里马学框架

帮助你了,就请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值