WindowManagerGlobal.java revision 2d5618c22101cfc4d6478cfe1d846798389540c1
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 android.view; 18 19import android.animation.ValueAnimator; 20import android.app.ActivityManager; 21import android.content.ComponentCallbacks2; 22import android.content.res.Configuration; 23import android.opengl.ManagedEGLContext; 24import android.os.IBinder; 25import android.os.Looper; 26import android.os.RemoteException; 27import android.os.ServiceManager; 28import android.os.SystemProperties; 29import android.util.AndroidRuntimeException; 30import android.util.Log; 31import android.view.inputmethod.InputMethodManager; 32 33import java.io.FileDescriptor; 34import java.io.FileOutputStream; 35import java.io.PrintWriter; 36 37/** 38 * Provides low-level communication with the system window manager for 39 * operations that are not associated with any particular context. 40 * 41 * This class is only used internally to implement global functions where 42 * the caller already knows the display and relevant compatibility information 43 * for the operation. For most purposes, you should use {@link WindowManager} instead 44 * since it is bound to a context. 45 * 46 * @see WindowManagerImpl 47 * @hide 48 */ 49public final class WindowManagerGlobal { 50 private static final String TAG = "WindowManager"; 51 52 /** 53 * The user is navigating with keys (not the touch screen), so 54 * navigational focus should be shown. 55 */ 56 public static final int RELAYOUT_RES_IN_TOUCH_MODE = 0x1; 57 58 /** 59 * This is the first time the window is being drawn, 60 * so the client must call drawingFinished() when done 61 */ 62 public static final int RELAYOUT_RES_FIRST_TIME = 0x2; 63 64 /** 65 * The window manager has changed the surface from the last call. 66 */ 67 public static final int RELAYOUT_RES_SURFACE_CHANGED = 0x4; 68 69 /** 70 * The window manager is currently animating. It will call 71 * IWindow.doneAnimating() when done. 72 */ 73 public static final int RELAYOUT_RES_ANIMATING = 0x8; 74 75 /** 76 * Flag for relayout: the client will be later giving 77 * internal insets; as a result, the window will not impact other window 78 * layouts until the insets are given. 79 */ 80 public static final int RELAYOUT_INSETS_PENDING = 0x1; 81 82 /** 83 * Flag for relayout: the client may be currently using the current surface, 84 * so if it is to be destroyed as a part of the relayout the destroy must 85 * be deferred until later. The client will call performDeferredDestroy() 86 * when it is okay. 87 */ 88 public static final int RELAYOUT_DEFER_SURFACE_DESTROY = 0x2; 89 90 public static final int ADD_FLAG_APP_VISIBLE = 0x2; 91 public static final int ADD_FLAG_IN_TOUCH_MODE = RELAYOUT_RES_IN_TOUCH_MODE; 92 93 public static final int ADD_OKAY = 0; 94 public static final int ADD_BAD_APP_TOKEN = -1; 95 public static final int ADD_BAD_SUBWINDOW_TOKEN = -2; 96 public static final int ADD_NOT_APP_TOKEN = -3; 97 public static final int ADD_APP_EXITING = -4; 98 public static final int ADD_DUPLICATE_ADD = -5; 99 public static final int ADD_STARTING_NOT_NEEDED = -6; 100 public static final int ADD_MULTIPLE_SINGLETON = -7; 101 public static final int ADD_PERMISSION_DENIED = -8; 102 public static final int ADD_INVALID_DISPLAY = -9; 103 104 private static WindowManagerGlobal sDefaultWindowManager; 105 private static IWindowManager sWindowManagerService; 106 private static IWindowSession sWindowSession; 107 108 private final Object mLock = new Object(); 109 110 private View[] mViews; 111 private ViewRootImpl[] mRoots; 112 private WindowManager.LayoutParams[] mParams; 113 private boolean mNeedsEglTerminate; 114 115 private Runnable mSystemPropertyUpdater; 116 117 private WindowManagerGlobal() { 118 } 119 120 public static WindowManagerGlobal getInstance() { 121 synchronized (WindowManagerGlobal.class) { 122 if (sDefaultWindowManager == null) { 123 sDefaultWindowManager = new WindowManagerGlobal(); 124 } 125 return sDefaultWindowManager; 126 } 127 } 128 129 public static IWindowManager getWindowManagerService() { 130 synchronized (WindowManagerGlobal.class) { 131 if (sWindowManagerService == null) { 132 sWindowManagerService = IWindowManager.Stub.asInterface( 133 ServiceManager.getService("window")); 134 } 135 return sWindowManagerService; 136 } 137 } 138 139 public static IWindowSession getWindowSession(Looper mainLooper) { 140 synchronized (WindowManagerGlobal.class) { 141 if (sWindowSession == null) { 142 try { 143 InputMethodManager imm = InputMethodManager.getInstance(mainLooper); 144 IWindowManager windowManager = getWindowManagerService(); 145 sWindowSession = windowManager.openSession( 146 imm.getClient(), imm.getInputContext()); 147 float animatorScale = windowManager.getAnimationScale(2); 148 ValueAnimator.setDurationScale(animatorScale); 149 } catch (RemoteException e) { 150 Log.e(TAG, "Failed to open window session", e); 151 } 152 } 153 return sWindowSession; 154 } 155 } 156 157 public static IWindowSession peekWindowSession() { 158 synchronized (WindowManagerGlobal.class) { 159 return sWindowSession; 160 } 161 } 162 163 public void addView(View view, ViewGroup.LayoutParams params, 164 Display display, Window parentWindow) { 165 if (view == null) { 166 throw new IllegalArgumentException("view must not be null"); 167 } 168 if (display == null) { 169 throw new IllegalArgumentException("display must not be null"); 170 } 171 if (!(params instanceof WindowManager.LayoutParams)) { 172 throw new IllegalArgumentException("Params must be WindowManager.LayoutParams"); 173 } 174 175 final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params; 176 if (parentWindow != null) { 177 parentWindow.adjustLayoutParamsForSubWindow(wparams); 178 } 179 180 ViewRootImpl root; 181 View panelParentView = null; 182 183 synchronized (mLock) { 184 // Start watching for system property changes. 185 if (mSystemPropertyUpdater == null) { 186 mSystemPropertyUpdater = new Runnable() { 187 @Override public void run() { 188 synchronized (mLock) { 189 for (ViewRootImpl root : mRoots) { 190 root.loadSystemProperties(); 191 } 192 } 193 } 194 }; 195 SystemProperties.addChangeCallback(mSystemPropertyUpdater); 196 } 197 198 int index = findViewLocked(view, false); 199 if (index >= 0) { 200 throw new IllegalStateException("View " + view 201 + " has already been added to the window manager."); 202 } 203 204 // If this is a panel window, then find the window it is being 205 // attached to for future reference. 206 if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW && 207 wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) { 208 final int count = mViews != null ? mViews.length : 0; 209 for (int i=0; i<count; i++) { 210 if (mRoots[i].mWindow.asBinder() == wparams.token) { 211 panelParentView = mViews[i]; 212 } 213 } 214 } 215 216 root = new ViewRootImpl(view.getContext(), display); 217 218 view.setLayoutParams(wparams); 219 220 if (mViews == null) { 221 index = 1; 222 mViews = new View[1]; 223 mRoots = new ViewRootImpl[1]; 224 mParams = new WindowManager.LayoutParams[1]; 225 } else { 226 index = mViews.length + 1; 227 Object[] old = mViews; 228 mViews = new View[index]; 229 System.arraycopy(old, 0, mViews, 0, index-1); 230 old = mRoots; 231 mRoots = new ViewRootImpl[index]; 232 System.arraycopy(old, 0, mRoots, 0, index-1); 233 old = mParams; 234 mParams = new WindowManager.LayoutParams[index]; 235 System.arraycopy(old, 0, mParams, 0, index-1); 236 } 237 index--; 238 239 mViews[index] = view; 240 mRoots[index] = root; 241 mParams[index] = wparams; 242 } 243 244 // do this last because it fires off messages to start doing things 245 root.setView(view, wparams, panelParentView); 246 } 247 248 public void updateViewLayout(View view, ViewGroup.LayoutParams params) { 249 if (view == null) { 250 throw new IllegalArgumentException("view must not be null"); 251 } 252 if (!(params instanceof WindowManager.LayoutParams)) { 253 throw new IllegalArgumentException("Params must be WindowManager.LayoutParams"); 254 } 255 256 final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params; 257 258 view.setLayoutParams(wparams); 259 260 synchronized (mLock) { 261 int index = findViewLocked(view, true); 262 ViewRootImpl root = mRoots[index]; 263 mParams[index] = wparams; 264 root.setLayoutParams(wparams, false); 265 } 266 } 267 268 public void removeView(View view, boolean immediate) { 269 if (view == null) { 270 throw new IllegalArgumentException("view must not be null"); 271 } 272 273 synchronized (mLock) { 274 int index = findViewLocked(view, true); 275 View curView = removeViewLocked(index, immediate); 276 if (curView == view) { 277 return; 278 } 279 280 throw new IllegalStateException("Calling with view " + view 281 + " but the ViewAncestor is attached to " + curView); 282 } 283 } 284 285 public void closeAll(IBinder token, String who, String what) { 286 synchronized (mLock) { 287 if (mViews == null) 288 return; 289 290 int count = mViews.length; 291 //Log.i("foo", "Closing all windows of " + token); 292 for (int i=0; i<count; i++) { 293 //Log.i("foo", "@ " + i + " token " + mParams[i].token 294 // + " view " + mRoots[i].getView()); 295 if (token == null || mParams[i].token == token) { 296 ViewRootImpl root = mRoots[i]; 297 298 //Log.i("foo", "Force closing " + root); 299 if (who != null) { 300 WindowLeaked leak = new WindowLeaked( 301 what + " " + who + " has leaked window " 302 + root.getView() + " that was originally added here"); 303 leak.setStackTrace(root.getLocation().getStackTrace()); 304 Log.e(TAG, leak.getMessage(), leak); 305 } 306 307 removeViewLocked(i, false); 308 i--; 309 count--; 310 } 311 } 312 } 313 } 314 315 private View removeViewLocked(int index, boolean immediate) { 316 ViewRootImpl root = mRoots[index]; 317 View view = root.getView(); 318 319 if (view != null) { 320 InputMethodManager imm = InputMethodManager.getInstance(view.getContext()); 321 if (imm != null) { 322 imm.windowDismissed(mViews[index].getWindowToken()); 323 } 324 } 325 root.die(immediate); 326 327 final int count = mViews.length; 328 329 // remove it from the list 330 View[] tmpViews = new View[count-1]; 331 removeItem(tmpViews, mViews, index); 332 mViews = tmpViews; 333 334 ViewRootImpl[] tmpRoots = new ViewRootImpl[count-1]; 335 removeItem(tmpRoots, mRoots, index); 336 mRoots = tmpRoots; 337 338 WindowManager.LayoutParams[] tmpParams 339 = new WindowManager.LayoutParams[count-1]; 340 removeItem(tmpParams, mParams, index); 341 mParams = tmpParams; 342 343 if (view != null) { 344 view.assignParent(null); 345 // func doesn't allow null... does it matter if we clear them? 346 //view.setLayoutParams(null); 347 } 348 return view; 349 } 350 351 private static void removeItem(Object[] dst, Object[] src, int index) { 352 if (dst.length > 0) { 353 if (index > 0) { 354 System.arraycopy(src, 0, dst, 0, index); 355 } 356 if (index < dst.length) { 357 System.arraycopy(src, index+1, dst, index, src.length-index-1); 358 } 359 } 360 } 361 362 private int findViewLocked(View view, boolean required) { 363 synchronized (mLock) { 364 if (mViews != null) { 365 final int count = mViews.length; 366 for (int i = 0; i < count; i++) { 367 if (mViews[i] == view) { 368 return i; 369 } 370 } 371 } 372 if (required) { 373 throw new IllegalArgumentException("View not attached to window manager"); 374 } 375 return -1; 376 } 377 } 378 379 public void startTrimMemory(int level) { 380 if (HardwareRenderer.isAvailable()) { 381 // On low-end gfx devices we trim when memory is moderate; 382 // on high-end devices we do this when low. 383 if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE 384 || (level >= ComponentCallbacks2.TRIM_MEMORY_MODERATE 385 && !ActivityManager.isHighEndGfx())) { 386 // Destroy all hardware surfaces and resources associated to 387 // known windows 388 synchronized (mLock) { 389 if (mViews == null) return; 390 int count = mViews.length; 391 for (int i = 0; i < count; i++) { 392 mRoots[i].terminateHardwareResources(); 393 } 394 } 395 // Force a full memory flush 396 mNeedsEglTerminate = true; 397 HardwareRenderer.startTrimMemory(ComponentCallbacks2.TRIM_MEMORY_COMPLETE); 398 return; 399 } 400 401 HardwareRenderer.startTrimMemory(level); 402 } 403 } 404 405 public void endTrimMemory() { 406 HardwareRenderer.endTrimMemory(); 407 408 if (mNeedsEglTerminate) { 409 ManagedEGLContext.doTerminate(); 410 mNeedsEglTerminate = false; 411 } 412 } 413 414 public void trimLocalMemory() { 415 synchronized (mLock) { 416 if (mViews == null) return; 417 int count = mViews.length; 418 for (int i = 0; i < count; i++) { 419 mRoots[i].destroyHardwareLayers(); 420 } 421 } 422 } 423 424 public void dumpGfxInfo(FileDescriptor fd) { 425 FileOutputStream fout = new FileOutputStream(fd); 426 PrintWriter pw = new PrintWriter(fout); 427 try { 428 synchronized (mLock) { 429 if (mViews != null) { 430 final int count = mViews.length; 431 432 pw.println("Profile data in ms:"); 433 434 for (int i = 0; i < count; i++) { 435 ViewRootImpl root = mRoots[i]; 436 String name = getWindowName(root); 437 pw.printf("\n\t%s", name); 438 439 HardwareRenderer renderer = 440 root.getView().mAttachInfo.mHardwareRenderer; 441 if (renderer != null) { 442 renderer.dumpGfxInfo(pw); 443 } 444 } 445 446 pw.println("\nView hierarchy:\n"); 447 448 int viewsCount = 0; 449 int displayListsSize = 0; 450 int[] info = new int[2]; 451 452 for (int i = 0; i < count; i++) { 453 ViewRootImpl root = mRoots[i]; 454 root.dumpGfxInfo(info); 455 456 String name = getWindowName(root); 457 pw.printf(" %s\n %d views, %.2f kB of display lists", 458 name, info[0], info[1] / 1024.0f); 459 HardwareRenderer renderer = 460 root.getView().mAttachInfo.mHardwareRenderer; 461 if (renderer != null) { 462 pw.printf(", %d frames rendered", renderer.getFrameCount()); 463 } 464 pw.printf("\n\n"); 465 466 viewsCount += info[0]; 467 displayListsSize += info[1]; 468 } 469 470 pw.printf("\nTotal ViewRootImpl: %d\n", count); 471 pw.printf("Total Views: %d\n", viewsCount); 472 pw.printf("Total DisplayList: %.2f kB\n\n", displayListsSize / 1024.0f); 473 } 474 } 475 } finally { 476 pw.flush(); 477 } 478 } 479 480 private static String getWindowName(ViewRootImpl root) { 481 return root.mWindowAttributes.getTitle() + "/" + 482 root.getClass().getName() + '@' + Integer.toHexString(root.hashCode()); 483 } 484 485 public void setStoppedState(IBinder token, boolean stopped) { 486 synchronized (mLock) { 487 if (mViews != null) { 488 int count = mViews.length; 489 for (int i=0; i < count; i++) { 490 if (token == null || mParams[i].token == token) { 491 ViewRootImpl root = mRoots[i]; 492 root.setStopped(stopped); 493 } 494 } 495 } 496 } 497 } 498 499 public void reportNewConfiguration(Configuration config) { 500 synchronized (mLock) { 501 if (mViews != null) { 502 int count = mViews.length; 503 config = new Configuration(config); 504 for (int i=0; i < count; i++) { 505 ViewRootImpl root = mRoots[i]; 506 root.requestUpdateConfiguration(config); 507 } 508 } 509 } 510 } 511} 512 513final class WindowLeaked extends AndroidRuntimeException { 514 public WindowLeaked(String msg) { 515 super(msg); 516 } 517} 518