Session.java revision a1fb9be437b672f52ad64e1506038757ec060dcf
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.DEVICE_POWER;
20import static android.Manifest.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
21import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
22import static android.content.pm.PackageManager.PERMISSION_GRANTED;
23import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
24import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
25import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType;
26
27import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
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.DisplayCutout;
48import android.view.IWindow;
49import android.view.IWindowId;
50import android.view.IWindowSession;
51import android.view.IWindowSessionCallback;
52import android.view.InputChannel;
53import android.view.Surface;
54import android.view.SurfaceControl;
55import android.view.SurfaceSession;
56import android.view.WindowManager;
57
58import com.android.internal.view.IInputContext;
59import com.android.internal.view.IInputMethodClient;
60import com.android.internal.view.IInputMethodManager;
61import com.android.server.wm.WindowManagerService.H;
62
63import java.io.PrintWriter;
64import java.util.HashSet;
65import 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 */
71class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
72    final WindowManagerService mService;
73    final IWindowSessionCallback mCallback;
74    final IInputMethodClient mClient;
75    final int mUid;
76    final int mPid;
77    private final String mStringName;
78    SurfaceSession mSurfaceSession;
79    private int mNumWindow = 0;
80    // Set of visible application overlay window surfaces connected to this session.
81    private final Set<WindowSurfaceController> mAppOverlaySurfaces = new HashSet<>();
82    // Set of visible alert window surfaces connected to this session.
83    private final Set<WindowSurfaceController> mAlertWindowSurfaces = new HashSet<>();
84    private final DragDropController mDragDropController;
85    final boolean mCanAddInternalSystemWindow;
86    final boolean mCanHideNonSystemOverlayWindows;
87    final boolean mCanAcquireSleepToken;
88    private AlertWindowNotification mAlertWindowNotification;
89    private boolean mShowingAlertWindowNotificationAllowed;
90    private boolean mClientDead = false;
91    private float mLastReportedAnimatorScale;
92    private String mPackageName;
93    private String mRelayoutTag;
94
95    public Session(WindowManagerService service, IWindowSessionCallback callback,
96            IInputMethodClient client, IInputContext inputContext) {
97        mService = service;
98        mCallback = callback;
99        mClient = client;
100        mUid = Binder.getCallingUid();
101        mPid = Binder.getCallingPid();
102        mLastReportedAnimatorScale = service.getCurrentAnimatorScale();
103        mCanAddInternalSystemWindow = service.mContext.checkCallingOrSelfPermission(
104                INTERNAL_SYSTEM_WINDOW) == PERMISSION_GRANTED;
105        mCanHideNonSystemOverlayWindows = service.mContext.checkCallingOrSelfPermission(
106                HIDE_NON_SYSTEM_OVERLAY_WINDOWS) == PERMISSION_GRANTED;
107        mCanAcquireSleepToken = service.mContext.checkCallingOrSelfPermission(DEVICE_POWER)
108                == PERMISSION_GRANTED;
109        mShowingAlertWindowNotificationAllowed = mService.mShowAlertWindowNotifications;
110        mDragDropController = mService.mDragDropController;
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 */, null /* cutout */,
196                outInputChannel);
197    }
198
199    @Override
200    public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
201            int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
202            Rect outOutsets, DisplayCutout.ParcelableWrapper outDisplayCutout,
203            InputChannel outInputChannel) {
204        return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
205                outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel);
206    }
207
208    @Override
209    public int addWithoutInputChannel(IWindow window, int seq, WindowManager.LayoutParams attrs,
210            int viewVisibility, Rect outContentInsets, Rect outStableInsets) {
211        return addToDisplayWithoutInputChannel(window, seq, attrs, viewVisibility,
212                Display.DEFAULT_DISPLAY, outContentInsets, outStableInsets);
213    }
214
215    @Override
216    public int addToDisplayWithoutInputChannel(IWindow window, int seq, WindowManager.LayoutParams attrs,
217            int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets) {
218        return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
219            outContentInsets, outStableInsets, null /* outOutsets */, null /* cutout */, null);
220    }
221
222    @Override
223    public void remove(IWindow window) {
224        mService.removeWindow(this, window);
225    }
226
227    @Override
228    public void prepareToReplaceWindows(IBinder appToken, boolean childrenOnly) {
229        mService.setWillReplaceWindows(appToken, childrenOnly);
230    }
231
232    @Override
233    public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,
234            int requestedWidth, int requestedHeight, int viewFlags,
235            int flags, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
236            Rect outVisibleInsets, Rect outStableInsets, Rect outsets, Rect outBackdropFrame,
237            DisplayCutout.ParcelableWrapper cutout,
238            MergedConfiguration mergedConfiguration, Surface outSurface) {
239        if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from "
240                + Binder.getCallingPid());
241        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag);
242        int res = mService.relayoutWindow(this, window, seq, attrs,
243                requestedWidth, requestedHeight, viewFlags, flags,
244                outFrame, outOverscanInsets, outContentInsets, outVisibleInsets,
245                outStableInsets, outsets, outBackdropFrame, cutout,
246                mergedConfiguration, outSurface);
247        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
248        if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to "
249                + Binder.getCallingPid());
250        return res;
251    }
252
253    @Override
254    public boolean outOfMemory(IWindow window) {
255        return mService.outOfMemoryWindow(this, window);
256    }
257
258    @Override
259    public void setTransparentRegion(IWindow window, Region region) {
260        mService.setTransparentRegionWindow(this, window, region);
261    }
262
263    @Override
264    public void setInsets(IWindow window, int touchableInsets,
265            Rect contentInsets, Rect visibleInsets, Region touchableArea) {
266        mService.setInsetsWindow(this, window, touchableInsets, contentInsets,
267                visibleInsets, touchableArea);
268    }
269
270    @Override
271    public void getDisplayFrame(IWindow window, Rect outDisplayFrame) {
272        mService.getWindowDisplayFrame(this, window, outDisplayFrame);
273    }
274
275    @Override
276    public void finishDrawing(IWindow window) {
277        if (WindowManagerService.localLOGV) Slog.v(
278            TAG_WM, "IWindow finishDrawing called for " + window);
279        mService.finishDrawingWindow(this, window);
280    }
281
282    @Override
283    public void setInTouchMode(boolean mode) {
284        synchronized(mService.mWindowMap) {
285            mService.mInTouchMode = mode;
286        }
287    }
288
289    @Override
290    public boolean getInTouchMode() {
291        synchronized(mService.mWindowMap) {
292            return mService.mInTouchMode;
293        }
294    }
295
296    @Override
297    public boolean performHapticFeedback(IWindow window, int effectId,
298            boolean always) {
299        synchronized(mService.mWindowMap) {
300            long ident = Binder.clearCallingIdentity();
301            try {
302                return mService.mPolicy.performHapticFeedbackLw(
303                        mService.windowForClientLocked(this, window, true),
304                        effectId, always);
305            } finally {
306                Binder.restoreCallingIdentity(ident);
307            }
308        }
309    }
310
311    /* Drag/drop */
312    @Override
313    public IBinder prepareDrag(IWindow window, int flags, int width, int height) {
314        final int callerPid = Binder.getCallingPid();
315        final int callerUid = Binder.getCallingUid();
316        final long ident = Binder.clearCallingIdentity();
317        try {
318            return mDragDropController.prepareDrag(mSurfaceSession, callerPid, callerUid, window,
319                    flags, width, height);
320        } finally {
321            Binder.restoreCallingIdentity(ident);
322        }
323    }
324
325    @Override
326    public boolean performDrag(IWindow window, IBinder dragToken, SurfaceControl surface,
327            int touchSource, float touchX, float touchY, float thumbCenterX, float thumbCenterY,
328            ClipData data) {
329        return mDragDropController.performDrag(mSurfaceSession, window, dragToken, surface,
330                touchSource, touchX, touchY, thumbCenterX, thumbCenterY, data);
331    }
332
333    @Override
334    public void reportDropResult(IWindow window, boolean consumed) {
335        final long ident = Binder.clearCallingIdentity();
336        try {
337            mDragDropController.reportDropResult(window, consumed);
338        } finally {
339            Binder.restoreCallingIdentity(ident);
340        }
341    }
342
343    @Override
344    public void cancelDragAndDrop(IBinder dragToken) {
345        final long ident = Binder.clearCallingIdentity();
346        try {
347            mDragDropController.cancelDragAndDrop(dragToken);
348        } finally {
349            Binder.restoreCallingIdentity(ident);
350        }
351    }
352
353    @Override
354    public void dragRecipientEntered(IWindow window) {
355        mDragDropController.dragRecipientEntered(window);
356    }
357
358    @Override
359    public void dragRecipientExited(IWindow window) {
360        mDragDropController.dragRecipientExited(window);
361    }
362
363    @Override
364    public boolean startMovingTask(IWindow window, float startX, float startY) {
365        if (DEBUG_TASK_POSITIONING) Slog.d(
366                TAG_WM, "startMovingTask: {" + startX + "," + startY + "}");
367
368        long ident = Binder.clearCallingIdentity();
369        try {
370            return mService.mTaskPositioningController.startMovingTask(window, startX, startY);
371        } finally {
372            Binder.restoreCallingIdentity(ident);
373        }
374    }
375
376    @Override
377    public void setWallpaperPosition(IBinder window, float x, float y, float xStep, float yStep) {
378        synchronized(mService.mWindowMap) {
379            long ident = Binder.clearCallingIdentity();
380            try {
381                mService.mRoot.mWallpaperController.setWindowWallpaperPosition(
382                        mService.windowForClientLocked(this, window, true),
383                        x, y, xStep, yStep);
384            } finally {
385                Binder.restoreCallingIdentity(ident);
386            }
387        }
388    }
389
390    @Override
391    public void wallpaperOffsetsComplete(IBinder window) {
392        synchronized (mService.mWindowMap) {
393            mService.mRoot.mWallpaperController.wallpaperOffsetsComplete(window);
394        }
395    }
396
397    @Override
398    public void setWallpaperDisplayOffset(IBinder window, int x, int y) {
399        synchronized(mService.mWindowMap) {
400            long ident = Binder.clearCallingIdentity();
401            try {
402                mService.mRoot.mWallpaperController.setWindowWallpaperDisplayOffset(
403                        mService.windowForClientLocked(this, window, true), x, y);
404            } finally {
405                Binder.restoreCallingIdentity(ident);
406            }
407        }
408    }
409
410    @Override
411    public Bundle sendWallpaperCommand(IBinder window, String action, int x, int y,
412            int z, Bundle extras, boolean sync) {
413        synchronized(mService.mWindowMap) {
414            long ident = Binder.clearCallingIdentity();
415            try {
416                return mService.mRoot.mWallpaperController.sendWindowWallpaperCommand(
417                        mService.windowForClientLocked(this, window, true),
418                        action, x, y, z, extras, sync);
419            } finally {
420                Binder.restoreCallingIdentity(ident);
421            }
422        }
423    }
424
425    @Override
426    public void wallpaperCommandComplete(IBinder window, Bundle result) {
427        synchronized (mService.mWindowMap) {
428            mService.mRoot.mWallpaperController.wallpaperCommandComplete(window);
429        }
430    }
431
432    @Override
433    public void onRectangleOnScreenRequested(IBinder token, Rect rectangle) {
434        synchronized(mService.mWindowMap) {
435            final long identity = Binder.clearCallingIdentity();
436            try {
437                mService.onRectangleOnScreenRequested(token, rectangle);
438            } finally {
439                Binder.restoreCallingIdentity(identity);
440            }
441        }
442    }
443
444    @Override
445    public IWindowId getWindowId(IBinder window) {
446        return mService.getWindowId(window);
447    }
448
449    @Override
450    public void pokeDrawLock(IBinder window) {
451        final long identity = Binder.clearCallingIdentity();
452        try {
453            mService.pokeDrawLock(this, window);
454        } finally {
455            Binder.restoreCallingIdentity(identity);
456        }
457    }
458
459    @Override
460    public void updatePointerIcon(IWindow window) {
461        final long identity = Binder.clearCallingIdentity();
462        try {
463            mService.updatePointerIcon(window);
464        } finally {
465            Binder.restoreCallingIdentity(identity);
466        }
467    }
468
469    void windowAddedLocked(String packageName) {
470        mPackageName = packageName;
471        mRelayoutTag = "relayoutWindow: " + mPackageName;
472        if (mSurfaceSession == null) {
473            if (WindowManagerService.localLOGV) Slog.v(
474                TAG_WM, "First window added to " + this + ", creating SurfaceSession");
475            mSurfaceSession = new SurfaceSession();
476            if (SHOW_TRANSACTIONS) Slog.i(
477                    TAG_WM, "  NEW SURFACE SESSION " + mSurfaceSession);
478            mService.mSessions.add(this);
479            if (mLastReportedAnimatorScale != mService.getCurrentAnimatorScale()) {
480                mService.dispatchNewAnimatorScaleLocked(this);
481            }
482        }
483        mNumWindow++;
484    }
485
486    void windowRemovedLocked() {
487        mNumWindow--;
488        killSessionLocked();
489    }
490
491
492    void onWindowSurfaceVisibilityChanged(WindowSurfaceController surfaceController,
493            boolean visible, int type) {
494
495        if (!isSystemAlertWindowType(type)) {
496            return;
497        }
498
499        boolean changed;
500
501        if (!mCanAddInternalSystemWindow) {
502            // We want to track non-system signature apps adding alert windows so we can post an
503            // on-going notification for the user to control their visibility.
504            if (visible) {
505                changed = mAlertWindowSurfaces.add(surfaceController);
506            } else {
507                changed = mAlertWindowSurfaces.remove(surfaceController);
508            }
509
510            if (changed) {
511                if (mAlertWindowSurfaces.isEmpty()) {
512                    cancelAlertWindowNotification();
513                } else if (mAlertWindowNotification == null){
514                    mAlertWindowNotification = new AlertWindowNotification(mService, mPackageName);
515                    if (mShowingAlertWindowNotificationAllowed) {
516                        mAlertWindowNotification.post();
517                    }
518                }
519            }
520        }
521
522        if (type != TYPE_APPLICATION_OVERLAY) {
523            return;
524        }
525
526        if (visible) {
527            changed = mAppOverlaySurfaces.add(surfaceController);
528        } else {
529            changed = mAppOverlaySurfaces.remove(surfaceController);
530        }
531
532        if (changed) {
533            // Notify activity manager of changes to app overlay windows so it can adjust the
534            // importance score for the process.
535            setHasOverlayUi(!mAppOverlaySurfaces.isEmpty());
536        }
537    }
538
539    void setShowingAlertWindowNotificationAllowed(boolean allowed) {
540        mShowingAlertWindowNotificationAllowed = allowed;
541        if (mAlertWindowNotification != null) {
542            if (allowed) {
543                mAlertWindowNotification.post();
544            } else {
545                mAlertWindowNotification.cancel();
546            }
547        }
548    }
549
550    private void killSessionLocked() {
551        if (mNumWindow > 0 || !mClientDead) {
552            return;
553        }
554
555        mService.mSessions.remove(this);
556        if (mSurfaceSession == null) {
557            return;
558        }
559
560        if (WindowManagerService.localLOGV) Slog.v(TAG_WM, "Last window removed from " + this
561                + ", destroying " + mSurfaceSession);
562        if (SHOW_TRANSACTIONS) Slog.i(TAG_WM, "  KILL SURFACE SESSION " + mSurfaceSession);
563        try {
564            mSurfaceSession.kill();
565        } catch (Exception e) {
566            Slog.w(TAG_WM, "Exception thrown when killing surface session " + mSurfaceSession
567                    + " in session " + this + ": " + e.toString());
568        }
569        mSurfaceSession = null;
570        mAlertWindowSurfaces.clear();
571        mAppOverlaySurfaces.clear();
572        setHasOverlayUi(false);
573        cancelAlertWindowNotification();
574    }
575
576    private void setHasOverlayUi(boolean hasOverlayUi) {
577        mService.mH.obtainMessage(H.SET_HAS_OVERLAY_UI, mPid, hasOverlayUi ? 1 : 0).sendToTarget();
578    }
579
580    private void cancelAlertWindowNotification() {
581        if (mAlertWindowNotification == null) {
582            return;
583        }
584        mAlertWindowNotification.cancel();
585        mAlertWindowNotification = null;
586    }
587
588    void dump(PrintWriter pw, String prefix) {
589        pw.print(prefix); pw.print("mNumWindow="); pw.print(mNumWindow);
590                pw.print(" mCanAddInternalSystemWindow="); pw.print(mCanAddInternalSystemWindow);
591                pw.print(" mAppOverlaySurfaces="); pw.print(mAppOverlaySurfaces);
592                pw.print(" mAlertWindowSurfaces="); pw.print(mAlertWindowSurfaces);
593                pw.print(" mClientDead="); pw.print(mClientDead);
594                pw.print(" mSurfaceSession="); pw.println(mSurfaceSession);
595        pw.print(prefix); pw.print("mPackageName="); pw.println(mPackageName);
596    }
597
598    @Override
599    public String toString() {
600        return mStringName;
601    }
602
603    boolean hasAlertWindowSurfaces() {
604        return !mAlertWindowSurfaces.isEmpty();
605    }
606}
607