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