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