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