侧边栏
首页代码

投屏成功后,手机横屏切竖屏小窗画面向右偏移

投屏成功后,手机横屏切竖屏小窗画面向右偏移

一、问题描述

  1. 手机投平板成功后,将手机横屏,平板横屏
  2. 点击手机Google File,选择一个视频进行观看,点击File的横屏锁定按钮功能,然后解锁,将手机竖屏
  3. 观察投屏小窗画面
  4. 小窗画面向右偏移
    image

二、问题分析

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动作在配置变更下发之前。
系统ContentRecorderonConfigurationChanged方法中会判断前后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的值就是调用mRecordedWindowContainergetOrientation()方法获取的,mRecordedWindowContainer是录屏的主屏displayContent,它的getOrientation()方法的返回值就是log中打印的xxx is requesting orientation ...这种log, 异常时这个返回值是2,等于lastOrientation,所以未走第2次matrix设置。

参数lastOrientation取值上来自于Configurationorientation变量,是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_r28android-14.0.0_r30ContentRecorder类的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
image image

并且通过查找发现Google主线版本对此问题已有修改:

https://android.googlesource.com/platform/frameworks/base/+/d71737d6f59fd21c75c540d1b5f62df9ff84181a^!/#F1
image

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
image

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
image

3.4、刷设备img

3.4.1、配置fastboot

执行fastboot devices命令查看是否有设备,如果没有,则查看Sdk\platform-tools目录下是否有fastboot.exe并且是否配置了环境变量
image

如果上面没问题,则应该是没有相关驱动的原因,可以按照ADB Interface驱动安装[Android Studio开发]来配置

配置好后,就可以执行fastboot devices查看到设备
image

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

image

执行完后,手机就更新最新的系统了。

3.5、替换services.jar

上面下载手机系统源码并编译后,会在.\out_sys\target\product\mssi_64_ww_armv82\system\framework目录下生成services.jar

image

替换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、问题验证

手机进行投屏平板后,在手机端进行横竖屏切换,可以发现不会在出现问题了,并通过打印的日志也证明了上面的分析结论

image

posted @ 2024-04-21 18:22  咸鱼Jay  阅读(172)  评论(0编辑  收藏  举报
页脚HTML代码