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