之前在分析power模块的时候,需要设置背光那个时候分析过DisplayManagerService,但是不够详细、系统。前面在分析WMS旋转屏幕的时候,也涉及到了DisplayManagerService,所以我准备详细分析下。
一、缺省设备
我们先看DisplayManagerService在SystemServer中调用的顺序。先是构造了对象,然后调用了windowManagerAndInputReady函数,这个函数会触发WMS重新刷新UI。然后调用了systemReady函数。
mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);
......
mDisplayManagerService.windowManagerAndInputReady();
......
mDisplayManagerService.systemReady(safeMode, mOnlyCore);
下面我们就先从DisplayManagerService的构造函数开始分析,构造函数就是初始化了一些变量。
public DisplayManagerService(Context context) {
super(context);
mContext = context;
mHandler = new DisplayManagerHandler(DisplayThread.get().getLooper());
mUiHandler = UiThread.getHandler();
mDisplayAdapterListener = new DisplayAdapterListener();
mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false);
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mGlobalDisplayBrightness = pm.getDefaultScreenBrightnessSetting();
}
我们再来看onStart函数,这里publish了BinderService和LocalService,然后发送了MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER消息。
@Override
public void onStart() {
mHandler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER);
publishBinderService(Context.DISPLAY_SERVICE, new BinderService(),
true /*allowIsolated*/);
publishLocalService(DisplayManagerInternal.class, new LocalService());
}
我们看下这个消息的处理,直接调用了registerDefaultDisplayAdapter函数。
switch (msg.what) {
case MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER:
registerDefaultDisplayAdapter();
break;
我们看下registerDefaultDisplayAdapter函数,直接新建一个LocalDisplayAdapter对象作为参数调用registerDisplayAdapterLocked函数。我们注意mDisplayAdapterListener这个参数。
private void registerDefaultDisplayAdapter() {
// Register default display adapter.
synchronized (mSyncRoot) {
registerDisplayAdapterLocked(new LocalDisplayAdapter(
mSyncRoot, mContext, mHandler, mDisplayAdapterListener));
}
}
registerDisplayAdapterLocked函数把上面新建的LocalDisplayAdapter对象放入mDisplayAdapters中,然后调用了LocalDisplayAdapter的registerLocked函数。
private void registerDisplayAdapterLocked(DisplayAdapter adapter) {
mDisplayAdapters.add(adapter);
adapter.registerLocked();
}
LocalDisplayAdapter的构造函数比较简单就是调用父类的构造函数初始化一些成员变量,我们看下LocalDisplayAdapter的父类DisplayAdapter的构造函数,其中mListener就是上面传入的DisplayAdapterListener回调。
public DisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
Context context, Handler handler, Listener listener, String name) {
mSyncRoot = syncRoot;
mContext = context;
mHandler = handler;
mListener = listener;
mName = name;
}
我们再来看下其registerLocked函数,先是新建了一个热插拔的回调。然后遍历了BUILT_IN_DISPLAY_IDS_TO_SCAN调用tryConnectDisplayLocked函数。
@Override
public void registerLocked() {
super.registerLocked();
mHotplugReceiver = new HotplugDisplayEventReceiver(getHandler().getLooper());
for (int builtInDisplayId : BUILT_IN_DISPLAY_IDS_TO_SCAN) {
tryConnectDisplayLocked(builtInDisplayId);
}
}
BUILT_IN_DISPLAY_IDS_TO_SCAN函数如下:
private static final int[] BUILT_IN_DISPLAY_IDS_TO_SCAN = new int[] {
SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN,
SurfaceControl.BUILT_IN_DISPLAY_ID_HDMI,
};
我们再来看看tryConnectDisplayLocked函数。先会传入builtInDisplayId参数调用SurfaceControl.getBuiltInDisplay函数来获取一个DisplayToken,这个token很关键是识别这个display的唯一性,然后我们看mDevices是否有一个builtInDisplayId的LocalDisplayDevice,没有的话就新建一个LocalDisplayDevice,并且放入mDevices中。然后sendDisplayDeviceEventLocked函数,参数是DISPLAY_DEVICE_EVENT_ADDED通知DisplayManagerService设备增加了。
private void tryConnectDisplayLocked(int builtInDisplayId) {
IBinder displayToken = SurfaceControl.getBuiltInDisplay(builtInDisplayId);//获取displayToken
if (displayToken != null) {
SurfaceControl.PhysicalDisplayInfo[] configs =
SurfaceControl.getDisplayConfigs(displayToken);
if (configs == null) {
// There are no valid configs for this device, so we can't use it
Slog.w(TAG, "No valid configs found for display device " +
builtInDisplayId);
return;
}
int activeConfig = SurfaceControl.getActiveConfig(displayToken);
if (activeConfig < 0) {
// There is no active config, and for now we don't have the
// policy to set one.
Slog.w(TAG, "No active config found for display device " +
builtInDisplayId);
return;
}
LocalDisplayDevice device = mDevices.get(builtInDisplayId);
if (device == null) {//mDevices没有builtInDisplayId对应的LocalDisplayDevice
// Display was added.
device = new LocalDisplayDevice(displayToken, builtInDisplayId,//新建LocalDisplayDevice
configs, activeConfig);
mDevices.put(builtInDisplayId, device);
sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED);
} else if (device.updatePhysicalDisplayInfoLocked(configs, activeConfig)) {
// Display properties changed.
sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_CHANGED);
}
} else {
// The display is no longer available. Ignore the attempt to add it.
// If it was connected but has already been disconnected, we'll get a
// disconnect event that will remove it from mDevices.
}
}
我们来看下sendDisplayDeviceEventLocked函数,就是调用了上面传入的回调
protected final void sendDisplayDeviceEventLocked(
final DisplayDevice device, final int event) {
mHandler.post(new Runnable() {
@Override
public void run() {
mListener.onDisplayDeviceEvent(device, event);
}
});
}
回调就是DisplayAdapterListener ,我们是DISPLAY_DEVICE_EVENT_ADDED设备增加事件,直接调用handleDisplayDeviceAdded函数。
private final class DisplayAdapterListener implements DisplayAdapter.Listener {
@Override
public void onDisplayDeviceEvent(DisplayDevice device, int event) {
switch (event) {
case DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED:
handleDisplayDeviceAdded(device);
break;
case DisplayAdapter.DISPLAY_DEVICE_EVENT_CHANGED:
handleDisplayDeviceChanged(device);
break;
case DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED:
handleDisplayDeviceRemoved(device);
break;
}
}
handleDisplayDeviceAdded直接调用了handleDisplayDeviceAddedLocked函数。handleDisplayDeviceAddedLocked函数会将device统一放入DisplayManagerService的mDisplayDevices中,类型是父类的DisplayDevice(这样方便统一管理),然后调用了addLogicalDisplayLocked函数。
private void handleDisplayDeviceAdded(DisplayDevice device) {
synchronized (mSyncRoot) {
handleDisplayDeviceAddedLocked(device);
}
}
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);//将该device统一放入DisplayManagerService的mDisplayDevices中,类型是父类的DisplayDevice
addLogicalDisplayLocked(device);
Runnable work = updateDisplayStateLocked(device);
if (work != null) {
work.run();
}
scheduleTraversalLocked(false);//通知WMS会刷新UI
}
addLogicalDisplayLocked函数,先调用assignDisplayIdLocked函数分配一个displayId(这个如果是isDefault就是固定id,其他的每次加1),然后新建一个LogicalDisplay并且把它放到mLogicalDisplays中,以displayId作为key。
private void addLogicalDisplayLocked(DisplayDevice device) {
DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked();
boolean isDefault = (deviceInfo.flags
& DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0;
......
final int displayId = assignDisplayIdLocked(isDefault);
final int layerStack = assignLayerStackLocked(displayId);
LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device);
display.updateLocked(mDisplayDevices);
......
mLogicalDisplays.put(displayId, display);
// Wake up waitForDefaultDisplay.
if (isDefault) {
mSyncRoot.notifyAll();
}
sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_ADDED);
}
二、WIFIDisplay、虚拟设备等
剩下继续分析DisplayManagerService的systemReady函数
public void systemReady(boolean safeMode, boolean onlyCore) {
synchronized (mSyncRoot) {
mSafeMode = safeMode;
mOnlyCore = onlyCore;
}
mHandler.sendEmptyMessage(MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS);
}
看下消息处理是调用了registerAdditionalDisplayAdapters函数
case MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS:
registerAdditionalDisplayAdapters();
break;
registerAdditionalDisplayAdapters函数和上面的registerDefaultDisplayAdapter函数类似。这里只是和WIFI、虚拟设备相关。流程类似最后都在DisplayManagerService中做管理。
先是新建一个DisplayAdapter 然后放入mDisplayAdapters中,然后在DisplayAdapter新建一个DisplayDevice。接着再到DisplayManagerService中放入到mDisplayDevices,接着又创建LogicalDisplay (当然这里可能不一样了)。
private void registerAdditionalDisplayAdapters() {
synchronized (mSyncRoot) {
if (shouldRegisterNonEssentialDisplayAdaptersLocked()) {
registerOverlayDisplayAdapterLocked();
registerWifiDisplayAdapterLocked();
registerVirtualDisplayAdapterLocked();
}
}
}
后面的流程那我们就不分析了。但是一些虚拟设备的connect等,都是由应用进程通过DisplayManger类通过binder发起的。DisplayManager是面向应用进程的,我们比如下面这个函数是连接WIFIDisplay的,我们再来看下这个mGlobal对象。
public void connectWifiDisplay(String deviceAddress) {
mGlobal.connectWifiDisplay(deviceAddress);
}
mGlobal最终还是通过Binder到DisplayManagerService。
public DisplayManager(Context context) {
mContext = context;
mGlobal = DisplayManagerGlobal.getInstance();
}
public static DisplayManagerGlobal getInstance() {
synchronized (DisplayManagerGlobal.class) {
if (sInstance == null) {
IBinder b = ServiceManager.getService(Context.DISPLAY_SERVICE);
if (b != null) {
sInstance = new DisplayManagerGlobal(IDisplayManager.Stub.asInterface(b));
}
}
return sInstance;
}
}
而DisplayManagerService的binder对象是放在了mDm成员变量中
private DisplayManagerGlobal(IDisplayManager dm) {
mDm = dm;
}
最后是到DisplayManagerService的connectWifiDisplay中。
public void connectWifiDisplay(String deviceAddress) {
if (deviceAddress == null) {
throw new IllegalArgumentException("deviceAddress must not be null");
}
try {
mDm.connectWifiDisplay(deviceAddress);
} catch (RemoteException ex) {
Log.e(TAG, "Failed to connect to Wifi display " + deviceAddress + ".", ex);
}
}
DisplayManagerService的connectWifiDisplay函数调用connectWifiDisplayInternal
@Override // Binder call
public void connectWifiDisplay(String address) {
if (address == null) {
throw new IllegalArgumentException("address must not be null");
}
mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
"Permission required to connect to a wifi display");
final long token = Binder.clearCallingIdentity();
try {
connectWifiDisplayInternal(address);
} finally {
Binder.restoreCallingIdentity(token);
}
}
最后是用WIFIDisplay的适配器类调用函数的。
private void connectWifiDisplayInternal(String address) {
synchronized (mSyncRoot) {
if (mWifiDisplayAdapter != null) {
mWifiDisplayAdapter.requestConnectLocked(address);
}
}
}
三、旋转屏幕
之前的旋转屏幕是调用了performTraversalInTransactionLocked函数
private void performTraversalInTransactionLocked() {
// Clear all viewports before configuring displays so that we can keep
// track of which ones we have configured.
clearViewportsLocked();
// Configure each display device.
final int count = mDisplayDevices.size();
for (int i = 0; i < count; i++) {
DisplayDevice device = mDisplayDevices.get(i);
configureDisplayInTransactionLocked(device);
device.performTraversalInTransactionLocked();
}
// Tell the input system about these new viewports.
if (mInputManagerInternal != null) {
mHandler.sendEmptyMessage(MSG_UPDATE_VIEWPORT);
}
}
我们主要还是看下configureDisplayInTransactionLocked函数,先还是用DisplayDevice的方法getDisplayDeviceInfoLocked(直接调用的是子类LocalDisplayDevice的getDisplayDeviceInfoLocked)获取DisplayDeviceInfo的信息,然后找到和该DisplayDevice对应的LogicalDisplay,然后调用其configureDisplayInTransactionLocked方法。
private void configureDisplayInTransactionLocked(DisplayDevice device) {
final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
final boolean ownContent = (info.flags & DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY) != 0;
LogicalDisplay display = findLogicalDisplayForDeviceLocked(device);
if (!ownContent) {
if (display != null && !display.hasContentLocked()) {
// If the display does not have any content of its own, then
// automatically mirror the default logical display contents.
display = null;
}
if (display == null) {
display = mLogicalDisplays.get(Display.DEFAULT_DISPLAY);
}
}
......
display.configureDisplayInTransactionLocked(device, info.state == Display.STATE_OFF);
......
}
最后在LogicalDisplay的configureDisplayInTransactionLocked方法中还是基本上调用了DisplayDevice的方法,最后真正设置方向是到DisplayDevice的setProjectionInTransactionLocked函数。
public void configureDisplayInTransactionLocked(DisplayDevice device,
boolean isBlanked) {
// Set the layer stack.
device.setLayerStackInTransactionLocked(isBlanked ? BLANK_LAYER_STACK : mLayerStack);
// Set the color transform and mode.
if (device == mPrimaryDisplayDevice) {
device.requestColorTransformAndModeInTransactionLocked(
mRequestedColorTransformId, mRequestedModeId);
} else {
device.requestColorTransformAndModeInTransactionLocked(0, 0); // Revert to default.
}
// Only grab the display info now as it may have been changed based on the requests above.
final DisplayInfo displayInfo = getDisplayInfoLocked();
final DisplayDeviceInfo displayDeviceInfo = device.getDisplayDeviceInfoLocked();
// Set the viewport.
// This is the area of the logical display that we intend to show on the
// display device. For now, it is always the full size of the logical display.
mTempLayerStackRect.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
// Set the orientation.
// The orientation specifies how the physical coordinate system of the display
// is rotated when the contents of the logical display are rendered.
int orientation = Surface.ROTATION_0;
if ((displayDeviceInfo.flags & DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT) != 0) {
orientation = displayInfo.rotation;
}
// Apply the physical rotation of the display device itself.
orientation = (orientation + displayDeviceInfo.rotation) % 4;
// Set the frame.
// The frame specifies the rotated physical coordinates into which the viewport
// is mapped. We need to take care to preserve the aspect ratio of the viewport.
// Currently we maximize the area to fill the display, but we could try to be
// more clever and match resolutions.
boolean rotated = (orientation == Surface.ROTATION_90
|| orientation == Surface.ROTATION_270);
int physWidth = rotated ? displayDeviceInfo.height : displayDeviceInfo.width;
int physHeight = rotated ? displayDeviceInfo.width : displayDeviceInfo.height;
// Determine whether the width or height is more constrained to be scaled.
// physWidth / displayInfo.logicalWidth => letter box
// or physHeight / displayInfo.logicalHeight => pillar box
//
// We avoid a division (and possible floating point imprecision) here by
// multiplying the fractions by the product of their denominators before
// comparing them.
int displayRectWidth, displayRectHeight;
if ((displayInfo.flags & Display.FLAG_SCALING_DISABLED) != 0) {
displayRectWidth = displayInfo.logicalWidth;
displayRectHeight = displayInfo.logicalHeight;
} else if (physWidth * displayInfo.logicalHeight
< physHeight * displayInfo.logicalWidth) {
// Letter box.
displayRectWidth = physWidth;
displayRectHeight = displayInfo.logicalHeight * physWidth / displayInfo.logicalWidth;
} else {
// Pillar box.
displayRectWidth = displayInfo.logicalWidth * physHeight / displayInfo.logicalHeight;
displayRectHeight = physHeight;
}
int displayRectTop = (physHeight - displayRectHeight) / 2;
int displayRectLeft = (physWidth - displayRectWidth) / 2;
mTempDisplayRect.set(displayRectLeft, displayRectTop,
displayRectLeft + displayRectWidth, displayRectTop + displayRectHeight);
mTempDisplayRect.left += mDisplayOffsetX;
mTempDisplayRect.right += mDisplayOffsetX;
mTempDisplayRect.top += mDisplayOffsetY;
mTempDisplayRect.bottom += mDisplayOffsetY;
device.setProjectionInTransactionLocked(orientation, mTempLayerStackRect, mTempDisplayRect);
}
DisplayDevice的setProjectionInTransactionLocked函数,最后也是调用SurfaceControl相关函数。
public final void setProjectionInTransactionLocked(int orientation,
Rect layerStackRect, Rect displayRect) {
if (mCurrentOrientation != orientation
|| mCurrentLayerStackRect == null
|| !mCurrentLayerStackRect.equals(layerStackRect)
|| mCurrentDisplayRect == null
|| !mCurrentDisplayRect.equals(displayRect)) {
mCurrentOrientation = orientation;
if (mCurrentLayerStackRect == null) {
mCurrentLayerStackRect = new Rect();
}
mCurrentLayerStackRect.set(layerStackRect);
if (mCurrentDisplayRect == null) {
mCurrentDisplayRect = new Rect();
}
mCurrentDisplayRect.set(displayRect);
SurfaceControl.setDisplayProjection(mDisplayToken,
orientation, layerStackRect, displayRect);
}
}
至于SurfaceControl的相关函数我们以后分析,也是通过SurfaceComposerClient到SurfaceFlinger中。