一、DisplayManagerService功能說明(根據DisplayManagerService.java注釋翻譯)
DisplayManagerService 用來管理顯示的生命周期,它決定如何根據當前連接的物理顯示設備控制其邏輯顯示,并且在狀態更改時,向系統和應用程序發送通知,等等。
DisplayAdapter 是 DisplayManagerService 所依賴的集合組件,其為系統顯示,收集并發現物理顯示設備提供了適配器的作用。
目前有以下四種方式的適配器供使用
一、本地顯示設備提供適配器。
二、無線連接顯示適配器。
三、虛擬顯示適配器。
四、開發者提供的模擬顯示適配器。
DisplayAdapter 與 DisplayManagerService 是弱耦合關系。DisplayAdapter通過注冊在 DisplayManagerService類中的 DisplayAdapter.Listener 實現異步通信。
這樣做有兩個原因
一、巧妙地封裝了這兩個類的職責,
DisplayAdapter :處理各個顯示設備
DisplayManagerService:處理全局顯示狀態。
二、消除異步顯示設備發現導致死鎖的可能性
Synchronization(同步鎖)
因為顯示管理器可能被多個線程訪問,所以同步鎖就會變得有點復雜。 特別是當窗口管理器(window manager)在保持繪制事務的同時調用顯示管理器(display manager),窗口管理器期望它可以立即應用并更改。 但不幸的是,顯示管理器(display manager)不能異步地做所有事情。
為了解決這個問題,顯示管理器的所有對象必須持有相同的鎖。 我們將此鎖稱為同步鎖,它具有唯一性。
二、DisplayManagerService類圖關系
以系統built in display為例,整理類圖關系。
三、DisplayManagerService啟動流程
啟動過程的主要工作是建立和Surfaceflinger的連接,獲取build in display設備信息,創建虛擬顯示設備,并通知啟動模塊,dms.onBootPhase檢查到虛擬顯示設備創建成功,就返回,系統繼續其他服務。
//SystemServer.java
552 // Display manager is needed to provide display metrics before package manager
553 // starts up.
554 traceBeginAndSlog("StartDisplayManager");
555 //step1: 啟動DisplayManagerService, 調用onStart方法
556 mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);
557 traceEnd();
558
559 // We need the default display before we can initialize the package manager.
560 traceBeginAndSlog("WaitForDisplay");
561 //step2: 等待啟動DisplayManagerService啟動完成,調用dms.onBootPhase方法
562 mSystemServiceManager.startBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
563 traceEnd();
//DisplayManagerService.java
256 DisplayManagerService(Context context, Injector injector) {
257 super(context);
258 mInjector = injector;
259 mContext = context;
260 //創建Handle,處理消息使用
261 mHandler = new DisplayManagerHandler(DisplayThread.get().getLooper());
262 mUiHandler = UiThread.getHandler();
263 //創建AdpterListener, 簡單顯示設備增加/刪除/改變
264 mDisplayAdapterListener = new DisplayAdapterListener();
265 mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false);
266 mDefaultDisplayDefaultColorMode = mContext.getResources().getInteger(
267 com.android.internal.R.integer.config_defaultDisplayDefaultColorMode);
268
269 PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
270 mGlobalDisplayBrightness = pm.getDefaultScreenBrightnessSetting();
271
272 }
284 @Override
285 public void onStart() {
286 // We need to pre-load the persistent data store so it's ready before the default display
287 // adapter is up so that we have it's configuration. We could load it lazily, but since
288 // we're going to have to read it in eventually we may as well do it here rather than after
289 // we've waited for the diplay to register itself with us.
290 mPersistentDataStore.loadIfNeeded();
291 //異步注冊adapter
292 mHandler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER);
293 //注冊系統服務
294 publishBinderService(Context.DISPLAY_SERVICE, new BinderService(),
295 true /*allowIsolated*/);
296 //注冊內部服務
297 publishLocalService(DisplayManagerInternal.class, new LocalService());
298 publishLocalService(DisplayTransformManager.class, new DisplayTransformManager());
299 }
300
301 @Override
302 public void onBootPhase(int phase) {
303 if (phase == PHASE_WAIT_FOR_DEFAULT_DISPLAY) {
304 synchronized (mSyncRoot) {
305 long timeout = SystemClock.uptimeMillis() + WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT;
306 //循環檢查邏輯屏幕是否存在
307 while (mLogicalDisplays.get(Display.DEFAULT_DISPLAY) == null) {
308 long delay = timeout - SystemClock.uptimeMillis();
309 if (delay <= 0) {
310 throw new RuntimeException("Timeout waiting for default display "
311 + "to be initialized.");
312 }
313 if (DEBUG) {
314 Slog.d(TAG, "waitForDefaultDisplay: waiting, timeout=" + delay);
315 }
316 try {
317 mSyncRoot.wait(delay);
318 } catch (InterruptedException ex) {
319 }
320 }
321 }
322 }
323 }
四、Build In Display本地顯示設備添加過程
啟動的過程中,onStart方法會發一個MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER消息出來。
//DisplayManagerService.java
1230 private final class DisplayManagerHandler extends Handler {
1231 public DisplayManagerHandler(Looper looper) {
1232 super(looper, null, true /*async*/);
1233 }
1234
1235 @Override
1236 public void handleMessage(Message msg) {
1237 switch (msg.what) {
1238 //處理注冊默認顯示設備適配器
1239 case MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER:
1240 registerDefaultDisplayAdapter();
1241 break;
1242
1243 case MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS:
1244 registerAdditionalDisplayAdapters();
1245 break;
1246
1247 case MSG_DELIVER_DISPLAY_EVENT:
1248 deliverDisplayEvent(msg.arg1, msg.arg2);
1249 break;
1250
1251 case MSG_REQUEST_TRAVERSAL:
1252 mWindowManagerInternal.requestTraversalFromDisplayManager();
1253 break;
1254
1255 case MSG_UPDATE_VIEWPORT: {
1256 synchronized (mSyncRoot) {
1257 mTempDefaultViewport.copyFrom(mDefaultViewport);
1258 mTempExternalTouchViewport.copyFrom(mExternalTouchViewport);
1259 if (!mTempVirtualTouchViewports.equals(mVirtualTouchViewports)) {
1260 mTempVirtualTouchViewports.clear();
1261 for (DisplayViewport d : mVirtualTouchViewports) {
1262 mTempVirtualTouchViewports.add(d.makeCopy());
1263 }
1264 }
1265 }
1266 mInputManagerInternal.setDisplayViewports(mTempDefaultViewport,
1267 mTempExternalTouchViewport, mTempVirtualTouchViewports);
1268 break;
1269 }
1270 }
1271 }
1272 }
693 private void registerDefaultDisplayAdapter() {
694 // Register default display adapter.
695 synchronized (mSyncRoot) {
696 // 創建LocalDisplayAdapter,并且調用registerLocked方法
697 registerDisplayAdapterLocked(new LocalDisplayAdapter(
698 mSyncRoot, mContext, mHandler, mDisplayAdapterListener));
699 }
700 }
744 private void registerDisplayAdapterLocked(DisplayAdapter adapter) {
745 //添加到mDisplayAdapters列表中,
746 mDisplayAdapters.add(adapter);
747 //調用對應適配器的registerLocked方法
748 adapter.registerLocked();
749 }
//LocalDisplayAdapter.java
76 public void registerLocked() {
77 super.registerLocked();
78
79 //熱插拔監聽回調
80 mHotplugReceiver = new HotplugDisplayEventReceiver(getHandler().getLooper());
81
82 //默認屏幕 嘗試和SurfaceFlingre建立連接
83 for (int builtInDisplayId : BUILT_IN_DISPLAY_IDS_TO_SCAN) {
84 tryConnectDisplayLocked(builtInDisplayId);
85 }
86 }
88 private void tryConnectDisplayLocked(int builtInDisplayId) {
89 //step1: 通過SurfaceControl和SurfaceFlinger打交道,或者client ibinder句柄
90 IBinder displayToken = SurfaceControl.getBuiltInDisplay(builtInDisplayId);
91 if (displayToken != null) {
92 //step2: 獲取display的硬件屬性,新建LocalDisplayDevice
93 SurfaceControl.PhysicalDisplayInfo[] configs =
94 SurfaceControl.getDisplayConfigs(displayToken);
95 if (configs == null) {
96 // There are no valid configs for this device, so we can't use it
97 Slog.w(TAG, "No valid configs found for display device " +
98 builtInDisplayId);
99 return;
100 }
101 int activeConfig = SurfaceControl.getActiveConfig(displayToken);
102 if (activeConfig < 0) {
103 // There is no active config, and for now we don't have the
104 // policy to set one.
105 Slog.w(TAG, "No active config found for display device " +
106 builtInDisplayId);
107 return;
108 }
109 int activeColorMode = SurfaceControl.getActiveColorMode(displayToken);
110 if (activeColorMode < 0) {
111 // We failed to get the active color mode. We don't bail out here since on the next
112 // configuration pass we'll go ahead and set it to whatever it was set to last (or
113 // COLOR_MODE_NATIVE if this is the first configuration).
114 Slog.w(TAG, "Unable to get active color mode for display device " +
115 builtInDisplayId);
116 activeColorMode = Display.COLOR_MODE_INVALID;
117 }
118 int[] colorModes = SurfaceControl.getDisplayColorModes(displayToken);
119 LocalDisplayDevice device = mDevices.get(builtInDisplayId);
120 if (device == null) {
121 // Display was added.
122 // 創建本地顯示設備
123 device = new LocalDisplayDevice(displayToken, builtInDisplayId,
124 configs, activeConfig, colorModes, activeColorMode);
125 mDevices.put(builtInDisplayId, device);
126 //通知本地顯示設備添加成功
127 sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED);
128 } else if (device.updatePhysicalDisplayInfoLocked(configs, activeConfig,
129 colorModes, activeColorMode)) {
130 // Display properties changed.
131 sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_CHANGED);
132 }
133 } else {
134 // The display is no longer available. Ignore the attempt to add it.
135 // If it was connected but has already been disconnected, we'll get a
136 // disconnect event that will remove it from mDevices.
137 }
138 }
139
//SurfaceControl.java,都是static,類函數通過id獲取display token
public static IBinder getBuiltInDisplay(int builtInDisplayId) {
return nativeGetBuiltInDisplay(builtInDisplayId);
}
//通過display token,獲取display硬件屬性
public static boolean getDisplayInfo(IBinder displayToken, SurfaceControl.PhysicalDisplayInfo outInfo) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
}
if (outInfo == null) {
throw new IllegalArgumentException("outInfo must not be null");
}
return nativeGetDisplayInfo(displayToken, outInfo);
}
LocalDisplayAdapter構造函數的mHandler和mDisplayAdapterListener分別為DisplayManagerHandler和DisplayAdapterListener,進而會去調用回到DisplayManagerService處DISPLAY_DEVICE_EVENT_ADDED消息,
//DisplayManagerService.java
1276 private final class DisplayAdapterListener implements DisplayAdapter.Listener {
1277 @Override
1278 public void onDisplayDeviceEvent(DisplayDevice device, int event) {
1279 switch (event) {
1280 case DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED:
1281 handleDisplayDeviceAdded(device);
1282 break;
1283
1284 case DisplayAdapter.DISPLAY_DEVICE_EVENT_CHANGED:
1285 handleDisplayDeviceChanged(device);
1286 break;
1287
1288 case DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED:
1289 handleDisplayDeviceRemoved(device);
1290 break;
1291 }
1292 }
744 private void registerDisplayAdapterLocked(DisplayAdapter adapter) {
745 //添加到mDisplayAdapters列表中,
746 mDisplayAdapters.add(adapter);
747 //調用對應適配器的registerLocked方法
748 adapter.registerLocked();
749 }
750
751 private void handleDisplayDeviceAdded(DisplayDevice device) {
752 synchronized (mSyncRoot) {
753 handleDisplayDeviceAddedLocked(device);
754 }
755 }
756
757 private void handleDisplayDeviceAddedLocked(DisplayDevice device) {
758 DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
759 if (mDisplayDevices.contains(device)) {
760 Slog.w(TAG, "Attempted to add already added display device: " + info);
761 return;
762 }
763
764 Slog.i(TAG, "Display device added: " + info);
765 device.mDebugLastLoggedDeviceInfo = info;
766
767 //將LocalDisplayDevice添加到mDisplayDevices
768 mDisplayDevices.add(device);
769 //為一個物理display添加一個logical display
770 LogicalDisplay display = addLogicalDisplayLocked(device);
771 Runnable work = updateDisplayStateLocked(device);
772 if (work != null) {
773 work.run();
774 }
775 if (display != null && display.getPrimaryDisplayDeviceLocked() == device) {
776 int colorMode = mPersistentDataStore.getColorMode(device);
777 if (colorMode == Display.COLOR_MODE_INVALID) {
778 if ((device.getDisplayDeviceInfoLocked().flags
779 & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0) {
780 colorMode = mDefaultDisplayDefaultColorMode;
781 } else {
782 colorMode = Display.COLOR_MODE_DEFAULT;
783 }
784 }
785 display.setRequestedColorModeLocked(colorMode);
786 }
787 //刷新處理
788 scheduleTraversalLocked(false);
789 }
為物理屏幕創建一個logical display,至此DisplayManagerService啟動就完成了,
863 // Adds a new logical display based on the given display device.
864 // Sends notifications if needed.
865 private LogicalDisplay addLogicalDisplayLocked(DisplayDevice device) {
866 DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked();
867 //主屏,同時mLogicalDisplays包含了這個device
868 boolean isDefault = (deviceInfo.flags
869 & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0;
870 if (isDefault && mLogicalDisplays.get(Display.DEFAULT_DISPLAY) != null) {
871 Slog.w(TAG, "Ignoring attempt to add a second default display: " + deviceInfo);
872 isDefault = false;
873 }
874
875 //不是主屏,但是mSingleDisplayDemoMode為真,即設置了單屏模式
876 //這時候不會去為這個物理display創建新的logical display,如果
877 //有hdmi,這時候會mirror主屏的內容
878 //看來邏輯display就是和顯示的內容有很大的關系
879 if (!isDefault && mSingleDisplayDemoMode) {
880 Slog.i(TAG, "Not creating a logical display for a secondary display "
881 + " because single display demo mode is enabled: " + deviceInfo);
882 return null;
883 }
884
885 //layerStack 就是displayId id,主屏0,hdmi 1
886 final int displayId = assignDisplayIdLocked(isDefault);
887 final int layerStack = assignLayerStackLocked(displayId);
888
889 //新建LogicalDisplay
890 LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device);
891 display.updateLocked(mDisplayDevices);
892 if (!display.isValidLocked()) {
893 // This should never happen currently.
894 Slog.w(TAG, "Ignoring display device because the logical display "
895 + "created from it was not considered valid: " + deviceInfo);
896 return null;
897 }
898
899 mLogicalDisplays.put(displayId, display);
900
901 // Wake up waitForDefaultDisplay.
902 //如果添加的是built-in display,需要mSyncRoot.notifyAll()
903 //因為systemserver.java中調用了waitForDefaultDisplay,這時候systemserver可以繼續運行了
904 if (isDefault) {
905 mSyncRoot.notifyAll();
906 }
907
908 //給mHandler發消息去處理
909 sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_ADDED);
910 return display;
911 }
DMS啟動完成,會通知其他服務注冊了回調接口進程,通知顯示設備以添加成功,回調接口就不繼續分析,一般其他的模塊通過aidl接口注冊。
1134 // Runs on Handler thread.
1135 // Delivers display event notifications to callbacks.
1136 private void deliverDisplayEvent(int displayId, int event) {
1137 if (DEBUG) {
1138 Slog.d(TAG, "Delivering display event: displayId="
1139 + displayId + ", event=" + event);
1140 }
1141
1142 // Grab the lock and copy the callbacks.
1143 final int count;
1144 synchronized (mSyncRoot) {
1145 count = mCallbacks.size();
1146 mTempCallbacks.clear();
1147 for (int i = 0; i < count; i++) {
1148 mTempCallbacks.add(mCallbacks.valueAt(i));
1149 }
1150 }
1151
1152 // After releasing the lock, send the notifications out.
1153 for (int i = 0; i < count; i++) {
1154 mTempCallbacks.get(i).notifyDisplayEventAsync(displayId, event);
1155 }
1156 mTempCallbacks.clear();
1157 }
五、 總結
DisplayManagerService只是對顯示設備做簡單管理,并不設計到太多東西,通過DisplayManager提供對外接口包括如下幾個:(省略了wifi相關..)
1 、public Display getDisplay(int displayId)
根據displayId參數獲得一個邏輯顯示器的信息
2、 public Display[] getDisplays()
獲得當前所有有效的邏輯顯示器列表
3、public void registerDisplayListener(DisplayListener listener, Handler handler)
登記一個顯示監聽對象,用來監聽顯示器的新增、去除或改變通知事件。
4、public void unregisterDisplayListener(DisplayListener listener)
取消先前登記的一個顯示監聽對象
...
梳理DMS主要是這里面有DisplayViewport會傳遞給IMS模塊,作為觸摸輸入區域會使用,這里簡單記錄下。
6、參考博客
android graphic(12)—display上層相關概念、關系
Android Framework 框架系列之 DisplayManagerService(一)
https://source.android.google.cn/devices/graphics?hl=zh_cn