Session.java revision e8069dcfcff15e060fc397b9ed5ea8b915b1cfa7
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.setLayer(mService.mDragState.getDragLayerLw()); 338 surfaceControl.setLayerStack(display.getLayerStack()); 339 surfaceControl.show(); 340 } finally { 341 SurfaceControl.closeTransaction(); 342 if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS) Slog.i( 343 WindowManagerService.TAG, "<<< CLOSE TRANSACTION performDrag"); 344 } 345 } 346 347 return true; // success! 348 } 349 350 public void reportDropResult(IWindow window, boolean consumed) { 351 IBinder token = window.asBinder(); 352 if (WindowManagerService.DEBUG_DRAG) { 353 Slog.d(WindowManagerService.TAG, "Drop result=" + consumed + " reported by " + token); 354 } 355 356 synchronized (mService.mWindowMap) { 357 long ident = Binder.clearCallingIdentity(); 358 try { 359 if (mService.mDragState == null) { 360 // Most likely the drop recipient ANRed and we ended the drag 361 // out from under it. Log the issue and move on. 362 Slog.w(WindowManagerService.TAG, "Drop result given but no drag in progress"); 363 return; 364 } 365 366 if (mService.mDragState.mToken != token) { 367 // We're in a drag, but the wrong window has responded. 368 Slog.w(WindowManagerService.TAG, "Invalid drop-result claim by " + window); 369 throw new IllegalStateException("reportDropResult() by non-recipient"); 370 } 371 372 // The right window has responded, even if it's no longer around, 373 // so be sure to halt the timeout even if the later WindowState 374 // lookup fails. 375 mService.mH.removeMessages(H.DRAG_END_TIMEOUT, window.asBinder()); 376 WindowState callingWin = mService.windowForClientLocked(null, window, false); 377 if (callingWin == null) { 378 Slog.w(WindowManagerService.TAG, "Bad result-reporting window " + window); 379 return; // !!! TODO: throw here? 380 } 381 382 mService.mDragState.mDragResult = consumed; 383 mService.mDragState.endDragLw(); 384 } finally { 385 Binder.restoreCallingIdentity(ident); 386 } 387 } 388 } 389 390 public void dragRecipientEntered(IWindow window) { 391 if (WindowManagerService.DEBUG_DRAG) { 392 Slog.d(WindowManagerService.TAG, "Drag into new candidate view @ " + window.asBinder()); 393 } 394 } 395 396 public void dragRecipientExited(IWindow window) { 397 if (WindowManagerService.DEBUG_DRAG) { 398 Slog.d(WindowManagerService.TAG, "Drag from old candidate view @ " + window.asBinder()); 399 } 400 } 401 402 public void setWallpaperPosition(IBinder window, float x, float y, float xStep, float yStep) { 403 synchronized(mService.mWindowMap) { 404 long ident = Binder.clearCallingIdentity(); 405 try { 406 mService.mWallpaperControllerLocked.setWindowWallpaperPosition( 407 mService.windowForClientLocked(this, window, true), 408 x, y, xStep, yStep); 409 } finally { 410 Binder.restoreCallingIdentity(ident); 411 } 412 } 413 } 414 415 public void wallpaperOffsetsComplete(IBinder window) { 416 synchronized (mService.mWindowMap) { 417 mService.mWallpaperControllerLocked.wallpaperOffsetsComplete(window); 418 } 419 } 420 421 public void setWallpaperDisplayOffset(IBinder window, int x, int y) { 422 synchronized(mService.mWindowMap) { 423 long ident = Binder.clearCallingIdentity(); 424 try { 425 mService.mWallpaperControllerLocked.setWindowWallpaperDisplayOffset( 426 mService.windowForClientLocked(this, window, true), x, y); 427 } finally { 428 Binder.restoreCallingIdentity(ident); 429 } 430 } 431 } 432 433 public Bundle sendWallpaperCommand(IBinder window, String action, int x, int y, 434 int z, Bundle extras, boolean sync) { 435 synchronized(mService.mWindowMap) { 436 long ident = Binder.clearCallingIdentity(); 437 try { 438 return mService.mWallpaperControllerLocked.sendWindowWallpaperCommand( 439 mService.windowForClientLocked(this, window, true), 440 action, x, y, z, extras, sync); 441 } finally { 442 Binder.restoreCallingIdentity(ident); 443 } 444 } 445 } 446 447 public void wallpaperCommandComplete(IBinder window, Bundle result) { 448 synchronized (mService.mWindowMap) { 449 mService.mWallpaperControllerLocked.wallpaperCommandComplete(window); 450 } 451 } 452 453 public void onRectangleOnScreenRequested(IBinder token, Rect rectangle) { 454 synchronized(mService.mWindowMap) { 455 final long identity = Binder.clearCallingIdentity(); 456 try { 457 mService.onRectangleOnScreenRequested(token, rectangle); 458 } finally { 459 Binder.restoreCallingIdentity(identity); 460 } 461 } 462 } 463 464 public IWindowId getWindowId(IBinder window) { 465 return mService.getWindowId(window); 466 } 467 468 @Override 469 public void pokeDrawLock(IBinder window) { 470 final long identity = Binder.clearCallingIdentity(); 471 try { 472 mService.pokeDrawLock(this, window); 473 } finally { 474 Binder.restoreCallingIdentity(identity); 475 } 476 } 477 478 void windowAddedLocked() { 479 if (mSurfaceSession == null) { 480 if (WindowManagerService.localLOGV) Slog.v( 481 WindowManagerService.TAG, "First window added to " + this + ", creating SurfaceSession"); 482 mSurfaceSession = new SurfaceSession(); 483 if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i( 484 WindowManagerService.TAG, " NEW SURFACE SESSION " + mSurfaceSession); 485 mService.mSessions.add(this); 486 if (mLastReportedAnimatorScale != mService.getCurrentAnimatorScale()) { 487 mService.dispatchNewAnimatorScaleLocked(this); 488 } 489 } 490 mNumWindow++; 491 } 492 493 void windowRemovedLocked() { 494 mNumWindow--; 495 killSessionLocked(); 496 } 497 498 void killSessionLocked() { 499 if (mNumWindow <= 0 && mClientDead) { 500 mService.mSessions.remove(this); 501 if (mSurfaceSession != null) { 502 if (WindowManagerService.localLOGV) Slog.v( 503 WindowManagerService.TAG, "Last window removed from " + this 504 + ", destroying " + mSurfaceSession); 505 if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i( 506 WindowManagerService.TAG, " KILL SURFACE SESSION " + mSurfaceSession); 507 try { 508 mSurfaceSession.kill(); 509 } catch (Exception e) { 510 Slog.w(WindowManagerService.TAG, "Exception thrown when killing surface session " 511 + mSurfaceSession + " in session " + this 512 + ": " + e.toString()); 513 } 514 mSurfaceSession = null; 515 } 516 } 517 } 518 519 void dump(PrintWriter pw, String prefix) { 520 pw.print(prefix); pw.print("mNumWindow="); pw.print(mNumWindow); 521 pw.print(" mClientDead="); pw.print(mClientDead); 522 pw.print(" mSurfaceSession="); pw.println(mSurfaceSession); 523 } 524 525 @Override 526 public String toString() { 527 return mStringName; 528 } 529} 530