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 17 package android.view; 18 19 import android.animation.ValueAnimator; 20 import android.app.ActivityManager; 21 import android.content.ComponentCallbacks2; 22 import android.content.res.Configuration; 23 import android.opengl.ManagedEGLContext; 24 import android.os.IBinder; 25 import android.os.Looper; 26 import android.os.RemoteException; 27 import android.os.ServiceManager; 28 import android.os.SystemProperties; 29 import android.util.AndroidRuntimeException; 30 import android.util.Log; 31 import android.view.inputmethod.InputMethodManager; 32 33 import java.io.FileDescriptor; 34 import java.io.FileOutputStream; 35 import 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 */ 49 public 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 WindowManagerGlobal()117 private WindowManagerGlobal() { 118 } 119 getInstance()120 public static WindowManagerGlobal getInstance() { 121 synchronized (WindowManagerGlobal.class) { 122 if (sDefaultWindowManager == null) { 123 sDefaultWindowManager = new WindowManagerGlobal(); 124 } 125 return sDefaultWindowManager; 126 } 127 } 128 getWindowManagerService()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 getWindowSession(Looper mainLooper)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 peekWindowSession()157 public static IWindowSession peekWindowSession() { 158 synchronized (WindowManagerGlobal.class) { 159 return sWindowSession; 160 } 161 } 162 addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow)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 viewRoot : mRoots) { 190 viewRoot.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 try { 246 root.setView(view, wparams, panelParentView); 247 } catch (RuntimeException e) { 248 // BadTokenException or InvalidDisplayException, clean up. 249 synchronized (mLock) { 250 final int index = findViewLocked(view, false); 251 if (index >= 0) { 252 removeViewLocked(index, true); 253 } 254 } 255 throw e; 256 } 257 } 258 updateViewLayout(View view, ViewGroup.LayoutParams params)259 public void updateViewLayout(View view, ViewGroup.LayoutParams params) { 260 if (view == null) { 261 throw new IllegalArgumentException("view must not be null"); 262 } 263 if (!(params instanceof WindowManager.LayoutParams)) { 264 throw new IllegalArgumentException("Params must be WindowManager.LayoutParams"); 265 } 266 267 final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params; 268 269 view.setLayoutParams(wparams); 270 271 synchronized (mLock) { 272 int index = findViewLocked(view, true); 273 ViewRootImpl root = mRoots[index]; 274 mParams[index] = wparams; 275 root.setLayoutParams(wparams, false); 276 } 277 } 278 removeView(View view, boolean immediate)279 public void removeView(View view, boolean immediate) { 280 if (view == null) { 281 throw new IllegalArgumentException("view must not be null"); 282 } 283 284 synchronized (mLock) { 285 int index = findViewLocked(view, true); 286 View curView = removeViewLocked(index, immediate); 287 if (curView == view) { 288 return; 289 } 290 291 throw new IllegalStateException("Calling with view " + view 292 + " but the ViewAncestor is attached to " + curView); 293 } 294 } 295 closeAll(IBinder token, String who, String what)296 public void closeAll(IBinder token, String who, String what) { 297 synchronized (mLock) { 298 if (mViews == null) 299 return; 300 301 int count = mViews.length; 302 //Log.i("foo", "Closing all windows of " + token); 303 for (int i=0; i<count; i++) { 304 //Log.i("foo", "@ " + i + " token " + mParams[i].token 305 // + " view " + mRoots[i].getView()); 306 if (token == null || mParams[i].token == token) { 307 ViewRootImpl root = mRoots[i]; 308 309 //Log.i("foo", "Force closing " + root); 310 if (who != null) { 311 WindowLeaked leak = new WindowLeaked( 312 what + " " + who + " has leaked window " 313 + root.getView() + " that was originally added here"); 314 leak.setStackTrace(root.getLocation().getStackTrace()); 315 Log.e(TAG, leak.getMessage(), leak); 316 } 317 318 removeViewLocked(i, false); 319 i--; 320 count--; 321 } 322 } 323 } 324 } 325 removeViewLocked(int index, boolean immediate)326 private View removeViewLocked(int index, boolean immediate) { 327 ViewRootImpl root = mRoots[index]; 328 View view = root.getView(); 329 330 if (view != null) { 331 InputMethodManager imm = InputMethodManager.getInstance(view.getContext()); 332 if (imm != null) { 333 imm.windowDismissed(mViews[index].getWindowToken()); 334 } 335 } 336 root.die(immediate); 337 338 final int count = mViews.length; 339 340 // remove it from the list 341 View[] tmpViews = new View[count-1]; 342 removeItem(tmpViews, mViews, index); 343 mViews = tmpViews; 344 345 ViewRootImpl[] tmpRoots = new ViewRootImpl[count-1]; 346 removeItem(tmpRoots, mRoots, index); 347 mRoots = tmpRoots; 348 349 WindowManager.LayoutParams[] tmpParams 350 = new WindowManager.LayoutParams[count-1]; 351 removeItem(tmpParams, mParams, index); 352 mParams = tmpParams; 353 354 if (view != null) { 355 view.assignParent(null); 356 // func doesn't allow null... does it matter if we clear them? 357 //view.setLayoutParams(null); 358 } 359 return view; 360 } 361 removeItem(Object[] dst, Object[] src, int index)362 private static void removeItem(Object[] dst, Object[] src, int index) { 363 if (dst.length > 0) { 364 if (index > 0) { 365 System.arraycopy(src, 0, dst, 0, index); 366 } 367 if (index < dst.length) { 368 System.arraycopy(src, index+1, dst, index, src.length-index-1); 369 } 370 } 371 } 372 findViewLocked(View view, boolean required)373 private int findViewLocked(View view, boolean required) { 374 if (mViews != null) { 375 final int count = mViews.length; 376 for (int i = 0; i < count; i++) { 377 if (mViews[i] == view) { 378 return i; 379 } 380 } 381 } 382 if (required) { 383 throw new IllegalArgumentException("View not attached to window manager"); 384 } 385 return -1; 386 } 387 startTrimMemory(int level)388 public void startTrimMemory(int level) { 389 if (HardwareRenderer.isAvailable()) { 390 // On low-end gfx devices we trim when memory is moderate; 391 // on high-end devices we do this when low. 392 if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE 393 || (level >= ComponentCallbacks2.TRIM_MEMORY_MODERATE 394 && !ActivityManager.isHighEndGfx())) { 395 // Destroy all hardware surfaces and resources associated to 396 // known windows 397 synchronized (mLock) { 398 if (mViews == null) return; 399 int count = mViews.length; 400 for (int i = 0; i < count; i++) { 401 mRoots[i].terminateHardwareResources(); 402 } 403 } 404 // Force a full memory flush 405 mNeedsEglTerminate = true; 406 HardwareRenderer.startTrimMemory(ComponentCallbacks2.TRIM_MEMORY_COMPLETE); 407 return; 408 } 409 410 HardwareRenderer.startTrimMemory(level); 411 } 412 } 413 endTrimMemory()414 public void endTrimMemory() { 415 HardwareRenderer.endTrimMemory(); 416 417 if (mNeedsEglTerminate) { 418 ManagedEGLContext.doTerminate(); 419 mNeedsEglTerminate = false; 420 } 421 } 422 trimLocalMemory()423 public void trimLocalMemory() { 424 synchronized (mLock) { 425 if (mViews == null) return; 426 int count = mViews.length; 427 for (int i = 0; i < count; i++) { 428 mRoots[i].destroyHardwareLayers(); 429 } 430 } 431 } 432 dumpGfxInfo(FileDescriptor fd)433 public void dumpGfxInfo(FileDescriptor fd) { 434 FileOutputStream fout = new FileOutputStream(fd); 435 PrintWriter pw = new PrintWriter(fout); 436 try { 437 synchronized (mLock) { 438 if (mViews != null) { 439 final int count = mViews.length; 440 441 pw.println("Profile data in ms:"); 442 443 for (int i = 0; i < count; i++) { 444 ViewRootImpl root = mRoots[i]; 445 String name = getWindowName(root); 446 pw.printf("\n\t%s", name); 447 448 HardwareRenderer renderer = 449 root.getView().mAttachInfo.mHardwareRenderer; 450 if (renderer != null) { 451 renderer.dumpGfxInfo(pw); 452 } 453 } 454 455 pw.println("\nView hierarchy:\n"); 456 457 int viewsCount = 0; 458 int displayListsSize = 0; 459 int[] info = new int[2]; 460 461 for (int i = 0; i < count; i++) { 462 ViewRootImpl root = mRoots[i]; 463 root.dumpGfxInfo(info); 464 465 String name = getWindowName(root); 466 pw.printf(" %s\n %d views, %.2f kB of display lists", 467 name, info[0], info[1] / 1024.0f); 468 HardwareRenderer renderer = 469 root.getView().mAttachInfo.mHardwareRenderer; 470 if (renderer != null) { 471 pw.printf(", %d frames rendered", renderer.getFrameCount()); 472 } 473 pw.printf("\n\n"); 474 475 viewsCount += info[0]; 476 displayListsSize += info[1]; 477 } 478 479 pw.printf("\nTotal ViewRootImpl: %d\n", count); 480 pw.printf("Total Views: %d\n", viewsCount); 481 pw.printf("Total DisplayList: %.2f kB\n\n", displayListsSize / 1024.0f); 482 } 483 } 484 } finally { 485 pw.flush(); 486 } 487 } 488 getWindowName(ViewRootImpl root)489 private static String getWindowName(ViewRootImpl root) { 490 return root.mWindowAttributes.getTitle() + "/" + 491 root.getClass().getName() + '@' + Integer.toHexString(root.hashCode()); 492 } 493 setStoppedState(IBinder token, boolean stopped)494 public void setStoppedState(IBinder token, boolean stopped) { 495 synchronized (mLock) { 496 if (mViews != null) { 497 int count = mViews.length; 498 for (int i=0; i < count; i++) { 499 if (token == null || mParams[i].token == token) { 500 ViewRootImpl root = mRoots[i]; 501 root.setStopped(stopped); 502 } 503 } 504 } 505 } 506 } 507 reportNewConfiguration(Configuration config)508 public void reportNewConfiguration(Configuration config) { 509 synchronized (mLock) { 510 if (mViews != null) { 511 int count = mViews.length; 512 config = new Configuration(config); 513 for (int i=0; i < count; i++) { 514 ViewRootImpl root = mRoots[i]; 515 root.requestUpdateConfiguration(config); 516 } 517 } 518 } 519 } 520 } 521 522 final class WindowLeaked extends AndroidRuntimeException { WindowLeaked(String msg)523 public WindowLeaked(String msg) { 524 super(msg); 525 } 526 } 527