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