DisplayManagerService.java revision 4f67ba6ba4e861b287a3ff0323c107aa77f66264
1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server.display; 18 19import android.Manifest; 20import android.content.Context; 21import android.content.pm.PackageManager; 22import android.hardware.display.IDisplayManager; 23import android.os.Binder; 24import android.os.SystemProperties; 25import android.util.Slog; 26import android.util.SparseArray; 27import android.view.Display; 28import android.view.DisplayInfo; 29import android.view.Surface; 30 31import java.io.FileDescriptor; 32import java.io.PrintWriter; 33import java.util.ArrayList; 34 35/** 36 * Manages the properties, media routing and power state of attached displays. 37 * <p> 38 * The display manager service does not own or directly control the displays. 39 * Instead, other components in the system register their display adapters with the 40 * display manager service which acts as a central controller. 41 * </p> 42 */ 43public final class DisplayManagerService extends IDisplayManager.Stub { 44 private static final String TAG = "DisplayManagerService"; 45 46 private static final String SYSTEM_HEADLESS = "ro.config.headless"; 47 48 private final Object mLock = new Object(); 49 50 private Context mContext; 51 private final boolean mHeadless; 52 53 private int mDisplayIdSeq = Display.DEFAULT_DISPLAY; 54 55 /** All registered DisplayAdapters. */ 56 private final ArrayList<DisplayAdapter> mDisplayAdapters = new ArrayList<DisplayAdapter>(); 57 58 /** All the DisplayAdapters showing the given displayId. */ 59 private final SparseArray<ArrayList<DisplayAdapter>> mLogicalToPhysicals = 60 new SparseArray<ArrayList<DisplayAdapter>>(); 61 62 /** All the DisplayInfos in the system indexed by deviceId */ 63 private final SparseArray<DisplayInfo> mDisplayInfos = new SparseArray<DisplayInfo>(); 64 65 public DisplayManagerService() { 66 mHeadless = SystemProperties.get(SYSTEM_HEADLESS).equals("1"); 67 registerDefaultDisplayAdapter(); 68 } 69 70 private void registerDefaultDisplayAdapter() { 71 if (mHeadless) { 72 registerDisplayAdapter(new HeadlessDisplayAdapter()); 73 } else { 74 registerDisplayAdapter(new SurfaceFlingerDisplayAdapter()); 75 } 76 } 77 78 public void setContext(Context context) { 79 mContext = context; 80 } 81 82 // FIXME: this isn't the right API for the long term 83 public void getDefaultExternalDisplayDeviceInfo(DisplayDeviceInfo info) { 84 // hardcoded assuming 720p touch screen plugged into HDMI and USB 85 // need to redesign this 86 info.width = 1280; 87 info.height = 720; 88 } 89 90 public boolean isHeadless() { 91 return mHeadless; 92 } 93 94 /** 95 * Save away new DisplayInfo data. 96 * @param displayId The local DisplayInfo to store the new data in. 97 * @param info The new data to be stored. 98 */ 99 public void setDisplayInfo(int displayId, DisplayInfo info) { 100 synchronized (mLock) { 101 DisplayInfo localInfo = mDisplayInfos.get(displayId); 102 if (localInfo == null) { 103 localInfo = new DisplayInfo(); 104 mDisplayInfos.put(displayId, localInfo); 105 } 106 localInfo.copyFrom(info); 107 } 108 } 109 110 /** 111 * Return requested DisplayInfo. 112 * @param displayId The data to retrieve. 113 * @param outInfo The structure to receive the data. 114 */ 115 @Override // Binder call 116 public boolean getDisplayInfo(int displayId, DisplayInfo outInfo) { 117 synchronized (mLock) { 118 DisplayInfo localInfo = mDisplayInfos.get(displayId); 119 if (localInfo == null) { 120 return false; 121 } 122 outInfo.copyFrom(localInfo); 123 return true; 124 } 125 } 126 127 /** 128 * Inform the service of a new physical display. A new logical displayId is created and the new 129 * physical display is immediately bound to it. Use removeAdapterFromDisplay to disconnect it. 130 * 131 * @param adapter The wrapper for information associated with the physical display. 132 */ 133 public void registerDisplayAdapter(DisplayAdapter adapter) { 134 synchronized (mLock) { 135 int displayId = mDisplayIdSeq++; 136 adapter.setDisplayId(displayId); 137 138 createDisplayInfoLocked(displayId, adapter); 139 140 ArrayList<DisplayAdapter> list = new ArrayList<DisplayAdapter>(); 141 list.add(adapter); 142 mLogicalToPhysicals.put(displayId, list); 143 144 mDisplayAdapters.add(adapter); 145 } 146 147 // TODO: Notify SurfaceFlinger of new addition. 148 } 149 150 /** 151 * Connect a logical display to a physical display. Will remove the physical display from any 152 * logical display it is currently attached to. 153 * 154 * @param displayId The logical display. Will be created if it does not already exist. 155 * @param adapter The physical display. 156 */ 157 public void addAdapterToDisplay(int displayId, DisplayAdapter adapter) { 158 if (adapter == null) { 159 // TODO: Or throw NPE? 160 Slog.e(TAG, "addDeviceToDisplay: Attempt to add null adapter"); 161 return; 162 } 163 164 synchronized (mLock) { 165 if (!mDisplayAdapters.contains(adapter)) { 166 // TOOD: Handle unregistered adapter with exception or return value. 167 Slog.e(TAG, "addDeviceToDisplay: Attempt to add an unregistered adapter"); 168 return; 169 } 170 171 DisplayInfo displayInfo = mDisplayInfos.get(displayId); 172 if (displayInfo == null) { 173 createDisplayInfoLocked(displayId, adapter); 174 } 175 176 Integer oldDisplayId = adapter.getDisplayId(); 177 if (oldDisplayId != Display.NO_DISPLAY) { 178 if (oldDisplayId == displayId) { 179 // adapter already added to displayId. 180 return; 181 } 182 183 removeAdapterLocked(adapter); 184 } 185 186 ArrayList<DisplayAdapter> list = mLogicalToPhysicals.get(displayId); 187 if (list == null) { 188 list = new ArrayList<DisplayAdapter>(); 189 mLogicalToPhysicals.put(displayId, list); 190 } 191 192 list.add(adapter); 193 adapter.setDisplayId(displayId); 194 } 195 196 // TODO: Notify SurfaceFlinger of new addition. 197 } 198 199 /** 200 * Disconnect the physical display from whichever logical display it is attached to. 201 * @param adapter The physical display to detach. 202 */ 203 public void removeAdapterFromDisplay(DisplayAdapter adapter) { 204 if (adapter == null) { 205 // TODO: Or throw NPE? 206 return; 207 } 208 209 synchronized (mLock) { 210 if (!mDisplayAdapters.contains(adapter)) { 211 // TOOD: Handle unregistered adapter with exception or return value. 212 Slog.e(TAG, "removeDeviceFromDisplay: Attempt to remove an unregistered adapter"); 213 return; 214 } 215 216 removeAdapterLocked(adapter); 217 } 218 219 // TODO: Notify SurfaceFlinger of removal. 220 } 221 222 /** 223 * Create a new logical DisplayInfo and fill it in with information from the physical display. 224 * @param displayId The logical identifier. 225 * @param adapter The physical display for initial values. 226 */ 227 private void createDisplayInfoLocked(int displayId, DisplayAdapter adapter) { 228 DisplayInfo displayInfo = new DisplayInfo(); 229 DisplayDeviceInfo deviceInfo = new DisplayDeviceInfo(); 230 adapter.getDisplayDevice().getInfo(deviceInfo); 231 copyDisplayInfoFromDeviceInfo(displayInfo, deviceInfo); 232 mDisplayInfos.put(displayId, displayInfo); 233 } 234 235 /** 236 * Disconnect a physical display from its logical display. If there are no more physical 237 * displays attached to the logical display, delete the logical display. 238 * @param adapter The physical display to detach. 239 */ 240 void removeAdapterLocked(DisplayAdapter adapter) { 241 int displayId = adapter.getDisplayId(); 242 adapter.setDisplayId(Display.NO_DISPLAY); 243 244 ArrayList<DisplayAdapter> list = mLogicalToPhysicals.get(displayId); 245 if (list != null) { 246 list.remove(adapter); 247 if (list.isEmpty()) { 248 mLogicalToPhysicals.remove(displayId); 249 // TODO: Keep count of Windows attached to logical display and don't delete if 250 // there are any outstanding. Also, what keeps the WindowManager from continuing 251 // to use the logical display? 252 mDisplayInfos.remove(displayId); 253 } 254 } 255 } 256 257 private void copyDisplayInfoFromDeviceInfo(DisplayInfo displayInfo, 258 DisplayDeviceInfo deviceInfo) { 259 // Bootstrap the logical display using the physical display. 260 displayInfo.appWidth = deviceInfo.width; 261 displayInfo.appHeight = deviceInfo.height; 262 displayInfo.logicalWidth = deviceInfo.width; 263 displayInfo.logicalHeight = deviceInfo.height; 264 displayInfo.rotation = Surface.ROTATION_0; 265 displayInfo.refreshRate = deviceInfo.refreshRate; 266 displayInfo.logicalDensityDpi = deviceInfo.densityDpi; 267 displayInfo.physicalXDpi = deviceInfo.xDpi; 268 displayInfo.physicalYDpi = deviceInfo.yDpi; 269 displayInfo.smallestNominalAppWidth = deviceInfo.width; 270 displayInfo.smallestNominalAppHeight = deviceInfo.height; 271 displayInfo.largestNominalAppWidth = deviceInfo.width; 272 displayInfo.largestNominalAppHeight = deviceInfo.height; 273 } 274 275 @Override // Binder call 276 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 277 if (mContext == null 278 || mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP) 279 != PackageManager.PERMISSION_GRANTED) { 280 pw.println("Permission Denial: can't dump DisplayManager from from pid=" 281 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()); 282 return; 283 } 284 285 pw.println("DISPLAY MANAGER (dumpsys display)\n"); 286 287 pw.println("Headless: " + mHeadless); 288 289 DisplayDeviceInfo info = new DisplayDeviceInfo(); 290 for (DisplayAdapter adapter : mDisplayAdapters) { 291 pw.println("Display for adapter " + adapter.getName()); 292 DisplayDevice device = adapter.getDisplayDevice(); 293 pw.print(" "); 294 device.getInfo(info); 295 pw.println(info); 296 } 297 } 298} 299