Android顯示設備管理-DisplayManagerService

一、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為例,整理類圖關系。


DMS類關系.png

三、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

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容