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