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