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