1 /*
2  * Copyright (C) 2011 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 com.android.server.wm;
18 
19 import static android.Manifest.permission.DEVICE_POWER;
20 import static android.Manifest.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
21 import static android.Manifest.permission.HIDE_OVERLAY_WINDOWS;
22 import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
23 import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
24 import static android.Manifest.permission.SYSTEM_APPLICATION_OVERLAY;
25 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
26 import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY;
27 import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
28 import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
29 import static android.content.Intent.EXTRA_PACKAGE_NAME;
30 import static android.content.Intent.EXTRA_SHORTCUT_ID;
31 import static android.content.Intent.EXTRA_TASK_ID;
32 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
33 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
34 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
35 import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType;
36 
37 import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
38 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
39 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
40 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
41 
42 import android.annotation.Nullable;
43 import android.app.PendingIntent;
44 import android.content.ClipData;
45 import android.content.ClipDescription;
46 import android.content.Intent;
47 import android.content.pm.ActivityInfo;
48 import android.content.pm.ShortcutServiceInternal;
49 import android.graphics.Point;
50 import android.graphics.Rect;
51 import android.graphics.Region;
52 import android.os.Binder;
53 import android.os.Bundle;
54 import android.os.IBinder;
55 import android.os.Parcel;
56 import android.os.Process;
57 import android.os.RemoteCallback;
58 import android.os.RemoteException;
59 import android.os.Trace;
60 import android.os.UserHandle;
61 import android.text.TextUtils;
62 import android.util.ArraySet;
63 import android.util.MergedConfiguration;
64 import android.util.Slog;
65 import android.view.IWindow;
66 import android.view.IWindowId;
67 import android.view.IWindowSession;
68 import android.view.IWindowSessionCallback;
69 import android.view.InputChannel;
70 import android.view.InsetsSourceControl;
71 import android.view.InsetsState;
72 import android.view.InsetsVisibilities;
73 import android.view.SurfaceControl;
74 import android.view.SurfaceSession;
75 import android.view.WindowManager;
76 import android.window.ClientWindowFrames;
77 
78 import com.android.internal.annotations.VisibleForTesting;
79 import com.android.internal.os.logging.MetricsLoggerWrapper;
80 import com.android.internal.protolog.common.ProtoLog;
81 import com.android.server.LocalServices;
82 import com.android.server.wm.WindowManagerService.H;
83 
84 import java.io.PrintWriter;
85 import java.util.List;
86 import java.util.function.BiConsumer;
87 
88 /**
89  * This class represents an active client session.  There is generally one
90  * Session object per process that is interacting with the window manager.
91  */
92 class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
93     final WindowManagerService mService;
94     final IWindowSessionCallback mCallback;
95     final int mUid;
96     final int mPid;
97     private final String mStringName;
98     SurfaceSession mSurfaceSession;
99     private int mNumWindow = 0;
100     // Set of visible application overlay window surfaces connected to this session.
101     private final ArraySet<WindowSurfaceController> mAppOverlaySurfaces = new ArraySet<>();
102     // Set of visible alert window surfaces connected to this session.
103     private final ArraySet<WindowSurfaceController> mAlertWindowSurfaces = new ArraySet<>();
104     private final DragDropController mDragDropController;
105     final boolean mCanAddInternalSystemWindow;
106     private final boolean mCanStartTasksFromRecents;
107 
108     final boolean mCanCreateSystemApplicationOverlay;
109     final boolean mCanHideNonSystemOverlayWindows;
110     final boolean mCanAcquireSleepToken;
111     private AlertWindowNotification mAlertWindowNotification;
112     private boolean mShowingAlertWindowNotificationAllowed;
113     private boolean mClientDead = false;
114     private float mLastReportedAnimatorScale;
115     private String mPackageName;
116     private String mRelayoutTag;
117     private final InsetsVisibilities mDummyRequestedVisibilities = new InsetsVisibilities();
118     private final InsetsSourceControl[] mDummyControls =  new InsetsSourceControl[0];
119 
Session(WindowManagerService service, IWindowSessionCallback callback)120     public Session(WindowManagerService service, IWindowSessionCallback callback) {
121         mService = service;
122         mCallback = callback;
123         mUid = Binder.getCallingUid();
124         mPid = Binder.getCallingPid();
125         mLastReportedAnimatorScale = service.getCurrentAnimatorScale();
126         mCanAddInternalSystemWindow = service.mContext.checkCallingOrSelfPermission(
127                 INTERNAL_SYSTEM_WINDOW) == PERMISSION_GRANTED;
128         mCanHideNonSystemOverlayWindows = service.mContext.checkCallingOrSelfPermission(
129                 HIDE_NON_SYSTEM_OVERLAY_WINDOWS) == PERMISSION_GRANTED
130                 || service.mContext.checkCallingOrSelfPermission(HIDE_OVERLAY_WINDOWS)
131                 == PERMISSION_GRANTED;
132         mCanCreateSystemApplicationOverlay =
133                 service.mContext.checkCallingOrSelfPermission(SYSTEM_APPLICATION_OVERLAY)
134                         == PERMISSION_GRANTED;
135         mCanStartTasksFromRecents = service.mContext.checkCallingOrSelfPermission(
136                 START_TASKS_FROM_RECENTS) == PERMISSION_GRANTED;
137         mCanAcquireSleepToken = service.mContext.checkCallingOrSelfPermission(DEVICE_POWER)
138                 == PERMISSION_GRANTED;
139         mShowingAlertWindowNotificationAllowed = mService.mShowAlertWindowNotifications;
140         mDragDropController = mService.mDragDropController;
141         StringBuilder sb = new StringBuilder();
142         sb.append("Session{");
143         sb.append(Integer.toHexString(System.identityHashCode(this)));
144         sb.append(" ");
145         sb.append(mPid);
146         if (mUid < Process.FIRST_APPLICATION_UID) {
147             sb.append(":");
148             sb.append(mUid);
149         } else {
150             sb.append(":u");
151             sb.append(UserHandle.getUserId(mUid));
152             sb.append('a');
153             sb.append(UserHandle.getAppId(mUid));
154         }
155         sb.append("}");
156         mStringName = sb.toString();
157 
158         try {
159             mCallback.asBinder().linkToDeath(this, 0);
160         } catch (RemoteException e) {
161             // The caller has died, so we can just forget about this.
162             // Hmmm, should we call killSessionLocked()??
163         }
164     }
165 
166     @Override
onTransact(int code, Parcel data, Parcel reply, int flags)167     public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
168             throws RemoteException {
169         try {
170             return super.onTransact(code, data, reply, flags);
171         } catch (RuntimeException e) {
172             // Log all 'real' exceptions thrown to the caller
173             if (!(e instanceof SecurityException)) {
174                 Slog.wtf(TAG_WM, "Window Session Crash", e);
175             }
176             throw e;
177         }
178     }
179 
180     @Override
binderDied()181     public void binderDied() {
182         synchronized (mService.mGlobalLock) {
183             mCallback.asBinder().unlinkToDeath(this, 0);
184             mClientDead = true;
185             killSessionLocked();
186         }
187     }
188 
189     @Override
addToDisplay(IWindow window, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, InsetsVisibilities requestedVisibilities, InputChannel outInputChannel, InsetsState outInsetsState, InsetsSourceControl[] outActiveControls)190     public int addToDisplay(IWindow window, WindowManager.LayoutParams attrs,
191             int viewVisibility, int displayId, InsetsVisibilities requestedVisibilities,
192             InputChannel outInputChannel, InsetsState outInsetsState,
193             InsetsSourceControl[] outActiveControls) {
194         return mService.addWindow(this, window, attrs, viewVisibility, displayId,
195                 UserHandle.getUserId(mUid), requestedVisibilities, outInputChannel, outInsetsState,
196                 outActiveControls);
197     }
198 
199     @Override
addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, int userId, InsetsVisibilities requestedVisibilities, InputChannel outInputChannel, InsetsState outInsetsState, InsetsSourceControl[] outActiveControls)200     public int addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs,
201             int viewVisibility, int displayId, int userId, InsetsVisibilities requestedVisibilities,
202             InputChannel outInputChannel, InsetsState outInsetsState,
203             InsetsSourceControl[] outActiveControls) {
204         return mService.addWindow(this, window, attrs, viewVisibility, displayId, userId,
205                 requestedVisibilities, outInputChannel, outInsetsState, outActiveControls);
206     }
207 
208     @Override
addToDisplayWithoutInputChannel(IWindow window, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, InsetsState outInsetsState)209     public int addToDisplayWithoutInputChannel(IWindow window, WindowManager.LayoutParams attrs,
210             int viewVisibility, int displayId, InsetsState outInsetsState) {
211         return mService.addWindow(this, window, attrs, viewVisibility, displayId,
212                 UserHandle.getUserId(mUid), mDummyRequestedVisibilities, null /* outInputChannel */,
213                 outInsetsState, mDummyControls);
214     }
215 
216     @Override
remove(IWindow window)217     public void remove(IWindow window) {
218         mService.removeWindow(this, window);
219     }
220 
221     @Override
prepareToReplaceWindows(IBinder appToken, boolean childrenOnly)222     public void prepareToReplaceWindows(IBinder appToken, boolean childrenOnly) {
223         mService.setWillReplaceWindows(appToken, childrenOnly);
224     }
225 
226     @Override
relayout(IWindow window, WindowManager.LayoutParams attrs, int requestedWidth, int requestedHeight, int viewFlags, int flags, long frameNumber, ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration, SurfaceControl outSurfaceControl, InsetsState outInsetsState, InsetsSourceControl[] outActiveControls, Point outSurfaceSize)227     public int relayout(IWindow window, WindowManager.LayoutParams attrs,
228             int requestedWidth, int requestedHeight, int viewFlags, int flags, long frameNumber,
229             ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,
230             SurfaceControl outSurfaceControl, InsetsState outInsetsState,
231             InsetsSourceControl[] outActiveControls, Point outSurfaceSize) {
232         if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from "
233                 + Binder.getCallingPid());
234         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag);
235         int res = mService.relayoutWindow(this, window, attrs,
236                 requestedWidth, requestedHeight, viewFlags, flags, frameNumber,
237                 outFrames, mergedConfiguration, outSurfaceControl, outInsetsState,
238                 outActiveControls, outSurfaceSize);
239         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
240         if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to "
241                 + Binder.getCallingPid());
242         return res;
243     }
244 
245     @Override
outOfMemory(IWindow window)246     public boolean outOfMemory(IWindow window) {
247         return mService.outOfMemoryWindow(this, window);
248     }
249 
250     @Override
setInsets(IWindow window, int touchableInsets, Rect contentInsets, Rect visibleInsets, Region touchableArea)251     public void setInsets(IWindow window, int touchableInsets,
252             Rect contentInsets, Rect visibleInsets, Region touchableArea) {
253         mService.setInsetsWindow(this, window, touchableInsets, contentInsets,
254                 visibleInsets, touchableArea);
255     }
256 
257     @Override
finishDrawing(IWindow window, @Nullable SurfaceControl.Transaction postDrawTransaction)258     public void finishDrawing(IWindow window,
259             @Nullable SurfaceControl.Transaction postDrawTransaction) {
260         if (DEBUG) Slog.v(TAG_WM, "IWindow finishDrawing called for " + window);
261         mService.finishDrawingWindow(this, window, postDrawTransaction);
262     }
263 
264     @Override
setInTouchMode(boolean mode)265     public void setInTouchMode(boolean mode) {
266         mService.setInTouchMode(mode);
267     }
268 
269     @Override
getInTouchMode()270     public boolean getInTouchMode() {
271         return mService.getInTouchMode();
272     }
273 
274     @Override
performHapticFeedback(int effectId, boolean always)275     public boolean performHapticFeedback(int effectId, boolean always) {
276         final long ident = Binder.clearCallingIdentity();
277         try {
278             return mService.mPolicy.performHapticFeedback(mUid, mPackageName,
279                         effectId, always, null);
280         } finally {
281             Binder.restoreCallingIdentity(ident);
282         }
283     }
284 
285     /* Drag/drop */
286 
287     @Override
performDrag(IWindow window, int flags, SurfaceControl surface, int touchSource, float touchX, float touchY, float thumbCenterX, float thumbCenterY, ClipData data)288     public IBinder performDrag(IWindow window, int flags, SurfaceControl surface, int touchSource,
289             float touchX, float touchY, float thumbCenterX, float thumbCenterY, ClipData data) {
290         // Validate and resolve ClipDescription data before clearing the calling identity
291         validateAndResolveDragMimeTypeExtras(data, Binder.getCallingUid(), Binder.getCallingPid(),
292                 mPackageName);
293         final long ident = Binder.clearCallingIdentity();
294         try {
295             return mDragDropController.performDrag(mPid, mUid, window, flags, surface, touchSource,
296                     touchX, touchY, thumbCenterX, thumbCenterY, data);
297         } finally {
298             Binder.restoreCallingIdentity(ident);
299         }
300     }
301 
302 
303     @Override
dropForAccessibility(IWindow window, int x, int y)304     public boolean dropForAccessibility(IWindow window, int x, int y) {
305         final long ident = Binder.clearCallingIdentity();
306         try {
307             return mDragDropController.dropForAccessibility(window, x, y);
308         } finally {
309             Binder.restoreCallingIdentity(ident);
310         }
311     }
312 
313     /**
314      * Validates the given drag data.
315      */
316     @VisibleForTesting
validateAndResolveDragMimeTypeExtras(ClipData data, int callingUid, int callingPid, String callingPackage)317     void validateAndResolveDragMimeTypeExtras(ClipData data, int callingUid, int callingPid,
318             String callingPackage) {
319         if (callingUid == Process.SYSTEM_UID) {
320             throw new IllegalStateException("Need to validate before calling identify is cleared");
321         }
322         final ClipDescription desc = data != null ? data.getDescription() : null;
323         if (desc == null) {
324             return;
325         }
326         // Ensure that only one of the app mime types are set
327         final boolean hasActivity = desc.hasMimeType(MIMETYPE_APPLICATION_ACTIVITY);
328         final boolean hasShortcut = desc.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT);
329         final boolean hasTask = desc.hasMimeType(MIMETYPE_APPLICATION_TASK);
330         int appMimeTypeCount = (hasActivity ? 1 : 0)
331                 + (hasShortcut ? 1 : 0)
332                 + (hasTask ? 1 : 0);
333         if (appMimeTypeCount == 0) {
334             return;
335         } else if (appMimeTypeCount > 1) {
336             throw new IllegalArgumentException("Can not specify more than one of activity, "
337                     + "shortcut, or task mime types");
338         }
339         // Ensure that data is provided and that they are intents
340         if (data.getItemCount() == 0) {
341             throw new IllegalArgumentException("Unexpected number of items (none)");
342         }
343         for (int i = 0; i < data.getItemCount(); i++) {
344             if (data.getItemAt(i).getIntent() == null) {
345                 throw new IllegalArgumentException("Unexpected item, expected an intent");
346             }
347         }
348 
349         if (hasActivity) {
350             long origId = Binder.clearCallingIdentity();
351             try {
352                 // Resolve the activity info for each intent
353                 for (int i = 0; i < data.getItemCount(); i++) {
354                     final ClipData.Item item = data.getItemAt(i);
355                     final Intent intent = item.getIntent();
356                     final PendingIntent pi = intent.getParcelableExtra(
357                             ClipDescription.EXTRA_PENDING_INTENT);
358                     final UserHandle user = intent.getParcelableExtra(Intent.EXTRA_USER);
359                     if (pi == null || user == null) {
360                         throw new IllegalArgumentException("Clip data must include the pending "
361                                 + "intent to launch and its associated user to launch for.");
362                     }
363                     final Intent launchIntent = mService.mAmInternal.getIntentForIntentSender(
364                             pi.getIntentSender().getTarget());
365                     final ActivityInfo info = mService.mAtmService.resolveActivityInfoForIntent(
366                             launchIntent, null /* resolvedType */, user.getIdentifier(),
367                             callingUid);
368                     item.setActivityInfo(info);
369                 }
370             } finally {
371                 Binder.restoreCallingIdentity(origId);
372             }
373         } else if (hasShortcut) {
374             // Restrict who can start a shortcut drag since it will start the shortcut as the
375             // target shortcut package
376             if (!mCanStartTasksFromRecents) {
377                 throw new SecurityException("Requires START_TASKS_FROM_RECENTS permission");
378             }
379             for (int i = 0; i < data.getItemCount(); i++) {
380                 final ClipData.Item item = data.getItemAt(i);
381                 final Intent intent = item.getIntent();
382                 final String shortcutId = intent.getStringExtra(EXTRA_SHORTCUT_ID);
383                 final String packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME);
384                 final UserHandle user = intent.getParcelableExtra(Intent.EXTRA_USER);
385                 if (TextUtils.isEmpty(shortcutId)
386                         || TextUtils.isEmpty(packageName)
387                         || user == null) {
388                     throw new IllegalArgumentException("Clip item must include the package name, "
389                             + "shortcut id, and the user to launch for.");
390                 }
391                 final ShortcutServiceInternal shortcutService =
392                         LocalServices.getService(ShortcutServiceInternal.class);
393                 final Intent[] shortcutIntents = shortcutService.createShortcutIntents(
394                         UserHandle.getUserId(callingUid), callingPackage, packageName, shortcutId,
395                         user.getIdentifier(), callingPid, callingUid);
396                 if (shortcutIntents == null || shortcutIntents.length == 0) {
397                     throw new IllegalArgumentException("Invalid shortcut id");
398                 }
399                 final ActivityInfo info = mService.mAtmService.resolveActivityInfoForIntent(
400                         shortcutIntents[0], null /* resolvedType */, user.getIdentifier(),
401                         callingUid);
402                 item.setActivityInfo(info);
403             }
404         } else if (hasTask) {
405             // TODO(b/169894807): Consider opening this up for tasks from the same app as the caller
406             if (!mCanStartTasksFromRecents) {
407                 throw new SecurityException("Requires START_TASKS_FROM_RECENTS permission");
408             }
409             for (int i = 0; i < data.getItemCount(); i++) {
410                 final ClipData.Item item = data.getItemAt(i);
411                 final Intent intent = item.getIntent();
412                 final int taskId = intent.getIntExtra(EXTRA_TASK_ID, INVALID_TASK_ID);
413                 if (taskId == INVALID_TASK_ID) {
414                     throw new IllegalArgumentException("Clip item must include the task id.");
415                 }
416                 final Task task = mService.mRoot.anyTaskForId(taskId);
417                 if (task == null) {
418                     throw new IllegalArgumentException("Invalid task id.");
419                 }
420                 if (task.getRootActivity() != null) {
421                     item.setActivityInfo(task.getRootActivity().info);
422                 } else {
423                     // Resolve the activity info manually if the task was restored after reboot
424                     final ActivityInfo info = mService.mAtmService.resolveActivityInfoForIntent(
425                             task.intent, null /* resolvedType */, task.mUserId, callingUid);
426                     item.setActivityInfo(info);
427                 }
428             }
429         }
430     }
431 
432     @Override
reportDropResult(IWindow window, boolean consumed)433     public void reportDropResult(IWindow window, boolean consumed) {
434         final long ident = Binder.clearCallingIdentity();
435         try {
436             mDragDropController.reportDropResult(window, consumed);
437         } finally {
438             Binder.restoreCallingIdentity(ident);
439         }
440     }
441 
442     @Override
cancelDragAndDrop(IBinder dragToken, boolean skipAnimation)443     public void cancelDragAndDrop(IBinder dragToken, boolean skipAnimation) {
444         final long ident = Binder.clearCallingIdentity();
445         try {
446             mDragDropController.cancelDragAndDrop(dragToken, skipAnimation);
447         } finally {
448             Binder.restoreCallingIdentity(ident);
449         }
450     }
451 
452     @Override
dragRecipientEntered(IWindow window)453     public void dragRecipientEntered(IWindow window) {
454         mDragDropController.dragRecipientEntered(window);
455     }
456 
457     @Override
dragRecipientExited(IWindow window)458     public void dragRecipientExited(IWindow window) {
459         mDragDropController.dragRecipientExited(window);
460     }
461 
462     @Override
startMovingTask(IWindow window, float startX, float startY)463     public boolean startMovingTask(IWindow window, float startX, float startY) {
464         if (DEBUG_TASK_POSITIONING) Slog.d(
465                 TAG_WM, "startMovingTask: {" + startX + "," + startY + "}");
466 
467         final long ident = Binder.clearCallingIdentity();
468         try {
469             return mService.mTaskPositioningController.startMovingTask(window, startX, startY);
470         } finally {
471             Binder.restoreCallingIdentity(ident);
472         }
473     }
474 
475     @Override
finishMovingTask(IWindow window)476     public void finishMovingTask(IWindow window) {
477         if (DEBUG_TASK_POSITIONING) Slog.d(TAG_WM, "finishMovingTask");
478 
479         final long ident = Binder.clearCallingIdentity();
480         try {
481             mService.mTaskPositioningController.finishTaskPositioning(window);
482         } finally {
483             Binder.restoreCallingIdentity(ident);
484         }
485     }
486 
487     @Override
reportSystemGestureExclusionChanged(IWindow window, List<Rect> exclusionRects)488     public void reportSystemGestureExclusionChanged(IWindow window, List<Rect> exclusionRects) {
489         final long ident = Binder.clearCallingIdentity();
490         try {
491             mService.reportSystemGestureExclusionChanged(this, window, exclusionRects);
492         } finally {
493             Binder.restoreCallingIdentity(ident);
494         }
495     }
496 
actionOnWallpaper(IBinder window, BiConsumer<WallpaperController, WindowState> action)497     private void actionOnWallpaper(IBinder window,
498             BiConsumer<WallpaperController, WindowState> action) {
499         final WindowState windowState = mService.windowForClientLocked(this, window, true);
500         action.accept(windowState.getDisplayContent().mWallpaperController, windowState);
501     }
502 
503     @Override
setWallpaperPosition(IBinder window, float x, float y, float xStep, float yStep)504     public void setWallpaperPosition(IBinder window, float x, float y, float xStep, float yStep) {
505         synchronized (mService.mGlobalLock) {
506             final long ident = Binder.clearCallingIdentity();
507             try {
508                 actionOnWallpaper(window, (wpController, windowState) ->
509                         wpController.setWindowWallpaperPosition(windowState, x, y, xStep, yStep));
510             } finally {
511                 Binder.restoreCallingIdentity(ident);
512             }
513         }
514     }
515 
516     @Override
setWallpaperZoomOut(IBinder window, float zoom)517     public void setWallpaperZoomOut(IBinder window, float zoom) {
518         if (Float.compare(0f, zoom) > 0 || Float.compare(1f, zoom) < 0 || Float.isNaN(zoom)) {
519             throw new IllegalArgumentException("Zoom must be a valid float between 0 and 1: "
520                     + zoom);
521         }
522         synchronized (mService.mGlobalLock) {
523             final long ident = Binder.clearCallingIdentity();
524             try {
525                 actionOnWallpaper(window, (wpController, windowState) ->
526                         wpController.setWallpaperZoomOut(windowState, zoom));
527             } finally {
528                 Binder.restoreCallingIdentity(ident);
529             }
530         }
531     }
532 
533     @Override
setShouldZoomOutWallpaper(IBinder window, boolean shouldZoom)534     public void setShouldZoomOutWallpaper(IBinder window, boolean shouldZoom) {
535         synchronized (mService.mGlobalLock) {
536             actionOnWallpaper(window, (wpController, windowState) ->
537                     wpController.setShouldZoomOutWallpaper(windowState, shouldZoom));
538         }
539     }
540 
541     @Override
wallpaperOffsetsComplete(IBinder window)542     public void wallpaperOffsetsComplete(IBinder window) {
543         synchronized (mService.mGlobalLock) {
544             actionOnWallpaper(window, (wpController, windowState) ->
545                     wpController.wallpaperOffsetsComplete(window));
546         }
547     }
548 
549     @Override
setWallpaperDisplayOffset(IBinder window, int x, int y)550     public void setWallpaperDisplayOffset(IBinder window, int x, int y) {
551         synchronized (mService.mGlobalLock) {
552             final long ident = Binder.clearCallingIdentity();
553             try {
554                 actionOnWallpaper(window, (wpController, windowState) ->
555                         wpController.setWindowWallpaperDisplayOffset(windowState, x, y));
556             } finally {
557                 Binder.restoreCallingIdentity(ident);
558             }
559         }
560     }
561 
562     @Override
sendWallpaperCommand(IBinder window, String action, int x, int y, int z, Bundle extras, boolean sync)563     public Bundle sendWallpaperCommand(IBinder window, String action, int x, int y,
564             int z, Bundle extras, boolean sync) {
565         synchronized (mService.mGlobalLock) {
566             final long ident = Binder.clearCallingIdentity();
567             try {
568                 final WindowState windowState = mService.windowForClientLocked(this, window, true);
569                 return windowState.getDisplayContent().mWallpaperController
570                         .sendWindowWallpaperCommand(windowState, action, x, y, z, extras, sync);
571             } finally {
572                 Binder.restoreCallingIdentity(ident);
573             }
574         }
575     }
576 
577     @Override
wallpaperCommandComplete(IBinder window, Bundle result)578     public void wallpaperCommandComplete(IBinder window, Bundle result) {
579         synchronized (mService.mGlobalLock) {
580             actionOnWallpaper(window, (wpController, windowState) ->
581                     wpController.wallpaperCommandComplete(window));
582         }
583     }
584 
585     @Override
onRectangleOnScreenRequested(IBinder token, Rect rectangle)586     public void onRectangleOnScreenRequested(IBinder token, Rect rectangle) {
587         synchronized (mService.mGlobalLock) {
588             final long identity = Binder.clearCallingIdentity();
589             try {
590                 mService.onRectangleOnScreenRequested(token, rectangle);
591             } finally {
592                 Binder.restoreCallingIdentity(identity);
593             }
594         }
595     }
596 
597     @Override
getWindowId(IBinder window)598     public IWindowId getWindowId(IBinder window) {
599         return mService.getWindowId(window);
600     }
601 
602     @Override
pokeDrawLock(IBinder window)603     public void pokeDrawLock(IBinder window) {
604         final long identity = Binder.clearCallingIdentity();
605         try {
606             mService.pokeDrawLock(this, window);
607         } finally {
608             Binder.restoreCallingIdentity(identity);
609         }
610     }
611 
612     @Override
updatePointerIcon(IWindow window)613     public void updatePointerIcon(IWindow window) {
614         final long identity = Binder.clearCallingIdentity();
615         try {
616             mService.updatePointerIcon(window);
617         } finally {
618             Binder.restoreCallingIdentity(identity);
619         }
620     }
621 
622     @Override
updateDisplayContentLocation(IWindow window, int x, int y, int displayId)623     public void updateDisplayContentLocation(IWindow window, int x, int y, int displayId) {
624         mService.updateDisplayContentLocation(window, x, y, displayId);
625     }
626 
627     @Override
updateTapExcludeRegion(IWindow window, Region region)628     public void updateTapExcludeRegion(IWindow window, Region region) {
629         final long identity = Binder.clearCallingIdentity();
630         try {
631             mService.updateTapExcludeRegion(window, region);
632         } finally {
633             Binder.restoreCallingIdentity(identity);
634         }
635     }
636 
637     @Override
updateRequestedVisibilities(IWindow window, InsetsVisibilities visibilities)638     public void updateRequestedVisibilities(IWindow window, InsetsVisibilities visibilities) {
639         synchronized (mService.mGlobalLock) {
640             final WindowState windowState = mService.windowForClientLocked(this, window,
641                     false /* throwOnError */);
642             if (windowState != null) {
643                 windowState.setRequestedVisibilities(visibilities);
644                 windowState.getDisplayContent().getInsetsPolicy().onInsetsModified(windowState);
645             }
646         }
647     }
648 
windowAddedLocked()649     void windowAddedLocked() {
650         if (mPackageName == null) {
651             final WindowProcessController wpc = mService.mAtmService.mProcessMap.getProcess(mPid);
652             if (wpc != null) {
653                 mPackageName = wpc.mInfo.packageName;
654                 mRelayoutTag = "relayoutWindow: " + mPackageName;
655             } else {
656                 Slog.e(TAG_WM, "Unknown process pid=" + mPid);
657             }
658         }
659         if (mSurfaceSession == null) {
660             if (DEBUG) {
661                 Slog.v(TAG_WM, "First window added to " + this + ", creating SurfaceSession");
662             }
663             mSurfaceSession = new SurfaceSession();
664             ProtoLog.i(WM_SHOW_TRANSACTIONS, "  NEW SURFACE SESSION %s", mSurfaceSession);
665             mService.mSessions.add(this);
666             if (mLastReportedAnimatorScale != mService.getCurrentAnimatorScale()) {
667                 mService.dispatchNewAnimatorScaleLocked(this);
668             }
669         }
670         mNumWindow++;
671     }
672 
windowRemovedLocked()673     void windowRemovedLocked() {
674         mNumWindow--;
675         killSessionLocked();
676     }
677 
678 
onWindowSurfaceVisibilityChanged(WindowSurfaceController surfaceController, boolean visible, int type)679     void onWindowSurfaceVisibilityChanged(WindowSurfaceController surfaceController,
680             boolean visible, int type) {
681 
682         if (!isSystemAlertWindowType(type)) {
683             return;
684         }
685 
686         boolean changed;
687 
688         if (!mCanAddInternalSystemWindow && !mCanCreateSystemApplicationOverlay) {
689             // We want to track non-system apps adding alert windows so we can post an
690             // on-going notification for the user to control their visibility.
691             if (visible) {
692                 changed = mAlertWindowSurfaces.add(surfaceController);
693                 MetricsLoggerWrapper.logAppOverlayEnter(mUid, mPackageName, changed, type, true);
694             } else {
695                 changed = mAlertWindowSurfaces.remove(surfaceController);
696                 MetricsLoggerWrapper.logAppOverlayExit(mUid, mPackageName, changed, type, true);
697             }
698 
699             if (changed) {
700                 if (mAlertWindowSurfaces.isEmpty()) {
701                     cancelAlertWindowNotification();
702                 } else if (mAlertWindowNotification == null){
703                     mAlertWindowNotification = new AlertWindowNotification(mService, mPackageName);
704                     if (mShowingAlertWindowNotificationAllowed) {
705                         mAlertWindowNotification.post();
706                     }
707                 }
708             }
709         }
710 
711         if (type != TYPE_APPLICATION_OVERLAY) {
712             return;
713         }
714 
715         if (visible) {
716             changed = mAppOverlaySurfaces.add(surfaceController);
717             MetricsLoggerWrapper.logAppOverlayEnter(mUid, mPackageName, changed, type, false);
718         } else {
719             changed = mAppOverlaySurfaces.remove(surfaceController);
720             MetricsLoggerWrapper.logAppOverlayExit(mUid, mPackageName, changed, type, false);
721         }
722 
723         if (changed) {
724             // Notify activity manager of changes to app overlay windows so it can adjust the
725             // importance score for the process.
726             setHasOverlayUi(!mAppOverlaySurfaces.isEmpty());
727         }
728     }
729 
setShowingAlertWindowNotificationAllowed(boolean allowed)730     void setShowingAlertWindowNotificationAllowed(boolean allowed) {
731         mShowingAlertWindowNotificationAllowed = allowed;
732         if (mAlertWindowNotification != null) {
733             if (allowed) {
734                 mAlertWindowNotification.post();
735             } else {
736                 mAlertWindowNotification.cancel(false /* deleteChannel */);
737             }
738         }
739     }
740 
killSessionLocked()741     private void killSessionLocked() {
742         if (mNumWindow > 0 || !mClientDead) {
743             return;
744         }
745 
746         mService.mSessions.remove(this);
747         if (mSurfaceSession == null) {
748             return;
749         }
750 
751         if (DEBUG) {
752             Slog.v(TAG_WM, "Last window removed from " + this
753                     + ", destroying " + mSurfaceSession);
754         }
755         ProtoLog.i(WM_SHOW_TRANSACTIONS, "  KILL SURFACE SESSION %s", mSurfaceSession);
756         try {
757             mSurfaceSession.kill();
758         } catch (Exception e) {
759             Slog.w(TAG_WM, "Exception thrown when killing surface session " + mSurfaceSession
760                     + " in session " + this + ": " + e.toString());
761         }
762         mSurfaceSession = null;
763         mAlertWindowSurfaces.clear();
764         mAppOverlaySurfaces.clear();
765         setHasOverlayUi(false);
766         cancelAlertWindowNotification();
767     }
768 
setHasOverlayUi(boolean hasOverlayUi)769     private void setHasOverlayUi(boolean hasOverlayUi) {
770         mService.mH.obtainMessage(H.SET_HAS_OVERLAY_UI, mPid, hasOverlayUi ? 1 : 0).sendToTarget();
771     }
772 
cancelAlertWindowNotification()773     private void cancelAlertWindowNotification() {
774         if (mAlertWindowNotification == null) {
775             return;
776         }
777         mAlertWindowNotification.cancel(true /* deleteChannel */);
778         mAlertWindowNotification = null;
779     }
780 
dump(PrintWriter pw, String prefix)781     void dump(PrintWriter pw, String prefix) {
782         pw.print(prefix); pw.print("mNumWindow="); pw.print(mNumWindow);
783                 pw.print(" mCanAddInternalSystemWindow="); pw.print(mCanAddInternalSystemWindow);
784                 pw.print(" mAppOverlaySurfaces="); pw.print(mAppOverlaySurfaces);
785                 pw.print(" mAlertWindowSurfaces="); pw.print(mAlertWindowSurfaces);
786                 pw.print(" mClientDead="); pw.print(mClientDead);
787                 pw.print(" mSurfaceSession="); pw.println(mSurfaceSession);
788         pw.print(prefix); pw.print("mPackageName="); pw.println(mPackageName);
789     }
790 
791     @Override
toString()792     public String toString() {
793         return mStringName;
794     }
795 
796     /** @return {@code true} if there is an alert window surface on the given display. */
hasAlertWindowSurfaces(DisplayContent displayContent)797     boolean hasAlertWindowSurfaces(DisplayContent displayContent) {
798         for (int i = mAlertWindowSurfaces.size() - 1; i >= 0; i--) {
799             final WindowSurfaceController surfaceController = mAlertWindowSurfaces.valueAt(i);
800             if (surfaceController.mAnimator.mWin.getDisplayContent() == displayContent) {
801                 return true;
802             }
803         }
804         return false;
805     }
806 
807     @Override
grantInputChannel(int displayId, SurfaceControl surface, IWindow window, IBinder hostInputToken, int flags, int privateFlags, int type, InputChannel outInputChannel)808     public void grantInputChannel(int displayId, SurfaceControl surface,
809             IWindow window, IBinder hostInputToken, int flags, int privateFlags, int type,
810             InputChannel outInputChannel) {
811         if (hostInputToken == null && !mCanAddInternalSystemWindow) {
812             // Callers without INTERNAL_SYSTEM_WINDOW permission cannot grant input channel to
813             // embedded windows without providing a host window input token
814             throw new SecurityException("Requires INTERNAL_SYSTEM_WINDOW permission");
815         }
816 
817         if (!mCanAddInternalSystemWindow && type != 0) {
818             Slog.w(TAG_WM, "Requires INTERNAL_SYSTEM_WINDOW permission if assign type to"
819                     + " input");
820         }
821 
822         final long identity = Binder.clearCallingIdentity();
823         try {
824             mService.grantInputChannel(this, mUid, mPid, displayId, surface, window, hostInputToken,
825                     flags, mCanAddInternalSystemWindow ? privateFlags : 0,
826                     mCanAddInternalSystemWindow ? type : 0, outInputChannel);
827         } finally {
828             Binder.restoreCallingIdentity(identity);
829         }
830     }
831 
832     @Override
updateInputChannel(IBinder channelToken, int displayId, SurfaceControl surface, int flags, int privateFlags, Region region)833     public void updateInputChannel(IBinder channelToken, int displayId, SurfaceControl surface,
834             int flags, int privateFlags, Region region) {
835         final long identity = Binder.clearCallingIdentity();
836         try {
837             mService.updateInputChannel(channelToken, displayId, surface, flags,
838                     mCanAddInternalSystemWindow ? privateFlags : 0, region);
839         } finally {
840             Binder.restoreCallingIdentity(identity);
841         }
842     }
843 
844     @Override
grantEmbeddedWindowFocus(IWindow callingWindow, IBinder targetInputToken, boolean grantFocus)845     public void grantEmbeddedWindowFocus(IWindow callingWindow, IBinder targetInputToken,
846                                          boolean grantFocus) {
847         final long identity = Binder.clearCallingIdentity();
848         try {
849             if (callingWindow == null) {
850                 if (!mCanAddInternalSystemWindow) {
851                     // Callers without INTERNAL_SYSTEM_WINDOW permission cannot request focus on
852                     // embedded windows without providing the calling window
853                     throw new SecurityException("Requires INTERNAL_SYSTEM_WINDOW permission");
854                 }
855                 mService.grantEmbeddedWindowFocus(this, targetInputToken, grantFocus);
856             } else {
857                 mService.grantEmbeddedWindowFocus(this, callingWindow, targetInputToken,
858                         grantFocus);
859             }
860         } finally {
861             Binder.restoreCallingIdentity(identity);
862         }
863     }
864 
865     @Override
generateDisplayHash(IWindow window, Rect boundsInWindow, String hashAlgorithm, RemoteCallback callback)866     public void generateDisplayHash(IWindow window, Rect boundsInWindow, String hashAlgorithm,
867             RemoteCallback callback) {
868         final long origId = Binder.clearCallingIdentity();
869         try {
870             mService.generateDisplayHash(this, window, boundsInWindow, hashAlgorithm, callback);
871         } finally {
872             Binder.restoreCallingIdentity(origId);
873         }
874     }
875 }
876