Session.java revision df88d73092c62a1a3cd2b2056ca63ae2e70cc238
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 com.android.internal.view.IInputContext; 21import com.android.internal.view.IInputMethodClient; 22import com.android.internal.view.IInputMethodManager; 23import com.android.server.wm.WindowManagerService.H; 24 25import android.content.ClipData; 26import android.content.Context; 27import android.content.res.Configuration; 28import android.graphics.Rect; 29import android.graphics.Region; 30import android.os.Binder; 31import android.os.Bundle; 32import android.os.IBinder; 33import android.os.Parcel; 34import android.os.Process; 35import android.os.RemoteException; 36import android.os.ServiceManager; 37import android.os.UserHandle; 38import android.util.Slog; 39import android.view.Display; 40import android.view.IWindow; 41import android.view.IWindowSession; 42import android.view.InputChannel; 43import android.view.Surface; 44import android.view.SurfaceControl; 45import android.view.SurfaceSession; 46import android.view.WindowManager; 47 48import java.io.PrintWriter; 49 50/** 51 * This class represents an active client session. There is generally one 52 * Session object per process that is interacting with the window manager. 53 */ 54final class Session extends IWindowSession.Stub 55 implements IBinder.DeathRecipient { 56 final WindowManagerService mService; 57 final IInputMethodClient mClient; 58 final IInputContext mInputContext; 59 final int mUid; 60 final int mPid; 61 final String mStringName; 62 SurfaceSession mSurfaceSession; 63 int mNumWindow = 0; 64 boolean mClientDead = false; 65 66 public Session(WindowManagerService service, IInputMethodClient client, 67 IInputContext inputContext) { 68 mService = service; 69 mClient = client; 70 mInputContext = inputContext; 71 mUid = Binder.getCallingUid(); 72 mPid = Binder.getCallingPid(); 73 StringBuilder sb = new StringBuilder(); 74 sb.append("Session{"); 75 sb.append(Integer.toHexString(System.identityHashCode(this))); 76 sb.append(" "); 77 sb.append(mPid); 78 if (mUid < Process.FIRST_APPLICATION_UID) { 79 sb.append(":"); 80 sb.append(mUid); 81 } else { 82 sb.append(":u"); 83 sb.append(UserHandle.getUserId(mUid)); 84 sb.append('a'); 85 sb.append(UserHandle.getAppId(mUid)); 86 } 87 sb.append("}"); 88 mStringName = sb.toString(); 89 90 synchronized (mService.mWindowMap) { 91 if (mService.mInputMethodManager == null && mService.mHaveInputMethods) { 92 IBinder b = ServiceManager.getService( 93 Context.INPUT_METHOD_SERVICE); 94 mService.mInputMethodManager = IInputMethodManager.Stub.asInterface(b); 95 } 96 } 97 long ident = Binder.clearCallingIdentity(); 98 try { 99 // Note: it is safe to call in to the input method manager 100 // here because we are not holding our lock. 101 if (mService.mInputMethodManager != null) { 102 mService.mInputMethodManager.addClient(client, inputContext, 103 mUid, mPid); 104 } else { 105 client.setUsingInputMethod(false); 106 } 107 client.asBinder().linkToDeath(this, 0); 108 } catch (RemoteException e) { 109 // The caller has died, so we can just forget about this. 110 try { 111 if (mService.mInputMethodManager != null) { 112 mService.mInputMethodManager.removeClient(client); 113 } 114 } catch (RemoteException ee) { 115 } 116 } finally { 117 Binder.restoreCallingIdentity(ident); 118 } 119 } 120 121 @Override 122 public boolean onTransact(int code, Parcel data, Parcel reply, int flags) 123 throws RemoteException { 124 try { 125 return super.onTransact(code, data, reply, flags); 126 } catch (RuntimeException e) { 127 // Log all 'real' exceptions thrown to the caller 128 if (!(e instanceof SecurityException)) { 129 Slog.wtf(WindowManagerService.TAG, "Window Session Crash", e); 130 } 131 throw e; 132 } 133 } 134 135 public void binderDied() { 136 // Note: it is safe to call in to the input method manager 137 // here because we are not holding our lock. 138 try { 139 if (mService.mInputMethodManager != null) { 140 mService.mInputMethodManager.removeClient(mClient); 141 } 142 } catch (RemoteException e) { 143 } 144 synchronized(mService.mWindowMap) { 145 mClient.asBinder().unlinkToDeath(this, 0); 146 mClientDead = true; 147 killSessionLocked(); 148 } 149 } 150 151 @Override 152 public int add(IWindow window, int seq, WindowManager.LayoutParams attrs, 153 int viewVisibility, Rect outContentInsets, InputChannel outInputChannel) { 154 return addToDisplay(window, seq, attrs, viewVisibility, Display.DEFAULT_DISPLAY, 155 outContentInsets, outInputChannel); 156 } 157 158 @Override 159 public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs, 160 int viewVisibility, int displayId, Rect outContentInsets, 161 InputChannel outInputChannel) { 162 return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, 163 outContentInsets, outInputChannel); 164 } 165 166 @Override 167 public int addWithoutInputChannel(IWindow window, int seq, WindowManager.LayoutParams attrs, 168 int viewVisibility, Rect outContentInsets) { 169 return addToDisplayWithoutInputChannel(window, seq, attrs, viewVisibility, 170 Display.DEFAULT_DISPLAY, outContentInsets); 171 } 172 173 @Override 174 public int addToDisplayWithoutInputChannel(IWindow window, int seq, WindowManager.LayoutParams attrs, 175 int viewVisibility, int displayId, Rect outContentInsets) { 176 return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, 177 outContentInsets, null); 178 } 179 180 public void remove(IWindow window) { 181 mService.removeWindow(this, window); 182 } 183 184 public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs, 185 int requestedWidth, int requestedHeight, int viewFlags, 186 int flags, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets, 187 Rect outVisibleInsets, Configuration outConfig, Surface outSurface) { 188 if (false) Slog.d(WindowManagerService.TAG, ">>>>>> ENTERED relayout from " 189 + Binder.getCallingPid()); 190 int res = mService.relayoutWindow(this, window, seq, attrs, 191 requestedWidth, requestedHeight, viewFlags, flags, 192 outFrame, outOverscanInsets, outContentInsets, outVisibleInsets, 193 outConfig, outSurface); 194 if (false) Slog.d(WindowManagerService.TAG, "<<<<<< EXITING relayout to " 195 + Binder.getCallingPid()); 196 return res; 197 } 198 199 public void performDeferredDestroy(IWindow window) { 200 mService.performDeferredDestroyWindow(this, window); 201 } 202 203 public boolean outOfMemory(IWindow window) { 204 return mService.outOfMemoryWindow(this, window); 205 } 206 207 public void setTransparentRegion(IWindow window, Region region) { 208 mService.setTransparentRegionWindow(this, window, region); 209 } 210 211 public void setInsets(IWindow window, int touchableInsets, 212 Rect contentInsets, Rect visibleInsets, Region touchableArea) { 213 mService.setInsetsWindow(this, window, touchableInsets, contentInsets, 214 visibleInsets, touchableArea); 215 } 216 217 public void getDisplayFrame(IWindow window, Rect outDisplayFrame) { 218 mService.getWindowDisplayFrame(this, window, outDisplayFrame); 219 } 220 221 public void finishDrawing(IWindow window) { 222 if (WindowManagerService.localLOGV) Slog.v( 223 WindowManagerService.TAG, "IWindow finishDrawing called for " + window); 224 mService.finishDrawingWindow(this, window); 225 } 226 227 public void setInTouchMode(boolean mode) { 228 synchronized(mService.mWindowMap) { 229 mService.mInTouchMode = mode; 230 } 231 } 232 233 public boolean getInTouchMode() { 234 synchronized(mService.mWindowMap) { 235 return mService.mInTouchMode; 236 } 237 } 238 239 public boolean performHapticFeedback(IWindow window, int effectId, 240 boolean always) { 241 synchronized(mService.mWindowMap) { 242 long ident = Binder.clearCallingIdentity(); 243 try { 244 return mService.mPolicy.performHapticFeedbackLw( 245 mService.windowForClientLocked(this, window, true), 246 effectId, always); 247 } finally { 248 Binder.restoreCallingIdentity(ident); 249 } 250 } 251 } 252 253 /* Drag/drop */ 254 public IBinder prepareDrag(IWindow window, int flags, 255 int width, int height, Surface outSurface) { 256 return mService.prepareDragSurface(window, mSurfaceSession, flags, 257 width, height, outSurface); 258 } 259 260 public boolean performDrag(IWindow window, IBinder dragToken, 261 float touchX, float touchY, float thumbCenterX, float thumbCenterY, 262 ClipData data) { 263 if (WindowManagerService.DEBUG_DRAG) { 264 Slog.d(WindowManagerService.TAG, "perform drag: win=" + window + " data=" + data); 265 } 266 267 synchronized (mService.mWindowMap) { 268 if (mService.mDragState == null) { 269 Slog.w(WindowManagerService.TAG, "No drag prepared"); 270 throw new IllegalStateException("performDrag() without prepareDrag()"); 271 } 272 273 if (dragToken != mService.mDragState.mToken) { 274 Slog.w(WindowManagerService.TAG, "Performing mismatched drag"); 275 throw new IllegalStateException("performDrag() does not match prepareDrag()"); 276 } 277 278 WindowState callingWin = mService.windowForClientLocked(null, window, false); 279 if (callingWin == null) { 280 Slog.w(WindowManagerService.TAG, "Bad requesting window " + window); 281 return false; // !!! TODO: throw here? 282 } 283 284 // !!! TODO: if input is not still focused on the initiating window, fail 285 // the drag initiation (e.g. an alarm window popped up just as the application 286 // called performDrag() 287 288 mService.mH.removeMessages(H.DRAG_START_TIMEOUT, window.asBinder()); 289 290 // !!! TODO: extract the current touch (x, y) in screen coordinates. That 291 // will let us eliminate the (touchX,touchY) parameters from the API. 292 293 // !!! FIXME: put all this heavy stuff onto the mH looper, as well as 294 // the actual drag event dispatch stuff in the dragstate 295 296 final DisplayContent displayContent = callingWin.getDisplayContent(); 297 if (displayContent == null) { 298 return false; 299 } 300 Display display = displayContent.getDisplay(); 301 mService.mDragState.register(display); 302 mService.mInputMonitor.updateInputWindowsLw(true /*force*/); 303 if (!mService.mInputManager.transferTouchFocus(callingWin.mInputChannel, 304 mService.mDragState.mServerChannel)) { 305 Slog.e(WindowManagerService.TAG, "Unable to transfer touch focus"); 306 mService.mDragState.unregister(); 307 mService.mDragState = null; 308 mService.mInputMonitor.updateInputWindowsLw(true /*force*/); 309 return false; 310 } 311 312 mService.mDragState.mData = data; 313 mService.mDragState.mCurrentX = touchX; 314 mService.mDragState.mCurrentY = touchY; 315 mService.mDragState.broadcastDragStartedLw(touchX, touchY); 316 317 // remember the thumb offsets for later 318 mService.mDragState.mThumbOffsetX = thumbCenterX; 319 mService.mDragState.mThumbOffsetY = thumbCenterY; 320 321 // Make the surface visible at the proper location 322 final SurfaceControl surfaceControl = mService.mDragState.mSurfaceControl; 323 if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS) Slog.i( 324 WindowManagerService.TAG, ">>> OPEN TRANSACTION performDrag"); 325 SurfaceControl.openTransaction(); 326 try { 327 surfaceControl.setPosition(touchX - thumbCenterX, 328 touchY - thumbCenterY); 329 surfaceControl.setAlpha(.7071f); 330 surfaceControl.setLayer(mService.mDragState.getDragLayerLw()); 331 surfaceControl.setLayerStack(display.getLayerStack()); 332 surfaceControl.show(); 333 } finally { 334 SurfaceControl.closeTransaction(); 335 if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS) Slog.i( 336 WindowManagerService.TAG, "<<< CLOSE TRANSACTION performDrag"); 337 } 338 } 339 340 return true; // success! 341 } 342 343 public void reportDropResult(IWindow window, boolean consumed) { 344 IBinder token = window.asBinder(); 345 if (WindowManagerService.DEBUG_DRAG) { 346 Slog.d(WindowManagerService.TAG, "Drop result=" + consumed + " reported by " + token); 347 } 348 349 synchronized (mService.mWindowMap) { 350 long ident = Binder.clearCallingIdentity(); 351 try { 352 if (mService.mDragState == null) { 353 // Most likely the drop recipient ANRed and we ended the drag 354 // out from under it. Log the issue and move on. 355 Slog.w(WindowManagerService.TAG, "Drop result given but no drag in progress"); 356 return; 357 } 358 359 if (mService.mDragState.mToken != token) { 360 // We're in a drag, but the wrong window has responded. 361 Slog.w(WindowManagerService.TAG, "Invalid drop-result claim by " + window); 362 throw new IllegalStateException("reportDropResult() by non-recipient"); 363 } 364 365 // The right window has responded, even if it's no longer around, 366 // so be sure to halt the timeout even if the later WindowState 367 // lookup fails. 368 mService.mH.removeMessages(H.DRAG_END_TIMEOUT, window.asBinder()); 369 WindowState callingWin = mService.windowForClientLocked(null, window, false); 370 if (callingWin == null) { 371 Slog.w(WindowManagerService.TAG, "Bad result-reporting window " + window); 372 return; // !!! TODO: throw here? 373 } 374 375 mService.mDragState.mDragResult = consumed; 376 mService.mDragState.endDragLw(); 377 } finally { 378 Binder.restoreCallingIdentity(ident); 379 } 380 } 381 } 382 383 public void dragRecipientEntered(IWindow window) { 384 if (WindowManagerService.DEBUG_DRAG) { 385 Slog.d(WindowManagerService.TAG, "Drag into new candidate view @ " + window.asBinder()); 386 } 387 } 388 389 public void dragRecipientExited(IWindow window) { 390 if (WindowManagerService.DEBUG_DRAG) { 391 Slog.d(WindowManagerService.TAG, "Drag from old candidate view @ " + window.asBinder()); 392 } 393 } 394 395 public void setWallpaperPosition(IBinder window, float x, float y, float xStep, float yStep) { 396 synchronized(mService.mWindowMap) { 397 long ident = Binder.clearCallingIdentity(); 398 try { 399 mService.setWindowWallpaperPositionLocked( 400 mService.windowForClientLocked(this, window, true), 401 x, y, xStep, yStep); 402 } finally { 403 Binder.restoreCallingIdentity(ident); 404 } 405 } 406 } 407 408 public void wallpaperOffsetsComplete(IBinder window) { 409 mService.wallpaperOffsetsComplete(window); 410 } 411 412 public Bundle sendWallpaperCommand(IBinder window, String action, int x, int y, 413 int z, Bundle extras, boolean sync) { 414 synchronized(mService.mWindowMap) { 415 long ident = Binder.clearCallingIdentity(); 416 try { 417 return mService.sendWindowWallpaperCommandLocked( 418 mService.windowForClientLocked(this, window, true), 419 action, x, y, z, extras, sync); 420 } finally { 421 Binder.restoreCallingIdentity(ident); 422 } 423 } 424 } 425 426 public void wallpaperCommandComplete(IBinder window, Bundle result) { 427 mService.wallpaperCommandComplete(window, result); 428 } 429 430 public void setUniverseTransform(IBinder window, float alpha, float offx, float offy, 431 float dsdx, float dtdx, float dsdy, float dtdy) { 432 synchronized(mService.mWindowMap) { 433 long ident = Binder.clearCallingIdentity(); 434 try { 435 mService.setUniverseTransformLocked( 436 mService.windowForClientLocked(this, window, true), 437 alpha, offx, offy, dsdx, dtdx, dsdy, dtdy); 438 } finally { 439 Binder.restoreCallingIdentity(ident); 440 } 441 } 442 } 443 444 public void onRectangleOnScreenRequested(IBinder token, Rect rectangle, boolean immediate) { 445 synchronized(mService.mWindowMap) { 446 final long identity = Binder.clearCallingIdentity(); 447 try { 448 mService.onRectangleOnScreenRequested(token, rectangle, immediate); 449 } finally { 450 Binder.restoreCallingIdentity(identity); 451 } 452 } 453 } 454 455 public IWindowId getWindowId(IBinder window) { 456 return mService.getWindowId(window); 457 } 458 459 void windowAddedLocked() { 460 if (mSurfaceSession == null) { 461 if (WindowManagerService.localLOGV) Slog.v( 462 WindowManagerService.TAG, "First window added to " + this + ", creating SurfaceSession"); 463 mSurfaceSession = new SurfaceSession(); 464 if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i( 465 WindowManagerService.TAG, " NEW SURFACE SESSION " + mSurfaceSession); 466 mService.mSessions.add(this); 467 } 468 mNumWindow++; 469 } 470 471 void windowRemovedLocked() { 472 mNumWindow--; 473 killSessionLocked(); 474 } 475 476 void killSessionLocked() { 477 if (mNumWindow <= 0 && mClientDead) { 478 mService.mSessions.remove(this); 479 if (mSurfaceSession != null) { 480 if (WindowManagerService.localLOGV) Slog.v( 481 WindowManagerService.TAG, "Last window removed from " + this 482 + ", destroying " + mSurfaceSession); 483 if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i( 484 WindowManagerService.TAG, " KILL SURFACE SESSION " + mSurfaceSession); 485 try { 486 mSurfaceSession.kill(); 487 } catch (Exception e) { 488 Slog.w(WindowManagerService.TAG, "Exception thrown when killing surface session " 489 + mSurfaceSession + " in session " + this 490 + ": " + e.toString()); 491 } 492 mSurfaceSession = null; 493 } 494 } 495 } 496 497 void dump(PrintWriter pw, String prefix) { 498 pw.print(prefix); pw.print("mNumWindow="); pw.print(mNumWindow); 499 pw.print(" mClientDead="); pw.print(mClientDead); 500 pw.print(" mSurfaceSession="); pw.println(mSurfaceSession); 501 } 502 503 @Override 504 public String toString() { 505 return mStringName; 506 } 507}