目录

window对应用层来说来,是view跟display解耦,对framework来说,是用来display跟layer(即surfaceflinger)解耦,简单的理解:display ->layer/view<-window。

从显示的角度来看,并没有windows这个概念,只有layer图层,display显示屏的概念,window提供了一个桥梁来连接display和layer,因为安卓系统只允许应用处理自己的view关系,而且display并不属于应用可以管理的范围,于是就在activity的生命周期加了入window来桥接displayt和view,window决定了view的显示,具体window和display创建的流程如下:

一、window创建流程

如上图,应用进程activity的生命周期函数里面按步骤创建window,view,关联view和window,会binder调到WMS的addwindow。

注:此处的WindowSession.addToDisplay 应为**com.android.server.wm**.Session

WMS, WindowToken 里的displaycontent即是Display。

addToDisplay 里会执行  WindowManagerService的addwindow。

1@Override 2public int addToDisplay(IWindow window, WindowManager.LayoutParams attrs, 3 int viewVisibility, int displayId, InsetsVisibilities requestedVisibilities, 4 InputChannel outInputChannel, InsetsState outInsetsState, 5 InsetsSourceControl[] outActiveControls) { 6 return mService.addWindow(this, window, attrs, viewVisibility, displayId, 7 UserHandle.getUserId(mUid), requestedVisibilities, outInputChannel, outInsetsState, 8 outActiveControls); 9} 10 11@Override 12public int addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs, 13 int viewVisibility, int displayId, int userId, InsetsVisibilities requestedVisibilities, 14 InputChannel outInputChannel, InsetsState outInsetsState, 15 InsetsSourceControl[] outActiveControls) { 16 return mService.addWindow(this, window, attrs, viewVisibility, displayId, userId, 17 requestedVisibilities, outInputChannel, outInsetsState, outActiveControls); 18} 19 20@Override 21public int addToDisplayWithoutInputChannel(IWindow window, WindowManager.LayoutParams attrs, 22 int viewVisibility, int displayId, InsetsState outInsetsState) { 23 return mService.addWindow(this, window, attrs, viewVisibility, displayId, 24 UserHandle.getUserId(mUid), mDummyRequestedVisibilities, null /* outInputChannel */, 25 outInsetsState, mDummyControls); 26}

在addwindow中对应不同场景。

1final boolean openInputChannels = (outInputChannel != null 2 && (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0); 3if (openInputChannels) { 4 win.openInputChannel(outInputChannel); 5} 6 7int userId = UserHandle.getUserId(session.mUid); 8if (requestUserId != userId) { 9 try { 10 mAmInternal.handleIncomingUser(callingPid, callingUid, requestUserId, 11 false /*allowAll*/, ALLOW_NON_FULL, null, null); 12 } catch (Exception exp) { 13 ProtoLog.w(WM_ERROR, "Trying to add window with invalid user=%d", 14 requestUserId); 15 return WindowManagerGlobal.ADD_INVALID_USER; 16 } 17 // It's fine to use this userId 18 userId = requestUserId; 19}

ViewRootImpl中requestLayout函数调用mWindowSession.relayout,最终调用WindowManagerservice 的relayoutWindow,这个函数会配置Display信息; WindowStateAnimator创建Surfacecontrol,通过SurfaceControl,设置Layerstack。即在触发view更新绘制的时候才会更新图层数据。

1// com.android.server.wm.WindowManagerService#relayoutWindow 2if (shouldRelayout) { 3 try { 4 result = createSurfaceControl(outSurfaceControl, result, win, winAnimator); 5 } catch (Exception e) { 6 displayContent.getInputMonitor().updateInputWindowsLw(true /*force*/); 7 8 ProtoLog.w(WM_ERROR, 9 "Exception thrown when creating surface for client %s (%s). %s", 10 client, win.mAttrs.getTitle(), e); 11 Binder.restoreCallingIdentity(origId); 12 return 0; 13 } 14}

至此,一个Windows对应一个ViewRootImpl,用来管理应用进程的view的绘制生命周期,事件机制等等,后续的流程是layer会在surfaceflinger里面处理后,经由GPU或者硬件合成渲染。

二、display创建流程

display主要由DisplayManagerService管理,DisplayManagerService是负责Display管理的系统服务之一,还有一些其他功能,包括屏幕亮度调节也涉及到DMS,其继承自SystemService,因此具有SystemService子类的共性:具有生命周期方法,由SystemServer启动、注册到系统服务中,通过Binder和其他组件进行交互等。

Display类的类型有四种:LocalDisplay、OverlayDisplay、WifiDisplay和VirtualDisplay。每一个Display对应一个DisplayAdapter。

  • LocalDisplayAdapter:本地已经存在的物理显示屏设备。

  • OverlayDisplayAdapter:模拟辅助显示设备,以类似浮动窗口的形式显示在主屏上,可以当第二个屏幕使用,默认也是镜像主屏。

  • WifiDisplayAdapter:WiFi Display

  • VirtualDisplayAdapter:显示一个虚拟屏幕

不同的类型的display的创建过程大同小异,在DMS里面的数据结构是DisplayDevice,不同类型的DisplayDevice都是由不同类型的DisplayAdapter创建的。虚拟屏mVirtualDisplayAdapter并没有在这里创建,在后面调用到的地方再创建。

1//注册主屏适配器 2 private void registerDefaultDisplayAdapters() { 3 // Register default display adapters. 4 synchronized (mSyncRoot) { 5 // main display adapter 6 registerDisplayAdapterLocked(new LocalDisplayAdapter( 7 mSyncRoot, mContext, mHandler, mDisplayDeviceRepo)); 8 9 // Standalone VR devices rely on a virtual display as their primary display for 10 // 2D UI. We register virtual display adapter along side the main display adapter 11 // here so that it is ready by the time the system sends the home Intent for 12 // early apps like SetupWizard/Launcher. In particular, SUW is displayed using 13 // the virtual display inside VR before any VR-specific apps even run. 14 mVirtualDisplayAdapter = mInjector.getVirtualDisplayAdapter(mSyncRoot, mContext, 15 mHandler, mDisplayDeviceRepo); 16 if (mVirtualDisplayAdapter != null) { 17 registerDisplayAdapterLocked(mVirtualDisplayAdapter); 18 } 19 } 20 } 21 private void registerAdditionalDisplayAdapters() { 22 synchronized (mSyncRoot) { 23 if (shouldRegisterNonEssentialDisplayAdaptersLocked()) { 24 registerOverlayDisplayAdapterLocked(); 25 registerWifiDisplayAdapterLocked(); 26 } 27 } 28 } 29 30 private void registerOverlayDisplayAdapterLocked() { 31 registerDisplayAdapterLocked(new OverlayDisplayAdapter( 32 mSyncRoot, mContext, mHandler, mDisplayDeviceRepo, mUiHandler)); 33 } 34 35 private void registerWifiDisplayAdapterLocked() { 36 if (mContext.getResources().getBoolean( 37 com.android.internal.R.bool.config_enableWifiDisplay) 38 || SystemProperties.getInt(FORCE_WIFI_DISPLAY_ENABLE, -1) == 1) { 39 mWifiDisplayAdapter = new WifiDisplayAdapter( 40 mSyncRoot, mContext, mHandler, mDisplayDeviceRepo, 41 mPersistentDataStore); 42 registerDisplayAdapterLocked(mWifiDisplayAdapter); 43 } 44 }

以VirtualDisplayDevice的创建为例来说明一个display创建过程,不同的安卓版本这部分代码有不少变动,以sdK-31为例:

应用进程调用到DisplayManagerGlobal,全局只有这一个,在里面提供了获取创建VirtualDisplay的方法。

1public VirtualDisplay createVirtualDisplay(Context context, MediaProjection projection, 2 String name, int width, int height, int densityDpi, Surface surface, int flags, 3 VirtualDisplay.Callback callback, Handler handler, String uniqueId)

获取所有逻辑id的方法getDisplayIds,和根据id返回info的方法,都是IPC调用到DisplayManagerService返回数据,可以遍历disaplyinfo。

1public int[] getDisplayIds() { 2 try { 3 synchronized (mLock) { 4 if (USE_CACHE) { 5 if (mDisplayIdCache != null) { 6 return mDisplayIdCache; 7 } 8 } 9 int[] displayIds = mDm.getDisplayIds(); 10... 11 return displayIds; 12 } 13 } catch (RemoteException ex) { 14 throw ex.rethrowFromSystemServer(); 15 } 16}
1public DisplayInfo getDisplayInfo(int displayId) { 2 try { 3 synchronized (mLock) { 4 DisplayInfo info; 5 if (USE_CACHE) { 6 info = mDisplayInfoCache.get(displayId); 7 if (info != null) { 8 return info; 9 } 10 } 11 12 info = mDm.getDisplayInfo(displayId); 13... 14 return info; 15 } 16 } catch (RemoteException ex) { 17 throw ex.rethrowFromSystemServer(); 18 } 19}

VirtualDisplayDevice创建流程如下:

经过如下三个函数的调用就创建了VirtualDisplayDevice,但是这时候只是创建好VirtualDisplay。

1com.android.server.display.DisplayManagerService#createVirtualDisplayInternal 2com.android.server.display.VirtualDisplayAdapter#createVirtualDisplayLocked 3com.android.server.display.VirtualDisplayAdapter.VirtualDisplayDevice#VirtualDisplayDevice

三、VirtualDisplayDevice的显示内容

创建后需要对DisplayDevices遍历处理,更新,同时也会加入到LogicDisplay。

1private void handleDisplayDeviceAddedLocked(DisplayDevice device) { 2 DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); 3 if (mDisplayDevices.contains(device)) { 4 Slog.w(TAG, "Attempted to add already added display device: " + info); 5 return; 6 } 7 8 Slog.i(TAG, "Display device added: " + info); 9 device.mDebugLastLoggedDeviceInfo = info; 10 11 mDisplayDevices.add(device); 12 LogicalDisplay display = addLogicalDisplayLocked(device); 13 Runnable work = updateDisplayStateLocked(device); 14 if (work != null) { 15 work.run(); 16 } 17 scheduleTraversalLocked(false);

遍历过程会对Device进行映射。默认是映射到Display.DEFAULT_DISPLAY即物理主屏。

1private void configureDisplayLocked(SurfaceControl.Transaction t, DisplayDevice device) { 2 final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); 3 final boolean ownContent = (info.flags & DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY) != 0; 4 5 // Find the logical display that the display device is showing. 6 // Certain displays only ever show their own content. 7 LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device); 8 // Proceed with display-managed mirroring only if window manager will not be handling it. 9 if (!ownContent && !device.isWindowManagerMirroringLocked()) { 10 // Only mirror the display if content recording is not taking place in WM. 11 if (display != null && !display.hasContentLocked()) { 12 // If the display does not have any content of its own, then 13 // automatically mirror the requested logical display contents if possible. 14 display = mLogicalDisplayMapper.getDisplayLocked( 15 device.getDisplayIdToMirrorLocked()); 16 } 17 if (display == null) { 18 display = mLogicalDisplayMapper.getDisplayLocked(Display.DEFAULT_DISPLAY); 19 } 20 } 21 22 // Apply the logical display configuration to the display device. 23 if (display == null) { 24 // TODO: no logical display for the device, blank it 25 Slog.w(TAG, "Missing logical display to use for physical display device: " 26 + device.getDisplayDeviceInfoLocked()); 27 return; 28 } 29 display.configureDisplayLocked(t, device, info.state == Display.STATE_OFF); 30 final Optional<Integer> viewportType = getViewportType(info); 31 if (viewportType.isPresent()) { 32 populateViewportLocked(viewportType.get(), display.getDisplayIdLocked(), device, info); 33 } 34 } 35

映射完成后会调用LogicDisplayDevice.configureDisplayLocked对显示的内容layer进行传递。

1public void configureDisplayLocked(SurfaceControl.Transaction t, 2 DisplayDevice device, 3 boolean isBlanked) { 4 // Set the layer stack. 5 device.setLayerStackLocked(t, isBlanked ? BLANK_LAYER_STACK : mLayerStack); 6 7 // Set the color mode and allowed display mode. 8 if (device == mPrimaryDisplayDevice) { 9 device.setAllowedDisplayModesLocked(mAllowedDisplayModes); 10 device.setRequestedColorModeLocked(mRequestedColorMode); 11 } else { 12 // Reset to default for non primary displays 13 device.setAllowedDisplayModesLocked(new int[] {0}); 14 device.setRequestedColorModeLocked(0); 15 } 16 .... 17}

此函数注释如下,意思是这个device可以不显示成主屏的内容,要看被你镜像的device是谁:

1/** 2 * Applies the layer stack and transformation to the given display device 3 * so that it shows the contents of this logical display. 4 * 5 * We know that the given display device is only ever showing the contents of 6 * a single logical display, so this method is expected to blow away all of its 7 * transformation properties to make it happen regardless of what the 8 * display device was previously showing. 9 * 10 * The caller must have an open Surface transaction. 11 * 12 * The display device may not be the primary display device, in the case 13 * where the display is being mirrored. 14 * 15 * @param device The display device to modify. 16 * @param isBlanked True if the device is being blanked. 17 */

也就是这段代码device.getDisplayIdToMirrorLocked():

1 private void configureDisplayLocked(SurfaceControl.Transaction t, DisplayDevice device) { 2 final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); 3 final boolean ownContent = (info.flags & DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY) != 0; 4 5 // Find the logical display that the display device is showing. 6 // Certain displays only ever show their own content. 7 LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device); 8 // Proceed with display-managed mirroring only if window manager will not be handling it. 9 if (!ownContent && !device.isWindowManagerMirroringLocked()) { 10 // Only mirror the display if content recording is not taking place in WM. 11 if (display != null && !display.hasContentLocked()) { 12 // If the display does not have any content of its own, then 13 // automatically mirror the requested logical display contents if possible. 14 display = mLogicalDisplayMapper.getDisplayLocked( 15 device.getDisplayIdToMirrorLocked()); 16 } 17 if (display == null) { 18 display = mLogicalDisplayMapper.getDisplayLocked(Display.DEFAULT_DISPLAY); 19 } 20 } 21 ...

在com.android.server.display.VirtualDisplayAdapter.VirtualDisplayDevice 里面这getDisplayIdToMirrorLocked被重写,这里可以指定自己想要镜像的ID,0,2,3...(已验证),可以实现的功能是,录像,截屏,分享等可以拿取到指定的屏幕。

1public int getDisplayIdToMirrorLocked() { 2 return mDisplayIdToMirror; 3}

这个mDisplayIdToMirror是在VirtualDisplayConfig里面的成员变量。

1public VirtualDisplay createVirtualDisplay(@NonNull String name, 2 int width, int height, int dpi, boolean isSecure, @Nullable Surface surface, 3 @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) { 4 int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR 5 | DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION; 6 if (isSecure) { 7 flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE; 8 } 9 final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(name, width, 10 height, dpi).setFlags(flags); 11 if (surface != null) { 12 builder.setSurface(surface); 13 } 14 VirtualDisplay virtualDisplay = createVirtualDisplay(builder, callback, handler); 15 return virtualDisplay; 16}

VirtualDisplayConfig的建造函数提供了setDisplayIdToMirror,此处是否可以实现指定被镜像的display待验证。

1@DataClass.Generated.Member 2public @NonNull Builder setDisplayIdToMirror(int value) { 3 checkNotUsed(); 4 mBuilderFieldsSet |= 0x80; 5 mDisplayIdToMirror = value; 6 return this; 7}

下一步可以分析,创建后正在绘制的display,动态更新到不同的指定屏上...

参考资料

  • [Android Display管理服务DMS]: https://www.jianshu.com/p/c2058c2dca95

  • [Android VirtualDisplay解析]: https://www.jianshu.com/p/476a357ed363