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