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.annotation.NonNull; 21 import android.app.ActivityManager; 22 import android.compat.annotation.UnsupportedAppUsage; 23 import android.content.ComponentCallbacks2; 24 import android.content.Context; 25 import android.content.pm.ApplicationInfo; 26 import android.content.res.Configuration; 27 import android.os.Build; 28 import android.os.IBinder; 29 import android.os.RemoteException; 30 import android.os.ServiceManager; 31 import android.os.SystemProperties; 32 import android.util.AndroidRuntimeException; 33 import android.util.ArraySet; 34 import android.util.Log; 35 import android.view.inputmethod.InputMethodManager; 36 37 import com.android.internal.util.FastPrintWriter; 38 39 import java.io.FileDescriptor; 40 import java.io.FileOutputStream; 41 import java.io.PrintWriter; 42 import java.util.ArrayList; 43 44 /** 45 * Provides low-level communication with the system window manager for 46 * operations that are not associated with any particular context. 47 * 48 * This class is only used internally to implement global functions where 49 * the caller already knows the display and relevant compatibility information 50 * for the operation. For most purposes, you should use {@link WindowManager} instead 51 * since it is bound to a context. 52 * 53 * @see WindowManagerImpl 54 * @hide 55 */ 56 public final class WindowManagerGlobal { 57 private static final String TAG = "WindowManager"; 58 59 private static boolean sUseBLASTAdapter = false; 60 61 /** 62 * The user is navigating with keys (not the touch screen), so 63 * navigational focus should be shown. 64 */ 65 public static final int RELAYOUT_RES_IN_TOUCH_MODE = 0x1; 66 67 /** 68 * This is the first time the window is being drawn, 69 * so the client must call drawingFinished() when done 70 */ 71 public static final int RELAYOUT_RES_FIRST_TIME = 0x2; 72 73 /** 74 * The window manager has changed the surface from the last call. 75 */ 76 public static final int RELAYOUT_RES_SURFACE_CHANGED = 0x4; 77 78 /** 79 * The window is being resized by dragging on the docked divider. The client should render 80 * at (0, 0) and extend its background to the background frame passed into 81 * {@link IWindow#resized}. 82 */ 83 public static final int RELAYOUT_RES_DRAG_RESIZING_DOCKED = 0x8; 84 85 /** 86 * The window is being resized by dragging one of the window corners, 87 * in this case the surface would be fullscreen-sized. The client should 88 * render to the actual frame location (instead of (0,curScrollY)). 89 */ 90 public static final int RELAYOUT_RES_DRAG_RESIZING_FREEFORM = 0x10; 91 92 /** 93 * The window manager has changed the size of the surface from the last call. 94 */ 95 public static final int RELAYOUT_RES_SURFACE_RESIZED = 0x20; 96 97 /** 98 * In multi-window we force show the system bars. Because we don't want that the surface size 99 * changes in this mode, we instead have a flag whether the system bar sizes should always be 100 * consumed, so the app is treated like there is no virtual system bars at all. 101 */ 102 public static final int RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS = 0x40; 103 104 /** 105 * This flag indicates the client should not directly submit it's next frame, 106 * but instead should pass it in the postDrawTransaction of 107 * {@link WindowManagerService#finishDrawing}. This is used by the WM 108 * BLASTSyncEngine to synchronize rendering of multiple windows. 109 */ 110 public static final int RELAYOUT_RES_BLAST_SYNC = 0x80; 111 112 /** 113 * Flag for relayout: the client will be later giving 114 * internal insets; as a result, the window will not impact other window 115 * layouts until the insets are given. 116 */ 117 public static final int RELAYOUT_INSETS_PENDING = 0x1; 118 119 public static final int ADD_FLAG_IN_TOUCH_MODE = 0x1; 120 public static final int ADD_FLAG_APP_VISIBLE = 0x2; 121 public static final int ADD_FLAG_USE_BLAST = 0x8; 122 123 /** 124 * Like {@link #RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS}, but as a "hint" when adding the 125 * window. 126 */ 127 public static final int ADD_FLAG_ALWAYS_CONSUME_SYSTEM_BARS = 0x4; 128 129 public static final int ADD_OKAY = 0; 130 public static final int ADD_BAD_APP_TOKEN = -1; 131 public static final int ADD_BAD_SUBWINDOW_TOKEN = -2; 132 public static final int ADD_NOT_APP_TOKEN = -3; 133 public static final int ADD_APP_EXITING = -4; 134 public static final int ADD_DUPLICATE_ADD = -5; 135 public static final int ADD_STARTING_NOT_NEEDED = -6; 136 public static final int ADD_MULTIPLE_SINGLETON = -7; 137 public static final int ADD_PERMISSION_DENIED = -8; 138 public static final int ADD_INVALID_DISPLAY = -9; 139 public static final int ADD_INVALID_TYPE = -10; 140 public static final int ADD_INVALID_USER = -11; 141 142 @UnsupportedAppUsage 143 private static WindowManagerGlobal sDefaultWindowManager; 144 @UnsupportedAppUsage 145 private static IWindowManager sWindowManagerService; 146 @UnsupportedAppUsage 147 private static IWindowSession sWindowSession; 148 149 @UnsupportedAppUsage 150 private final Object mLock = new Object(); 151 152 @UnsupportedAppUsage 153 private final ArrayList<View> mViews = new ArrayList<View>(); 154 @UnsupportedAppUsage 155 private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>(); 156 @UnsupportedAppUsage 157 private final ArrayList<WindowManager.LayoutParams> mParams = 158 new ArrayList<WindowManager.LayoutParams>(); 159 private final ArraySet<View> mDyingViews = new ArraySet<View>(); 160 161 private Runnable mSystemPropertyUpdater; 162 WindowManagerGlobal()163 private WindowManagerGlobal() { 164 } 165 166 @UnsupportedAppUsage initialize()167 public static void initialize() { 168 getWindowManagerService(); 169 } 170 171 @UnsupportedAppUsage getInstance()172 public static WindowManagerGlobal getInstance() { 173 synchronized (WindowManagerGlobal.class) { 174 if (sDefaultWindowManager == null) { 175 sDefaultWindowManager = new WindowManagerGlobal(); 176 } 177 return sDefaultWindowManager; 178 } 179 } 180 181 @UnsupportedAppUsage getWindowManagerService()182 public static IWindowManager getWindowManagerService() { 183 synchronized (WindowManagerGlobal.class) { 184 if (sWindowManagerService == null) { 185 sWindowManagerService = IWindowManager.Stub.asInterface( 186 ServiceManager.getService("window")); 187 try { 188 if (sWindowManagerService != null) { 189 ValueAnimator.setDurationScale( 190 sWindowManagerService.getCurrentAnimatorScale()); 191 sUseBLASTAdapter = sWindowManagerService.useBLAST(); 192 } 193 } catch (RemoteException e) { 194 throw e.rethrowFromSystemServer(); 195 } 196 } 197 return sWindowManagerService; 198 } 199 } 200 201 @UnsupportedAppUsage getWindowSession()202 public static IWindowSession getWindowSession() { 203 synchronized (WindowManagerGlobal.class) { 204 if (sWindowSession == null) { 205 try { 206 // Emulate the legacy behavior. The global instance of InputMethodManager 207 // was instantiated here. 208 // TODO(b/116157766): Remove this hack after cleaning up @UnsupportedAppUsage 209 InputMethodManager.ensureDefaultInstanceForDefaultDisplayIfNecessary(); 210 IWindowManager windowManager = getWindowManagerService(); 211 sWindowSession = windowManager.openSession( 212 new IWindowSessionCallback.Stub() { 213 @Override 214 public void onAnimatorScaleChanged(float scale) { 215 ValueAnimator.setDurationScale(scale); 216 } 217 }); 218 } catch (RemoteException e) { 219 throw e.rethrowFromSystemServer(); 220 } 221 } 222 return sWindowSession; 223 } 224 } 225 226 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) peekWindowSession()227 public static IWindowSession peekWindowSession() { 228 synchronized (WindowManagerGlobal.class) { 229 return sWindowSession; 230 } 231 } 232 233 /** 234 * Whether or not to use BLAST for ViewRootImpl 235 */ useBLAST()236 public static boolean useBLAST() { 237 return sUseBLASTAdapter; 238 } 239 240 @UnsupportedAppUsage getViewRootNames()241 public String[] getViewRootNames() { 242 synchronized (mLock) { 243 final int numRoots = mRoots.size(); 244 String[] mViewRoots = new String[numRoots]; 245 for (int i = 0; i < numRoots; ++i) { 246 mViewRoots[i] = getWindowName(mRoots.get(i)); 247 } 248 return mViewRoots; 249 } 250 } 251 252 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getRootViews(IBinder token)253 public ArrayList<ViewRootImpl> getRootViews(IBinder token) { 254 ArrayList<ViewRootImpl> views = new ArrayList<>(); 255 synchronized (mLock) { 256 final int numRoots = mRoots.size(); 257 for (int i = 0; i < numRoots; ++i) { 258 WindowManager.LayoutParams params = mParams.get(i); 259 if (params.token == null) { 260 continue; 261 } 262 if (params.token != token) { 263 boolean isChild = false; 264 if (params.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW 265 && params.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) { 266 for (int j = 0 ; j < numRoots; ++j) { 267 View viewj = mViews.get(j); 268 WindowManager.LayoutParams paramsj = mParams.get(j); 269 if (params.token == viewj.getWindowToken() 270 && paramsj.token == token) { 271 isChild = true; 272 break; 273 } 274 } 275 } 276 if (!isChild) { 277 continue; 278 } 279 } 280 views.add(mRoots.get(i)); 281 } 282 } 283 return views; 284 } 285 286 /** 287 * @return the list of all views attached to the global window manager 288 */ 289 @NonNull getWindowViews()290 public ArrayList<View> getWindowViews() { 291 synchronized (mLock) { 292 return new ArrayList<>(mViews); 293 } 294 } 295 getWindowView(IBinder windowToken)296 public View getWindowView(IBinder windowToken) { 297 synchronized (mLock) { 298 final int numViews = mViews.size(); 299 for (int i = 0; i < numViews; ++i) { 300 final View view = mViews.get(i); 301 if (view.getWindowToken() == windowToken) { 302 return view; 303 } 304 } 305 } 306 return null; 307 } 308 309 @UnsupportedAppUsage getRootView(String name)310 public View getRootView(String name) { 311 synchronized (mLock) { 312 for (int i = mRoots.size() - 1; i >= 0; --i) { 313 final ViewRootImpl root = mRoots.get(i); 314 if (name.equals(getWindowName(root))) return root.getView(); 315 } 316 } 317 318 return null; 319 } 320 addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow, int userId)321 public void addView(View view, ViewGroup.LayoutParams params, 322 Display display, Window parentWindow, int userId) { 323 if (view == null) { 324 throw new IllegalArgumentException("view must not be null"); 325 } 326 if (display == null) { 327 throw new IllegalArgumentException("display must not be null"); 328 } 329 if (!(params instanceof WindowManager.LayoutParams)) { 330 throw new IllegalArgumentException("Params must be WindowManager.LayoutParams"); 331 } 332 333 final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params; 334 if (parentWindow != null) { 335 parentWindow.adjustLayoutParamsForSubWindow(wparams); 336 } else { 337 // If there's no parent, then hardware acceleration for this view is 338 // set from the application's hardware acceleration setting. 339 final Context context = view.getContext(); 340 if (context != null 341 && (context.getApplicationInfo().flags 342 & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) { 343 wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; 344 } 345 } 346 347 ViewRootImpl root; 348 View panelParentView = null; 349 350 synchronized (mLock) { 351 // Start watching for system property changes. 352 if (mSystemPropertyUpdater == null) { 353 mSystemPropertyUpdater = new Runnable() { 354 @Override public void run() { 355 synchronized (mLock) { 356 for (int i = mRoots.size() - 1; i >= 0; --i) { 357 mRoots.get(i).loadSystemProperties(); 358 } 359 } 360 } 361 }; 362 SystemProperties.addChangeCallback(mSystemPropertyUpdater); 363 } 364 365 int index = findViewLocked(view, false); 366 if (index >= 0) { 367 if (mDyingViews.contains(view)) { 368 // Don't wait for MSG_DIE to make it's way through root's queue. 369 mRoots.get(index).doDie(); 370 } else { 371 throw new IllegalStateException("View " + view 372 + " has already been added to the window manager."); 373 } 374 // The previous removeView() had not completed executing. Now it has. 375 } 376 377 // If this is a panel window, then find the window it is being 378 // attached to for future reference. 379 if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW && 380 wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) { 381 final int count = mViews.size(); 382 for (int i = 0; i < count; i++) { 383 if (mRoots.get(i).mWindow.asBinder() == wparams.token) { 384 panelParentView = mViews.get(i); 385 } 386 } 387 } 388 389 root = new ViewRootImpl(view.getContext(), display); 390 391 view.setLayoutParams(wparams); 392 393 mViews.add(view); 394 mRoots.add(root); 395 mParams.add(wparams); 396 397 // do this last because it fires off messages to start doing things 398 try { 399 root.setView(view, wparams, panelParentView, userId); 400 } catch (RuntimeException e) { 401 // BadTokenException or InvalidDisplayException, clean up. 402 if (index >= 0) { 403 removeViewLocked(index, true); 404 } 405 throw e; 406 } 407 } 408 } 409 updateViewLayout(View view, ViewGroup.LayoutParams params)410 public void updateViewLayout(View view, ViewGroup.LayoutParams params) { 411 if (view == null) { 412 throw new IllegalArgumentException("view must not be null"); 413 } 414 if (!(params instanceof WindowManager.LayoutParams)) { 415 throw new IllegalArgumentException("Params must be WindowManager.LayoutParams"); 416 } 417 418 final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params; 419 420 view.setLayoutParams(wparams); 421 422 synchronized (mLock) { 423 int index = findViewLocked(view, true); 424 ViewRootImpl root = mRoots.get(index); 425 mParams.remove(index); 426 mParams.add(index, wparams); 427 root.setLayoutParams(wparams, false); 428 } 429 } 430 431 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) removeView(View view, boolean immediate)432 public void removeView(View view, boolean immediate) { 433 if (view == null) { 434 throw new IllegalArgumentException("view must not be null"); 435 } 436 437 synchronized (mLock) { 438 int index = findViewLocked(view, true); 439 View curView = mRoots.get(index).getView(); 440 removeViewLocked(index, immediate); 441 if (curView == view) { 442 return; 443 } 444 445 throw new IllegalStateException("Calling with view " + view 446 + " but the ViewAncestor is attached to " + curView); 447 } 448 } 449 450 /** 451 * Remove all roots with specified token. 452 * 453 * @param token app or window token. 454 * @param who name of caller, used in logs. 455 * @param what type of caller, used in logs. 456 */ closeAll(IBinder token, String who, String what)457 public void closeAll(IBinder token, String who, String what) { 458 closeAllExceptView(token, null /* view */, who, what); 459 } 460 461 /** 462 * Remove all roots with specified token, except maybe one view. 463 * 464 * @param token app or window token. 465 * @param view view that should be should be preserved along with it's root. 466 * Pass null if everything should be removed. 467 * @param who name of caller, used in logs. 468 * @param what type of caller, used in logs. 469 */ closeAllExceptView(IBinder token, View view, String who, String what)470 public void closeAllExceptView(IBinder token, View view, String who, String what) { 471 synchronized (mLock) { 472 int count = mViews.size(); 473 for (int i = 0; i < count; i++) { 474 if ((view == null || mViews.get(i) != view) 475 && (token == null || mParams.get(i).token == token)) { 476 ViewRootImpl root = mRoots.get(i); 477 478 if (who != null) { 479 WindowLeaked leak = new WindowLeaked( 480 what + " " + who + " has leaked window " 481 + root.getView() + " that was originally added here"); 482 leak.setStackTrace(root.getLocation().getStackTrace()); 483 Log.e(TAG, "", leak); 484 } 485 486 removeViewLocked(i, false); 487 } 488 } 489 } 490 } 491 removeViewLocked(int index, boolean immediate)492 private void removeViewLocked(int index, boolean immediate) { 493 ViewRootImpl root = mRoots.get(index); 494 View view = root.getView(); 495 496 if (root != null) { 497 root.getImeFocusController().onWindowDismissed(); 498 } 499 boolean deferred = root.die(immediate); 500 if (view != null) { 501 view.assignParent(null); 502 if (deferred) { 503 mDyingViews.add(view); 504 } 505 } 506 } 507 doRemoveView(ViewRootImpl root)508 void doRemoveView(ViewRootImpl root) { 509 boolean allViewsRemoved; 510 synchronized (mLock) { 511 final int index = mRoots.indexOf(root); 512 if (index >= 0) { 513 mRoots.remove(index); 514 mParams.remove(index); 515 final View view = mViews.remove(index); 516 mDyingViews.remove(view); 517 } 518 allViewsRemoved = mRoots.isEmpty(); 519 } 520 if (ThreadedRenderer.sTrimForeground) { 521 doTrimForeground(); 522 } 523 524 // If we don't have any views anymore in our process, we no longer need the 525 // InsetsAnimationThread to save some resources. 526 if (allViewsRemoved) { 527 InsetsAnimationThread.release(); 528 } 529 } 530 findViewLocked(View view, boolean required)531 private int findViewLocked(View view, boolean required) { 532 final int index = mViews.indexOf(view); 533 if (required && index < 0) { 534 throw new IllegalArgumentException("View=" + view + " not attached to window manager"); 535 } 536 return index; 537 } 538 shouldDestroyEglContext(int trimLevel)539 public static boolean shouldDestroyEglContext(int trimLevel) { 540 // On low-end gfx devices we trim when memory is moderate; 541 // on high-end devices we do this when low. 542 if (trimLevel >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE) { 543 return true; 544 } 545 if (trimLevel >= ComponentCallbacks2.TRIM_MEMORY_MODERATE 546 && !ActivityManager.isHighEndGfx()) { 547 return true; 548 } 549 return false; 550 } 551 552 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) trimMemory(int level)553 public void trimMemory(int level) { 554 555 if (shouldDestroyEglContext(level)) { 556 // Destroy all hardware surfaces and resources associated to 557 // known windows 558 synchronized (mLock) { 559 for (int i = mRoots.size() - 1; i >= 0; --i) { 560 mRoots.get(i).destroyHardwareResources(); 561 } 562 } 563 // Force a full memory flush 564 level = ComponentCallbacks2.TRIM_MEMORY_COMPLETE; 565 } 566 567 ThreadedRenderer.trimMemory(level); 568 569 if (ThreadedRenderer.sTrimForeground) { 570 doTrimForeground(); 571 } 572 } 573 trimForeground()574 public static void trimForeground() { 575 if (ThreadedRenderer.sTrimForeground) { 576 WindowManagerGlobal wm = WindowManagerGlobal.getInstance(); 577 wm.doTrimForeground(); 578 } 579 } 580 doTrimForeground()581 private void doTrimForeground() { 582 boolean hasVisibleWindows = false; 583 synchronized (mLock) { 584 for (int i = mRoots.size() - 1; i >= 0; --i) { 585 final ViewRootImpl root = mRoots.get(i); 586 if (root.mView != null && root.getHostVisibility() == View.VISIBLE 587 && root.mAttachInfo.mThreadedRenderer != null) { 588 hasVisibleWindows = true; 589 } else { 590 root.destroyHardwareResources(); 591 } 592 } 593 } 594 if (!hasVisibleWindows) { 595 ThreadedRenderer.trimMemory( 596 ComponentCallbacks2.TRIM_MEMORY_COMPLETE); 597 } 598 } 599 dumpGfxInfo(FileDescriptor fd, String[] args)600 public void dumpGfxInfo(FileDescriptor fd, String[] args) { 601 FileOutputStream fout = new FileOutputStream(fd); 602 PrintWriter pw = new FastPrintWriter(fout); 603 try { 604 synchronized (mLock) { 605 final int count = mViews.size(); 606 607 pw.println("Profile data in ms:"); 608 609 for (int i = 0; i < count; i++) { 610 ViewRootImpl root = mRoots.get(i); 611 String name = getWindowName(root); 612 pw.printf("\n\t%s (visibility=%d)", name, root.getHostVisibility()); 613 614 ThreadedRenderer renderer = 615 root.getView().mAttachInfo.mThreadedRenderer; 616 if (renderer != null) { 617 renderer.dumpGfxInfo(pw, fd, args); 618 } 619 } 620 621 pw.println("\nView hierarchy:\n"); 622 623 ViewRootImpl.GfxInfo totals = new ViewRootImpl.GfxInfo(); 624 625 for (int i = 0; i < count; i++) { 626 ViewRootImpl root = mRoots.get(i); 627 ViewRootImpl.GfxInfo info = root.getGfxInfo(); 628 totals.add(info); 629 630 String name = getWindowName(root); 631 pw.printf(" %s\n %d views, %.2f kB of render nodes", 632 name, info.viewCount, info.renderNodeMemoryUsage / 1024.f); 633 pw.printf("\n\n"); 634 } 635 636 pw.printf("\nTotal %-15s: %d\n", "ViewRootImpl", count); 637 pw.printf("Total %-15s: %d\n", "attached Views", totals.viewCount); 638 pw.printf("Total %-15s: %.2f kB (used) / %.2f kB (capacity)\n\n", "RenderNode", 639 totals.renderNodeMemoryUsage / 1024.0f, 640 totals.renderNodeMemoryAllocated / 1024.0f); 641 } 642 } finally { 643 pw.flush(); 644 } 645 } 646 getWindowName(ViewRootImpl root)647 private static String getWindowName(ViewRootImpl root) { 648 return root.mWindowAttributes.getTitle() + "/" + 649 root.getClass().getName() + '@' + Integer.toHexString(root.hashCode()); 650 } 651 setStoppedState(IBinder token, boolean stopped)652 public void setStoppedState(IBinder token, boolean stopped) { 653 ArrayList<ViewRootImpl> nonCurrentThreadRoots = null; 654 synchronized (mLock) { 655 int count = mViews.size(); 656 for (int i = count - 1; i >= 0; i--) { 657 if (token == null || mParams.get(i).token == token) { 658 ViewRootImpl root = mRoots.get(i); 659 // Client might remove the view by "stopped" event. 660 if (root.mThread == Thread.currentThread()) { 661 root.setWindowStopped(stopped); 662 } else { 663 if (nonCurrentThreadRoots == null) { 664 nonCurrentThreadRoots = new ArrayList<>(); 665 } 666 nonCurrentThreadRoots.add(root); 667 } 668 // Recursively forward stopped state to View's attached 669 // to this Window rather than the root application token, 670 // e.g. PopupWindow's. 671 setStoppedState(root.mAttachInfo.mWindowToken, stopped); 672 } 673 } 674 } 675 676 // Update the stopped state synchronously to ensure the surface won't be used after server 677 // side has destroyed it. This operation should be outside the lock to avoid any potential 678 // paths from setWindowStopped to WindowManagerGlobal which may cause deadlocks. 679 if (nonCurrentThreadRoots != null) { 680 for (int i = nonCurrentThreadRoots.size() - 1; i >= 0; i--) { 681 ViewRootImpl root = nonCurrentThreadRoots.get(i); 682 root.mHandler.runWithScissors(() -> root.setWindowStopped(stopped), 0); 683 } 684 } 685 } 686 reportNewConfiguration(Configuration config)687 public void reportNewConfiguration(Configuration config) { 688 synchronized (mLock) { 689 int count = mViews.size(); 690 config = new Configuration(config); 691 for (int i=0; i < count; i++) { 692 ViewRootImpl root = mRoots.get(i); 693 root.requestUpdateConfiguration(config); 694 } 695 } 696 } 697 698 /** @hide */ changeCanvasOpacity(IBinder token, boolean opaque)699 public void changeCanvasOpacity(IBinder token, boolean opaque) { 700 if (token == null) { 701 return; 702 } 703 synchronized (mLock) { 704 for (int i = mParams.size() - 1; i >= 0; --i) { 705 if (mParams.get(i).token == token) { 706 mRoots.get(i).changeCanvasOpacity(opaque); 707 return; 708 } 709 } 710 } 711 } 712 } 713 714 final class WindowLeaked extends AndroidRuntimeException { 715 @UnsupportedAppUsage WindowLeaked(String msg)716 public WindowLeaked(String msg) { 717 super(msg); 718 } 719 } 720