当前位置:   article > 正文

Android显示设备管理以及转屏流程_addlogicaldisplaylocked

addlogicaldisplaylocked

在处理android双屏异显项目,发现异显副屏(HDMI)显示竖屏内容时是拉伸的,在解决问题的过程中跟了WMS和DisplayManagerService的流程,也接触了转屏的过程,在此记录下来。

先来看看系统流程:

  1. //SystemServer.java
  2. private void run() {
  3. // Display manager is needed to provide display metrics before package manager
  4. // 1.初始化DisplayManagerService
  5. mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);
  6. // We need the default display before we can initialize the package manager.
  7. //2.保证lcd已经初始化
  8. mSystemServiceManager.startBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
  9. //3.初始化WMS,并将其加入ServiceManager中
  10. wm = WindowManagerService.main(context, inputManager,
  11. mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
  12. !mFirstBoot, mOnlyCore);
  13. ServiceManager.addService(Context.WINDOW_SERVICE, wm);
  14. ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
  15. mActivityManagerService.setWindowManager(wm);
  16. inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
  17. inputManager.start();
  18. //4.在wms和ims初始化后,调用DMS的方法,设置DMS
  19. mDisplayManagerService.windowManagerAndInputReady();
  20. try {
  21. //5.调用WMS的方法,
  22. wm.displayReady();
  23. } catch (Throwable e) {
  24. reportWtf("making display ready", e);
  25. }
  26. }

 

一:DisplayManagerService的初始化

关于displaymanagerservice的初始化可以参考前文 https://blog.csdn.net/ywlyg/article/details/79584916  的第一部分,主要作用就是向系统提供IDisplayManager.Stub的接口,我们接着链接文章继续讨论关于显示设备的部分。

  1. public void onStart() {
  2. mHandler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER);
  3. publishBinderService(Context.DISPLAY_SERVICE, new BinderService(),
  4. true /*allowIsolated*/);
  5. publishLocalService(DisplayManagerInternal.class, new LocalService());
  6. }
  7. public void handleMessage(Message msg) {
  8. switch (msg.what) {
  9. case MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER:
  10. registerDefaultDisplayAdapter();
  11. break;
  12. }

进入函数

  1. private void registerDefaultDisplayAdapter() {
  2. // Register default display adapter.
  3. synchronized (mSyncRoot) {
  4. registerDisplayAdapterLocked(new LocalDisplayAdapter(
  5. mSyncRoot, mContext, mHandler, mDisplayAdapterListener));
  6. }
  7. }

LocalDisplayAdapter构造函数比较简单,就是传入些基本的变量,可以自己看代码。DMS中有很多类型的的DisplayAdapter:

LocalDisplayAdapter是针对本地已经存在的物理显示屏设备;WifiDisplayAdapter针对WiFi Display;VirtualDisplayAdapter 显示一个虚拟屏幕,在这里我们只关注物理显示设备。

进入注册函数:

  1. private void registerDisplayAdapterLocked(DisplayAdapter adapter) {
  2. mDisplayAdapters.add(adapter);
  3. adapter.registerLocked();
  4. }
  5. public void registerLocked() {
  6. super.registerLocked();
  7. //创建对热插拔设备的处理
  8. mHotplugReceiver = new HotplugDisplayEventReceiver(getHandler().getLooper());
  9. //尝试连接物理设备,其中TO_SCAN为2,即build-in和HDMI
  10. for (int builtInDisplayId : BUILT_IN_DISPLAY_IDS_TO_SCAN) {
  11. tryConnectDisplayLocked(builtInDisplayId);
  12. }
  13. }
  14. private void tryConnectDisplayLocked(int builtInDisplayId) {
  15. //通过SurfaceControl向SurfaceFlinger获取displayToken
  16. IBinder displayToken = SurfaceControl.getBuiltInDisplay(builtInDisplayId);
  17. //displayToken不为空,证明底层已经检测到该设备了
  18. if (displayToken != null) {
  19. //通过SurfaceControl向SurfaceFlinger获取物理设备的信息数组
  20. SurfaceControl.PhysicalDisplayInfo[] configs =
  21. SurfaceControl.getDisplayConfigs(displayToken);
  22. //获取数组的哪个index是当前的配置
  23. int activeConfig = SurfaceControl.getActiveConfig(displayToken);
  24. //从mDevices中获取LocalDisplayDevice,如果为空,就说明还没有构造
  25. LocalDisplayDevice device = mDevices.get(builtInDisplayId);
  26. if (device == null) {
  27. // Display was added.
  28. //底层有这个物理设备的,上层还是空,则构造一个物理设备在上层的抽象,就是LocalDisplayDevice
  29. device = new LocalDisplayDevice(displayToken, builtInDisplayId,
  30. configs, activeConfig);
  31. mDevices.put(builtInDisplayId, device);
  32. //发送设备添加广播
  33. sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED);
  34. } else if (device.updatePhysicalDisplayInfoLocked(configs, activeConfig)) {
  35. // Display properties changed.
  36. sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_CHANGED);
  37. }
  38. } else {
  39. // The display is no longer available. Ignore the attempt to add it.
  40. // If it was connected but has already been disconnected, we'll get a
  41. // disconnect event that will remove it from mDevices.
  42. }
  43. }

 

LocalDisplayDevice的构造函数不复杂,最重要的就是将从底层获取的显示设备信息保存到mPhys变量中,接着看DISPLAY_DEVICE_EVENT_ADDED信息的处理,这个处理在DMS中:

  1. private void handleDisplayDeviceAddedLocked(DisplayDevice device) {
  2. //将这个LocalDisplayDevice保存到数组中
  3. mDisplayDevices.add(device);
  4. //添加LogicalDisplay
  5. addLogicalDisplayLocked(device);
  6. Runnable work = updateDisplayStateLocked(device);
  7. if (work != null) {
  8. work.run();
  9. }
  10. scheduleTraversalLocked(false);
  11. }

1.1进入addLogicalDisplayLocked方法:

  1. private void addLogicalDisplayLocked(DisplayDevice device) {
  2. //获取DisplayDeviceInfo信息,就是根据LocalDisplayDevice的mPhys参数构造DisplayDeviceInfo
  3. DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked();
  4. boolean isDefault = (deviceInfo.flags
  5. & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0;
  6. //根据是否主设备来分配显示id和layerstack
  7. final int displayId = assignDisplayIdLocked(isDefault);
  8. final int layerStack = assignLayerStackLocked(displayId);
  9. //构造LogicalDisplay
  10. LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device);
  11. //更新LogicalDisplay的信息
  12. display.updateLocked(mDisplayDevices);
  13. mLogicalDisplays.put(displayId, display);
  14. // Wake up waitForDefaultDisplay.
  15. if (isDefault) {
  16. mSyncRoot.notifyAll();
  17. }
  18. //发送消息
  19. sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_ADDED);
  20. }

具体来看每个方法:

1.getDisplayDeviceInfoLocked

  1. public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
  2. //构造mInfo,就是将mPhys的参数设置到mInfo中
  3. if (mInfo == null) {
  4. mInfo = new DisplayDeviceInfo();
  5. mInfo.width = mPhys.width;
  6. mInfo.height = mPhys.height;
  7. mInfo.refreshRate = mPhys.refreshRate;
  8. mInfo.supportedRefreshRates = mSupportedRefreshRates;
  9. mInfo.appVsyncOffsetNanos = mPhys.appVsyncOffsetNanos;
  10. mInfo.presentationDeadlineNanos = mPhys.presentationDeadlineNanos;
  11. mInfo.state = mState;
  12. mInfo.uniqueId = getUniqueId();
  13. if (mPhys.secure) {
  14. mInfo.flags = DisplayDeviceInfo.FLAG_SECURE
  15. | DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS;
  16. }
  17. //针对主副屏做不同处理,可以看出,副屏(HDMI)是没有dpi和density的
  18. if (mBuiltInDisplayId == SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
  19. mInfo.name = getContext().getResources().getString(
  20. com.android.internal.R.string.display_manager_built_in_display_name);
  21. mInfo.flags |= DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY
  22. | DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT;
  23. mInfo.type = Display.TYPE_BUILT_IN;
  24. mInfo.densityDpi = (int)(mPhys.density * 160 + 0.5f);
  25. mInfo.xDpi = mPhys.xDpi;
  26. mInfo.yDpi = mPhys.yDpi;
  27. mInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL;
  28. } else {
  29. mInfo.type = Display.TYPE_HDMI;
  30. mInfo.flags |= DisplayDeviceInfo.FLAG_PRESENTATION;
  31. mInfo.name = getContext().getResources().getString(
  32. com.android.internal.R.string.display_manager_hdmi_display_name);
  33. mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL;
  34. mInfo.setAssumedDensityForExternalDisplay(mPhys.width, mPhys.height);
  35. // For demonstration purposes, allow rotation of the external display.
  36. // In the future we might allow the user to configure this directly.
  37. //注意,在HDMI中,如果有这个属性,则将内容旋转270度,这个属性会影响hdmi的显示方向
  38. if ("portrait".equals(SystemProperties.get("persist.demo.hdmirotation"))) {
  39. mInfo.rotation = Surface.ROTATION_270;
  40. }
  41. // For demonstration purposes, allow rotation of the external display
  42. // to follow the built-in display.
  43. if (SystemProperties.getBoolean("persist.demo.hdmirotates", false)) {
  44. mInfo.flags |= DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT;
  45. }
  46. }
  47. }
  48. return mInfo;
  49. }

其实这个方法就是将mPhys中的信息同步给mInfo,然后根据属性配置方向;若mInfo已经被配置了,则直接返回。

2.LogicalDisplay构造方法

  1. public LogicalDisplay(int displayId, int layerStack, DisplayDevice primaryDisplayDevice) {
  2. mDisplayId = displayId;
  3. mLayerStack = layerStack;
  4. mPrimaryDisplayDevice = primaryDisplayDevice;
  5. }

3.LogicalDisplay.updateLocked

  1. /**
  2. * Updates the state of the logical display based on the availab
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/964179
推荐阅读
相关标签
  

闽ICP备14008679号