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 17package com.android.server.wm; 18 19import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG; 20import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING; 21import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS; 22import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS; 23import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 24 25import android.content.ClipData; 26import android.content.Context; 27import android.content.res.Configuration; 28import android.graphics.Rect; 29import android.graphics.Region; 30import android.os.Binder; 31import android.os.Bundle; 32import android.os.IBinder; 33import android.os.Parcel; 34import android.os.Process; 35import android.os.RemoteException; 36import android.os.ServiceManager; 37import android.os.UserHandle; 38import android.util.Slog; 39import android.view.Display; 40import android.view.IWindow; 41import android.view.IWindowId; 42import android.view.IWindowSession; 43import android.view.IWindowSessionCallback; 44import android.view.InputChannel; 45import android.view.Surface; 46import android.view.SurfaceControl; 47import android.view.SurfaceSession; 48import android.view.WindowManager; 49 50import com.android.internal.view.IInputContext; 51import com.android.internal.view.IInputMethodClient; 52import com.android.internal.view.IInputMethodManager; 53import com.android.server.wm.WindowManagerService.H; 54 55import java.io.PrintWriter; 56 57/** 58 * This class represents an active client session. There is generally one 59 * Session object per process that is interacting with the window manager. 60 */ 61final class Session extends IWindowSession.Stub 62 implements IBinder.DeathRecipient { 63 final WindowManagerService mService; 64 final IWindowSessionCallback mCallback; 65 final IInputMethodClient mClient; 66 final IInputContext mInputContext; 67 final int mUid; 68 final int mPid; 69 final String mStringName; 70 SurfaceSession mSurfaceSession; 71 int mNumWindow = 0; 72 boolean mClientDead = false; 73 float mLastReportedAnimatorScale; 74 75 public Session(WindowManagerService service, IWindowSessionCallback callback, 76 IInputMethodClient client, IInputContext inputContext) { 77 mService = service; 78 mCallback = callback; 79 mClient = client; 80 mInputContext = inputContext; 81 mUid = Binder.getCallingUid(); 82 mPid = Binder.getCallingPid(); 83 mLastReportedAnimatorScale = service.getCurrentAnimatorScale(); 84 StringBuilder sb = new StringBuilder(); 85 sb.append("Session{"); 86 sb.append(Integer.toHexString(System.identityHashCode(this))); 87 sb.append(" "); 88 sb.append(mPid); 89 if (mUid < Process.FIRST_APPLICATION_UID) { 90 sb.append(":"); 91 sb.append(mUid); 92 } else { 93 sb.append(":u"); 94 sb.append(UserHandle.getUserId(mUid)); 95 sb.append('a'); 96 sb.append(UserHandle.getAppId(mUid)); 97 } 98 sb.append("}"); 99 mStringName = sb.toString(); 100 101 synchronized (mService.mWindowMap) { 102 if (mService.mInputMethodManager == null && mService.mHaveInputMethods) { 103 IBinder b = ServiceManager.getService( 104 Context.INPUT_METHOD_SERVICE); 105 mService.mInputMethodManager = IInputMethodManager.Stub.asInterface(b); 106 } 107 } 108 long ident = Binder.clearCallingIdentity(); 109 try { 110 // Note: it is safe to call in to the input method manager 111 // here because we are not holding our lock. 112 if (mService.mInputMethodManager != null) { 113 mService.mInputMethodManager.addClient(client, inputContext, 114 mUid, mPid); 115 } else { 116 client.setUsingInputMethod(false); 117 } 118 client.asBinder().linkToDeath(this, 0); 119 } catch (RemoteException e) { 120 // The caller has died, so we can just forget about this. 121 try { 122 if (mService.mInputMethodManager != null) { 123 mService.mInputMethodManager.removeClient(client); 124 } 125 } catch (RemoteException ee) { 126 } 127 } finally { 128 Binder.restoreCallingIdentity(ident); 129 } 130 } 131 132 @Override 133 public boolean onTransact(int code, Parcel data, Parcel reply, int flags) 134 throws RemoteException { 135 try { 136 return super.onTransact(code, data, reply, flags); 137 } catch (RuntimeException e) { 138 // Log all 'real' exceptions thrown to the caller 139 if (!(e instanceof SecurityException)) { 140 Slog.wtf(TAG_WM, "Window Session Crash", e); 141 } 142 throw e; 143 } 144 } 145 146 public void binderDied() { 147 // Note: it is safe to call in to the input method manager 148 // here because we are not holding our lock. 149 try { 150 if (mService.mInputMethodManager != null) { 151 mService.mInputMethodManager.removeClient(mClient); 152 } 153 } catch (RemoteException e) { 154 } 155 synchronized(mService.mWindowMap) { 156 mClient.asBinder().unlinkToDeath(this, 0); 157 mClientDead = true; 158 killSessionLocked(); 159 } 160 } 161 162 @Override 163 public int add(IWindow window, int seq, WindowManager.LayoutParams attrs, 164 int viewVisibility, Rect outContentInsets, Rect outStableInsets, 165 InputChannel outInputChannel) { 166 return addToDisplay(window, seq, attrs, viewVisibility, Display.DEFAULT_DISPLAY, 167 outContentInsets, outStableInsets, null /* outOutsets */, outInputChannel); 168 } 169 170 @Override 171 public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs, 172 int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets, 173 Rect outOutsets, InputChannel outInputChannel) { 174 return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, 175 outContentInsets, outStableInsets, outOutsets, outInputChannel); 176 } 177 178 @Override 179 public int addWithoutInputChannel(IWindow window, int seq, WindowManager.LayoutParams attrs, 180 int viewVisibility, Rect outContentInsets, Rect outStableInsets) { 181 return addToDisplayWithoutInputChannel(window, seq, attrs, viewVisibility, 182 Display.DEFAULT_DISPLAY, outContentInsets, outStableInsets); 183 } 184 185 @Override 186 public int addToDisplayWithoutInputChannel(IWindow window, int seq, WindowManager.LayoutParams attrs, 187 int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets) { 188 return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, 189 outContentInsets, outStableInsets, null /* outOutsets */, null); 190 } 191 192 public void remove(IWindow window) { 193 mService.removeWindow(this, window); 194 } 195 196 @Override 197 public void repositionChild(IWindow window, int left, int top, int right, int bottom, 198 long deferTransactionUntilFrame, Rect outFrame) { 199 mService.repositionChild(this, window, left, top, right, bottom, 200 deferTransactionUntilFrame, outFrame); 201 } 202 203 @Override 204 public void prepareToReplaceWindows(IBinder appToken, boolean childrenOnly) { 205 mService.setReplacingWindows(appToken, childrenOnly); 206 } 207 208 public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs, 209 int requestedWidth, int requestedHeight, int viewFlags, 210 int flags, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets, 211 Rect outVisibleInsets, Rect outStableInsets, Rect outsets, Rect outBackdropFrame, 212 Configuration outConfig, Surface outSurface) { 213 if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from " 214 + Binder.getCallingPid()); 215 int res = mService.relayoutWindow(this, window, seq, attrs, 216 requestedWidth, requestedHeight, viewFlags, flags, 217 outFrame, outOverscanInsets, outContentInsets, outVisibleInsets, 218 outStableInsets, outsets, outBackdropFrame, outConfig, outSurface); 219 if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to " 220 + Binder.getCallingPid()); 221 return res; 222 } 223 224 public void performDeferredDestroy(IWindow window) { 225 mService.performDeferredDestroyWindow(this, window); 226 } 227 228 public boolean outOfMemory(IWindow window) { 229 return mService.outOfMemoryWindow(this, window); 230 } 231 232 public void setTransparentRegion(IWindow window, Region region) { 233 mService.setTransparentRegionWindow(this, window, region); 234 } 235 236 public void setInsets(IWindow window, int touchableInsets, 237 Rect contentInsets, Rect visibleInsets, Region touchableArea) { 238 mService.setInsetsWindow(this, window, touchableInsets, contentInsets, 239 visibleInsets, touchableArea); 240 } 241 242 public void getDisplayFrame(IWindow window, Rect outDisplayFrame) { 243 mService.getWindowDisplayFrame(this, window, outDisplayFrame); 244 } 245 246 public void finishDrawing(IWindow window) { 247 if (WindowManagerService.localLOGV) Slog.v( 248 TAG_WM, "IWindow finishDrawing called for " + window); 249 mService.finishDrawingWindow(this, window); 250 } 251 252 public void setInTouchMode(boolean mode) { 253 synchronized(mService.mWindowMap) { 254 mService.mInTouchMode = mode; 255 } 256 } 257 258 public boolean getInTouchMode() { 259 synchronized(mService.mWindowMap) { 260 return mService.mInTouchMode; 261 } 262 } 263 264 public boolean performHapticFeedback(IWindow window, int effectId, 265 boolean always) { 266 synchronized(mService.mWindowMap) { 267 long ident = Binder.clearCallingIdentity(); 268 try { 269 return mService.mPolicy.performHapticFeedbackLw( 270 mService.windowForClientLocked(this, window, true), 271 effectId, always); 272 } finally { 273 Binder.restoreCallingIdentity(ident); 274 } 275 } 276 } 277 278 /* Drag/drop */ 279 public IBinder prepareDrag(IWindow window, int flags, 280 int width, int height, Surface outSurface) { 281 return mService.prepareDragSurface(window, mSurfaceSession, flags, 282 width, height, outSurface); 283 } 284 285 public boolean performDrag(IWindow window, IBinder dragToken, 286 int touchSource, float touchX, float touchY, float thumbCenterX, float thumbCenterY, 287 ClipData data) { 288 if (DEBUG_DRAG) { 289 Slog.d(TAG_WM, "perform drag: win=" + window + " data=" + data); 290 } 291 292 synchronized (mService.mWindowMap) { 293 if (mService.mDragState == null) { 294 Slog.w(TAG_WM, "No drag prepared"); 295 throw new IllegalStateException("performDrag() without prepareDrag()"); 296 } 297 298 if (dragToken != mService.mDragState.mToken) { 299 Slog.w(TAG_WM, "Performing mismatched drag"); 300 throw new IllegalStateException("performDrag() does not match prepareDrag()"); 301 } 302 303 WindowState callingWin = mService.windowForClientLocked(null, window, false); 304 if (callingWin == null) { 305 Slog.w(TAG_WM, "Bad requesting window " + window); 306 return false; // !!! TODO: throw here? 307 } 308 309 // !!! TODO: if input is not still focused on the initiating window, fail 310 // the drag initiation (e.g. an alarm window popped up just as the application 311 // called performDrag() 312 313 mService.mH.removeMessages(H.DRAG_START_TIMEOUT, window.asBinder()); 314 315 // !!! TODO: extract the current touch (x, y) in screen coordinates. That 316 // will let us eliminate the (touchX,touchY) parameters from the API. 317 318 // !!! FIXME: put all this heavy stuff onto the mH looper, as well as 319 // the actual drag event dispatch stuff in the dragstate 320 321 final DisplayContent displayContent = callingWin.getDisplayContent(); 322 if (displayContent == null) { 323 return false; 324 } 325 Display display = displayContent.getDisplay(); 326 mService.mDragState.register(display); 327 mService.mInputMonitor.updateInputWindowsLw(true /*force*/); 328 if (!mService.mInputManager.transferTouchFocus(callingWin.mInputChannel, 329 mService.mDragState.mServerChannel)) { 330 Slog.e(TAG_WM, "Unable to transfer touch focus"); 331 mService.mDragState.unregister(); 332 mService.mDragState = null; 333 mService.mInputMonitor.updateInputWindowsLw(true /*force*/); 334 return false; 335 } 336 337 mService.mDragState.mData = data; 338 mService.mDragState.broadcastDragStartedLw(touchX, touchY); 339 mService.mDragState.overridePointerIconLw(touchSource); 340 341 // remember the thumb offsets for later 342 mService.mDragState.mThumbOffsetX = thumbCenterX; 343 mService.mDragState.mThumbOffsetY = thumbCenterY; 344 345 // Make the surface visible at the proper location 346 final SurfaceControl surfaceControl = mService.mDragState.mSurfaceControl; 347 if (SHOW_LIGHT_TRANSACTIONS) Slog.i( 348 TAG_WM, ">>> OPEN TRANSACTION performDrag"); 349 SurfaceControl.openTransaction(); 350 try { 351 surfaceControl.setPosition(touchX - thumbCenterX, 352 touchY - thumbCenterY); 353 surfaceControl.setLayer(mService.mDragState.getDragLayerLw()); 354 surfaceControl.setLayerStack(display.getLayerStack()); 355 surfaceControl.show(); 356 } finally { 357 SurfaceControl.closeTransaction(); 358 if (SHOW_LIGHT_TRANSACTIONS) Slog.i( 359 TAG_WM, "<<< CLOSE TRANSACTION performDrag"); 360 } 361 362 mService.mDragState.notifyLocationLw(touchX, touchY); 363 } 364 365 return true; // success! 366 } 367 368 public boolean startMovingTask(IWindow window, float startX, float startY) { 369 if (DEBUG_TASK_POSITIONING) Slog.d( 370 TAG_WM, "startMovingTask: {" + startX + "," + startY + "}"); 371 372 long ident = Binder.clearCallingIdentity(); 373 try { 374 return mService.startMovingTask(window, startX, startY); 375 } finally { 376 Binder.restoreCallingIdentity(ident); 377 } 378 } 379 380 public void reportDropResult(IWindow window, boolean consumed) { 381 IBinder token = window.asBinder(); 382 if (DEBUG_DRAG) { 383 Slog.d(TAG_WM, "Drop result=" + consumed + " reported by " + token); 384 } 385 386 synchronized (mService.mWindowMap) { 387 long ident = Binder.clearCallingIdentity(); 388 try { 389 if (mService.mDragState == null) { 390 // Most likely the drop recipient ANRed and we ended the drag 391 // out from under it. Log the issue and move on. 392 Slog.w(TAG_WM, "Drop result given but no drag in progress"); 393 return; 394 } 395 396 if (mService.mDragState.mToken != token) { 397 // We're in a drag, but the wrong window has responded. 398 Slog.w(TAG_WM, "Invalid drop-result claim by " + window); 399 throw new IllegalStateException("reportDropResult() by non-recipient"); 400 } 401 402 // The right window has responded, even if it's no longer around, 403 // so be sure to halt the timeout even if the later WindowState 404 // lookup fails. 405 mService.mH.removeMessages(H.DRAG_END_TIMEOUT, window.asBinder()); 406 WindowState callingWin = mService.windowForClientLocked(null, window, false); 407 if (callingWin == null) { 408 Slog.w(TAG_WM, "Bad result-reporting window " + window); 409 return; // !!! TODO: throw here? 410 } 411 412 mService.mDragState.mDragResult = consumed; 413 mService.mDragState.endDragLw(); 414 } finally { 415 Binder.restoreCallingIdentity(ident); 416 } 417 } 418 } 419 420 public void cancelDragAndDrop(IBinder dragToken) { 421 if (DEBUG_DRAG) { 422 Slog.d(TAG_WM, "cancelDragAndDrop"); 423 } 424 425 synchronized (mService.mWindowMap) { 426 long ident = Binder.clearCallingIdentity(); 427 try { 428 if (mService.mDragState == null) { 429 Slog.w(TAG_WM, "cancelDragAndDrop() without prepareDrag()"); 430 throw new IllegalStateException("cancelDragAndDrop() without prepareDrag()"); 431 } 432 433 if (mService.mDragState.mToken != dragToken) { 434 Slog.w(TAG_WM, 435 "cancelDragAndDrop() does not match prepareDrag()"); 436 throw new IllegalStateException( 437 "cancelDragAndDrop() does not match prepareDrag()"); 438 } 439 440 mService.mDragState.mDragResult = false; 441 mService.mDragState.cancelDragLw(); 442 } finally { 443 Binder.restoreCallingIdentity(ident); 444 } 445 } 446 } 447 448 public void dragRecipientEntered(IWindow window) { 449 if (DEBUG_DRAG) { 450 Slog.d(TAG_WM, "Drag into new candidate view @ " + window.asBinder()); 451 } 452 } 453 454 public void dragRecipientExited(IWindow window) { 455 if (DEBUG_DRAG) { 456 Slog.d(TAG_WM, "Drag from old candidate view @ " + window.asBinder()); 457 } 458 } 459 460 public void setWallpaperPosition(IBinder window, float x, float y, float xStep, float yStep) { 461 synchronized(mService.mWindowMap) { 462 long ident = Binder.clearCallingIdentity(); 463 try { 464 mService.mWallpaperControllerLocked.setWindowWallpaperPosition( 465 mService.windowForClientLocked(this, window, true), 466 x, y, xStep, yStep); 467 } finally { 468 Binder.restoreCallingIdentity(ident); 469 } 470 } 471 } 472 473 public void wallpaperOffsetsComplete(IBinder window) { 474 synchronized (mService.mWindowMap) { 475 mService.mWallpaperControllerLocked.wallpaperOffsetsComplete(window); 476 } 477 } 478 479 public void setWallpaperDisplayOffset(IBinder window, int x, int y) { 480 synchronized(mService.mWindowMap) { 481 long ident = Binder.clearCallingIdentity(); 482 try { 483 mService.mWallpaperControllerLocked.setWindowWallpaperDisplayOffset( 484 mService.windowForClientLocked(this, window, true), x, y); 485 } finally { 486 Binder.restoreCallingIdentity(ident); 487 } 488 } 489 } 490 491 public Bundle sendWallpaperCommand(IBinder window, String action, int x, int y, 492 int z, Bundle extras, boolean sync) { 493 synchronized(mService.mWindowMap) { 494 long ident = Binder.clearCallingIdentity(); 495 try { 496 return mService.mWallpaperControllerLocked.sendWindowWallpaperCommand( 497 mService.windowForClientLocked(this, window, true), 498 action, x, y, z, extras, sync); 499 } finally { 500 Binder.restoreCallingIdentity(ident); 501 } 502 } 503 } 504 505 public void wallpaperCommandComplete(IBinder window, Bundle result) { 506 synchronized (mService.mWindowMap) { 507 mService.mWallpaperControllerLocked.wallpaperCommandComplete(window); 508 } 509 } 510 511 public void onRectangleOnScreenRequested(IBinder token, Rect rectangle) { 512 synchronized(mService.mWindowMap) { 513 final long identity = Binder.clearCallingIdentity(); 514 try { 515 mService.onRectangleOnScreenRequested(token, rectangle); 516 } finally { 517 Binder.restoreCallingIdentity(identity); 518 } 519 } 520 } 521 522 public IWindowId getWindowId(IBinder window) { 523 return mService.getWindowId(window); 524 } 525 526 @Override 527 public void pokeDrawLock(IBinder window) { 528 final long identity = Binder.clearCallingIdentity(); 529 try { 530 mService.pokeDrawLock(this, window); 531 } finally { 532 Binder.restoreCallingIdentity(identity); 533 } 534 } 535 536 @Override 537 public void updatePointerIcon(IWindow window) { 538 final long identity = Binder.clearCallingIdentity(); 539 try { 540 mService.updatePointerIcon(window); 541 } finally { 542 Binder.restoreCallingIdentity(identity); 543 } 544 } 545 546 void windowAddedLocked() { 547 if (mSurfaceSession == null) { 548 if (WindowManagerService.localLOGV) Slog.v( 549 TAG_WM, "First window added to " + this + ", creating SurfaceSession"); 550 mSurfaceSession = new SurfaceSession(); 551 if (SHOW_TRANSACTIONS) Slog.i( 552 TAG_WM, " NEW SURFACE SESSION " + mSurfaceSession); 553 mService.mSessions.add(this); 554 if (mLastReportedAnimatorScale != mService.getCurrentAnimatorScale()) { 555 mService.dispatchNewAnimatorScaleLocked(this); 556 } 557 } 558 mNumWindow++; 559 } 560 561 void windowRemovedLocked() { 562 mNumWindow--; 563 killSessionLocked(); 564 } 565 566 void killSessionLocked() { 567 if (mNumWindow <= 0 && mClientDead) { 568 mService.mSessions.remove(this); 569 if (mSurfaceSession != null) { 570 if (WindowManagerService.localLOGV) Slog.v( 571 TAG_WM, "Last window removed from " + this 572 + ", destroying " + mSurfaceSession); 573 if (SHOW_TRANSACTIONS) Slog.i( 574 TAG_WM, " KILL SURFACE SESSION " + mSurfaceSession); 575 try { 576 mSurfaceSession.kill(); 577 } catch (Exception e) { 578 Slog.w(TAG_WM, "Exception thrown when killing surface session " 579 + mSurfaceSession + " in session " + this 580 + ": " + e.toString()); 581 } 582 mSurfaceSession = null; 583 } 584 } 585 } 586 587 void dump(PrintWriter pw, String prefix) { 588 pw.print(prefix); pw.print("mNumWindow="); pw.print(mNumWindow); 589 pw.print(" mClientDead="); pw.print(mClientDead); 590 pw.print(" mSurfaceSession="); pw.println(mSurfaceSession); 591 } 592 593 @Override 594 public String toString() { 595 return mStringName; 596 } 597} 598