安卓VirtualDisplay虚拟屏幕如何实现没有内容显示mirror屏幕内容(aosp13)

背景:

在录屏或者投屏创建VirtualDisplay时候经常会用到一个flag属性:

在这里插入图片描述简单说这个VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR功能就是在自己屏幕没有内容时候,会把另一个屏幕的内容进行镜像显示。即看到的如下状态:

在这里插入图片描述

上图既可以很好展示出这个虚拟屏幕的镜像功能,就是把主屏幕内容都复制一遍进行显示,即虚拟屏幕看到内容都和主屏幕内容一模一样,这个也就是录屏投屏必须会设置的VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR。

但VirtualDisplay也是可以进行自己内容的独立显示,比如可以把Activity单独搞到这Display上显示:
在这里插入图片描述

那么问题来了,请问系统是怎么做到的在有内容时候就不显示mirror主屏幕内容,没有内容就就只显示mirror内容呢?

原理调研方法步骤:

这里有了以前sf课程的知识基础,肯定知道一般各个layer要是显示在Display上,说明就是这个layer可以被Display包含,主要就是如下参数:
dumpsys SurfaceFlinger命令输出如下:

看看display的层级数据
在这里插入图片描述
同时在看看对应的每个layer也有对应的图层索引数据:
在这里插入图片描述
二者可以匹配那么就代表layer可以在这Display进行显示

看看镜像模式和自己内容显示时候,对于这个Display的layerStack有啥差异

显示自己内容时候如下:
在这里插入图片描述
显示镜像时候如下:
在这里插入图片描述
明显可以看到这里时候得layerStack居然变成0。

所以这里就可以有一个非常重要线索,那就是在VirtualDisplay没有显示内容和有显示内容时候会涉及一个layerStack的变化,这layerStack变化是不是可以通过打印啥的来抓取一下是哪里触发的这个layerStack的变化呢?所以下面就需要在相关变化layerStack的地方加入堆栈打印来追踪

堆栈追踪

这里上层一旦有Task移入VirtualDisplay,就会导致相关的layerStack进行变化,这里一般的最后触发到SurfaceFlinger体现了,说明会通过SurfaceControl相关方法。
在这里插入图片描述
加入相关堆栈后,操作把Task移入虚拟屏幕和移出虚拟屏幕看看打印情况如下:

移入Activity到Display:
在这里插入图片描述
移出:
在这里插入图片描述
看一看到确实有对这个layerStack进行修改在Task进行移入和移出时候

核心源码分析

核心源码经过追踪最后发现如下部分是核心:

在这里插入图片描述
首先通过判断是否有FLAG_OWN_CONTENT_ONLY,我们是VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR所以自然这地方的ownContent是false

    
 final boolean ownContent = (info.flags & DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY) != 0;

所以核心会进入如下这个判断
在这里插入图片描述
这里的display.hasContentLocked标志就是返回当前Display是否有内容,如果没内容,那么就会吧dispkay变化成 device.getDisplayIdToMirrorLocked即这个displaydevice虚拟mirror的Display
在这里插入图片描述

而上面的hasContentLocked其实本质也是在通过遍历DisplayContent下面有没有可以显示Window决定的。
在这里插入图片描述

总结

VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR设置

1、会在DisplayContent的mApplySurfaceChangesTransaction中对Display是否有内容进行确定

2、一旦涉及了Display的上有内容到无内容的变化会调用setDisplayLayerStack来重新设置layerStack

3、在sf中layer会对layerStack进行匹配然后决定显示哪个Display

本文章更多详细代码和资料需要购买课程获取
hal+perfetto+surfaceflinger
https://mp.weixin.qq.com/s/LbVLnu1udqExHVKxd74ILg
在这里插入图片描述

私聊作者+v(androidframework007)

其他课程七件套专题:在这里插入图片描述
点击这里
https://mp.weixin.qq.com/s/Qv8zjgQ0CkalKmvi8tMGaw

视频试看:
https://www.bilibili.com/video/BV1wc41117L4/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在Android 7.1 AOSP中添加屏幕密度选项并实现功能选项的功能,可以按照以下步骤进行操作: 1. 在AOSP源代码中找到Settings应用程序的代码目录,路径为packages/apps/Settings。 2. 在该目录下找到res/values/arrays.xml文件,并打开该文件。 3. 在该文件中添加一个新的数组,用于表示屏幕密度选项的值。例如: ``` <string-array name="screen_density_values"> <item>120</item> <item>160</item> <item>240</item> <item>320</item> <item>480</item> <item>640</item> </string-array> ``` 4. 在该文件中添加一个新的数组,用于表示屏幕密度选项的标签。例如: ``` <string-array name="screen_density_labels"> <item>@string/screen_density_120</item> <item>@string/screen_density_160</item> <item>@string/screen_density_240</item> <item>@string/screen_density_320</item> <item>@string/screen_density_480</item> <item>@string/screen_density_640</item> </string-array> ``` 5. 在该文件中添加对应的字符串资源,例如: ``` <string name="screen_density_120">Low Density (120)</string> <string name="screen_density_160">Medium Density (160)</string> <string name="screen_density_240">High Density (240)</string> <string name="screen_density_320">Extra High Density (320)</string> <string name="screen_density_480">Extra Extra High Density (480)</string> <string name="screen_density_640">Extra Extra Extra High Density (640)</string> ``` 6. 在Settings应用程序的代码中,找到DisplaySettings.java文件,并打开该文件。 7. 在该文件中找到屏幕密度选项的相关代码,在onCreate方法中添加以下代码: ``` mScreenDensityPreference = (ListPreference) findPreference(KEY_SCREEN_DENSITY); mScreenDensityPreference.setEntries(R.array.screen_density_labels); mScreenDensityPreference.setEntryValues(R.array.screen_density_values); mScreenDensityPreference.setValue(String.valueOf(currentDensity)); mScreenDensityPreference.setOnPreferenceChangeListener(this); ``` 其中,KEY_SCREEN_DENSITY是一个常量,表示屏幕密度选项对应的键值。currentDensity是当前屏幕密度的值。 8. 在该文件中实现功能选项的功能,在onPreferenceChange方法中添加以下代码: ``` if (preference == mScreenDensityPreference) { int density = Integer.parseInt((String) newValue); DisplayMetrics metrics = getResources().getDisplayMetrics(); metrics.densityDpi = density; getBaseContext().getResources().updateConfiguration(getResources().getConfiguration(), metrics); try { IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService("window")); if (wm != null) { wm.updateSettings(); } } catch (RemoteException e) { Log.e(TAG, "Unable to update window manager settings", e); } return true; } ``` 其中,newValue是用户选择的屏幕密度的值。该代码将用户选择的屏幕密度值更新到系统DisplayMetrics中,并更新配置信息。然后,它调用IWindowManager接口更新窗口管理器的设置。 9. 构建AOSP源代码并运行生成的系统镜像。 10. 在系统设置中,找到显示选项,即可看到屏幕密度选项,并且可以根据用户选择的屏幕密度值来改变屏幕显示效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值