• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 
20 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
21 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
22 
23 import android.annotation.Nullable;
24 import android.os.IBinder;
25 import android.os.RemoteException;
26 import android.os.UserHandle;
27 import android.util.ArrayMap;
28 import android.util.Slog;
29 import android.view.IWindow;
30 import android.view.InputApplicationHandle;
31 import android.view.InputChannel;
32 
33 /**
34  * Keeps track of embedded windows.
35  *
36  * If the embedded window does not receive input then Window Manager does not keep track of it.
37  * But if they do receive input, we keep track of the calling PID to blame the right app and
38  * the host window to send pointerDownOutsideFocus.
39  */
40 class EmbeddedWindowController {
41     private static final String TAG = TAG_WITH_CLASS_NAME ? "EmbeddedWindowController" : TAG_WM;
42     /* maps input token to an embedded window */
43     private ArrayMap<IBinder /*input token */, EmbeddedWindow> mWindows = new ArrayMap<>();
44     private final Object mGlobalLock;
45     private final ActivityTaskManagerService mAtmService;
46 
EmbeddedWindowController(ActivityTaskManagerService atmService)47     EmbeddedWindowController(ActivityTaskManagerService atmService) {
48         mAtmService = atmService;
49         mGlobalLock = atmService.getGlobalLock();
50     }
51 
52     /**
53      * Adds a new embedded window.
54      *
55      * @param inputToken input channel token passed in by the embedding process when it requests
56      *                   the server to add an input channel to the embedded surface.
57      * @param window An {@link EmbeddedWindow} object to add to this controller.
58      */
add(IBinder inputToken, EmbeddedWindow window)59     void add(IBinder inputToken, EmbeddedWindow window) {
60         try {
61             mWindows.put(inputToken, window);
62             updateProcessController(window);
63             window.mClient.asBinder().linkToDeath(()-> {
64                 synchronized (mGlobalLock) {
65                     mWindows.remove(inputToken);
66                 }
67             }, 0);
68         } catch (RemoteException e) {
69             // The caller has died, remove from the map
70             mWindows.remove(inputToken);
71         }
72     }
73 
74     /**
75      * Track the host activity in the embedding process so we can determine if the
76      * process is currently showing any UI to the user.
77      */
updateProcessController(EmbeddedWindow window)78     private void updateProcessController(EmbeddedWindow window) {
79         if (window.mHostActivityRecord == null) {
80             return;
81         }
82         final WindowProcessController processController =
83                 mAtmService.getProcessController(window.mOwnerPid, window.mOwnerUid);
84         if (processController == null) {
85             Slog.w(TAG, "Could not find the embedding process.");
86         } else {
87             processController.addHostActivity(window.mHostActivityRecord);
88         }
89     }
90 
getHostWindow(IBinder inputToken)91     WindowState getHostWindow(IBinder inputToken) {
92         EmbeddedWindow embeddedWindow = mWindows.get(inputToken);
93         return embeddedWindow != null ? embeddedWindow.mHostWindowState : null;
94     }
95 
remove(IWindow client)96     void remove(IWindow client) {
97         for (int i = mWindows.size() - 1; i >= 0; i--) {
98             if (mWindows.valueAt(i).mClient.asBinder() == client.asBinder()) {
99                 mWindows.removeAt(i).onRemoved();
100                 return;
101             }
102         }
103     }
104 
onWindowRemoved(WindowState host)105     void onWindowRemoved(WindowState host) {
106         for (int i = mWindows.size() - 1; i >= 0; i--) {
107             if (mWindows.valueAt(i).mHostWindowState == host) {
108                 mWindows.removeAt(i).onRemoved();
109             }
110         }
111     }
112 
get(IBinder inputToken)113     EmbeddedWindow get(IBinder inputToken) {
114         return mWindows.get(inputToken);
115     }
116 
onActivityRemoved(ActivityRecord activityRecord)117     void onActivityRemoved(ActivityRecord activityRecord) {
118         for (int i = mWindows.size() - 1; i >= 0; i--) {
119             final EmbeddedWindow window = mWindows.valueAt(i);
120             if (window.mHostActivityRecord == activityRecord) {
121                 final WindowProcessController processController =
122                         mAtmService.getProcessController(window.mOwnerPid, window.mOwnerUid);
123                 if (processController != null) {
124                     processController.removeHostActivity(activityRecord);
125                 }
126             }
127         }
128     }
129 
130     static class EmbeddedWindow {
131         final IWindow mClient;
132         @Nullable final WindowState mHostWindowState;
133         @Nullable final ActivityRecord mHostActivityRecord;
134         final int mOwnerUid;
135         final int mOwnerPid;
136         final WindowManagerService mWmService;
137         final int mDisplayId;
138         public Session mSession;
139         InputChannel mInputChannel;
140         final int mWindowType;
141 
142         /**
143          * @param session  calling session to check ownership of the window
144          * @param clientToken client token used to clean up the map if the embedding process dies
145          * @param hostWindowState input channel token belonging to the host window. This is needed
146          *                        to handle input callbacks to wm. It's used when raising ANR and
147          *                        when the user taps out side of the focused region on screen. This
148          *                        can be null if there is no host window.
149          * @param ownerUid  calling uid
150          * @param ownerPid  calling pid used for anr blaming
151          * @param windowType to forward to input
152          * @param displayId used for focus requests
153          */
EmbeddedWindow(Session session, WindowManagerService service, IWindow clientToken, WindowState hostWindowState, int ownerUid, int ownerPid, int windowType, int displayId)154         EmbeddedWindow(Session session, WindowManagerService service, IWindow clientToken,
155                        WindowState hostWindowState, int ownerUid, int ownerPid, int windowType,
156                        int displayId) {
157             mSession = session;
158             mWmService = service;
159             mClient = clientToken;
160             mHostWindowState = hostWindowState;
161             mHostActivityRecord = (mHostWindowState != null) ? mHostWindowState.mActivityRecord
162                     : null;
163             mOwnerUid = ownerUid;
164             mOwnerPid = ownerPid;
165             mWindowType = windowType;
166             mDisplayId = displayId;
167         }
168 
getName()169         String getName() {
170             final String hostWindowName = (mHostWindowState != null)
171                     ? mHostWindowState.getWindowTag().toString() : "Internal";
172             return "EmbeddedWindow{ u" + UserHandle.getUserId(mOwnerUid) + " " + hostWindowName
173                     + "}";
174         }
175 
getApplicationHandle()176         InputApplicationHandle getApplicationHandle() {
177             if (mHostWindowState == null
178                     || mHostWindowState.mInputWindowHandle.getInputApplicationHandle() == null) {
179                 return null;
180             }
181             return new InputApplicationHandle(
182                     mHostWindowState.mInputWindowHandle.getInputApplicationHandle());
183         }
184 
openInputChannel()185         InputChannel openInputChannel() {
186             final String name = getName();
187             mInputChannel = mWmService.mInputManager.createInputChannel(name);
188             return mInputChannel;
189         }
190 
onRemoved()191         void onRemoved() {
192             if (mInputChannel != null) {
193                 mWmService.mInputManager.removeInputChannel(mInputChannel.getToken());
194                 mInputChannel.dispose();
195                 mInputChannel = null;
196             }
197         }
198     }
199 }
200