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