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