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 17 package com.android.server.wm; 18 19 import android.view.IWindowId; 20 import android.view.IWindowSessionCallback; 21 import com.android.internal.view.IInputContext; 22 import com.android.internal.view.IInputMethodClient; 23 import com.android.internal.view.IInputMethodManager; 24 import com.android.server.wm.WindowManagerService.H; 25 26 import android.content.ClipData; 27 import android.content.Context; 28 import android.content.res.Configuration; 29 import android.graphics.Rect; 30 import android.graphics.Region; 31 import android.os.Binder; 32 import android.os.Bundle; 33 import android.os.IBinder; 34 import android.os.Parcel; 35 import android.os.Process; 36 import android.os.RemoteException; 37 import android.os.ServiceManager; 38 import android.os.UserHandle; 39 import android.util.Slog; 40 import android.view.Display; 41 import android.view.IWindow; 42 import android.view.IWindowSession; 43 import android.view.InputChannel; 44 import android.view.Surface; 45 import android.view.SurfaceControl; 46 import android.view.SurfaceSession; 47 import android.view.WindowManager; 48 49 import 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 */ 55 final 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 Session(WindowManagerService service, IWindowSessionCallback callback, IInputMethodClient client, IInputContext inputContext)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 onTransact(int code, Parcel data, Parcel reply, int flags)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 binderDied()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 add(IWindow window, int seq, WindowManager.LayoutParams attrs, int viewVisibility, Rect outContentInsets, Rect outStableInsets, InputChannel outInputChannel)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, outInputChannel); 162 } 163 164 @Override addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets, InputChannel outInputChannel)165 public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs, 166 int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets, 167 InputChannel outInputChannel) { 168 return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, 169 outContentInsets, outStableInsets, outInputChannel); 170 } 171 172 @Override addWithoutInputChannel(IWindow window, int seq, WindowManager.LayoutParams attrs, int viewVisibility, Rect outContentInsets, Rect outStableInsets)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 addToDisplayWithoutInputChannel(IWindow window, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets)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); 184 } 185 remove(IWindow window)186 public void remove(IWindow window) { 187 mService.removeWindow(this, window); 188 } 189 relayout(IWindow window, int seq, WindowManager.LayoutParams attrs, int requestedWidth, int requestedHeight, int viewFlags, int flags, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets, Rect outVisibleInsets, Rect outStableInsets, Configuration outConfig, Surface outSurface)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, Configuration outConfig, 194 Surface outSurface) { 195 if (false) Slog.d(WindowManagerService.TAG, ">>>>>> ENTERED relayout from " 196 + Binder.getCallingPid()); 197 int res = mService.relayoutWindow(this, window, seq, attrs, 198 requestedWidth, requestedHeight, viewFlags, flags, 199 outFrame, outOverscanInsets, outContentInsets, outVisibleInsets, 200 outStableInsets, outConfig, outSurface); 201 if (false) Slog.d(WindowManagerService.TAG, "<<<<<< EXITING relayout to " 202 + Binder.getCallingPid()); 203 return res; 204 } 205 performDeferredDestroy(IWindow window)206 public void performDeferredDestroy(IWindow window) { 207 mService.performDeferredDestroyWindow(this, window); 208 } 209 outOfMemory(IWindow window)210 public boolean outOfMemory(IWindow window) { 211 return mService.outOfMemoryWindow(this, window); 212 } 213 setTransparentRegion(IWindow window, Region region)214 public void setTransparentRegion(IWindow window, Region region) { 215 mService.setTransparentRegionWindow(this, window, region); 216 } 217 setInsets(IWindow window, int touchableInsets, Rect contentInsets, Rect visibleInsets, Region touchableArea)218 public void setInsets(IWindow window, int touchableInsets, 219 Rect contentInsets, Rect visibleInsets, Region touchableArea) { 220 mService.setInsetsWindow(this, window, touchableInsets, contentInsets, 221 visibleInsets, touchableArea); 222 } 223 getDisplayFrame(IWindow window, Rect outDisplayFrame)224 public void getDisplayFrame(IWindow window, Rect outDisplayFrame) { 225 mService.getWindowDisplayFrame(this, window, outDisplayFrame); 226 } 227 finishDrawing(IWindow window)228 public void finishDrawing(IWindow window) { 229 if (WindowManagerService.localLOGV) Slog.v( 230 WindowManagerService.TAG, "IWindow finishDrawing called for " + window); 231 mService.finishDrawingWindow(this, window); 232 } 233 setInTouchMode(boolean mode)234 public void setInTouchMode(boolean mode) { 235 synchronized(mService.mWindowMap) { 236 mService.mInTouchMode = mode; 237 } 238 } 239 getInTouchMode()240 public boolean getInTouchMode() { 241 synchronized(mService.mWindowMap) { 242 return mService.mInTouchMode; 243 } 244 } 245 performHapticFeedback(IWindow window, int effectId, boolean always)246 public boolean performHapticFeedback(IWindow window, int effectId, 247 boolean always) { 248 synchronized(mService.mWindowMap) { 249 long ident = Binder.clearCallingIdentity(); 250 try { 251 return mService.mPolicy.performHapticFeedbackLw( 252 mService.windowForClientLocked(this, window, true), 253 effectId, always); 254 } finally { 255 Binder.restoreCallingIdentity(ident); 256 } 257 } 258 } 259 260 /* Drag/drop */ prepareDrag(IWindow window, int flags, int width, int height, Surface outSurface)261 public IBinder prepareDrag(IWindow window, int flags, 262 int width, int height, Surface outSurface) { 263 return mService.prepareDragSurface(window, mSurfaceSession, flags, 264 width, height, outSurface); 265 } 266 performDrag(IWindow window, IBinder dragToken, float touchX, float touchY, float thumbCenterX, float thumbCenterY, ClipData data)267 public boolean performDrag(IWindow window, IBinder dragToken, 268 float touchX, float touchY, float thumbCenterX, float thumbCenterY, 269 ClipData data) { 270 if (WindowManagerService.DEBUG_DRAG) { 271 Slog.d(WindowManagerService.TAG, "perform drag: win=" + window + " data=" + data); 272 } 273 274 synchronized (mService.mWindowMap) { 275 if (mService.mDragState == null) { 276 Slog.w(WindowManagerService.TAG, "No drag prepared"); 277 throw new IllegalStateException("performDrag() without prepareDrag()"); 278 } 279 280 if (dragToken != mService.mDragState.mToken) { 281 Slog.w(WindowManagerService.TAG, "Performing mismatched drag"); 282 throw new IllegalStateException("performDrag() does not match prepareDrag()"); 283 } 284 285 WindowState callingWin = mService.windowForClientLocked(null, window, false); 286 if (callingWin == null) { 287 Slog.w(WindowManagerService.TAG, "Bad requesting window " + window); 288 return false; // !!! TODO: throw here? 289 } 290 291 // !!! TODO: if input is not still focused on the initiating window, fail 292 // the drag initiation (e.g. an alarm window popped up just as the application 293 // called performDrag() 294 295 mService.mH.removeMessages(H.DRAG_START_TIMEOUT, window.asBinder()); 296 297 // !!! TODO: extract the current touch (x, y) in screen coordinates. That 298 // will let us eliminate the (touchX,touchY) parameters from the API. 299 300 // !!! FIXME: put all this heavy stuff onto the mH looper, as well as 301 // the actual drag event dispatch stuff in the dragstate 302 303 final DisplayContent displayContent = callingWin.getDisplayContent(); 304 if (displayContent == null) { 305 return false; 306 } 307 Display display = displayContent.getDisplay(); 308 mService.mDragState.register(display); 309 mService.mInputMonitor.updateInputWindowsLw(true /*force*/); 310 if (!mService.mInputManager.transferTouchFocus(callingWin.mInputChannel, 311 mService.mDragState.mServerChannel)) { 312 Slog.e(WindowManagerService.TAG, "Unable to transfer touch focus"); 313 mService.mDragState.unregister(); 314 mService.mDragState = null; 315 mService.mInputMonitor.updateInputWindowsLw(true /*force*/); 316 return false; 317 } 318 319 mService.mDragState.mData = data; 320 mService.mDragState.mCurrentX = touchX; 321 mService.mDragState.mCurrentY = touchY; 322 mService.mDragState.broadcastDragStartedLw(touchX, touchY); 323 324 // remember the thumb offsets for later 325 mService.mDragState.mThumbOffsetX = thumbCenterX; 326 mService.mDragState.mThumbOffsetY = thumbCenterY; 327 328 // Make the surface visible at the proper location 329 final SurfaceControl surfaceControl = mService.mDragState.mSurfaceControl; 330 if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS) Slog.i( 331 WindowManagerService.TAG, ">>> OPEN TRANSACTION performDrag"); 332 SurfaceControl.openTransaction(); 333 try { 334 surfaceControl.setPosition(touchX - thumbCenterX, 335 touchY - thumbCenterY); 336 surfaceControl.setAlpha(.7071f); 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 reportDropResult(IWindow window, boolean consumed)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 dragRecipientEntered(IWindow window)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 dragRecipientExited(IWindow window)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 setWallpaperPosition(IBinder window, float x, float y, float xStep, float yStep)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.setWindowWallpaperPositionLocked( 407 mService.windowForClientLocked(this, window, true), 408 x, y, xStep, yStep); 409 } finally { 410 Binder.restoreCallingIdentity(ident); 411 } 412 } 413 } 414 wallpaperOffsetsComplete(IBinder window)415 public void wallpaperOffsetsComplete(IBinder window) { 416 mService.wallpaperOffsetsComplete(window); 417 } 418 setWallpaperDisplayOffset(IBinder window, int x, int y)419 public void setWallpaperDisplayOffset(IBinder window, int x, int y) { 420 synchronized(mService.mWindowMap) { 421 long ident = Binder.clearCallingIdentity(); 422 try { 423 mService.setWindowWallpaperDisplayOffsetLocked( 424 mService.windowForClientLocked(this, window, true), x, y); 425 } finally { 426 Binder.restoreCallingIdentity(ident); 427 } 428 } 429 } 430 sendWallpaperCommand(IBinder window, String action, int x, int y, int z, Bundle extras, boolean sync)431 public Bundle sendWallpaperCommand(IBinder window, String action, int x, int y, 432 int z, Bundle extras, boolean sync) { 433 synchronized(mService.mWindowMap) { 434 long ident = Binder.clearCallingIdentity(); 435 try { 436 return mService.sendWindowWallpaperCommandLocked( 437 mService.windowForClientLocked(this, window, true), 438 action, x, y, z, extras, sync); 439 } finally { 440 Binder.restoreCallingIdentity(ident); 441 } 442 } 443 } 444 wallpaperCommandComplete(IBinder window, Bundle result)445 public void wallpaperCommandComplete(IBinder window, Bundle result) { 446 mService.wallpaperCommandComplete(window, result); 447 } 448 setUniverseTransform(IBinder window, float alpha, float offx, float offy, float dsdx, float dtdx, float dsdy, float dtdy)449 public void setUniverseTransform(IBinder window, float alpha, float offx, float offy, 450 float dsdx, float dtdx, float dsdy, float dtdy) { 451 synchronized(mService.mWindowMap) { 452 long ident = Binder.clearCallingIdentity(); 453 try { 454 mService.setUniverseTransformLocked( 455 mService.windowForClientLocked(this, window, true), 456 alpha, offx, offy, dsdx, dtdx, dsdy, dtdy); 457 } finally { 458 Binder.restoreCallingIdentity(ident); 459 } 460 } 461 } 462 onRectangleOnScreenRequested(IBinder token, Rect rectangle)463 public void onRectangleOnScreenRequested(IBinder token, Rect rectangle) { 464 synchronized(mService.mWindowMap) { 465 final long identity = Binder.clearCallingIdentity(); 466 try { 467 mService.onRectangleOnScreenRequested(token, rectangle); 468 } finally { 469 Binder.restoreCallingIdentity(identity); 470 } 471 } 472 } 473 getWindowId(IBinder window)474 public IWindowId getWindowId(IBinder window) { 475 return mService.getWindowId(window); 476 } 477 windowAddedLocked()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 windowRemovedLocked()493 void windowRemovedLocked() { 494 mNumWindow--; 495 killSessionLocked(); 496 } 497 killSessionLocked()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 dump(PrintWriter pw, String prefix)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 toString()526 public String toString() { 527 return mStringName; 528 } 529 }