背景:
上次blog分享了给学员朋友们布置的作业,今天来进行简单的揭秘。
问题:
在多屏互动时候有一个屏幕的画面是一个MirrorLayer,另一个屏幕画面是真实的,即2个屏幕上有一个是MirrorLayer,这个时候疑问就来了,经过在aosp13上体验发现,两个屏幕画面都可以正常接受触摸事件进行正常的事件响应。
分析套路和步骤:
和触摸相关第一时间是分析input相关的信息:
adb shell dumpsys input
核心信息如下:
TouchStates: <no displays touched>
Display: 2
logicalSize=1440x2960
transform (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_UNTRUSTED
transform (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_UNTRUSTED
transform (ROT_0) (TRANSLATE)
1.0000 0.0000 -0.0000
0.0000 1.0000 -2792.0000
0.0000 0.0000 1.0000
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_UNTRUSTED
transform (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_UNTRUSTED
transform (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_UNTRUSTED
transform (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_UNTRUSTED
transform (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_UNTRUSTED
transform (ROT_0) (SCALE TRANSLATE)
0.3145 -0.0000 22.6451
-0.0000 0.3145 46.5455
0.0000 0.0000 1.0000
7: 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_UNTRUSTED
transform (ROT_0) (SCALE TRANSLATE)
0.3145 -0.0000 22.6451
-0.0000 0.3145 46.5455
0.0000 0.0000 1.0000
Display: 0
logicalSize=1440x2960
transform (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_UNTRUSTED
transform (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_UNTRUSTED
transform (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_UNTRUSTED
transform (ROT_0) (TRANSLATE)
1.0000 0.0000 -0.0000
0.0000 1.0000 -2792.0000
0.0000 0.0000 1.0000
3: 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_UNTRUSTED
transform (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_UNTRUSTED
transform (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_UNTRUSTED
transform (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_UNTRUSTED
transform (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_UNTRUSTED
transform (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_UNTRUSTED
transform (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_UNTRUSTED
transform (ROT_0) (SCALE TRANSLATE)
0.3145 -0.0000 22.6451
-0.0000 0.3145 46.5455
0.0000 0.0000 1.0000
10: 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_UNTRUSTED
transform (ROT_0) (SCALE TRANSLATE)
0.3145 -0.0000 22.6451
-0.0000 0.3145 46.5455
0.0000 0.0000 1.0000
因为dump input信息较多,一般我们只关注相关window的部分,这个部分就是代表了每个屏幕的window有哪些在接受触摸事件,一般是上到下顺序依次寻找接受事件。
可以明显看到无论是display 2还是display 0都是有对相关的短信Activity的图层
display 2明显有ApplicationSettingsActivity的对应windowInfo
Display: 2
logicalSize=1440x2960
transform (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_UNTRUSTED
transform (ROT_0) (IDENTITY)
display 0也明显有ApplicationSettingsActivity的对应windowInfo,而且和上面display2的windowinfo是同一个对象(name='a0396ce 这个可以看出)
Display: 0
logicalSize=1440x2960
transform (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_UNTRUSTED
transform (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/