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.ALWAYS_UPDATE_WALLPAPER; 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.SET_UNRESTRICTED_GESTURE_EXCLUSION; 24 import static android.Manifest.permission.SET_UNRESTRICTED_KEEP_CLEAR_AREAS; 25 import static android.Manifest.permission.START_TASKS_FROM_RECENTS; 26 import static android.Manifest.permission.STATUS_BAR_SERVICE; 27 import static android.Manifest.permission.SYSTEM_APPLICATION_OVERLAY; 28 import static android.app.ActivityTaskManager.INVALID_TASK_ID; 29 import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY; 30 import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT; 31 import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK; 32 import static android.content.Intent.EXTRA_PACKAGE_NAME; 33 import static android.content.Intent.EXTRA_SHORTCUT_ID; 34 import static android.content.Intent.EXTRA_TASK_ID; 35 import static android.content.pm.PackageManager.PERMISSION_GRANTED; 36 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; 37 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; 38 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG; 39 import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType; 40 41 import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_IME; 42 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG; 43 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 44 45 import android.annotation.NonNull; 46 import android.annotation.Nullable; 47 import android.app.PendingIntent; 48 import android.content.ClipData; 49 import android.content.ClipDescription; 50 import android.content.Intent; 51 import android.content.pm.ActivityInfo; 52 import android.content.pm.ShortcutServiceInternal; 53 import android.graphics.Rect; 54 import android.graphics.Region; 55 import android.os.Binder; 56 import android.os.Bundle; 57 import android.os.IBinder; 58 import android.os.Parcel; 59 import android.os.Process; 60 import android.os.RemoteCallback; 61 import android.os.RemoteException; 62 import android.os.Trace; 63 import android.os.UserHandle; 64 import android.text.TextUtils; 65 import android.util.ArraySet; 66 import android.util.Slog; 67 import android.view.IWindow; 68 import android.view.IWindowId; 69 import android.view.IWindowSession; 70 import android.view.IWindowSessionCallback; 71 import android.view.InputChannel; 72 import android.view.InsetsSourceControl; 73 import android.view.InsetsState; 74 import android.view.SurfaceControl; 75 import android.view.View; 76 import android.view.View.FocusDirection; 77 import android.view.WindowInsets; 78 import android.view.WindowInsets.Type.InsetsType; 79 import android.view.WindowManager; 80 import android.view.WindowRelayoutResult; 81 import android.view.inputmethod.ImeTracker; 82 import android.window.InputTransferToken; 83 import android.window.OnBackInvokedCallbackInfo; 84 85 import com.android.internal.annotations.VisibleForTesting; 86 import com.android.internal.os.logging.MetricsLoggerWrapper; 87 import com.android.internal.protolog.ProtoLog; 88 import com.android.server.LocalServices; 89 import com.android.server.wm.WindowManagerService.H; 90 import com.android.window.flags.Flags; 91 92 import java.io.PrintWriter; 93 import java.util.ArrayList; 94 import java.util.Collections; 95 import java.util.List; 96 import java.util.function.BiConsumer; 97 98 /** 99 * This class represents an active client session. There is generally one 100 * Session object per process that is interacting with the window manager. 101 */ 102 class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { 103 final WindowManagerService mService; 104 final IWindowSessionCallback mCallback; 105 final int mUid; 106 final int mPid; 107 @NonNull 108 final WindowProcessController mProcess; 109 private final String mStringName; 110 private final ArrayList<WindowState> mAddedWindows = new ArrayList<>(); 111 /** Set of visible alert/app-overlay windows connected to this session. */ 112 private final ArraySet<WindowState> mAlertWindows = new ArraySet<>(); 113 private final DragDropController mDragDropController; 114 final boolean mCanAddInternalSystemWindow; 115 boolean mCanForceShowingInsets; 116 private final boolean mCanStartTasksFromRecents; 117 118 final boolean mCanCreateSystemApplicationOverlay; 119 final boolean mCanHideNonSystemOverlayWindows; 120 final boolean mCanSetUnrestrictedGestureExclusion; 121 final boolean mCanAlwaysUpdateWallpaper; 122 private AlertWindowNotification mAlertWindowNotification; 123 private boolean mShowingAlertWindowNotificationAllowed; 124 private boolean mClientDead = false; 125 private float mLastReportedAnimatorScale; 126 protected String mPackageName; 127 private String mRelayoutTag; 128 private final InsetsSourceControl.Array mDummyControls = new InsetsSourceControl.Array(); 129 final boolean mSetsUnrestrictedKeepClearAreas; 130 Session(WindowManagerService service, IWindowSessionCallback callback)131 public Session(WindowManagerService service, IWindowSessionCallback callback) { 132 this(service, callback, Binder.getCallingPid(), Binder.getCallingUid()); 133 } 134 135 @VisibleForTesting Session(WindowManagerService service, IWindowSessionCallback callback, int callingPid, int callingUid)136 Session(WindowManagerService service, IWindowSessionCallback callback, 137 int callingPid, int callingUid) { 138 mService = service; 139 mCallback = callback; 140 mPid = callingPid; 141 mUid = callingUid; 142 synchronized (service.mGlobalLock) { 143 mLastReportedAnimatorScale = service.getCurrentAnimatorScale(); 144 mProcess = service.mAtmService.mProcessMap.getProcess(mPid); 145 } 146 if (mProcess == null) { 147 throw new IllegalStateException("Unknown pid=" + mPid + " uid=" + mUid); 148 } 149 mCanAddInternalSystemWindow = service.mContext.checkCallingOrSelfPermission( 150 INTERNAL_SYSTEM_WINDOW) == PERMISSION_GRANTED; 151 mCanForceShowingInsets = service.mAtmService.isCallerRecents(mUid) 152 || service.mContext.checkCallingOrSelfPermission(STATUS_BAR_SERVICE) 153 == PERMISSION_GRANTED; 154 mCanHideNonSystemOverlayWindows = service.mContext.checkCallingOrSelfPermission( 155 HIDE_NON_SYSTEM_OVERLAY_WINDOWS) == PERMISSION_GRANTED 156 || service.mContext.checkCallingOrSelfPermission(HIDE_OVERLAY_WINDOWS) 157 == PERMISSION_GRANTED; 158 mCanCreateSystemApplicationOverlay = 159 service.mContext.checkCallingOrSelfPermission(SYSTEM_APPLICATION_OVERLAY) 160 == PERMISSION_GRANTED; 161 mCanStartTasksFromRecents = service.mContext.checkCallingOrSelfPermission( 162 START_TASKS_FROM_RECENTS) == PERMISSION_GRANTED; 163 mSetsUnrestrictedKeepClearAreas = 164 service.mContext.checkCallingOrSelfPermission(SET_UNRESTRICTED_KEEP_CLEAR_AREAS) 165 == PERMISSION_GRANTED; 166 mCanSetUnrestrictedGestureExclusion = 167 service.mContext.checkCallingOrSelfPermission(SET_UNRESTRICTED_GESTURE_EXCLUSION) 168 == PERMISSION_GRANTED; 169 mCanAlwaysUpdateWallpaper = Flags.alwaysUpdateWallpaperPermission() 170 && service.mContext.checkCallingOrSelfPermission(ALWAYS_UPDATE_WALLPAPER) 171 == PERMISSION_GRANTED; 172 mShowingAlertWindowNotificationAllowed = mService.mShowAlertWindowNotifications; 173 mDragDropController = mService.mDragDropController; 174 StringBuilder sb = new StringBuilder(); 175 sb.append("Session{"); 176 sb.append(Integer.toHexString(System.identityHashCode(this))); 177 sb.append(" "); 178 sb.append(mPid); 179 if (mUid < Process.FIRST_APPLICATION_UID) { 180 sb.append(":"); 181 sb.append(mUid); 182 } else { 183 sb.append(":u"); 184 sb.append(UserHandle.getUserId(mUid)); 185 sb.append('a'); 186 sb.append(UserHandle.getAppId(mUid)); 187 } 188 sb.append("}"); 189 mStringName = sb.toString(); 190 191 try { 192 mCallback.asBinder().linkToDeath(this, 0); 193 } catch (RemoteException e) { 194 mClientDead = true; 195 } 196 } 197 198 @Override onTransact(int code, Parcel data, Parcel reply, int flags)199 public boolean onTransact(int code, Parcel data, Parcel reply, int flags) 200 throws RemoteException { 201 try { 202 return super.onTransact(code, data, reply, flags); 203 } catch (RuntimeException e) { 204 // Log all 'real' exceptions thrown to the caller 205 if (!(e instanceof SecurityException)) { 206 Slog.wtf(TAG_WM, "Window Session Crash", e); 207 } 208 throw e; 209 } 210 } 211 isClientDead()212 boolean isClientDead() { 213 return mClientDead; 214 } 215 216 @Override binderDied()217 public void binderDied() { 218 synchronized (mService.mGlobalLock) { 219 mCallback.asBinder().unlinkToDeath(this, 0); 220 mClientDead = true; 221 try { 222 for (int i = mAddedWindows.size() - 1; i >= 0; i--) { 223 final WindowState w = mAddedWindows.get(i); 224 Slog.i(TAG_WM, "WIN DEATH: " + w); 225 if (w.mActivityRecord != null && w.mActivityRecord.findMainWindow() == w) { 226 mService.mSnapshotController.onAppDied(w.mActivityRecord); 227 } 228 w.removeIfPossible(); 229 } 230 } finally { 231 killSessionLocked(); 232 } 233 } 234 } 235 236 @Override addToDisplay(IWindow window, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, @InsetsType int requestedVisibleTypes, InputChannel outInputChannel, InsetsState outInsetsState, InsetsSourceControl.Array outActiveControls, Rect outAttachedFrame, float[] outSizeCompatScale)237 public int addToDisplay(IWindow window, WindowManager.LayoutParams attrs, 238 int viewVisibility, int displayId, @InsetsType int requestedVisibleTypes, 239 InputChannel outInputChannel, InsetsState outInsetsState, 240 InsetsSourceControl.Array outActiveControls, Rect outAttachedFrame, 241 float[] outSizeCompatScale) { 242 return mService.addWindow(this, window, attrs, viewVisibility, displayId, 243 UserHandle.getUserId(mUid), requestedVisibleTypes, outInputChannel, outInsetsState, 244 outActiveControls, outAttachedFrame, outSizeCompatScale); 245 } 246 247 @Override addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, int userId, @InsetsType int requestedVisibleTypes, InputChannel outInputChannel, InsetsState outInsetsState, InsetsSourceControl.Array outActiveControls, Rect outAttachedFrame, float[] outSizeCompatScale)248 public int addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs, 249 int viewVisibility, int displayId, int userId, @InsetsType int requestedVisibleTypes, 250 InputChannel outInputChannel, InsetsState outInsetsState, 251 InsetsSourceControl.Array outActiveControls, Rect outAttachedFrame, 252 float[] outSizeCompatScale) { 253 return mService.addWindow(this, window, attrs, viewVisibility, displayId, userId, 254 requestedVisibleTypes, outInputChannel, outInsetsState, outActiveControls, 255 outAttachedFrame, outSizeCompatScale); 256 } 257 258 @Override addToDisplayWithoutInputChannel(IWindow window, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, InsetsState outInsetsState, Rect outAttachedFrame, float[] outSizeCompatScale)259 public int addToDisplayWithoutInputChannel(IWindow window, WindowManager.LayoutParams attrs, 260 int viewVisibility, int displayId, InsetsState outInsetsState, Rect outAttachedFrame, 261 float[] outSizeCompatScale) { 262 return mService.addWindow(this, window, attrs, viewVisibility, displayId, 263 UserHandle.getUserId(mUid), WindowInsets.Type.defaultVisible(), 264 null /* outInputChannel */, outInsetsState, mDummyControls, outAttachedFrame, 265 outSizeCompatScale); 266 } 267 268 @Override remove(IBinder clientToken)269 public void remove(IBinder clientToken) { 270 mService.removeClientToken(this, clientToken); 271 } 272 273 @Override cancelDraw(IWindow window)274 public boolean cancelDraw(IWindow window) { 275 return mService.cancelDraw(this, window); 276 } 277 278 @Override relayout(IWindow window, WindowManager.LayoutParams attrs, int requestedWidth, int requestedHeight, int viewFlags, int flags, int seq, int lastSyncSeqId, WindowRelayoutResult outRelayoutResult)279 public int relayout(IWindow window, WindowManager.LayoutParams attrs, 280 int requestedWidth, int requestedHeight, int viewFlags, int flags, int seq, 281 int lastSyncSeqId, WindowRelayoutResult outRelayoutResult) { 282 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag); 283 int res = mService.relayoutWindow(this, window, attrs, requestedWidth, 284 requestedHeight, viewFlags, flags, seq, lastSyncSeqId, outRelayoutResult); 285 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); 286 return res; 287 } 288 289 @Override relayoutAsync(IWindow window, WindowManager.LayoutParams attrs, int requestedWidth, int requestedHeight, int viewFlags, int flags, int seq, int lastSyncSeqId)290 public void relayoutAsync(IWindow window, WindowManager.LayoutParams attrs, 291 int requestedWidth, int requestedHeight, int viewFlags, int flags, int seq, 292 int lastSyncSeqId) { 293 relayout(window, attrs, requestedWidth, requestedHeight, viewFlags, flags, seq, 294 lastSyncSeqId, null /* outRelayoutResult */); 295 } 296 297 @Override outOfMemory(IWindow window)298 public boolean outOfMemory(IWindow window) { 299 return mService.outOfMemoryWindow(this, window); 300 } 301 302 @Override setInsets(IWindow window, int touchableInsets, Rect contentInsets, Rect visibleInsets, Region touchableArea)303 public void setInsets(IWindow window, int touchableInsets, 304 Rect contentInsets, Rect visibleInsets, Region touchableArea) { 305 mService.setInsetsWindow(this, window, touchableInsets, contentInsets, 306 visibleInsets, touchableArea); 307 } 308 309 @Override clearTouchableRegion(IWindow window)310 public void clearTouchableRegion(IWindow window) { 311 mService.clearTouchableRegion(this, window); 312 } 313 314 @Override finishDrawing(IWindow window, @Nullable SurfaceControl.Transaction postDrawTransaction, int seqId)315 public void finishDrawing(IWindow window, 316 @Nullable SurfaceControl.Transaction postDrawTransaction, int seqId) { 317 if (DEBUG) Slog.v(TAG_WM, "IWindow finishDrawing called for " + window); 318 if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) { 319 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "finishDrawing: " + mPackageName); 320 } 321 mService.finishDrawingWindow(this, window, postDrawTransaction, seqId); 322 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); 323 } 324 325 /* Drag/drop */ 326 327 @Override performDrag(IWindow window, int flags, SurfaceControl surface, int touchSource, int touchDeviceId, int touchPointerId, float touchX, float touchY, float thumbCenterX, float thumbCenterY, ClipData data)328 public IBinder performDrag(IWindow window, int flags, SurfaceControl surface, int touchSource, 329 int touchDeviceId, int touchPointerId, float touchX, float touchY, float thumbCenterX, 330 float thumbCenterY, ClipData data) { 331 final int callingUid = Binder.getCallingUid(); 332 final int callingPid = Binder.getCallingPid(); 333 // Validate and resolve ClipDescription data before clearing the calling identity 334 validateAndResolveDragMimeTypeExtras(data, callingUid, callingPid, mPackageName); 335 validateDragFlags(flags, callingUid); 336 final long ident = Binder.clearCallingIdentity(); 337 try { 338 return mDragDropController.performDrag(mPid, mUid, window, flags, surface, touchSource, 339 touchDeviceId, touchPointerId, touchX, touchY, thumbCenterX, thumbCenterY, 340 data); 341 } finally { 342 Binder.restoreCallingIdentity(ident); 343 } 344 } 345 346 347 @Override dropForAccessibility(IWindow window, int x, int y)348 public boolean dropForAccessibility(IWindow window, int x, int y) { 349 final long ident = Binder.clearCallingIdentity(); 350 try { 351 return mDragDropController.dropForAccessibility(window, x, y); 352 } finally { 353 Binder.restoreCallingIdentity(ident); 354 } 355 } 356 357 /** 358 * Validates the given drag flags. 359 */ 360 @VisibleForTesting validateDragFlags(int flags, int callingUid)361 void validateDragFlags(int flags, int callingUid) { 362 if ((flags & View.DRAG_FLAG_REQUEST_SURFACE_FOR_RETURN_ANIMATION) != 0) { 363 if (!mCanStartTasksFromRecents) { 364 throw new SecurityException("Requires START_TASKS_FROM_RECENTS permission"); 365 } 366 } 367 if ((flags & View.DRAG_FLAG_HIDE_CALLING_TASK_ON_DRAG_START) != 0) { 368 if (!SafeActivityOptions.isAssistant(mService.mAtmService, callingUid)) { 369 throw new SecurityException("Caller is not the assistant"); 370 } 371 } 372 } 373 374 /** 375 * Validates the given drag data. 376 */ 377 @VisibleForTesting validateAndResolveDragMimeTypeExtras(ClipData data, int callingUid, int callingPid, String callingPackage)378 void validateAndResolveDragMimeTypeExtras(ClipData data, int callingUid, int callingPid, 379 String callingPackage) { 380 final ClipDescription desc = data != null ? data.getDescription() : null; 381 if (desc == null) { 382 return; 383 } 384 // Ensure that only one of the app mime types are set 385 final boolean hasActivity = desc.hasMimeType(MIMETYPE_APPLICATION_ACTIVITY); 386 final boolean hasShortcut = desc.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT); 387 final boolean hasTask = desc.hasMimeType(MIMETYPE_APPLICATION_TASK); 388 int appMimeTypeCount = (hasActivity ? 1 : 0) 389 + (hasShortcut ? 1 : 0) 390 + (hasTask ? 1 : 0); 391 if (appMimeTypeCount == 0) { 392 return; 393 } else if (appMimeTypeCount > 1) { 394 throw new IllegalArgumentException("Can not specify more than one of activity, " 395 + "shortcut, or task mime types"); 396 } 397 // Ensure that data is provided and that they are intents 398 if (data.getItemCount() == 0) { 399 throw new IllegalArgumentException("Unexpected number of items (none)"); 400 } 401 for (int i = 0; i < data.getItemCount(); i++) { 402 if (data.getItemAt(i).getIntent() == null) { 403 throw new IllegalArgumentException("Unexpected item, expected an intent"); 404 } 405 } 406 407 if (hasActivity) { 408 long origId = Binder.clearCallingIdentity(); 409 try { 410 // Resolve the activity info for each intent 411 for (int i = 0; i < data.getItemCount(); i++) { 412 final ClipData.Item item = data.getItemAt(i); 413 final Intent intent = item.getIntent(); 414 final PendingIntent pi = intent.getParcelableExtra( 415 ClipDescription.EXTRA_PENDING_INTENT); 416 final UserHandle user = intent.getParcelableExtra(Intent.EXTRA_USER); 417 if (pi == null || user == null) { 418 throw new IllegalArgumentException("Clip data must include the pending " 419 + "intent to launch and its associated user to launch for."); 420 } 421 final Intent launchIntent = mService.mAmInternal.getIntentForIntentSender( 422 pi.getIntentSender().getTarget()); 423 final ActivityInfo info = mService.mAtmService.resolveActivityInfoForIntent( 424 launchIntent, null /* resolvedType */, user.getIdentifier(), 425 callingUid, callingPid); 426 item.setActivityInfo(info); 427 } 428 } finally { 429 Binder.restoreCallingIdentity(origId); 430 } 431 } else if (hasShortcut) { 432 // Restrict who can start a shortcut drag since it will start the shortcut as the 433 // target shortcut package 434 if (!mCanStartTasksFromRecents) { 435 throw new SecurityException("Requires START_TASKS_FROM_RECENTS permission"); 436 } 437 for (int i = 0; i < data.getItemCount(); i++) { 438 final ClipData.Item item = data.getItemAt(i); 439 final Intent intent = item.getIntent(); 440 final String shortcutId = intent.getStringExtra(EXTRA_SHORTCUT_ID); 441 final String packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME); 442 final UserHandle user = intent.getParcelableExtra(Intent.EXTRA_USER); 443 if (TextUtils.isEmpty(shortcutId) 444 || TextUtils.isEmpty(packageName) 445 || user == null) { 446 throw new IllegalArgumentException("Clip item must include the package name, " 447 + "shortcut id, and the user to launch for."); 448 } 449 final ShortcutServiceInternal shortcutService = 450 LocalServices.getService(ShortcutServiceInternal.class); 451 final Intent[] shortcutIntents = shortcutService.createShortcutIntents( 452 UserHandle.getUserId(callingUid), callingPackage, packageName, shortcutId, 453 user.getIdentifier(), callingPid, callingUid); 454 if (shortcutIntents == null || shortcutIntents.length == 0) { 455 throw new IllegalArgumentException("Invalid shortcut id"); 456 } 457 final ActivityInfo info = mService.mAtmService.resolveActivityInfoForIntent( 458 shortcutIntents[0], null /* resolvedType */, user.getIdentifier(), 459 callingUid, callingPid); 460 item.setActivityInfo(info); 461 } 462 } else if (hasTask) { 463 // TODO(b/169894807): Consider opening this up for tasks from the same app as the caller 464 if (!mCanStartTasksFromRecents) { 465 throw new SecurityException("Requires START_TASKS_FROM_RECENTS permission"); 466 } 467 for (int i = 0; i < data.getItemCount(); i++) { 468 final ClipData.Item item = data.getItemAt(i); 469 final Intent intent = item.getIntent(); 470 final int taskId = intent.getIntExtra(EXTRA_TASK_ID, INVALID_TASK_ID); 471 if (taskId == INVALID_TASK_ID) { 472 throw new IllegalArgumentException("Clip item must include the task id."); 473 } 474 final Task task = mService.mRoot.anyTaskForId(taskId); 475 if (task == null) { 476 throw new IllegalArgumentException("Invalid task id."); 477 } 478 if (task.getRootActivity() != null) { 479 item.setActivityInfo(task.getRootActivity().info); 480 } else { 481 // Resolve the activity info manually if the task was restored after reboot 482 final ActivityInfo info = mService.mAtmService.resolveActivityInfoForIntent( 483 task.intent, null /* resolvedType */, task.mUserId, callingUid, 484 callingPid); 485 item.setActivityInfo(info); 486 } 487 } 488 } 489 } 490 491 @Override reportDropResult(IWindow window, boolean consumed)492 public void reportDropResult(IWindow window, boolean consumed) { 493 final long ident = Binder.clearCallingIdentity(); 494 try { 495 mDragDropController.reportDropResult(window, consumed); 496 } finally { 497 Binder.restoreCallingIdentity(ident); 498 } 499 } 500 501 @Override cancelDragAndDrop(IBinder dragToken, boolean skipAnimation)502 public void cancelDragAndDrop(IBinder dragToken, boolean skipAnimation) { 503 final long ident = Binder.clearCallingIdentity(); 504 try { 505 mDragDropController.cancelDragAndDrop(dragToken, skipAnimation); 506 } finally { 507 Binder.restoreCallingIdentity(ident); 508 } 509 } 510 511 @Override dragRecipientEntered(IWindow window)512 public void dragRecipientEntered(IWindow window) { 513 mDragDropController.dragRecipientEntered(window); 514 } 515 516 @Override dragRecipientExited(IWindow window)517 public void dragRecipientExited(IWindow window) { 518 mDragDropController.dragRecipientExited(window); 519 } 520 521 @Override startMovingTask(IWindow window, float startX, float startY)522 public boolean startMovingTask(IWindow window, float startX, float startY) { 523 return false; 524 } 525 526 @Override finishMovingTask(IWindow window)527 public void finishMovingTask(IWindow window) { 528 } 529 530 @Override reportSystemGestureExclusionChanged(IWindow window, List<Rect> exclusionRects)531 public void reportSystemGestureExclusionChanged(IWindow window, List<Rect> exclusionRects) { 532 final long ident = Binder.clearCallingIdentity(); 533 try { 534 mService.reportSystemGestureExclusionChanged(this, window, exclusionRects); 535 } finally { 536 Binder.restoreCallingIdentity(ident); 537 } 538 } 539 540 @Override reportDecorViewGestureInterceptionChanged(IWindow window, boolean intercepted)541 public void reportDecorViewGestureInterceptionChanged(IWindow window, boolean intercepted) { 542 final long ident = Binder.clearCallingIdentity(); 543 try { 544 mService.reportDecorViewGestureChanged(this, window, intercepted); 545 } finally { 546 Binder.restoreCallingIdentity(ident); 547 } 548 } 549 550 @Override reportKeepClearAreasChanged(IWindow window, List<Rect> restricted, List<Rect> unrestricted)551 public void reportKeepClearAreasChanged(IWindow window, List<Rect> restricted, 552 List<Rect> unrestricted) { 553 if (!mSetsUnrestrictedKeepClearAreas && !unrestricted.isEmpty()) { 554 unrestricted = Collections.emptyList(); 555 } 556 557 final long ident = Binder.clearCallingIdentity(); 558 try { 559 mService.reportKeepClearAreasChanged(this, window, restricted, unrestricted); 560 } finally { 561 Binder.restoreCallingIdentity(ident); 562 } 563 } 564 actionOnWallpaper(IBinder window, BiConsumer<WallpaperController, WindowState> action)565 private void actionOnWallpaper(IBinder window, 566 BiConsumer<WallpaperController, WindowState> action) { 567 final WindowState windowState = mService.windowForClientLocked(this, window, true); 568 action.accept(windowState.getDisplayContent().mWallpaperController, windowState); 569 } 570 571 @Override setWallpaperPosition(IBinder window, float x, float y, float xStep, float yStep)572 public void setWallpaperPosition(IBinder window, float x, float y, float xStep, float yStep) { 573 synchronized (mService.mGlobalLock) { 574 final long ident = Binder.clearCallingIdentity(); 575 try { 576 actionOnWallpaper(window, (wpController, windowState) -> 577 wpController.setWindowWallpaperPosition(windowState, x, y, xStep, yStep)); 578 } finally { 579 Binder.restoreCallingIdentity(ident); 580 } 581 } 582 } 583 584 @Override setWallpaperZoomOut(IBinder window, float zoom)585 public void setWallpaperZoomOut(IBinder window, float zoom) { 586 if (Float.compare(0f, zoom) > 0 || Float.compare(1f, zoom) < 0 || Float.isNaN(zoom)) { 587 throw new IllegalArgumentException("Zoom must be a valid float between 0 and 1: " 588 + zoom); 589 } 590 synchronized (mService.mGlobalLock) { 591 final long ident = Binder.clearCallingIdentity(); 592 try { 593 actionOnWallpaper(window, (wpController, windowState) -> 594 wpController.setWallpaperZoomOut(windowState, zoom)); 595 } finally { 596 Binder.restoreCallingIdentity(ident); 597 } 598 } 599 } 600 601 @Override setShouldZoomOutWallpaper(IBinder window, boolean shouldZoom)602 public void setShouldZoomOutWallpaper(IBinder window, boolean shouldZoom) { 603 synchronized (mService.mGlobalLock) { 604 actionOnWallpaper(window, (wpController, windowState) -> 605 wpController.setShouldZoomOutWallpaper(windowState, shouldZoom)); 606 } 607 } 608 609 @Override wallpaperOffsetsComplete(IBinder window)610 public void wallpaperOffsetsComplete(IBinder window) { 611 synchronized (mService.mGlobalLock) { 612 actionOnWallpaper(window, (wpController, windowState) -> 613 wpController.wallpaperOffsetsComplete(window)); 614 } 615 } 616 617 @Override setWallpaperDisplayOffset(IBinder window, int x, int y)618 public void setWallpaperDisplayOffset(IBinder window, int x, int y) { 619 synchronized (mService.mGlobalLock) { 620 final long ident = Binder.clearCallingIdentity(); 621 try { 622 actionOnWallpaper(window, (wpController, windowState) -> 623 wpController.setWindowWallpaperDisplayOffset(windowState, x, y)); 624 } finally { 625 Binder.restoreCallingIdentity(ident); 626 } 627 } 628 } 629 630 @Override sendWallpaperCommand(IBinder window, String action, int x, int y, int z, Bundle extras, boolean sync)631 public void sendWallpaperCommand(IBinder window, String action, int x, int y, 632 int z, Bundle extras, boolean sync) { 633 synchronized (mService.mGlobalLock) { 634 final long ident = Binder.clearCallingIdentity(); 635 try { 636 final WindowState windowState = mService.windowForClientLocked(this, window, true); 637 WallpaperController wallpaperController = 638 windowState.getDisplayContent().mWallpaperController; 639 if (mCanAlwaysUpdateWallpaper 640 || windowState == wallpaperController.getWallpaperTarget() 641 || windowState == wallpaperController.getPrevWallpaperTarget()) { 642 wallpaperController.sendWindowWallpaperCommandUnchecked( 643 windowState, action, x, y, z, extras, sync); 644 } 645 } finally { 646 Binder.restoreCallingIdentity(ident); 647 } 648 } 649 } 650 651 @Override wallpaperCommandComplete(IBinder window, Bundle result)652 public void wallpaperCommandComplete(IBinder window, Bundle result) { 653 synchronized (mService.mGlobalLock) { 654 actionOnWallpaper(window, (wpController, windowState) -> 655 wpController.wallpaperCommandComplete(window)); 656 } 657 } 658 659 @Override onRectangleOnScreenRequested(IBinder token, Rect rectangle)660 public void onRectangleOnScreenRequested(IBinder token, Rect rectangle) { 661 synchronized (mService.mGlobalLock) { 662 final long identity = Binder.clearCallingIdentity(); 663 try { 664 mService.onRectangleOnScreenRequested(token, rectangle); 665 } finally { 666 Binder.restoreCallingIdentity(identity); 667 } 668 } 669 } 670 671 @Override getWindowId(IBinder window)672 public IWindowId getWindowId(IBinder window) { 673 return mService.getWindowId(window); 674 } 675 676 @Override pokeDrawLock(IBinder window)677 public void pokeDrawLock(IBinder window) { 678 final long identity = Binder.clearCallingIdentity(); 679 try { 680 mService.pokeDrawLock(this, window); 681 } finally { 682 Binder.restoreCallingIdentity(identity); 683 } 684 } 685 686 @Override updateTapExcludeRegion(IWindow window, Region region)687 public void updateTapExcludeRegion(IWindow window, Region region) { 688 final long identity = Binder.clearCallingIdentity(); 689 try { 690 mService.updateTapExcludeRegion(window, region); 691 } finally { 692 Binder.restoreCallingIdentity(identity); 693 } 694 } 695 696 @Override updateRequestedVisibleTypes(IWindow window, @InsetsType int requestedVisibleTypes, @Nullable ImeTracker.Token imeStatsToken)697 public void updateRequestedVisibleTypes(IWindow window, @InsetsType int requestedVisibleTypes, 698 @Nullable ImeTracker.Token imeStatsToken) { 699 synchronized (mService.mGlobalLock) { 700 final WindowState win = mService.windowForClientLocked(this, window, 701 false /* throwOnError */); 702 if (win != null) { 703 if (android.view.inputmethod.Flags.refactorInsetsController()) { 704 ImeTracker.forLogging().onProgress(imeStatsToken, 705 ImeTracker.PHASE_WM_UPDATE_REQUESTED_VISIBLE_TYPES); 706 } 707 final @InsetsType int changedTypes = 708 win.setRequestedVisibleTypes(requestedVisibleTypes); 709 win.getDisplayContent().getInsetsPolicy().onRequestedVisibleTypesChanged(win, 710 changedTypes, imeStatsToken); 711 final Task task = win.getTask(); 712 if (task != null) { 713 task.dispatchTaskInfoChangedIfNeeded(/* forced= */ true); 714 } 715 } else { 716 EmbeddedWindowController.EmbeddedWindow embeddedWindow = null; 717 if (android.view.inputmethod.Flags.refactorInsetsController()) { 718 embeddedWindow = mService.mEmbeddedWindowController.getByWindowToken( 719 window.asBinder()); 720 } 721 if (embeddedWindow != null) { 722 // If there is no WindowState for the IWindow, it could be still an 723 // EmbeddedWindow. Therefore, check the EmbeddedWindowController as well 724 // TODO(b/353463205) Use different phase here 725 ImeTracker.forLogging().onProgress(imeStatsToken, 726 ImeTracker.PHASE_WM_UPDATE_REQUESTED_VISIBLE_TYPES); 727 final @InsetsType int changedTypes = embeddedWindow.setRequestedVisibleTypes( 728 requestedVisibleTypes & WindowInsets.Type.ime()); 729 embeddedWindow.getDisplayContent().getInsetsPolicy() 730 .onRequestedVisibleTypesChanged( 731 embeddedWindow, changedTypes, imeStatsToken); 732 } else { 733 ImeTracker.forLogging().onFailed(imeStatsToken, 734 ImeTracker.PHASE_WM_UPDATE_REQUESTED_VISIBLE_TYPES); 735 } 736 } 737 } 738 } 739 740 @Override updateAnimatingTypes(IWindow window, @InsetsType int animatingTypes, @Nullable ImeTracker.Token statsToken)741 public void updateAnimatingTypes(IWindow window, @InsetsType int animatingTypes, 742 @Nullable ImeTracker.Token statsToken) { 743 synchronized (mService.mGlobalLock) { 744 final WindowState win = mService.windowForClientLocked(this, window, 745 false /* throwOnError */); 746 if (win != null) { 747 ImeTracker.forLogging().onProgress(statsToken, 748 ImeTracker.PHASE_WM_UPDATE_ANIMATING_TYPES); 749 win.setAnimatingTypes(animatingTypes, statsToken); 750 } else { 751 ImeTracker.forLogging().onFailed(statsToken, 752 ImeTracker.PHASE_WM_UPDATE_ANIMATING_TYPES); 753 } 754 } 755 } 756 onWindowAdded(WindowState w)757 void onWindowAdded(WindowState w) { 758 if (mPackageName == null) { 759 mPackageName = mProcess.mInfo.packageName; 760 mRelayoutTag = "relayoutWindow: " + mPackageName; 761 } 762 if (mProcess.mWindowSession == null) { 763 if (DEBUG) { 764 Slog.v(TAG_WM, "First window added to " + mProcess); 765 } 766 mService.mSessions.add(this); 767 if (mLastReportedAnimatorScale != mService.getCurrentAnimatorScale()) { 768 mService.dispatchNewAnimatorScaleLocked(this); 769 } 770 mProcess.mWindowSession = this; 771 } 772 mAddedWindows.add(w); 773 } 774 onWindowRemoved(WindowState w)775 void onWindowRemoved(WindowState w) { 776 mAddedWindows.remove(w); 777 if (mAddedWindows.isEmpty()) { 778 killSessionLocked(); 779 } 780 } 781 hasWindow()782 boolean hasWindow() { 783 return !mAddedWindows.isEmpty(); 784 } 785 onWindowSurfaceVisibilityChanged(WindowState window, boolean visible)786 void onWindowSurfaceVisibilityChanged(WindowState window, boolean visible) { 787 final int type = window.mAttrs.type; 788 if (!isSystemAlertWindowType(type) && type != TYPE_SYSTEM_DIALOG) { 789 return; 790 } 791 792 boolean changed; 793 // Track non-system apps adding overlay/alert windows, so a notification can post for the 794 // user to control their visibility. 795 final boolean noSystemOverlayPermission = 796 !mCanAddInternalSystemWindow && !mCanCreateSystemApplicationOverlay; 797 if (visible) { 798 changed = mAlertWindows.add(window); 799 if (type == TYPE_APPLICATION_OVERLAY) { 800 MetricsLoggerWrapper.logAppOverlayEnter(mUid, mPackageName, changed, type, 801 false /* set false to only log for TYPE_APPLICATION_OVERLAY */); 802 } else if (noSystemOverlayPermission) { 803 MetricsLoggerWrapper.logAppOverlayEnter(mUid, mPackageName, changed, type, 804 true /* only log for non-TYPE_APPLICATION_OVERLAY */); 805 } 806 } else { 807 changed = mAlertWindows.remove(window); 808 if (type == TYPE_APPLICATION_OVERLAY) { 809 MetricsLoggerWrapper.logAppOverlayExit(mUid, mPackageName, changed, type, 810 false /* set false to only log for TYPE_APPLICATION_OVERLAY */); 811 } else if (noSystemOverlayPermission) { 812 MetricsLoggerWrapper.logAppOverlayExit(mUid, mPackageName, changed, type, 813 true /* only log for non-TYPE_APPLICATION_OVERLAY */); 814 } 815 } 816 817 if (changed && noSystemOverlayPermission) { 818 if (mAlertWindows.isEmpty()) { 819 cancelAlertWindowNotification(); 820 } else if (mAlertWindowNotification == null && !isSatellitePointingUiPackage()) { 821 mAlertWindowNotification = new AlertWindowNotification(mService, mPackageName); 822 if (mShowingAlertWindowNotificationAllowed) { 823 mAlertWindowNotification.post(); 824 } 825 } 826 } 827 828 if (changed && mPid != WindowManagerService.MY_PID) { 829 // Notify activity manager that the process contains overlay/alert windows, so it can 830 // adjust the importance score for the process. 831 setHasOverlayUi(!mAlertWindows.isEmpty()); 832 } 833 } 834 835 // TODO b/349195999 - short term solution to not show the satellite pointing ui notification. isSatellitePointingUiPackage()836 private boolean isSatellitePointingUiPackage() { 837 if (mPackageName == null || !mPackageName.equals(mService.mContext.getString( 838 com.android.internal.R.string.config_pointing_ui_package))) { 839 return false; 840 } 841 return ActivityTaskManagerService.checkPermission( 842 android.Manifest.permission.SATELLITE_COMMUNICATION, mPid, mUid) == PERMISSION_GRANTED; 843 } 844 setShowingAlertWindowNotificationAllowed(boolean allowed)845 void setShowingAlertWindowNotificationAllowed(boolean allowed) { 846 mShowingAlertWindowNotificationAllowed = allowed; 847 if (mAlertWindowNotification != null) { 848 if (allowed) { 849 mAlertWindowNotification.post(); 850 } else { 851 mAlertWindowNotification.cancel(false /* deleteChannel */); 852 } 853 } 854 } 855 killSessionLocked()856 private void killSessionLocked() { 857 if (!mClientDead) { 858 return; 859 } 860 861 mService.mSessions.remove(this); 862 if (mProcess.mWindowSession == null) { 863 return; 864 } 865 866 mProcess.mWindowSession = null; 867 mAddedWindows.clear(); 868 mAlertWindows.clear(); 869 setHasOverlayUi(false); 870 cancelAlertWindowNotification(); 871 } 872 873 @VisibleForTesting setHasOverlayUi(boolean hasOverlayUi)874 void setHasOverlayUi(boolean hasOverlayUi) { 875 mService.mH.obtainMessage(H.SET_HAS_OVERLAY_UI, mPid, hasOverlayUi ? 1 : 0).sendToTarget(); 876 } 877 cancelAlertWindowNotification()878 private void cancelAlertWindowNotification() { 879 if (mAlertWindowNotification == null) { 880 return; 881 } 882 mAlertWindowNotification.cancel(true /* deleteChannel */); 883 mAlertWindowNotification = null; 884 } 885 dump(PrintWriter pw, String prefix)886 void dump(PrintWriter pw, String prefix) { 887 pw.print(prefix); pw.print("numWindow="); pw.print(mAddedWindows.size()); 888 pw.print(" mCanAddInternalSystemWindow="); pw.print(mCanAddInternalSystemWindow); 889 pw.print(" mAlertWindows="); pw.print(mAlertWindows); 890 pw.print(" mClientDead="); pw.print(mClientDead); 891 pw.print(prefix); pw.print("mPackageName="); pw.println(mPackageName); 892 if (isSatellitePointingUiPackage()) { 893 pw.print(prefix); pw.println("mIsSatellitePointingUiPackage=true"); 894 } 895 } 896 897 @Override toString()898 public String toString() { 899 return mStringName; 900 } 901 902 /** @return {@code true} if there is an alert window surface on the given display. */ hasAlertWindowSurfaces(DisplayContent displayContent)903 boolean hasAlertWindowSurfaces(DisplayContent displayContent) { 904 for (int i = mAlertWindows.size() - 1; i >= 0; i--) { 905 final WindowState window = mAlertWindows.valueAt(i); 906 if (window.mDisplayContent == displayContent) { 907 return true; 908 } 909 } 910 return false; 911 } 912 913 @Override grantInputChannel(int displayId, SurfaceControl surface, IBinder clientToken, @Nullable InputTransferToken hostInputTransferToken, int flags, int privateFlags, int inputFeatures, int type, IBinder windowToken, InputTransferToken inputTransferToken, String inputHandleName, InputChannel outInputChannel)914 public void grantInputChannel(int displayId, SurfaceControl surface, 915 IBinder clientToken, @Nullable InputTransferToken hostInputTransferToken, int flags, 916 int privateFlags, int inputFeatures, int type, IBinder windowToken, 917 InputTransferToken inputTransferToken, String inputHandleName, 918 InputChannel outInputChannel) { 919 if (hostInputTransferToken == null && !mCanAddInternalSystemWindow) { 920 // Callers without INTERNAL_SYSTEM_WINDOW permission cannot grant input channel to 921 // embedded windows without providing a host window input token 922 throw new SecurityException("Requires INTERNAL_SYSTEM_WINDOW permission"); 923 } 924 925 final long identity = Binder.clearCallingIdentity(); 926 try { 927 mService.grantInputChannel(this, mUid, mPid, displayId, surface, clientToken, 928 hostInputTransferToken, flags, mCanAddInternalSystemWindow ? privateFlags : 0, 929 inputFeatures, type, windowToken, inputTransferToken, inputHandleName, 930 outInputChannel); 931 } finally { 932 Binder.restoreCallingIdentity(identity); 933 } 934 } 935 936 @Override updateInputChannel(IBinder channelToken, int displayId, SurfaceControl surface, int flags, int privateFlags, int inputFeatures, Region region)937 public void updateInputChannel(IBinder channelToken, int displayId, SurfaceControl surface, 938 int flags, int privateFlags, int inputFeatures, Region region) { 939 final long identity = Binder.clearCallingIdentity(); 940 try { 941 mService.updateInputChannel(channelToken, displayId, surface, flags, 942 mCanAddInternalSystemWindow ? privateFlags : 0, inputFeatures, region); 943 } finally { 944 Binder.restoreCallingIdentity(identity); 945 } 946 } 947 948 @Override grantEmbeddedWindowFocus(IWindow callingWindow, InputTransferToken targetInputToken, boolean grantFocus)949 public void grantEmbeddedWindowFocus(IWindow callingWindow, InputTransferToken targetInputToken, 950 boolean grantFocus) { 951 final long identity = Binder.clearCallingIdentity(); 952 try { 953 if (callingWindow == null) { 954 if (!mCanAddInternalSystemWindow) { 955 // Callers without INTERNAL_SYSTEM_WINDOW permission cannot request focus on 956 // embedded windows without providing the calling window 957 throw new SecurityException("Requires INTERNAL_SYSTEM_WINDOW permission"); 958 } 959 mService.grantEmbeddedWindowFocus(this, targetInputToken, grantFocus); 960 } else { 961 mService.grantEmbeddedWindowFocus(this, callingWindow, targetInputToken, 962 grantFocus); 963 } 964 } finally { 965 Binder.restoreCallingIdentity(identity); 966 } 967 } 968 969 @Override moveFocusToAdjacentWindow(IWindow fromWindow, @FocusDirection int direction)970 public boolean moveFocusToAdjacentWindow(IWindow fromWindow, @FocusDirection int direction) { 971 final long identity = Binder.clearCallingIdentity(); 972 try { 973 synchronized (mService.mGlobalLock) { 974 final WindowState win = 975 mService.windowForClientLocked(this, fromWindow, false /* throwOnError */); 976 if (win == null) { 977 return false; 978 } 979 return mService.moveFocusToAdjacentWindow(win, direction); 980 } 981 } finally { 982 Binder.restoreCallingIdentity(identity); 983 } 984 } 985 986 @Override generateDisplayHash(IWindow window, Rect boundsInWindow, String hashAlgorithm, RemoteCallback callback)987 public void generateDisplayHash(IWindow window, Rect boundsInWindow, String hashAlgorithm, 988 RemoteCallback callback) { 989 final long origId = Binder.clearCallingIdentity(); 990 try { 991 mService.generateDisplayHash(this, window, boundsInWindow, hashAlgorithm, callback); 992 } finally { 993 Binder.restoreCallingIdentity(origId); 994 } 995 } 996 997 @Override setOnBackInvokedCallbackInfo( IWindow window, OnBackInvokedCallbackInfo callbackInfo)998 public void setOnBackInvokedCallbackInfo( 999 IWindow window, 1000 OnBackInvokedCallbackInfo callbackInfo) { 1001 synchronized (mService.mGlobalLock) { 1002 WindowState windowState = mService.windowForClientLocked(this, window, false); 1003 if (windowState == null) { 1004 Slog.i(TAG_WM, 1005 "setOnBackInvokedCallback(): No window state for package:" + mPackageName); 1006 } else { 1007 windowState.setOnBackInvokedCallbackInfo(callbackInfo); 1008 } 1009 } 1010 } 1011 1012 @Override notifyImeWindowVisibilityChangedFromClient(IWindow window, boolean visible, @NonNull ImeTracker.Token statsToken)1013 public void notifyImeWindowVisibilityChangedFromClient(IWindow window, boolean visible, 1014 @NonNull ImeTracker.Token statsToken) { 1015 synchronized (mService.mGlobalLock) { 1016 // TODO(b/353463205) check if we can use mService.getDefaultDisplayContentLocked() 1017 // instead of window 1018 final WindowState win = mService.windowForClientLocked(this, window, 1019 false /* throwOnError */); 1020 if (win != null) { 1021 final InsetsStateController insetsStateController = 1022 win.getDisplayContent().getInsetsStateController(); 1023 ProtoLog.d(WM_DEBUG_IME, "notifyImeWindowVisibilityChangedFromClient: %s", 1024 insetsStateController.getImeSourceProvider()); 1025 ImeTracker.forLogging().onProgress(statsToken, 1026 ImeTracker.PHASE_WM_NOTIFY_IME_VISIBILITY_CHANGED_FROM_CLIENT); 1027 insetsStateController.getImeSourceProvider().receiveImeStatsToken(visible, 1028 statsToken); 1029 } else { 1030 ImeTracker.forLogging().onFailed(statsToken, 1031 ImeTracker.PHASE_WM_NOTIFY_IME_VISIBILITY_CHANGED_FROM_CLIENT); 1032 } 1033 } 1034 } 1035 } 1036