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