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