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 static android.view.Display.INVALID_DISPLAY;
20 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
21 
22 import android.animation.ValueAnimator;
23 import android.annotation.NonNull;
24 import android.annotation.Nullable;
25 import android.compat.annotation.UnsupportedAppUsage;
26 import android.content.Context;
27 import android.content.pm.ApplicationInfo;
28 import android.content.res.Configuration;
29 import android.graphics.HardwareRenderer;
30 import android.os.Binder;
31 import android.os.Build;
32 import android.os.IBinder;
33 import android.os.Looper;
34 import android.os.RemoteException;
35 import android.os.ServiceManager;
36 import android.os.SystemProperties;
37 import android.util.AndroidRuntimeException;
38 import android.util.ArrayMap;
39 import android.util.ArraySet;
40 import android.util.Log;
41 import android.util.Pair;
42 import android.util.SparseArray;
43 import android.view.inputmethod.InputMethodManager;
44 import android.window.ITrustedPresentationListener;
45 import android.window.InputTransferToken;
46 import android.window.TrustedPresentationThresholds;
47 
48 import com.android.internal.annotations.GuardedBy;
49 import com.android.internal.util.FastPrintWriter;
50 
51 import java.io.FileDescriptor;
52 import java.io.FileOutputStream;
53 import java.io.PrintWriter;
54 import java.lang.ref.WeakReference;
55 import java.util.ArrayList;
56 import java.util.WeakHashMap;
57 import java.util.concurrent.Executor;
58 import java.util.function.Consumer;
59 import java.util.function.IntConsumer;
60 
61 /**
62  * Provides low-level communication with the system window manager for
63  * operations that are not associated with any particular context.
64  *
65  * This class is only used internally to implement global functions where
66  * the caller already knows the display and relevant compatibility information
67  * for the operation.  For most purposes, you should use {@link WindowManager} instead
68  * since it is bound to a context.
69  *
70  * @see WindowManagerImpl
71  * @hide
72  */
73 public final class WindowManagerGlobal {
74     private static final String TAG = "WindowManager";
75 
76     /**
77      * This is the first time the window is being drawn,
78      * so the client must call drawingFinished() when done
79      */
80     public static final int RELAYOUT_RES_FIRST_TIME = 1;
81 
82     /**
83      * The window manager has changed the surface from the last call.
84      */
85     public static final int RELAYOUT_RES_SURFACE_CHANGED = 1 << 1;
86 
87     /**
88      * The window manager has changed the size of the surface from the last call.
89      */
90     public static final int RELAYOUT_RES_SURFACE_RESIZED = 1 << 2;
91 
92     /**
93      * In multi-window we force show the system bars. Because we don't want that the surface size
94      * changes in this mode, we instead have a flag whether the system bar sizes should always be
95      * consumed, so the app is treated like there is no virtual system bars at all.
96      */
97     public static final int RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS = 1 << 3;
98 
99     /**
100      * The window manager has told the window it cannot draw this frame and should retry again.
101      */
102     public static final int RELAYOUT_RES_CANCEL_AND_REDRAW = 1 << 4;
103 
104     /**
105      * Flag for relayout: the client will be later giving
106      * internal insets; as a result, the window will not impact other window
107      * layouts until the insets are given.
108      */
109     public static final int RELAYOUT_INSETS_PENDING = 0x1;
110 
111     public static final int ADD_FLAG_IN_TOUCH_MODE = 0x1;
112     public static final int ADD_FLAG_APP_VISIBLE = 0x2;
113 
114     /**
115      * Like {@link #RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS}, but as a "hint" when adding the
116      * window.
117      */
118     public static final int ADD_FLAG_ALWAYS_CONSUME_SYSTEM_BARS = 0x4;
119 
120     public static final int ADD_OKAY = 0;
121     public static final int ADD_BAD_APP_TOKEN = -1;
122     public static final int ADD_BAD_SUBWINDOW_TOKEN = -2;
123     public static final int ADD_NOT_APP_TOKEN = -3;
124     public static final int ADD_APP_EXITING = -4;
125     public static final int ADD_DUPLICATE_ADD = -5;
126     public static final int ADD_STARTING_NOT_NEEDED = -6;
127     public static final int ADD_MULTIPLE_SINGLETON = -7;
128     public static final int ADD_PERMISSION_DENIED = -8;
129     public static final int ADD_INVALID_DISPLAY = -9;
130     public static final int ADD_INVALID_TYPE = -10;
131     public static final int ADD_INVALID_USER = -11;
132 
133     @UnsupportedAppUsage
134     private static WindowManagerGlobal sDefaultWindowManager;
135     @UnsupportedAppUsage
136     private static IWindowManager sWindowManagerService;
137     @UnsupportedAppUsage
138     private static IWindowSession sWindowSession;
139 
140     @UnsupportedAppUsage
141     private final Object mLock = new Object();
142 
143     @UnsupportedAppUsage
144     private final ArrayList<View> mViews = new ArrayList<View>();
145     @UnsupportedAppUsage
146     private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
147     @UnsupportedAppUsage
148     private final ArrayList<WindowManager.LayoutParams> mParams =
149             new ArrayList<WindowManager.LayoutParams>();
150     private final ArraySet<View> mDyingViews = new ArraySet<View>();
151 
152     private final ArrayList<ViewRootImpl> mWindowlessRoots = new ArrayList<ViewRootImpl>();
153 
154     /** A context token only has one remote registration to system. */
155     private WeakHashMap<IBinder, ProposedRotationListenerDelegate> mProposedRotationListenerMap;
156 
157     private Runnable mSystemPropertyUpdater;
158 
159     private final TrustedPresentationListener mTrustedPresentationListener =
160             new TrustedPresentationListener();
161 
162     @GuardedBy("mSurfaceControlInputReceivers")
163     private final SparseArray<SurfaceControlInputReceiverInfo>
164             mSurfaceControlInputReceivers = new SparseArray<>();
165 
WindowManagerGlobal()166     private WindowManagerGlobal() {
167     }
168 
169     @UnsupportedAppUsage
initialize()170     public static void initialize() {
171         getWindowManagerService();
172     }
173 
174     @UnsupportedAppUsage
getInstance()175     public static WindowManagerGlobal getInstance() {
176         synchronized (WindowManagerGlobal.class) {
177             if (sDefaultWindowManager == null) {
178                 sDefaultWindowManager = new WindowManagerGlobal();
179             }
180             return sDefaultWindowManager;
181         }
182     }
183 
184     /**
185      * Sets {@link com.android.server.wm.WindowManagerService} for the system process.
186      * <p>
187      * It is needed to prevent possible deadlock. A possible scenario is:
188      * In system process, WMS holds {@link com.android.server.wm.WindowManagerGlobalLock} to call
189      * {@code WindowManagerGlobal} APIs and wait to lock {@code WindowManagerGlobal} itself
190      * (i.e. call {@link #getWindowManagerService()} in the global lock), while
191      * another component may lock {@code WindowManagerGlobal} and wait to lock
192      * {@link com.android.server.wm.WindowManagerGlobalLock}(i.e call {@link #addView} in the
193      * system process, which calls to {@link com.android.server.wm.WindowManagerService} API
194      * directly).
195      */
setWindowManagerServiceForSystemProcess(@onNull IWindowManager wms)196     public static void setWindowManagerServiceForSystemProcess(@NonNull IWindowManager wms) {
197         sWindowManagerService = wms;
198     }
199 
200     @Nullable
201     @UnsupportedAppUsage
getWindowManagerService()202     public static IWindowManager getWindowManagerService() {
203         if (sWindowManagerService != null) {
204             // Use WMS directly without locking WMGlobal to prevent deadlock.
205             return sWindowManagerService;
206         }
207         synchronized (WindowManagerGlobal.class) {
208             if (sWindowManagerService == null) {
209                 sWindowManagerService = IWindowManager.Stub.asInterface(
210                         ServiceManager.getService("window"));
211                 try {
212                     // Can be null if this is called before WindowManagerService is initialized.
213                     if (sWindowManagerService != null) {
214                         ValueAnimator.setDurationScale(
215                                 sWindowManagerService.getCurrentAnimatorScale());
216                     }
217                 } catch (RemoteException e) {
218                     throw e.rethrowFromSystemServer();
219                 }
220             }
221             return sWindowManagerService;
222         }
223     }
224 
225     @UnsupportedAppUsage
getWindowSession()226     public static IWindowSession getWindowSession() {
227         synchronized (WindowManagerGlobal.class) {
228             if (sWindowSession == null) {
229                 try {
230                     // Emulate the legacy behavior.  The global instance of InputMethodManager
231                     // was instantiated here.
232                     // TODO(b/116157766): Remove this hack after cleaning up @UnsupportedAppUsage
233                     InputMethodManager.ensureDefaultInstanceForDefaultDisplayIfNecessary();
234                     IWindowManager windowManager = getWindowManagerService();
235                     sWindowSession = windowManager.openSession(
236                             new IWindowSessionCallback.Stub() {
237                                 @Override
238                                 public void onAnimatorScaleChanged(float scale) {
239                                     ValueAnimator.setDurationScale(scale);
240                                 }
241                             });
242                 } catch (RemoteException e) {
243                     throw e.rethrowFromSystemServer();
244                 }
245             }
246             return sWindowSession;
247         }
248     }
249 
250     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
peekWindowSession()251     public static IWindowSession peekWindowSession() {
252         synchronized (WindowManagerGlobal.class) {
253             return sWindowSession;
254         }
255     }
256 
257     @UnsupportedAppUsage
getViewRootNames()258     public String[] getViewRootNames() {
259         synchronized (mLock) {
260             final int numRoots = mRoots.size();
261             final int windowlessRoots = mWindowlessRoots.size();
262             String[] mViewRoots = new String[numRoots + windowlessRoots];
263             for (int i = 0; i < numRoots; ++i) {
264                 mViewRoots[i] = getWindowName(mRoots.get(i));
265             }
266             for (int i = 0; i < windowlessRoots; ++i) {
267                 mViewRoots[i + numRoots] = getWindowName(mWindowlessRoots.get(i));
268             }
269             return mViewRoots;
270         }
271     }
272 
273     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
getRootViews(IBinder token)274     public ArrayList<ViewRootImpl> getRootViews(IBinder token) {
275         ArrayList<ViewRootImpl> views = new ArrayList<>();
276         synchronized (mLock) {
277             final int numRoots = mRoots.size();
278             for (int i = 0; i < numRoots; ++i) {
279                 WindowManager.LayoutParams params = mParams.get(i);
280                 if (params.token == null) {
281                     continue;
282                 }
283                 if (params.token != token) {
284                     boolean isChild = false;
285                     if (params.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW
286                             && params.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
287                         for (int j = 0 ; j < numRoots; ++j) {
288                             View viewj = mViews.get(j);
289                             WindowManager.LayoutParams paramsj = mParams.get(j);
290                             if (params.token == viewj.getWindowToken()
291                                     && paramsj.token == token) {
292                                 isChild = true;
293                                 break;
294                             }
295                         }
296                     }
297                     if (!isChild) {
298                         continue;
299                     }
300                 }
301                 views.add(mRoots.get(i));
302             }
303         }
304         return views;
305     }
306 
307     /**
308      * @return the list of all views attached to the global window manager
309      */
310     @NonNull
getWindowViews()311     public ArrayList<View> getWindowViews() {
312         synchronized (mLock) {
313             return new ArrayList<>(mViews);
314         }
315     }
316 
getWindowView(IBinder windowToken)317     public View getWindowView(IBinder windowToken) {
318         synchronized (mLock) {
319             final int numViews = mViews.size();
320             for (int i = 0; i < numViews; ++i) {
321                 final View view = mViews.get(i);
322                 if (view.getWindowToken() == windowToken) {
323                     return view;
324                 }
325             }
326         }
327         return null;
328     }
329 
330     @UnsupportedAppUsage
getRootView(String name)331     public View getRootView(String name) {
332         synchronized (mLock) {
333             for (int i = mRoots.size() - 1; i >= 0; --i) {
334                 final ViewRootImpl root = mRoots.get(i);
335                 if (name.equals(getWindowName(root))) return root.getView();
336             }
337             for (int i = mWindowlessRoots.size() - 1; i >= 0; --i) {
338                 final ViewRootImpl root = mWindowlessRoots.get(i);
339                 if (name.equals(getWindowName(root))) return root.getView();
340             }
341         }
342 
343         return null;
344     }
345 
addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow, int userId)346     public void addView(View view, ViewGroup.LayoutParams params,
347             Display display, Window parentWindow, int userId) {
348         if (view == null) {
349             throw new IllegalArgumentException("view must not be null");
350         }
351         if (display == null) {
352             throw new IllegalArgumentException("display must not be null");
353         }
354         if (!(params instanceof WindowManager.LayoutParams)) {
355             throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
356         }
357 
358         final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
359         if (parentWindow != null) {
360             parentWindow.adjustLayoutParamsForSubWindow(wparams);
361         } else {
362             // If there's no parent, then hardware acceleration for this view is
363             // set from the application's hardware acceleration setting.
364             final Context context = view.getContext();
365             if (context != null
366                     && (context.getApplicationInfo().flags
367                     & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
368                 wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
369             }
370         }
371 
372         ViewRootImpl root;
373         View panelParentView = null;
374 
375         synchronized (mLock) {
376             // Start watching for system property changes.
377             if (mSystemPropertyUpdater == null) {
378                 mSystemPropertyUpdater = new Runnable() {
379                     @Override public void run() {
380                         synchronized (mLock) {
381                             for (int i = mRoots.size() - 1; i >= 0; --i) {
382                                 mRoots.get(i).loadSystemProperties();
383                             }
384                         }
385                     }
386                 };
387                 SystemProperties.addChangeCallback(mSystemPropertyUpdater);
388             }
389 
390             int index = findViewLocked(view, false);
391             if (index >= 0) {
392                 if (mDyingViews.contains(view)) {
393                     // Don't wait for MSG_DIE to make it's way through root's queue.
394                     mRoots.get(index).doDie();
395                 } else {
396                     throw new IllegalStateException("View " + view
397                             + " has already been added to the window manager.");
398                 }
399                 // The previous removeView() had not completed executing. Now it has.
400             }
401 
402             // If this is a panel window, then find the window it is being
403             // attached to for future reference.
404             if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
405                     wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
406                 final int count = mViews.size();
407                 for (int i = 0; i < count; i++) {
408                     if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
409                         panelParentView = mViews.get(i);
410                     }
411                 }
412             }
413 
414             IWindowSession windowlessSession = null;
415             // If there is a parent set, but we can't find it, it may be coming
416             // from a SurfaceControlViewHost hierarchy.
417             if (wparams.token != null && panelParentView == null) {
418                 for (int i = 0; i < mWindowlessRoots.size(); i++) {
419                     ViewRootImpl maybeParent = mWindowlessRoots.get(i);
420                     if (maybeParent.getWindowToken() == wparams.token) {
421                         windowlessSession = maybeParent.getWindowSession();
422                         break;
423                     }
424                 }
425             }
426 
427             if (windowlessSession == null) {
428                 root = new ViewRootImpl(view.getContext(), display);
429             } else {
430                 root = new ViewRootImpl(view.getContext(), display,
431                         windowlessSession, new WindowlessWindowLayout());
432             }
433 
434             view.setLayoutParams(wparams);
435 
436             mViews.add(view);
437             mRoots.add(root);
438             mParams.add(wparams);
439 
440             // do this last because it fires off messages to start doing things
441             try {
442                 root.setView(view, wparams, panelParentView, userId);
443             } catch (RuntimeException e) {
444                 final int viewIndex = (index >= 0) ? index : (mViews.size() - 1);
445                 // BadTokenException or InvalidDisplayException, clean up.
446                 if (viewIndex >= 0) {
447                     removeViewLocked(viewIndex, true);
448                 }
449                 throw e;
450             }
451         }
452     }
453 
updateViewLayout(View view, ViewGroup.LayoutParams params)454     public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
455         if (view == null) {
456             throw new IllegalArgumentException("view must not be null");
457         }
458         if (!(params instanceof WindowManager.LayoutParams)) {
459             throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
460         }
461 
462         final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
463 
464         view.setLayoutParams(wparams);
465 
466         synchronized (mLock) {
467             int index = findViewLocked(view, true);
468             ViewRootImpl root = mRoots.get(index);
469             mParams.remove(index);
470             mParams.add(index, wparams);
471             root.setLayoutParams(wparams, false);
472         }
473     }
474 
475     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
removeView(View view, boolean immediate)476     public void removeView(View view, boolean immediate) {
477         if (view == null) {
478             throw new IllegalArgumentException("view must not be null");
479         }
480 
481         synchronized (mLock) {
482             int index = findViewLocked(view, true);
483             View curView = mRoots.get(index).getView();
484             removeViewLocked(index, immediate);
485             if (curView == view) {
486                 return;
487             }
488 
489             throw new IllegalStateException("Calling with view " + view
490                     + " but the ViewAncestor is attached to " + curView);
491         }
492     }
493 
494     /**
495      * Remove all roots with specified token.
496      *
497      * @param token app or window token.
498      * @param who name of caller, used in logs.
499      * @param what type of caller, used in logs.
500      */
closeAll(IBinder token, String who, String what)501     public void closeAll(IBinder token, String who, String what) {
502         closeAllExceptView(token, null /* view */, who, what);
503     }
504 
505     /**
506      * Remove all roots with specified token, except maybe one view.
507      *
508      * @param token app or window token.
509      * @param view view that should be should be preserved along with it's root.
510      *             Pass null if everything should be removed.
511      * @param who name of caller, used in logs.
512      * @param what type of caller, used in logs.
513      */
closeAllExceptView(IBinder token, View view, String who, String what)514     public void closeAllExceptView(IBinder token, View view, String who, String what) {
515         synchronized (mLock) {
516             int count = mViews.size();
517             for (int i = 0; i < count; i++) {
518                 if ((view == null || mViews.get(i) != view)
519                         && (token == null || mParams.get(i).token == token)) {
520                     ViewRootImpl root = mRoots.get(i);
521 
522                     if (who != null) {
523                         WindowLeaked leak = new WindowLeaked(
524                                 what + " " + who + " has leaked window "
525                                         + root.getView() + " that was originally added here");
526                         leak.setStackTrace(root.getLocation().getStackTrace());
527                         Log.e(TAG, "", leak);
528                     }
529 
530                     removeViewLocked(i, false);
531                 }
532             }
533         }
534     }
535 
removeViewLocked(int index, boolean immediate)536     private void removeViewLocked(int index, boolean immediate) {
537         ViewRootImpl root = mRoots.get(index);
538         View view = root.getView();
539 
540         if (root != null) {
541             root.getImeFocusController().onWindowDismissed();
542         }
543         boolean deferred = root.die(immediate);
544         if (view != null) {
545             view.assignParent(null);
546             if (deferred) {
547                 mDyingViews.add(view);
548             }
549         }
550     }
551 
doRemoveView(ViewRootImpl root)552     void doRemoveView(ViewRootImpl root) {
553         boolean allViewsRemoved;
554         synchronized (mLock) {
555             final int index = mRoots.indexOf(root);
556             if (index >= 0) {
557                 mRoots.remove(index);
558                 mParams.remove(index);
559                 final View view = mViews.remove(index);
560                 mDyingViews.remove(view);
561             }
562             allViewsRemoved = mRoots.isEmpty();
563         }
564 
565         // If we don't have any views anymore in our process, we no longer need the
566         // InsetsAnimationThread to save some resources.
567         if (allViewsRemoved) {
568             InsetsAnimationThread.release();
569         }
570     }
571 
findViewLocked(View view, boolean required)572     private int findViewLocked(View view, boolean required) {
573         final int index = mViews.indexOf(view);
574         if (required && index < 0) {
575             throw new IllegalArgumentException("View=" + view + " not attached to window manager");
576         }
577         return index;
578     }
579 
580     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
trimMemory(int level)581     public void trimMemory(int level) {
582         ThreadedRenderer.trimMemory(level);
583     }
584 
585     /** @hide */
trimCaches(@ardwareRenderer.CacheTrimLevel int level)586     public void trimCaches(@HardwareRenderer.CacheTrimLevel int level) {
587         ThreadedRenderer.trimCaches(level);
588     }
589 
dumpGfxInfo(FileDescriptor fd, String[] args)590     public void dumpGfxInfo(FileDescriptor fd, String[] args) {
591         FileOutputStream fout = new FileOutputStream(fd);
592         PrintWriter pw = new FastPrintWriter(fout);
593         try {
594             synchronized (mLock) {
595                 final int count = mViews.size();
596 
597                 pw.println("Profile data in ms:");
598 
599                 for (int i = 0; i < count; i++) {
600                     ViewRootImpl root = mRoots.get(i);
601                     String name = getWindowName(root);
602                     pw.printf("\n\t%s (visibility=%d)", name, root.getHostVisibility());
603 
604                     ThreadedRenderer renderer =
605                             root.getView().mAttachInfo.mThreadedRenderer;
606                     if (renderer != null) {
607                         renderer.dumpGfxInfo(pw, fd, args);
608                     }
609                 }
610 
611                 pw.println("\nView hierarchy:\n");
612 
613                 ViewRootImpl.GfxInfo totals = new ViewRootImpl.GfxInfo();
614 
615                 for (int i = 0; i < count; i++) {
616                     ViewRootImpl root = mRoots.get(i);
617                     ViewRootImpl.GfxInfo info = root.getGfxInfo();
618                     totals.add(info);
619 
620                     String name = getWindowName(root);
621                     pw.printf("  %s\n  %d views, %.2f kB of render nodes",
622                             name, info.viewCount, info.renderNodeMemoryUsage / 1024.f);
623                     pw.printf("\n\n");
624                 }
625 
626                 pw.printf("\nTotal %-15s: %d\n", "ViewRootImpl", count);
627                 pw.printf("Total %-15s: %d\n", "attached Views", totals.viewCount);
628                 pw.printf("Total %-15s: %.2f kB (used) / %.2f kB (capacity)\n\n", "RenderNode",
629                         totals.renderNodeMemoryUsage / 1024.0f,
630                         totals.renderNodeMemoryAllocated / 1024.0f);
631             }
632         } finally {
633             pw.flush();
634         }
635     }
636 
getWindowName(ViewRootImpl root)637     private static String getWindowName(ViewRootImpl root) {
638         return root.mWindowAttributes.getTitle() + "/" +
639                 root.getClass().getName() + '@' + Integer.toHexString(root.hashCode());
640     }
641 
setStoppedState(IBinder token, boolean stopped)642     public void setStoppedState(IBinder token, boolean stopped) {
643         ArrayList<ViewRootImpl> nonCurrentThreadRoots = null;
644         synchronized (mLock) {
645             int count = mViews.size();
646             for (int i = count - 1; i >= 0; i--) {
647                 if (token == null || mParams.get(i).token == token) {
648                     ViewRootImpl root = mRoots.get(i);
649                     // Client might remove the view by "stopped" event.
650                     if (root.mThread == Thread.currentThread()) {
651                         root.setWindowStopped(stopped);
652                     } else {
653                         if (nonCurrentThreadRoots == null) {
654                             nonCurrentThreadRoots = new ArrayList<>();
655                         }
656                         nonCurrentThreadRoots.add(root);
657                     }
658                     // Recursively forward stopped state to View's attached
659                     // to this Window rather than the root application token,
660                     // e.g. PopupWindow's.
661                     setStoppedState(root.mAttachInfo.mWindowToken, stopped);
662                 }
663             }
664         }
665 
666         // Update the stopped state synchronously to ensure the surface won't be used after server
667         // side has destroyed it. This operation should be outside the lock to avoid any potential
668         // paths from setWindowStopped to WindowManagerGlobal which may cause deadlocks.
669         if (nonCurrentThreadRoots != null) {
670             for (int i = nonCurrentThreadRoots.size() - 1; i >= 0; i--) {
671                 ViewRootImpl root = nonCurrentThreadRoots.get(i);
672                 root.mHandler.runWithScissors(() -> root.setWindowStopped(stopped), 0);
673             }
674         }
675     }
676 
reportNewConfiguration(Configuration config)677     public void reportNewConfiguration(Configuration config) {
678         synchronized (mLock) {
679             int count = mViews.size();
680             config = new Configuration(config);
681             for (int i=0; i < count; i++) {
682                 ViewRootImpl root = mRoots.get(i);
683                 root.requestUpdateConfiguration(config);
684             }
685         }
686     }
687 
688     /** @hide */
changeCanvasOpacity(IBinder token, boolean opaque)689     public void changeCanvasOpacity(IBinder token, boolean opaque) {
690         if (token == null) {
691             return;
692         }
693         synchronized (mLock) {
694             for (int i = mParams.size() - 1; i >= 0; --i) {
695                 if (mParams.get(i).token == token) {
696                     mRoots.get(i).changeCanvasOpacity(opaque);
697                     return;
698                 }
699             }
700         }
701     }
702 
703     /** @hide */
704     @Nullable
mirrorWallpaperSurface(int displayId)705     public SurfaceControl mirrorWallpaperSurface(int displayId) {
706         try {
707             return getWindowManagerService().mirrorWallpaperSurface(displayId);
708         } catch (RemoteException e) {
709             throw e.rethrowFromSystemServer();
710         }
711     }
712 
713     /** Registers the listener to the context token and returns the current proposed rotation. */
registerProposedRotationListener(IBinder contextToken, Executor executor, IntConsumer listener)714     public void registerProposedRotationListener(IBinder contextToken, Executor executor,
715             IntConsumer listener) {
716         ProposedRotationListenerDelegate delegate;
717         synchronized (mLock) {
718             if (mProposedRotationListenerMap == null) {
719                 mProposedRotationListenerMap = new WeakHashMap<>(1);
720             }
721             delegate = mProposedRotationListenerMap.get(contextToken);
722             final ProposedRotationListenerDelegate existingDelegate = delegate;
723             if (delegate == null) {
724                 mProposedRotationListenerMap.put(contextToken,
725                         delegate = new ProposedRotationListenerDelegate());
726             }
727             if (!delegate.add(executor, listener)) {
728                 // Duplicated listener.
729                 return;
730             }
731             if (existingDelegate != null) {
732                 executor.execute(() -> listener.accept(existingDelegate.mLastRotation));
733                 return;
734             }
735         }
736         try {
737             final int currentRotation = getWindowManagerService().registerProposedRotationListener(
738                     contextToken, delegate);
739             delegate.onRotationChanged(currentRotation);
740         } catch (RemoteException e) {
741             throw e.rethrowFromSystemServer();
742         }
743     }
744 
745     /** Unregisters the proposed rotation listener of the given token. */
unregisterProposedRotationListener(IBinder contextToken, IntConsumer listener)746     public void unregisterProposedRotationListener(IBinder contextToken, IntConsumer listener) {
747         final ProposedRotationListenerDelegate delegate;
748         synchronized (mLock) {
749             if (mProposedRotationListenerMap == null) {
750                 return;
751             }
752             delegate = mProposedRotationListenerMap.get(contextToken);
753             if (delegate == null) {
754                 return;
755             }
756             if (delegate.remove(listener)) {
757                 // The delegate becomes empty.
758                 mProposedRotationListenerMap.remove(contextToken);
759             } else {
760                 // The delegate still contains other listeners.
761                 return;
762             }
763         }
764         try {
765             getWindowManagerService().removeRotationWatcher(delegate);
766         } catch (RemoteException e) {
767             e.rethrowFromSystemServer();
768         }
769     }
770 
771     private static class ProposedRotationListenerDelegate extends IRotationWatcher.Stub {
772         static class ListenerWrapper {
773             final Executor mExecutor;
774             final WeakReference<IntConsumer> mListener;
775 
ListenerWrapper(Executor executor, IntConsumer listener)776             ListenerWrapper(Executor executor, IntConsumer listener) {
777                 mExecutor = executor;
778                 mListener = new WeakReference<>(listener);
779             }
780         }
781 
782         /** The registered listeners. */
783         private final ArrayList<ListenerWrapper> mListeners = new ArrayList<>(1);
784         /** A thread-safe copy of registered listeners for dispatching events. */
785         private volatile ListenerWrapper[] mListenerArray;
786         int mLastRotation;
787 
add(Executor executor, IntConsumer listener)788         boolean add(Executor executor, IntConsumer listener) {
789             for (int i = mListeners.size() - 1; i >= 0; i--) {
790                 if (mListeners.get(i).mListener.get() == listener) {
791                     // Ignore adding duplicated listener.
792                     return false;
793                 }
794             }
795             mListeners.add(new ListenerWrapper(executor, listener));
796             mListenerArray = mListeners.toArray(new ListenerWrapper[0]);
797             return true;
798         }
799 
remove(IntConsumer listener)800         boolean remove(IntConsumer listener) {
801             for (int i = mListeners.size() - 1; i >= 0; i--) {
802                 if (mListeners.get(i).mListener.get() == listener) {
803                     mListeners.remove(i);
804                     mListenerArray = mListeners.toArray(new ListenerWrapper[0]);
805                     return mListeners.isEmpty();
806                 }
807             }
808             return false;
809         }
810 
811         @Override
onRotationChanged(int rotation)812         public void onRotationChanged(int rotation) {
813             mLastRotation = rotation;
814             boolean alive = false;
815             for (ListenerWrapper listenerWrapper : mListenerArray) {
816                 final IntConsumer listener = listenerWrapper.mListener.get();
817                 if (listener != null) {
818                     listenerWrapper.mExecutor.execute(() -> listener.accept(rotation));
819                     alive = true;
820                 }
821             }
822             if (!alive) {
823                 // Unregister if there is no strong reference.
824                 try {
825                     getWindowManagerService().removeRotationWatcher(this);
826                 } catch (RemoteException e) {
827                     e.rethrowFromSystemServer();
828                 }
829             }
830         }
831     }
832 
registerTrustedPresentationListener(@onNull IBinder window, @NonNull TrustedPresentationThresholds thresholds, Executor executor, @NonNull Consumer<Boolean> listener)833     public void registerTrustedPresentationListener(@NonNull IBinder window,
834             @NonNull TrustedPresentationThresholds thresholds, Executor executor,
835             @NonNull Consumer<Boolean> listener) {
836         mTrustedPresentationListener.addListener(window, thresholds, listener, executor);
837     }
838 
unregisterTrustedPresentationListener(@onNull Consumer<Boolean> listener)839     public void unregisterTrustedPresentationListener(@NonNull Consumer<Boolean> listener) {
840         mTrustedPresentationListener.removeListener(listener);
841     }
842 
createInputChannel(@onNull IBinder clientToken, @NonNull InputTransferToken hostToken, @NonNull SurfaceControl surfaceControl, @Nullable InputTransferToken inputTransferToken)843     private static InputChannel createInputChannel(@NonNull IBinder clientToken,
844             @NonNull InputTransferToken hostToken, @NonNull SurfaceControl surfaceControl,
845             @Nullable InputTransferToken inputTransferToken) {
846         InputChannel inputChannel = new InputChannel();
847         try {
848             // TODO (b/329860681): Use INVALID_DISPLAY for now because the displayId will be
849             // selected in  SurfaceFlinger. This should be cleaned up so grantInputChannel doesn't
850             // take in a displayId at all
851             WindowManagerGlobal.getWindowSession().grantInputChannel(INVALID_DISPLAY,
852                     surfaceControl, clientToken, hostToken, 0, 0, TYPE_APPLICATION, 0, null,
853                     inputTransferToken, surfaceControl.getName(), inputChannel);
854         } catch (RemoteException e) {
855             Log.e(TAG, "Failed to create input channel", e);
856             e.rethrowAsRuntimeException();
857         }
858         return inputChannel;
859     }
860 
removeInputChannel(IBinder clientToken)861     private static void removeInputChannel(IBinder clientToken) {
862         try {
863             WindowManagerGlobal.getWindowSession().remove(clientToken);
864         } catch (RemoteException e) {
865             Log.e(TAG, "Failed to remove input channel", e);
866             e.rethrowAsRuntimeException();
867         }
868     }
869 
registerBatchedSurfaceControlInputReceiver( @onNull InputTransferToken hostToken, @NonNull SurfaceControl surfaceControl, @NonNull Choreographer choreographer, @NonNull SurfaceControlInputReceiver receiver)870     InputTransferToken registerBatchedSurfaceControlInputReceiver(
871             @NonNull InputTransferToken hostToken, @NonNull SurfaceControl surfaceControl,
872             @NonNull Choreographer choreographer, @NonNull SurfaceControlInputReceiver receiver) {
873         IBinder clientToken = new Binder();
874         InputTransferToken inputTransferToken = new InputTransferToken();
875         InputChannel inputChannel = createInputChannel(clientToken, hostToken,
876                 surfaceControl, inputTransferToken);
877 
878         synchronized (mSurfaceControlInputReceivers) {
879             mSurfaceControlInputReceivers.put(surfaceControl.getLayerId(),
880                     new SurfaceControlInputReceiverInfo(clientToken,
881                             new BatchedInputEventReceiver(inputChannel, choreographer.getLooper(),
882                                     choreographer) {
883                                 @Override
884                                 public void onInputEvent(InputEvent event) {
885                                     boolean handled = receiver.onInputEvent(event);
886                                     finishInputEvent(event, handled);
887                                 }
888                             }));
889         }
890         return inputTransferToken;
891     }
892 
registerUnbatchedSurfaceControlInputReceiver( @onNull InputTransferToken hostToken, @NonNull SurfaceControl surfaceControl, @NonNull Looper looper, @NonNull SurfaceControlInputReceiver receiver)893     InputTransferToken registerUnbatchedSurfaceControlInputReceiver(
894             @NonNull InputTransferToken hostToken, @NonNull SurfaceControl surfaceControl,
895             @NonNull Looper looper, @NonNull SurfaceControlInputReceiver receiver) {
896         IBinder clientToken = new Binder();
897         InputTransferToken inputTransferToken = new InputTransferToken();
898         InputChannel inputChannel = createInputChannel(clientToken, hostToken,
899                 surfaceControl, inputTransferToken);
900 
901         synchronized (mSurfaceControlInputReceivers) {
902             mSurfaceControlInputReceivers.put(surfaceControl.getLayerId(),
903                     new SurfaceControlInputReceiverInfo(clientToken,
904                             new InputEventReceiver(inputChannel, looper) {
905                                 @Override
906                                 public void onInputEvent(InputEvent event) {
907                                     boolean handled = receiver.onInputEvent(event);
908                                     finishInputEvent(event, handled);
909                                 }
910                             }));
911         }
912         return inputTransferToken;
913     }
914 
unregisterSurfaceControlInputReceiver(@onNull SurfaceControl surfaceControl)915     void unregisterSurfaceControlInputReceiver(@NonNull SurfaceControl surfaceControl) {
916         SurfaceControlInputReceiverInfo surfaceControlInputReceiverInfo;
917         synchronized (mSurfaceControlInputReceivers) {
918             surfaceControlInputReceiverInfo = mSurfaceControlInputReceivers.removeReturnOld(
919                     surfaceControl.getLayerId());
920         }
921 
922         if (surfaceControlInputReceiverInfo == null) {
923             Log.w(TAG, "No registered input event receiver with sc: " + surfaceControl);
924             return;
925         }
926         removeInputChannel(surfaceControlInputReceiverInfo.mClientToken);
927 
928         surfaceControlInputReceiverInfo.mInputEventReceiver.dispose();
929     }
930 
getSurfaceControlInputClientToken(@onNull SurfaceControl surfaceControl)931     IBinder getSurfaceControlInputClientToken(@NonNull SurfaceControl surfaceControl) {
932         SurfaceControlInputReceiverInfo surfaceControlInputReceiverInfo;
933         synchronized (mSurfaceControlInputReceivers) {
934             surfaceControlInputReceiverInfo = mSurfaceControlInputReceivers.get(
935                     surfaceControl.getLayerId());
936         }
937 
938         if (surfaceControlInputReceiverInfo == null) {
939             Log.w(TAG, "No registered input event receiver with sc: " + surfaceControl);
940             return null;
941         }
942         return surfaceControlInputReceiverInfo.mClientToken;
943     }
944 
transferTouchGesture(@onNull InputTransferToken transferFromToken, @NonNull InputTransferToken transferToToken)945     boolean transferTouchGesture(@NonNull InputTransferToken transferFromToken,
946             @NonNull InputTransferToken transferToToken) {
947         try {
948             return getWindowManagerService().transferTouchGesture(transferFromToken,
949                     transferToToken);
950         } catch (RemoteException e) {
951             e.rethrowAsRuntimeException();
952         }
953         return false;
954     }
955 
956     private final class TrustedPresentationListener extends
957             ITrustedPresentationListener.Stub {
958         private static int sId = 0;
959         private final ArrayMap<Consumer<Boolean>, Pair<Integer, Executor>> mListeners =
960                 new ArrayMap<>();
961 
962         private final Object mTplLock = new Object();
963 
addListener(IBinder window, TrustedPresentationThresholds thresholds, Consumer<Boolean> listener, Executor executor)964         private void addListener(IBinder window, TrustedPresentationThresholds thresholds,
965                 Consumer<Boolean> listener, Executor executor) {
966             synchronized (mTplLock) {
967                 if (mListeners.containsKey(listener)) {
968                     Log.i(TAG, "Updating listener " + listener + " thresholds to " + thresholds);
969                     removeListener(listener);
970                 }
971                 int id = sId++;
972                 mListeners.put(listener, new Pair<>(id, executor));
973                 try {
974                     WindowManagerGlobal.getWindowManagerService()
975                             .registerTrustedPresentationListener(window, this, thresholds, id);
976                 } catch (RemoteException e) {
977                     e.rethrowFromSystemServer();
978                 }
979             }
980         }
981 
removeListener(Consumer<Boolean> listener)982         private void removeListener(Consumer<Boolean> listener) {
983             synchronized (mTplLock) {
984                 var removedListener = mListeners.remove(listener);
985                 if (removedListener == null) {
986                     Log.i(TAG, "listener " + listener + " does not exist.");
987                     return;
988                 }
989 
990                 try {
991                     WindowManagerGlobal.getWindowManagerService()
992                             .unregisterTrustedPresentationListener(this, removedListener.first);
993                 } catch (RemoteException e) {
994                     e.rethrowFromSystemServer();
995                 }
996             }
997         }
998 
999         @Override
onTrustedPresentationChanged(int[] inTrustedStateListenerIds, int[] outOfTrustedStateListenerIds)1000         public void onTrustedPresentationChanged(int[] inTrustedStateListenerIds,
1001                 int[] outOfTrustedStateListenerIds) {
1002             ArrayList<Runnable> firedListeners = new ArrayList<>();
1003             synchronized (mTplLock) {
1004                 mListeners.forEach((listener, idExecutorPair) -> {
1005                     final var listenerId =  idExecutorPair.first;
1006                     final var executor = idExecutorPair.second;
1007                     for (int id : inTrustedStateListenerIds) {
1008                         if (listenerId == id) {
1009                             firedListeners.add(() -> executor.execute(
1010                                     () -> listener.accept(/*presentationState*/true)));
1011                         }
1012                     }
1013                     for (int id : outOfTrustedStateListenerIds) {
1014                         if (listenerId == id) {
1015                             firedListeners.add(() -> executor.execute(
1016                                     () -> listener.accept(/*presentationState*/false)));
1017                         }
1018                     }
1019                 });
1020             }
1021             for (int i = 0; i < firedListeners.size(); i++) {
1022                 firedListeners.get(i).run();
1023             }
1024         }
1025     }
1026 
1027     /** @hide */
addWindowlessRoot(ViewRootImpl impl)1028     public void addWindowlessRoot(ViewRootImpl impl) {
1029         synchronized (mLock) {
1030             mWindowlessRoots.add(impl);
1031         }
1032     }
1033 
1034     /** @hide */
removeWindowlessRoot(ViewRootImpl impl)1035     public void removeWindowlessRoot(ViewRootImpl impl) {
1036         synchronized (mLock) {
1037             mWindowlessRoots.remove(impl);
1038         }
1039     }
1040 
setRecentsAppBehindSystemBars(boolean behindSystemBars)1041     public void setRecentsAppBehindSystemBars(boolean behindSystemBars) {
1042         try {
1043             getWindowManagerService().setRecentsAppBehindSystemBars(behindSystemBars);
1044         } catch (RemoteException e) {
1045             throw e.rethrowFromSystemServer();
1046         }
1047     }
1048 
1049     private static class SurfaceControlInputReceiverInfo {
1050         final IBinder mClientToken;
1051         final InputEventReceiver mInputEventReceiver;
1052 
SurfaceControlInputReceiverInfo(IBinder clientToken, InputEventReceiver inputEventReceiver)1053         private SurfaceControlInputReceiverInfo(IBinder clientToken,
1054                 InputEventReceiver inputEventReceiver) {
1055             mClientToken = clientToken;
1056             mInputEventReceiver = inputEventReceiver;
1057         }
1058     }
1059 }
1060 
1061 final class WindowLeaked extends AndroidRuntimeException {
1062     @UnsupportedAppUsage
WindowLeaked(String msg)1063     public WindowLeaked(String msg) {
1064         super(msg);
1065     }
1066 }
1067