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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容