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