投屏成功後,手機橫屏切豎屏小窗畫面向右偏移

咸鱼Jay發表於2024-04-21

投屏成功後,手機橫屏切豎屏小窗畫面向右偏移

一、問題描述

  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

相關文章