投屏成功后,手机横屏切竖屏小窗画面向右偏移
投屏成功后,手机横屏切竖屏小窗画面向右偏移
一、问题描述
- 手机投平板成功后,将手机横屏,平板横屏
- 点击手机Google File,选择一个视频进行观看,点击File的横屏锁定按钮功能,然后解锁,将手机竖屏
- 观察投屏小窗画面
- 小窗画面向右偏移
二、问题分析
2.1、日志分析
对比正常和异常的log,手机转屏时tMultiDisplay 虚拟屏都被设置了一次异常的matrix:dsdx 0.223325 dtdx 0.000000 dtdy 0.000000 dsdy 0.223325, 但正常时,在设置了异常matrix之后,又设置了一次正常的matrix: setMatrix dsdx 0.500000 dtdx 0.000000 dtdy 0.000000 dsdy 0.500000,最终结果就是正常的。
对比正常matrix设置时上下文的log,都有display configuration的变更和变更下发,tMultiDisplay应该在onConfigurationChanged
中重新设置matirx,异常时tMultiDisplay没有设置正常matrix的原因,怀疑是此时tMultiDisplay还没有disconnect和conncet,正常情况下tMultiDisplay disconnect和connect动作在配置变更下发之前。
系统ContentRecorder
的onConfigurationChanged
方法中会判断前后2次配置是否一致,如果一致,后面的配置变更就不下发了,怀疑tMultiDisplay disconnect和conncet log代表着录屏的某种重置,会让正常情况下第2次配置变更能让tMultiDisplay 的matrix正常变更。
异常:
03-30 13:34:28.102 1370 2116 V WindowManager: Content Recording: Display 3 was already recording, so apply transformations if necessary
03-30 13:33:25.267 1370 2821 V WindowManager: Content Recording: Going ahead with updating recording for display 3 to new bounds Rect(0, 0 - 720, 1612) and/or orientation 2.
03-30 13:33:25.267 1370 2821 E SurfaceComposerClient: cx setMatrix dsdx 0.223325 dtdx 0.000000 dtdy 0.000000 dsdy 0.223325
03-30 13:33:26.100 1370 1426 I DisplayDeviceRepository: Display device changed: DisplayDeviceInfo{"tMultiDisplay": uniqueId="virtual:com.xxx.smartlink,10268,tMultiDisplay,0", 360 x 806, modeId 6, renderFrameRate 60.0, defaultModeId 6, supportedModes [{id=6, width=360, height=806, fps=60.0, alternativeRefreshRates=[], supportedHdrTypes=[]}], colorMode 0, supportedColorModes [0], hdrCapabilities null, allmSupported false, gameContentTypeSupported false, density 106, 106.0 x 106.0 dpi, appVsyncOff 0, presDeadline 16666666, touch NONE, rotation 0, type VIRTUAL, deviceProductInfo null, state ON, committedState UNKNOWN, owner com.xxx.smartlink (uid 10268), frameRateOverride , brightnessMinimum 0.0, brightnessMaximum 0.0, brightnessDefault 0.0, hdrSdrRatio NaN, FLAG_PRESENTATION, installOrientation 0, displayShape DisplayShape{ spec=2098940347 displayWidth=360 displayHeight=806 physicalPixelDisplaySizeRatio=1.0 rotation=0 offsetX=0 offsetY=0 scale=1.0}}
03-30 13:33:26.112 1370 1424 I WindowManager: Override config changes=20000480 {0.0 ?mcc0mnc ?localeList ?layoutDir sw543dp w543dp h1217dp 106dpi lrg long port ?uimode ?night -touch -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 360, 806) mAppBounds=Rect(0, 0 - 360, 806) mMaxBounds=Rect(0, 0 - 360, 806) mDisplayRotation=ROTATION_0 mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=undefined mAlwaysOnTop=undefined mRotation=ROTATION_0 mSmartLandscapeMode=undefined} ?fontWeightAdjustment?ecid} for displayId=3
03-30 13:33:26.112 1370 1424 V WindowManager: Content Recording: Display 3 was already recording, so apply transformations if necessary
03-30 13:33:26.113 1370 1424 V WindowManager: DefaultTaskDisplayArea@135486604 is requesting orientation 2 (SCREEN_ORIENTATION_USER)
03-30 13:33:26.113 1370 1424 V WindowManager: FullscreenMagnification:0:12@34685930 is requesting orientation 2 (SCREEN_ORIENTATION_USER)
03-30 13:33:26.113 1370 1424 V WindowManager: OneHanded:0:14@84371163 is requesting orientation 2 (SCREEN_ORIENTATION_USER)
03-30 13:33:26.118 868 868 D BufferQueueConsumer: [VDS: tMultiDisplay](id:36400000003,api:1,p:868,c:868) disconnect
03-30 13:33:26.118 868 868 D BufferQueueProducer: [VDS: tMultiDisplay](id:36400000003,api:1,p:868,c:868) disconnect: api 1
03-30 13:33:26.121 868 868 D BufferQueueProducer: [VDS: tMultiDisplay](id:36400000004,api:1,p:868,c:868) connect: api=1 producerControlledByApp=false
正常:
03-30 13:34:28.103 1370 2116 V WindowManager: Content Recording: Going ahead with updating recording for display 3 to new bounds Rect(0, 0 - 720, 1612) and/or orientation -1.
03-30 13:34:28.103 1370 2116 E SurfaceComposerClient: cx setMatrix dsdx 0.223325 dtdx 0.000000 dtdy 0.000000 dsdy 0.223325
03-30 13:34:28.946 1370 1426 I DisplayDeviceRepository: Display device changed: DisplayDeviceInfo{"tMultiDisplay": uniqueId="virtual:com.xxx.smartlink,10268,tMultiDisplay,0", 360 x 806, modeId 8, renderFrameRate 60.0, defaultModeId 8, supportedModes [{id=8, width=360, height=806, fps=60.0, alternativeRefreshRates=[], supportedHdrTypes=[]}], colorMode 0, supportedColorModes [0], hdrCapabilities null, allmSupported false, gameContentTypeSupported false, density 106, 106.0 x 106.0 dpi, appVsyncOff 0, presDeadline 16666666, touch NONE, rotation 0, type VIRTUAL, deviceProductInfo null, state ON, committedState UNKNOWN, owner com.xxx.smartlink (uid 10268), frameRateOverride , brightnessMinimum 0.0, brightnessMaximum 0.0, brightnessDefault 0.0, hdrSdrRatio NaN, FLAG_PRESENTATION, installOrientation 0, displayShape DisplayShape{ spec=2098940347 displayWidth=360 displayHeight=806 physicalPixelDisplaySizeRatio=1.0 rotation=0 offsetX=0 offsetY=0 scale=1.0}}
03-30 13:34:28.952 868 868 D BufferQueueConsumer: [VDS: tMultiDisplay](id:36400000005,api:1,p:868,c:868) disconnect
03-30 13:34:28.952 868 868 D BufferQueueProducer: [VDS: tMultiDisplay](id:36400000005,api:1,p:868,c:868) disconnect: api 1
03-30 13:34:28.955 868 868 D BufferQueueProducer: [VDS: tMultiDisplay](id:36400000006,api:1,p:868,c:868) connect: api=1 producerControlledByApp=false
03-30 13:34:28.964 1370 1424 V WindowManager: Content Recording: Display 3 was already recording, so apply transformations if necessary
03-30 13:34:28.964 1370 1424 V WindowManager: App is requesting an orientation, return -1 for display id=0
03-30 13:34:28.964 1370 1424 V WindowManager: DefaultTaskDisplayArea@135486604 is requesting orientation -1 (SCREEN_ORIENTATION_UNSPECIFIED)
03-30 13:34:28.964 1370 1424 V WindowManager: FullscreenMagnification:0:12@34685930 is requesting orientation -1 (SCREEN_ORIENTATION_UNSPECIFIED)
03-30 13:34:28.964 1370 1424 V WindowManager: OneHanded:0:14@84371163 is requesting orientation -1 (SCREEN_ORIENTATION_UNSPECIFIED)
03-30 13:34:28.966 1370 1424 V WindowManager: Content Recording: Going ahead with updating recording for display 3 to new bounds Rect(0, 0 - 720, 1612) and/or orientation -1.
03-30 13:34:28.966 1370 1424 E SurfaceComposerClient: cx setMatrix dsdx 0.500000 dtdx 0.000000 dtdy 0.000000 dsdy 0.500000
03-30 13:34:29.043 1370 1424 V WindowManager: Content Recording: Display 3 state is now (2), so update recording?
上面日志Tag为WindowManager默认是不会打印的,因此需要打开开关才可以:
wm logging enable-text WM_DEBUG_ADD_REMOVE
wm logging enable-text WM_DEBUG_APP_TRANSITIONS_ANIM
wm logging enable-text WM_DEBUG_APP_TRANSITIONS
wm logging enable-text WM_DEBUG_DRAW
wm logging enable-text WM_SHOW_TRANSACTIONS
wm logging enable-text WM_SHOW_SURFACE_ALLOC
wm logging enable-text WM_DEBUG_FOCUS
wm logging enable-text WM_DEBUG_FOCUS_LIGHT
wm logging enable-text WM_DEBUG_BOOT
wm logging enable-text WM_DEBUG_SCREEN_ON
wm logging enable-text WM_DEBUG_KEEP_SCREEN_ON
wm logging enable-text WM_DEBUG_ORIENTATION
wm logging enable-text WM_DEBUG_CONFIGURATION
wm logging enable-text WM_DEBUG_SWITCH
wm logging enable-text WM_DEBUG_STATES
wm logging enable-text WM_DEBUG_TASKS
wm logging enable-text WM_DEBUG_STARTING_WINDOW
wm logging enable-text WM_DEBUG_ANIM
wm logging enable-text WM_DEBUG_RECENTS_ANIMATIONS
wm logging enable-text WM_DEBUG_REMOTE_ANIMATIONS
wm logging enable-text WM_DEBUG_WINDOW_ORGANIZER
wm logging enable-text WM_DEBUG_SYNC_ENGINE
wm logging enable-text WM_DEBUG_WINDOW_TRANSITIONS
wm logging enable-text WM_DEBUG_RESIZE
wm logging enable-text WM_DEBUG_CONTAINERS
wm logging enable-text WM_DEBUG_FOCUS
wm logging enable-text WM_DEBUG_WINDOW_MOVEMENT
wm logging enable-text WM_DEBUG_CONTENT_RECORDING
2.2、系统源码分析
异常时第2次Override config changes没有设置正确的matrix的原因是ContentRecorder.java
的下面这段代码中 lastOrientation != recordedContentOrientation
这个条件没有满足,手机横屏切竖屏时,参数lastOrientation
是横屏,就是Configuration.ORIENTATION_LANDSCAPE = 2
,而recordedContentOrientation
的值就是调用mRecordedWindowContainer
的getOrientation()
方法获取的,mRecordedWindowContainer
是录屏的主屏displayContent
,它的getOrientation()
方法的返回值就是log中打印的xxx is requesting orientation ...这种log, 异常时这个返回值是2,等于lastOrientation
,所以未走第2次matrix设置。
参数lastOrientation
取值上来自于Configuration
的orientation
变量,是land或port这种,而mRecordedWindowContainer.getOrientation()
返回的是当前应用请求的orientation
,取值是ActivityInfo
中的SCREEN_ORIENTATION_xxx
这类值,2者不是一个维度的,数值可能有重叠。
void onConfigurationChanged(@Configuration.Orientation int lastOrientation) {
......
final Rect recordedContentBounds = mRecordedWindowContainer.getBounds();
int recordedContentOrientation = mRecordedWindowContainer.getOrientation();
if (!mLastRecordedBounds.equals(recordedContentBounds)
|| lastOrientation != recordedContentOrientation ) {
Point surfaceSize = fetchSurfaceSizeIfPresent();
if (surfaceSize != null) {
...走到这个条件才会设置正确的surface matrix...
}
}
03-30 13:33:26.112 1370 1424 V WindowManager: Content Recording: Display 3 was already recording, so apply transformations if necessary
03-30 13:33:26.113 1370 1424 V WindowManager: DefaultTaskDisplayArea@135486604 is requesting orientation 2 (SCREEN_ORIENTATION_USER)
03-30 13:33:26.113 1370 1424 V WindowManager: FullscreenMagnification:0:12@34685930 is requesting orientation 2 (SCREEN_ORIENTATION_USER)
03-30 13:33:26.113 1370 1424 V WindowManager: OneHanded:0:14@84371163 is requesting orientation 2 (SCREEN_ORIENTATION_USER)
系统ContentRecorder
类是在Android T之后新增的,并且在Android U上也存在此问题,因此通过查看android-14.0.0_r28和android-14.0.0_r30的ContentRecorder
类的onConfigurationChanged
方法可以知道,在android-14.0.0_r30
开始使用了@Configuration.Orientation int recordedContentOrientation = mRecordedWindowContainer.getConfiguration().orientation;
替换了int recordedContentOrientation = mRecordedWindowContainer.getOrientation();
android-14.0.0_r28 | android-14.0.0_r30 |
---|---|
并且通过查找发现Google主线版本对此问题已有修改:
google还有一笔录屏旋转场景相关的patch,需要评估是否合入:
https://android.googlesource.com/platform/frameworks/base/+/ed63bbfecfc9690e9cece917e217630f5df9ce36
三、验证问题
正好我手上有个Android T的公司手机,可以通过此手机进行验证
3.1、下载手机系统源码
下载手机的系统源码
repo init -u git@xxx.com:xxx/manifest_t.git -m rom-t-mtk-ssi-xxx-ta.xml --depth=1 && repo sync -c --no-tag -j4
3.2、修改代码
我们在.\frameworks\base\services\core\java\com\android\server\wm
目录找到ContentRecorder.java
3.3、编译系统
source build/envsetup.sh && export OUT_DIR=out_sys && chooseconfig phone VZW && lunch sys_mssi_64_ww_armv82-userdebug && make sys_images -j24
因为我现有的手机系统比较旧,因此需要刷上面的编译的系统,而上面编译命令不会生成system.img
等文件,因此需要执行
m snod pnod -j32;m vbmetaimage -j32
执行完后会在 .\out_sys\target\product\mssi_64_ww_armv82
目录下生成相关.img
3.4、刷设备img
3.4.1、配置fastboot
执行fastboot devices
命令查看是否有设备,如果没有,则查看Sdk\platform-tools
目录下是否有fastboot.exe
并且是否配置了环境变量
如果上面没问题,则应该是没有相关驱动的原因,可以按照ADB Interface驱动安装[Android Studio开发]来配置
配置好后,就可以执行fastboot devices
查看到设备
3.4.2、执行fastboot命令
adb reboot bootloader
fastboot flash --disable-verity --disable-verification vbmeta_system vbmeta_system.img
fastboot reboot fastboot
fastboot flash system system.img
fastboot flash product product.img
fastboot reboot
执行完后,手机就更新最新的系统了。
3.5、替换services.jar
上面下载手机系统源码并编译后,会在.\out_sys\target\product\mssi_64_ww_armv82\system\framework
目录下生成services.jar
替换services.jar
前线进行手机root
adb root
adb remount
然后在进行adb shell
adb shell
cd /system/framework
mv services.jar services.jar_back // 备份原来的services.jar
// 将生成的services.jar push到手机的/system/framework目录内
adb push services.jar /system/framework
adb reboot
3.6、问题验证
手机进行投屏平板后,在手机端进行横竖屏切换,可以发现不会在出现问题了,并通过打印的日志也证明了上面的分析结论