背景:
上次blog分享了给学员朋友们布置的作业,今天来进行简单的揭秘。
问题:
在多屏互动时候有一个屏幕的画面是一个MirrorLayer,另一个屏幕画面是真实的,即2个屏幕上有一个是MirrorLayer,这个时候疑问就来了,经过在aosp13上体验发现,两个屏幕画面都可以正常接受触摸事件进行正常的事件响应。
分析套路和步骤:
和触摸相关第一时间是分析input相关的信息:
adb shell dumpsys input
核心信息如下:
TouchStates: <no displays touched>Display: 2logicalSize=1440x2960transform (ROT_0) (IDENTITY)Windows:0: name='e5e3fdf PointerLocation - display 2', id=137, displayId=2, inputConfig=NO_INPUT_CHANNEL | NOT_FOCUSABLE | NOT_TOUCHABLE | PREVENT_SPLITTING | TRUSTED_OVERLAY, alpha=1.00, frame=[0,0][1440,2960], globalScale=1.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=<empty>, ownerPid=552, ownerUid=1000, dispatchingTimeout=0ms, hasToken=false, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (IDENTITY)1: name='642754 NavigationBar2', id=146, displayId=2, inputConfig=NOT_FOCUSABLE | TRUSTED_OVERLAY | WATCH_OUTSIDE_TOUCH | SLIPPERY, alpha=1.00, frame=[0,2792][1440,2960], globalScale=1.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=[166,2792][442,2960]|[580,2792][860,2960], ownerPid=742, ownerUid=10098, dispatchingTimeout=5000ms, hasToken=true, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (TRANSLATE)1.0000 0.0000 -0.00000.0000 1.0000 -2792.00000.0000 0.0000 1.00002: name='a0396ce com.android.messaging/com.android.messaging.ui.appsettings.ApplicationSettingsActivity', id=217, displayId=2, inputConfig=0x0, alpha=1.00, frame=[0,0][1440,2960], globalScale=1.000000, applicationInfo.name=ActivityRecord{363f04d u0 com.android.messaging/.ui.appsettings.ApplicationSettingsActivity} t32}, applicationInfo.token=0x7f37d78fa730, touchableRegion=[0,0][1440,2960], ownerPid=1596, ownerUid=10084, dispatchingTimeout=5000ms, hasToken=true, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (IDENTITY)3: name='3411b77 ActivityRecordInputSink com.android.messaging/.ui.appsettings.ApplicationSettingsActivity', id=231, displayId=2, inputConfig=NO_INPUT_CHANNEL | NOT_FOCUSABLE | NOT_TOUCHABLE, alpha=1.00, frame=[0,0][0,0], globalScale=0.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=[-14399,-29599][14400,29600], ownerPid=552, ownerUid=1000, dispatchingTimeout=0ms, hasToken=false, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (IDENTITY)4: name='598595e ActivityRecordInputSink com.android.messaging/.ui.conversationlist.ConversationListActivity', id=160, displayId=2, inputConfig=NO_INPUT_CHANNEL | NOT_VISIBLE | NOT_FOCUSABLE | NOT_TOUCHABLE, alpha=1.00, frame=[0,0][0,0], globalScale=0.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=[-14399,-29599][14400,29600], ownerPid=552, ownerUid=1000, dispatchingTimeout=0ms, hasToken=false, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (IDENTITY)5: name='2754cb8 ActivityRecordInputSink com.android.launcher3/.secondarydisplay.SecondaryDisplayLauncher', id=132, displayId=2, inputConfig=NO_INPUT_CHANNEL | NOT_VISIBLE | NOT_FOCUSABLE, alpha=1.00, frame=[0,0][0,0], globalScale=0.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=[-14399,-29599][14400,29600], ownerPid=552, ownerUid=1000, dispatchingTimeout=0ms, hasToken=false, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (IDENTITY)6: name='Wallpaper BBQ wrapper#140', id=140, displayId=2, inputConfig=NO_INPUT_CHANNEL | NOT_VISIBLE, alpha=1.00, frame=[-71,-147][2860,3108], globalScale=1.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=<empty>, ownerPid=742, ownerUid=10098, dispatchingTimeout=5000ms, hasToken=false, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (SCALE TRANSLATE)0.3145 -0.0000 22.6451-0.0000 0.3145 46.54550.0000 0.0000 1.00007: name='c0e9fea com.android.systemui.ImageWallpaper', id=139, displayId=2, inputConfig=NOT_VISIBLE | NOT_FOCUSABLE | NOT_TOUCHABLE | PREVENT_SPLITTING | IS_WALLPAPER, alpha=1.00, frame=[-71,-147][-71,-147], globalScale=1.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=<empty>, ownerPid=742, ownerUid=10098, dispatchingTimeout=5000ms, hasToken=true, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (SCALE TRANSLATE)0.3145 -0.0000 22.6451-0.0000 0.3145 46.54550.0000 0.0000 1.0000Display: 0logicalSize=1440x2960transform (ROT_0) (IDENTITY)Windows:0: name='StrictModeFlash', id=47, displayId=0, inputConfig=NO_INPUT_CHANNEL | NOT_VISIBLE | NOT_FOCUSABLE | NOT_TOUCHABLE | PREVENT_SPLITTING | TRUSTED_OVERLAY, alpha=1.00, frame=[0,0][1440,2960], globalScale=1.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=<empty>, ownerPid=0, ownerUid=0, dispatchingTimeout=0ms, hasToken=false, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (IDENTITY)1: name='e997ecb PointerLocation - display 0', id=50, displayId=0, inputConfig=NO_INPUT_CHANNEL | NOT_FOCUSABLE | NOT_TOUCHABLE | PREVENT_SPLITTING | TRUSTED_OVERLAY, alpha=1.00, frame=[0,0][1440,2960], globalScale=1.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=<empty>, ownerPid=552, ownerUid=1000, dispatchingTimeout=0ms, hasToken=false, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (IDENTITY)2: name='da1cb67 NavigationBar0', id=77, displayId=0, inputConfig=NOT_FOCUSABLE | TRUSTED_OVERLAY | WATCH_OUTSIDE_TOUCH | SLIPPERY, alpha=1.00, frame=[0,2792][1440,2960], globalScale=1.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=[166,2792][442,2960]|[580,2792][860,2960]|[996,2792][1273,2960], ownerPid=742, ownerUid=10098, dispatchingTimeout=5000ms, hasToken=true, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (TRANSLATE)1.0000 0.0000 -0.00000.0000 1.0000 -2792.00000.0000 0.0000 1.00003: name='621c16b StatusBar', id=78, displayId=0, inputConfig=NOT_FOCUSABLE | TRUSTED_OVERLAY, alpha=1.00, frame=[0,0][1440,84], globalScale=1.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=[0,0][1440,84], ownerPid=742, ownerUid=10098, dispatchingTimeout=5000ms, hasToken=true, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (IDENTITY)4: name='a0396ce com.android.messaging/com.android.messaging.ui.appsettings.ApplicationSettingsActivity', id=219, displayId=0, inputConfig=0x0, alpha=1.00, frame=[0,0][1440,2960], globalScale=1.000000, applicationInfo.name=ActivityRecord{363f04d u0 com.android.messaging/.ui.appsettings.ApplicationSettingsActivity} t32}, applicationInfo.token=0x7f37d78fa730, touchableRegion=[0,0][1440,2960], ownerPid=1596, ownerUid=10084, dispatchingTimeout=5000ms, hasToken=true, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (IDENTITY)5: name='3411b77 ActivityRecordInputSink com.android.messaging/.ui.appsettings.ApplicationSettingsActivity', id=232, displayId=0, inputConfig=NO_INPUT_CHANNEL | NOT_FOCUSABLE | NOT_TOUCHABLE, alpha=1.00, frame=[0,0][0,0], globalScale=0.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=[-14399,-29599][14400,29600], ownerPid=552, ownerUid=1000, dispatchingTimeout=0ms, hasToken=false, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (IDENTITY)6: name='598595e ActivityRecordInputSink com.android.messaging/.ui.conversationlist.ConversationListActivity', id=175, displayId=0, inputConfig=NO_INPUT_CHANNEL | NOT_VISIBLE | NOT_FOCUSABLE | NOT_TOUCHABLE, alpha=1.00, frame=[0,0][0,0], globalScale=0.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=[-14399,-29599][14400,29600], ownerPid=552, ownerUid=1000, dispatchingTimeout=0ms, hasToken=false, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (IDENTITY)7: name='80c19b3 com.android.launcher3/com.android.launcher3.uioverrides.QuickstepLauncher', id=179, displayId=0, inputConfig=NOT_FOCUSABLE | DUPLICATE_TOUCH_TO_WALLPAPER, alpha=1.00, frame=[0,0][1440,2960], globalScale=1.000000, applicationInfo.name=ActivityRecord{19be992 u0 com.android.launcher3/.uioverrides.QuickstepLauncher} t29}, applicationInfo.token=0x7f37d78bc210, touchableRegion=[0,0][1440,2960], ownerPid=1078, ownerUid=10096, dispatchingTimeout=5000ms, hasToken=true, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (IDENTITY)8: name='98e4748 ActivityRecordInputSink com.android.launcher3/.uioverrides.QuickstepLauncher', id=105, displayId=0, inputConfig=NO_INPUT_CHANNEL | NOT_FOCUSABLE, alpha=1.00, frame=[0,0][0,0], globalScale=0.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=[-14399,-29599][14400,29600], ownerPid=552, ownerUid=1000, dispatchingTimeout=0ms, hasToken=false, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (IDENTITY)9: name='Wallpaper BBQ wrapper#83', id=83, displayId=0, inputConfig=NO_INPUT_CHANNEL, alpha=1.00, frame=[-71,-147][2860,3108], globalScale=1.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=<empty>, ownerPid=742, ownerUid=10098, dispatchingTimeout=5000ms, hasToken=false, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (SCALE TRANSLATE)0.3145 -0.0000 22.6451-0.0000 0.3145 46.54550.0000 0.0000 1.000010: name='55a8a23 com.android.systemui.ImageWallpaper', id=82, displayId=0, inputConfig=NOT_FOCUSABLE | NOT_TOUCHABLE | PREVENT_SPLITTING | IS_WALLPAPER, alpha=1.00, frame=[-71,-147][-71,-147], globalScale=1.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=<empty>, ownerPid=742, ownerUid=10098, dispatchingTimeout=5000ms, hasToken=true, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (SCALE TRANSLATE)0.3145 -0.0000 22.6451-0.0000 0.3145 46.54550.0000 0.0000 1.0000
因为dump input信息较多,一般我们只关注相关window的部分,这个部分就是代表了每个屏幕的window有哪些在接受触摸事件,一般是上到下顺序依次寻找接受事件。
可以明显看到无论是display 2还是display 0都是有对相关的短信Activity的图层
display 2明显有ApplicationSettingsActivity的对应windowInfo
Display: 2logicalSize=1440x2960transform (ROT_0) (IDENTITY)Windows:2: name='a0396ce com.android.messaging/com.android.messaging.ui.appsettings.ApplicationSettingsActivity', id=217, displayId=2, inputConfig=0x0, alpha=1.00, frame=[0,0][1440,2960], globalScale=1.000000, applicationInfo.name=ActivityRecord{363f04d u0 com.android.messaging/.ui.appsettings.ApplicationSettingsActivity} t32}, applicationInfo.token=0x7f37d78fa730, touchableRegion=[0,0][1440,2960], ownerPid=1596, ownerUid=10084, dispatchingTimeout=5000ms, hasToken=true, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (IDENTITY)
display 0也明显有ApplicationSettingsActivity的对应windowInfo,而且和上面display2的windowinfo是同一个对象(name='a0396ce 这个可以看出)
Display: 0logicalSize=1440x2960transform (ROT_0) (IDENTITY)Windows:4: name='a0396ce com.android.messaging/com.android.messaging.ui.appsettings.ApplicationSettingsActivity', id=219, displayId=0, inputConfig=0x0, alpha=1.00, frame=[0,0][1440,2960], globalScale=1.000000, applicationInfo.name=ActivityRecord{363f04d u0 com.android.messaging/.ui.appsettings.ApplicationSettingsActivity} t32}, applicationInfo.token=0x7f37d78fa730, touchableRegion=[0,0][1440,2960], ownerPid=1596, ownerUid=10084, dispatchingTimeout=5000ms, hasToken=true, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (IDENTITY)
到这里就可以理解为啥两个屏幕各自的mirrorlayer和正常layer都可以正常接受触摸事件的原因,因为在input派发选择窗口,遍历window时候,都对应是同一个windowinfo。
为啥可以实现在input层中两个sf的layer都是对应同一个windowinfo呢?这个部分就需要深入分析sf部分的源码
不同display的Layer对应相同windowinfo
分析一下sf中mirrorLayer的源码实现
status_t SurfaceFlinger::mirrorLayer(const LayerCreationArgs& args,const sp<IBinder>& mirrorFromHandle, sp<IBinder>* outHandle,int32_t* outLayerId) {ATRACE_CALL();if (!mirrorFromHandle) {return NAME_NOT_FOUND;}sp<Layer> mirrorLayer;sp<Layer> mirrorFrom;{status_t result = createContainerLayer(args, outHandle, &mirrorLayer);mirrorLayer->setClonedChild(mirrorFrom->createClone());}*outLayerId = mirrorLayer->sequence;return addClientLayer(args.client, *outHandle, mirrorLayer /* layer */, nullptr /* parent */,false /* addToRoot */, nullptr /* outTransformHint */);
}
创建好根部mirrorLayer,且把mirrorFrom也创建了一个Clone Layer,作为mirrorLayer的child,但是并没有对mirrorFrom的Child Layer进行相关的创建,相当于现在只有个最顶层的mirrorFrom的mirror如下:
如上图所示,只有个Task的Mirror,但是Task下面的ActivityRecord等并没有进行创建,得等到下一次vsync来时
void Layer::updateMirrorInfo() {ATRACE_FORMAT("%s updateMirrorInfo",mName.c_str());//省略mClonedChild->updateClonedDrawingState(clonedLayersMap);mClonedChild->updateClonedChildren(this, clonedLayersMap);mClonedChild->updateClonedRelatives(clonedLayersMap);
}
这里updateClonedChildren会导致最后相关Children Layer进行createClone
sp<Layer> BufferStateLayer::createClone() {LayerCreationArgs args(mFlinger.get(), nullptr, mName + " (Mirror)", 0, LayerMetadata());args.textureName = mTextureName;sp<BufferStateLayer> layer = mFlinger->getFactory().createBufferStateLayer(args);layer->mHwcSlotGenerator = mHwcSlotGenerator;layer->setInitialValuesForClone(this);return layer;
}
这里有个核心方法setInitialValuesForClone
void BufferLayer::setInitialValuesForClone(const sp<Layer>& clonedFrom) {Layer::setInitialValuesForClone(clonedFrom);sp<BufferLayer> bufferClonedFrom = static_cast<BufferLayer*>(clonedFrom.get());mPremultipliedAlpha = bufferClonedFrom->mPremultipliedAlpha;mPotentialCursor = bufferClonedFrom->mPotentialCursor;mProtectedByApp = bufferClonedFrom->mProtectedByApp;updateCloneBufferInfo();
}
这里会调用到updateCloneBufferInfo方法
mirrorLayer时候会进行全部信息的克隆拷贝模式,包含了这次分析最重要的windowInfo信息:
可以看到mirror的mDrawingState的inputInfo信息相当于是完全从real layer中拷贝过来的。
这里的inputInfo就是最为关键的信息,也就是最后传递给input端的关键点
传递WindowInfo的补充
在updateInputFlinger时候会进行windowInfos集合信息填充
接下来看看这里buildWindowInfos
这里看看fillInputInfo方法
可以看到其实这里就是把前面的的inputInfo最后通过updateInputFlinger中的跨进程调用到了InputDispatcher中去了
本文章对应视频手把手教你学framework:
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/