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