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。
@Override
public int addToDisplay(IWindow window, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, InsetsVisibilities requestedVisibilities,
InputChannel outInputChannel, InsetsState outInsetsState,
InsetsSourceControl[] outActiveControls) {
return mService.addWindow(this, window, attrs, viewVisibility, displayId,
UserHandle.getUserId(mUid), requestedVisibilities, outInputChannel, outInsetsState,
outActiveControls);
}
@Override
public int addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, int userId, InsetsVisibilities requestedVisibilities,
InputChannel outInputChannel, InsetsState outInsetsState,
InsetsSourceControl[] outActiveControls) {
return mService.addWindow(this, window, attrs, viewVisibility, displayId, userId,
requestedVisibilities, outInputChannel, outInsetsState, outActiveControls);
}
@Override
public int addToDisplayWithoutInputChannel(IWindow window, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, InsetsState outInsetsState) {
return mService.addWindow(this, window, attrs, viewVisibility, displayId,
UserHandle.getUserId(mUid), mDummyRequestedVisibilities, null /* outInputChannel */,
outInsetsState, mDummyControls);
}在addwindow中对应不同场景。
final boolean openInputChannels = (outInputChannel != null
&& (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
if (openInputChannels) {
win.openInputChannel(outInputChannel);
}
int userId = UserHandle.getUserId(session.mUid);
if (requestUserId != userId) {
try {
mAmInternal.handleIncomingUser(callingPid, callingUid, requestUserId,
false /*allowAll*/, ALLOW_NON_FULL, null, null);
} catch (Exception exp) {
ProtoLog.w(WM_ERROR, "Trying to add window with invalid user=%d",
requestUserId);
return WindowManagerGlobal.ADD_INVALID_USER;
}
// It's fine to use this userId
userId = requestUserId;
}ViewRootImpl中requestLayout函数调用mWindowSession.relayout,最终调用WindowManagerservice 的relayoutWindow,这个函数会配置Display信息; WindowStateAnimator创建Surfacecontrol,通过SurfaceControl,设置Layerstack。即在触发view更新绘制的时候才会更新图层数据。
// com.android.server.wm.WindowManagerService#relayoutWindow
if (shouldRelayout) {
try {
result = createSurfaceControl(outSurfaceControl, result, win, winAnimator);
} catch (Exception e) {
displayContent.getInputMonitor().updateInputWindowsLw(true /*force*/);
ProtoLog.w(WM_ERROR,
"Exception thrown when creating surface for client %s (%s). %s",
client, win.mAttrs.getTitle(), e);
Binder.restoreCallingIdentity(origId);
return 0;
}
}至此,一个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并没有在这里创建,在后面调用到的地方再创建。
//注册主屏适配器
private void registerDefaultDisplayAdapters() {
// Register default display adapters.
synchronized (mSyncRoot) {
// main display adapter
registerDisplayAdapterLocked(new LocalDisplayAdapter(
mSyncRoot, mContext, mHandler, mDisplayDeviceRepo));
// Standalone VR devices rely on a virtual display as their primary display for
// 2D UI. We register virtual display adapter along side the main display adapter
// here so that it is ready by the time the system sends the home Intent for
// early apps like SetupWizard/Launcher. In particular, SUW is displayed using
// the virtual display inside VR before any VR-specific apps even run.
mVirtualDisplayAdapter = mInjector.getVirtualDisplayAdapter(mSyncRoot, mContext,
mHandler, mDisplayDeviceRepo);
if (mVirtualDisplayAdapter != null) {
registerDisplayAdapterLocked(mVirtualDisplayAdapter);
}
}
}
private void registerAdditionalDisplayAdapters() {
synchronized (mSyncRoot) {
if (shouldRegisterNonEssentialDisplayAdaptersLocked()) {
registerOverlayDisplayAdapterLocked();
registerWifiDisplayAdapterLocked();
}
}
}
private void registerOverlayDisplayAdapterLocked() {
registerDisplayAdapterLocked(new OverlayDisplayAdapter(
mSyncRoot, mContext, mHandler, mDisplayDeviceRepo, mUiHandler));
}
private void registerWifiDisplayAdapterLocked() {
if (mContext.getResources().getBoolean(
com.android.internal.R.bool.config_enableWifiDisplay)
|| SystemProperties.getInt(FORCE_WIFI_DISPLAY_ENABLE, -1) == 1) {
mWifiDisplayAdapter = new WifiDisplayAdapter(
mSyncRoot, mContext, mHandler, mDisplayDeviceRepo,
mPersistentDataStore);
registerDisplayAdapterLocked(mWifiDisplayAdapter);
}
}以VirtualDisplayDevice的创建为例来说明一个display创建过程,不同的安卓版本这部分代码有不少变动,以sdK-31为例:
应用进程调用到DisplayManagerGlobal,全局只有这一个,在里面提供了获取创建VirtualDisplay的方法。
public VirtualDisplay createVirtualDisplay(Context context, MediaProjection projection,
String name, int width, int height, int densityDpi, Surface surface, int flags,
VirtualDisplay.Callback callback, Handler handler, String uniqueId) 获取所有逻辑id的方法getDisplayIds,和根据id返回info的方法,都是IPC调用到DisplayManagerService返回数据,可以遍历disaplyinfo。
public int[] getDisplayIds() {
try {
synchronized (mLock) {
if (USE_CACHE) {
if (mDisplayIdCache != null) {
return mDisplayIdCache;
}
}
int[] displayIds = mDm.getDisplayIds();
...
return displayIds;
}
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
public DisplayInfo getDisplayInfo(int displayId) {
try {
synchronized (mLock) {
DisplayInfo info;
if (USE_CACHE) {
info = mDisplayInfoCache.get(displayId);
if (info != null) {
return info;
}
}
info = mDm.getDisplayInfo(displayId);
...
return info;
}
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}VirtualDisplayDevice创建流程如下:
经过如下三个函数的调用就创建了VirtualDisplayDevice,但是这时候只是创建好VirtualDisplay。
com.android.server.display.DisplayManagerService#createVirtualDisplayInternal
com.android.server.display.VirtualDisplayAdapter#createVirtualDisplayLocked
com.android.server.display.VirtualDisplayAdapter.VirtualDisplayDevice#VirtualDisplayDevice三、VirtualDisplayDevice的显示内容
创建后需要对DisplayDevices遍历处理,更新,同时也会加入到LogicDisplay。
private void handleDisplayDeviceAddedLocked(DisplayDevice device) {
DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
if (mDisplayDevices.contains(device)) {
Slog.w(TAG, "Attempted to add already added display device: " + info);
return;
}
Slog.i(TAG, "Display device added: " + info);
device.mDebugLastLoggedDeviceInfo = info;
mDisplayDevices.add(device);
LogicalDisplay display = addLogicalDisplayLocked(device);
Runnable work = updateDisplayStateLocked(device);
if (work != null) {
work.run();
}
scheduleTraversalLocked(false);遍历过程会对Device进行映射。默认是映射到Display.DEFAULT_DISPLAY即物理主屏。
private void configureDisplayLocked(SurfaceControl.Transaction t, DisplayDevice device) {
final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
final boolean ownContent = (info.flags & DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY) != 0;
// Find the logical display that the display device is showing.
// Certain displays only ever show their own content.
LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device);
// Proceed with display-managed mirroring only if window manager will not be handling it.
if (!ownContent && !device.isWindowManagerMirroringLocked()) {
// Only mirror the display if content recording is not taking place in WM.
if (display != null && !display.hasContentLocked()) {
// If the display does not have any content of its own, then
// automatically mirror the requested logical display contents if possible.
display = mLogicalDisplayMapper.getDisplayLocked(
device.getDisplayIdToMirrorLocked());
}
if (display == null) {
display = mLogicalDisplayMapper.getDisplayLocked(Display.DEFAULT_DISPLAY);
}
}
// Apply the logical display configuration to the display device.
if (display == null) {
// TODO: no logical display for the device, blank it
Slog.w(TAG, "Missing logical display to use for physical display device: "
+ device.getDisplayDeviceInfoLocked());
return;
}
display.configureDisplayLocked(t, device, info.state == Display.STATE_OFF);
final Optional<Integer> viewportType = getViewportType(info);
if (viewportType.isPresent()) {
populateViewportLocked(viewportType.get(), display.getDisplayIdLocked(), device, info);
}
}
映射完成后会调用LogicDisplayDevice.configureDisplayLocked对显示的内容layer进行传递。
public void configureDisplayLocked(SurfaceControl.Transaction t,
DisplayDevice device,
boolean isBlanked) {
// Set the layer stack.
device.setLayerStackLocked(t, isBlanked ? BLANK_LAYER_STACK : mLayerStack);
// Set the color mode and allowed display mode.
if (device == mPrimaryDisplayDevice) {
device.setAllowedDisplayModesLocked(mAllowedDisplayModes);
device.setRequestedColorModeLocked(mRequestedColorMode);
} else {
// Reset to default for non primary displays
device.setAllowedDisplayModesLocked(new int[] {0});
device.setRequestedColorModeLocked(0);
}
....
}此函数注释如下,意思是这个device可以不显示成主屏的内容,要看被你镜像的device是谁:
/**
* Applies the layer stack and transformation to the given display device
* so that it shows the contents of this logical display.
*
* We know that the given display device is only ever showing the contents of
* a single logical display, so this method is expected to blow away all of its
* transformation properties to make it happen regardless of what the
* display device was previously showing.
*
* The caller must have an open Surface transaction.
*
* The display device may not be the primary display device, in the case
* where the display is being mirrored.
*
* @param device The display device to modify.
* @param isBlanked True if the device is being blanked.
*/也就是这段代码device.getDisplayIdToMirrorLocked():
private void configureDisplayLocked(SurfaceControl.Transaction t, DisplayDevice device) {
final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
final boolean ownContent = (info.flags & DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY) != 0;
// Find the logical display that the display device is showing.
// Certain displays only ever show their own content.
LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device);
// Proceed with display-managed mirroring only if window manager will not be handling it.
if (!ownContent && !device.isWindowManagerMirroringLocked()) {
// Only mirror the display if content recording is not taking place in WM.
if (display != null && !display.hasContentLocked()) {
// If the display does not have any content of its own, then
// automatically mirror the requested logical display contents if possible.
display = mLogicalDisplayMapper.getDisplayLocked(
device.getDisplayIdToMirrorLocked());
}
if (display == null) {
display = mLogicalDisplayMapper.getDisplayLocked(Display.DEFAULT_DISPLAY);
}
}
...在com.android.server.display.VirtualDisplayAdapter.VirtualDisplayDevice 里面这getDisplayIdToMirrorLocked被重写,这里可以指定自己想要镜像的ID,0,2,3...(已验证),可以实现的功能是,录像,截屏,分享等可以拿取到指定的屏幕。
public int getDisplayIdToMirrorLocked() {
return mDisplayIdToMirror;
}这个mDisplayIdToMirror是在VirtualDisplayConfig里面的成员变量。
public VirtualDisplay createVirtualDisplay(@NonNull String name,
int width, int height, int dpi, boolean isSecure, @Nullable Surface surface,
@Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR
| DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION;
if (isSecure) {
flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE;
}
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(name, width,
height, dpi).setFlags(flags);
if (surface != null) {
builder.setSurface(surface);
}
VirtualDisplay virtualDisplay = createVirtualDisplay(builder, callback, handler);
return virtualDisplay;
}VirtualDisplayConfig的建造函数提供了setDisplayIdToMirror,此处是否可以实现指定被镜像的display待验证。
@DataClass.Generated.Member
public @NonNull Builder setDisplayIdToMirror(int value) {
checkNotUsed();
mBuilderFieldsSet |= 0x80;
mDisplayIdToMirror = value;
return this;
}下一步可以分析,创建后正在绘制的display,动态更新到不同的指定屏上...
参考资料
[Android Display管理服务DMS]: https://www.jianshu.com/p/c2058c2dca95
[Android VirtualDisplay解析]: https://www.jianshu.com/p/476a357ed363