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