投屏成功後,手機橫屏切豎屏小窗畫面向右偏移
一、問題描述
- 手機投平板成功後,將手機橫屏,平板橫屏
- 點選手機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主線版本對此問題已有修改:
https://android.googlesource.com/platform/frameworks/base/+/d71737d6f59fd21c75c540d1b5f62df9ff84181a^!/#F1
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、問題驗證
手機進行投屏平板後,在手機端進行橫豎屏切換,可以發現不會在出現問題了,並透過列印的日誌也證明了上面的分析結論