Session.java revision 2e95a488e0a12d4263d101e888fdd89fd123aec3
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 public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs, 204 int requestedWidth, int requestedHeight, int viewFlags, 205 int flags, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets, 206 Rect outVisibleInsets, Rect outStableInsets, Rect outsets, Rect outBackdropFrame, 207 Configuration outConfig, Surface outSurface) { 208 if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from " 209 + Binder.getCallingPid()); 210 int res = mService.relayoutWindow(this, window, seq, attrs, 211 requestedWidth, requestedHeight, viewFlags, flags, 212 outFrame, outOverscanInsets, outContentInsets, outVisibleInsets, 213 outStableInsets, outsets, outBackdropFrame, outConfig, outSurface); 214 if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to " 215 + Binder.getCallingPid()); 216 return res; 217 } 218 219 public void performDeferredDestroy(IWindow window) { 220 mService.performDeferredDestroyWindow(this, window); 221 } 222 223 public boolean outOfMemory(IWindow window) { 224 return mService.outOfMemoryWindow(this, window); 225 } 226 227 public void setTransparentRegion(IWindow window, Region region) { 228 mService.setTransparentRegionWindow(this, window, region); 229 } 230 231 public void setInsets(IWindow window, int touchableInsets, 232 Rect contentInsets, Rect visibleInsets, Region touchableArea) { 233 mService.setInsetsWindow(this, window, touchableInsets, contentInsets, 234 visibleInsets, touchableArea); 235 } 236 237 public void getDisplayFrame(IWindow window, Rect outDisplayFrame) { 238 mService.getWindowDisplayFrame(this, window, outDisplayFrame); 239 } 240 241 public void finishDrawing(IWindow window) { 242 if (WindowManagerService.localLOGV) Slog.v( 243 TAG_WM, "IWindow finishDrawing called for " + window); 244 mService.finishDrawingWindow(this, window); 245 } 246 247 public void setInTouchMode(boolean mode) { 248 synchronized(mService.mWindowMap) { 249 mService.mInTouchMode = mode; 250 } 251 } 252 253 public boolean getInTouchMode() { 254 synchronized(mService.mWindowMap) { 255 return mService.mInTouchMode; 256 } 257 } 258 259 public boolean performHapticFeedback(IWindow window, int effectId, 260 boolean always) { 261 synchronized(mService.mWindowMap) { 262 long ident = Binder.clearCallingIdentity(); 263 try { 264 return mService.mPolicy.performHapticFeedbackLw( 265 mService.windowForClientLocked(this, window, true), 266 effectId, always); 267 } finally { 268 Binder.restoreCallingIdentity(ident); 269 } 270 } 271 } 272 273 /* Drag/drop */ 274 public IBinder prepareDrag(IWindow window, int flags, 275 int width, int height, Surface outSurface) { 276 return mService.prepareDragSurface(window, mSurfaceSession, flags, 277 width, height, outSurface); 278 } 279 280 public boolean performDrag(IWindow window, IBinder dragToken, 281 float touchX, float touchY, float thumbCenterX, float thumbCenterY, 282 ClipData data) { 283 if (DEBUG_DRAG) { 284 Slog.d(TAG_WM, "perform drag: win=" + window + " data=" + data); 285 } 286 287 synchronized (mService.mWindowMap) { 288 if (mService.mDragState == null) { 289 Slog.w(TAG_WM, "No drag prepared"); 290 throw new IllegalStateException("performDrag() without prepareDrag()"); 291 } 292 293 if (dragToken != mService.mDragState.mToken) { 294 Slog.w(TAG_WM, "Performing mismatched drag"); 295 throw new IllegalStateException("performDrag() does not match prepareDrag()"); 296 } 297 298 WindowState callingWin = mService.windowForClientLocked(null, window, false); 299 if (callingWin == null) { 300 Slog.w(TAG_WM, "Bad requesting window " + window); 301 return false; // !!! TODO: throw here? 302 } 303 304 // !!! TODO: if input is not still focused on the initiating window, fail 305 // the drag initiation (e.g. an alarm window popped up just as the application 306 // called performDrag() 307 308 mService.mH.removeMessages(H.DRAG_START_TIMEOUT, window.asBinder()); 309 310 // !!! TODO: extract the current touch (x, y) in screen coordinates. That 311 // will let us eliminate the (touchX,touchY) parameters from the API. 312 313 // !!! FIXME: put all this heavy stuff onto the mH looper, as well as 314 // the actual drag event dispatch stuff in the dragstate 315 316 final DisplayContent displayContent = callingWin.getDisplayContent(); 317 if (displayContent == null) { 318 return false; 319 } 320 Display display = displayContent.getDisplay(); 321 mService.mDragState.register(display); 322 mService.mInputMonitor.updateInputWindowsLw(true /*force*/); 323 if (!mService.mInputManager.transferTouchFocus(callingWin.mInputChannel, 324 mService.mDragState.mServerChannel)) { 325 Slog.e(TAG_WM, "Unable to transfer touch focus"); 326 mService.mDragState.unregister(); 327 mService.mDragState = null; 328 mService.mInputMonitor.updateInputWindowsLw(true /*force*/); 329 return false; 330 } 331 332 mService.mDragState.mData = data; 333 mService.mDragState.broadcastDragStartedLw(touchX, touchY); 334 335 // remember the thumb offsets for later 336 mService.mDragState.mThumbOffsetX = thumbCenterX; 337 mService.mDragState.mThumbOffsetY = thumbCenterY; 338 339 // Make the surface visible at the proper location 340 final SurfaceControl surfaceControl = mService.mDragState.mSurfaceControl; 341 if (SHOW_LIGHT_TRANSACTIONS) Slog.i( 342 TAG_WM, ">>> OPEN TRANSACTION performDrag"); 343 SurfaceControl.openTransaction(); 344 try { 345 surfaceControl.setPosition(touchX - thumbCenterX, 346 touchY - thumbCenterY); 347 surfaceControl.setLayer(mService.mDragState.getDragLayerLw()); 348 surfaceControl.setLayerStack(display.getLayerStack()); 349 surfaceControl.show(); 350 } finally { 351 SurfaceControl.closeTransaction(); 352 if (SHOW_LIGHT_TRANSACTIONS) Slog.i( 353 TAG_WM, "<<< CLOSE TRANSACTION performDrag"); 354 } 355 } 356 357 return true; // success! 358 } 359 360 public boolean startMovingTask(IWindow window, float startX, float startY) { 361 if (DEBUG_TASK_POSITIONING) Slog.d( 362 TAG_WM, "startMovingTask: {" + startX + "," + startY + "}"); 363 364 return mService.startMovingTask(window, startX, startY); 365 } 366 367 public void reportDropResult(IWindow window, boolean consumed) { 368 IBinder token = window.asBinder(); 369 if (DEBUG_DRAG) { 370 Slog.d(TAG_WM, "Drop result=" + consumed + " reported by " + token); 371 } 372 373 synchronized (mService.mWindowMap) { 374 long ident = Binder.clearCallingIdentity(); 375 try { 376 if (mService.mDragState == null) { 377 // Most likely the drop recipient ANRed and we ended the drag 378 // out from under it. Log the issue and move on. 379 Slog.w(TAG_WM, "Drop result given but no drag in progress"); 380 return; 381 } 382 383 if (mService.mDragState.mToken != token) { 384 // We're in a drag, but the wrong window has responded. 385 Slog.w(TAG_WM, "Invalid drop-result claim by " + window); 386 throw new IllegalStateException("reportDropResult() by non-recipient"); 387 } 388 389 // The right window has responded, even if it's no longer around, 390 // so be sure to halt the timeout even if the later WindowState 391 // lookup fails. 392 mService.mH.removeMessages(H.DRAG_END_TIMEOUT, window.asBinder()); 393 WindowState callingWin = mService.windowForClientLocked(null, window, false); 394 if (callingWin == null) { 395 Slog.w(TAG_WM, "Bad result-reporting window " + window); 396 return; // !!! TODO: throw here? 397 } 398 399 mService.mDragState.mDragResult = consumed; 400 mService.mDragState.endDragLw(); 401 } finally { 402 Binder.restoreCallingIdentity(ident); 403 } 404 } 405 } 406 407 public void cancelDragAndDrop(IBinder dragToken) { 408 if (DEBUG_DRAG) { 409 Slog.d(TAG_WM, "cancelDragAndDrop"); 410 } 411 412 synchronized (mService.mWindowMap) { 413 long ident = Binder.clearCallingIdentity(); 414 try { 415 if (mService.mDragState == null) { 416 Slog.w(TAG_WM, "cancelDragAndDrop() without prepareDrag()"); 417 throw new IllegalStateException("cancelDragAndDrop() without prepareDrag()"); 418 } 419 420 if (mService.mDragState.mToken != dragToken) { 421 Slog.w(TAG_WM, 422 "cancelDragAndDrop() does not match prepareDrag()"); 423 throw new IllegalStateException( 424 "cancelDragAndDrop() does not match prepareDrag()"); 425 } 426 427 mService.mDragState.mDragResult = false; 428 mService.mDragState.cancelDragLw(); 429 } finally { 430 Binder.restoreCallingIdentity(ident); 431 } 432 } 433 } 434 435 public void dragRecipientEntered(IWindow window) { 436 if (DEBUG_DRAG) { 437 Slog.d(TAG_WM, "Drag into new candidate view @ " + window.asBinder()); 438 } 439 } 440 441 public void dragRecipientExited(IWindow window) { 442 if (DEBUG_DRAG) { 443 Slog.d(TAG_WM, "Drag from old candidate view @ " + window.asBinder()); 444 } 445 } 446 447 public void setWallpaperPosition(IBinder window, float x, float y, float xStep, float yStep) { 448 synchronized(mService.mWindowMap) { 449 long ident = Binder.clearCallingIdentity(); 450 try { 451 mService.mWallpaperControllerLocked.setWindowWallpaperPosition( 452 mService.windowForClientLocked(this, window, true), 453 x, y, xStep, yStep); 454 } finally { 455 Binder.restoreCallingIdentity(ident); 456 } 457 } 458 } 459 460 public void wallpaperOffsetsComplete(IBinder window) { 461 synchronized (mService.mWindowMap) { 462 mService.mWallpaperControllerLocked.wallpaperOffsetsComplete(window); 463 } 464 } 465 466 public void setWallpaperDisplayOffset(IBinder window, int x, int y) { 467 synchronized(mService.mWindowMap) { 468 long ident = Binder.clearCallingIdentity(); 469 try { 470 mService.mWallpaperControllerLocked.setWindowWallpaperDisplayOffset( 471 mService.windowForClientLocked(this, window, true), x, y); 472 } finally { 473 Binder.restoreCallingIdentity(ident); 474 } 475 } 476 } 477 478 public Bundle sendWallpaperCommand(IBinder window, String action, int x, int y, 479 int z, Bundle extras, boolean sync) { 480 synchronized(mService.mWindowMap) { 481 long ident = Binder.clearCallingIdentity(); 482 try { 483 return mService.mWallpaperControllerLocked.sendWindowWallpaperCommand( 484 mService.windowForClientLocked(this, window, true), 485 action, x, y, z, extras, sync); 486 } finally { 487 Binder.restoreCallingIdentity(ident); 488 } 489 } 490 } 491 492 public void wallpaperCommandComplete(IBinder window, Bundle result) { 493 synchronized (mService.mWindowMap) { 494 mService.mWallpaperControllerLocked.wallpaperCommandComplete(window); 495 } 496 } 497 498 public void onRectangleOnScreenRequested(IBinder token, Rect rectangle) { 499 synchronized(mService.mWindowMap) { 500 final long identity = Binder.clearCallingIdentity(); 501 try { 502 mService.onRectangleOnScreenRequested(token, rectangle); 503 } finally { 504 Binder.restoreCallingIdentity(identity); 505 } 506 } 507 } 508 509 public IWindowId getWindowId(IBinder window) { 510 return mService.getWindowId(window); 511 } 512 513 @Override 514 public void pokeDrawLock(IBinder window) { 515 final long identity = Binder.clearCallingIdentity(); 516 try { 517 mService.pokeDrawLock(this, window); 518 } finally { 519 Binder.restoreCallingIdentity(identity); 520 } 521 } 522 523 void windowAddedLocked() { 524 if (mSurfaceSession == null) { 525 if (WindowManagerService.localLOGV) Slog.v( 526 TAG_WM, "First window added to " + this + ", creating SurfaceSession"); 527 mSurfaceSession = new SurfaceSession(); 528 if (SHOW_TRANSACTIONS) Slog.i( 529 TAG_WM, " NEW SURFACE SESSION " + mSurfaceSession); 530 mService.mSessions.add(this); 531 if (mLastReportedAnimatorScale != mService.getCurrentAnimatorScale()) { 532 mService.dispatchNewAnimatorScaleLocked(this); 533 } 534 } 535 mNumWindow++; 536 } 537 538 void windowRemovedLocked() { 539 mNumWindow--; 540 killSessionLocked(); 541 } 542 543 void killSessionLocked() { 544 if (mNumWindow <= 0 && mClientDead) { 545 mService.mSessions.remove(this); 546 if (mSurfaceSession != null) { 547 if (WindowManagerService.localLOGV) Slog.v( 548 TAG_WM, "Last window removed from " + this 549 + ", destroying " + mSurfaceSession); 550 if (SHOW_TRANSACTIONS) Slog.i( 551 TAG_WM, " KILL SURFACE SESSION " + mSurfaceSession); 552 try { 553 mSurfaceSession.kill(); 554 } catch (Exception e) { 555 Slog.w(TAG_WM, "Exception thrown when killing surface session " 556 + mSurfaceSession + " in session " + this 557 + ": " + e.toString()); 558 } 559 mSurfaceSession = null; 560 } 561 } 562 } 563 564 void dump(PrintWriter pw, String prefix) { 565 pw.print(prefix); pw.print("mNumWindow="); pw.print(mNumWindow); 566 pw.print(" mClientDead="); pw.print(mClientDead); 567 pw.print(" mSurfaceSession="); pw.println(mSurfaceSession); 568 } 569 570 @Override 571 public String toString() { 572 return mStringName; 573 } 574} 575