blob: 9bbd4cd0778ac59cdb7a5b567e7e1ca2abaddf90 [file] [log] [blame]
Vishnu Nair5cf253192019-11-07 15:33:20 -08001/*
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
17package com.android.server.wm;
18
Vishnu Nair5cf253192019-11-07 15:33:20 -080019
Vishnu Nairfca78472020-03-09 15:34:47 -070020import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
21import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
22
Vishnu Nairddbd2512019-11-12 14:39:43 -080023import android.annotation.Nullable;
Vishnu Nair5cf253192019-11-07 15:33:20 -080024import android.os.IBinder;
25import android.os.RemoteException;
Evan Rosky680377e2020-01-10 19:12:10 -080026import android.os.UserHandle;
Vishnu Nair5cf253192019-11-07 15:33:20 -080027import android.util.ArrayMap;
Vishnu Nairfca78472020-03-09 15:34:47 -070028import android.util.Slog;
Vishnu Nair5cf253192019-11-07 15:33:20 -080029import android.view.IWindow;
Evan Rosky680377e2020-01-10 19:12:10 -080030import android.view.InputApplicationHandle;
arthurhung03d65a72020-04-28 09:19:24 +080031import android.view.InputChannel;
Vishnu Nair5cf253192019-11-07 15:33:20 -080032
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 */
40class EmbeddedWindowController {
Vishnu Nairfca78472020-03-09 15:34:47 -070041 private static final String TAG = TAG_WITH_CLASS_NAME ? "EmbeddedWindowController" : TAG_WM;
Vishnu Nair5cf253192019-11-07 15:33:20 -080042 /* maps input token to an embedded window */
43 private ArrayMap<IBinder /*input token */, EmbeddedWindow> mWindows = new ArrayMap<>();
Vishnu Nairfca78472020-03-09 15:34:47 -070044 private final Object mGlobalLock;
45 private final ActivityTaskManagerService mAtmService;
Vishnu Nair5cf253192019-11-07 15:33:20 -080046
Vishnu Nairfca78472020-03-09 15:34:47 -070047 EmbeddedWindowController(ActivityTaskManagerService atmService) {
48 mAtmService = atmService;
49 mGlobalLock = atmService.getGlobalLock();
Vishnu Nair5cf253192019-11-07 15:33:20 -080050 }
51
Vishnu Nairddbd2512019-11-12 14:39:43 -080052 /**
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.
Vishnu Nairfca78472020-03-09 15:34:47 -070057 * @param window An {@link EmbeddedWindow} object to add to this controller.
Vishnu Nairddbd2512019-11-12 14:39:43 -080058 */
Vishnu Nairfca78472020-03-09 15:34:47 -070059 void add(IBinder inputToken, EmbeddedWindow window) {
Vishnu Nair5cf253192019-11-07 15:33:20 -080060 try {
Vishnu Nairfca78472020-03-09 15:34:47 -070061 mWindows.put(inputToken, window);
62 updateProcessController(window);
63 window.mClient.asBinder().linkToDeath(()-> {
64 synchronized (mGlobalLock) {
Vishnu Nair5cf253192019-11-07 15:33:20 -080065 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
Vishnu Nairfca78472020-03-09 15:34:47 -070074 /**
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 */
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
Vishnu Nair5cf253192019-11-07 15:33:20 -080091 WindowState getHostWindow(IBinder inputToken) {
92 EmbeddedWindow embeddedWindow = mWindows.get(inputToken);
93 return embeddedWindow != null ? embeddedWindow.mHostWindowState : null;
94 }
95
Vishnu Nair5cf253192019-11-07 15:33:20 -080096 void remove(IWindow client) {
Vishnu Nairddbd2512019-11-12 14:39:43 -080097 for (int i = mWindows.size() - 1; i >= 0; i--) {
98 if (mWindows.valueAt(i).mClient.asBinder() == client.asBinder()) {
arthurhung03d65a72020-04-28 09:19:24 +080099 mWindows.removeAt(i).onRemoved();
Vishnu Nair5cf253192019-11-07 15:33:20 -0800100 return;
101 }
102 }
103 }
104
Vishnu Nairfca78472020-03-09 15:34:47 -0700105 void onWindowRemoved(WindowState host) {
Vishnu Nairddbd2512019-11-12 14:39:43 -0800106 for (int i = mWindows.size() - 1; i >= 0; i--) {
107 if (mWindows.valueAt(i).mHostWindowState == host) {
arthurhung03d65a72020-04-28 09:19:24 +0800108 mWindows.removeAt(i).onRemoved();
Vishnu Nair5cf253192019-11-07 15:33:20 -0800109 }
110 }
111 }
112
Vishnu Nairddbd2512019-11-12 14:39:43 -0800113 EmbeddedWindow get(IBinder inputToken) {
114 return mWindows.get(inputToken);
115 }
116
Vishnu Nairfca78472020-03-09 15:34:47 -0700117 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
Vishnu Nairddbd2512019-11-12 14:39:43 -0800130 static class EmbeddedWindow {
Vishnu Nair5cf253192019-11-07 15:33:20 -0800131 final IWindow mClient;
Vishnu Nairddbd2512019-11-12 14:39:43 -0800132 @Nullable final WindowState mHostWindowState;
Vishnu Nairfca78472020-03-09 15:34:47 -0700133 @Nullable final ActivityRecord mHostActivityRecord;
Vishnu Nair5cf253192019-11-07 15:33:20 -0800134 final int mOwnerUid;
135 final int mOwnerPid;
arthurhung03d65a72020-04-28 09:19:24 +0800136 final WindowManagerService mWmService;
137 InputChannel mInputChannel;
Vishnu Nair5cf253192019-11-07 15:33:20 -0800138
Evan Rosky680377e2020-01-10 19:12:10 -0800139 /**
140 * @param clientToken client token used to clean up the map if the embedding process dies
141 * @param hostWindowState input channel token belonging to the host window. This is needed
142 * to handle input callbacks to wm. It's used when raising ANR and
143 * when the user taps out side of the focused region on screen. This
144 * can be null if there is no host window.
145 * @param ownerUid calling uid
146 * @param ownerPid calling pid used for anr blaming
147 */
arthurhung03d65a72020-04-28 09:19:24 +0800148 EmbeddedWindow(WindowManagerService service, IWindow clientToken,
149 WindowState hostWindowState, int ownerUid, int ownerPid) {
150 mWmService = service;
Vishnu Nair5cf253192019-11-07 15:33:20 -0800151 mClient = clientToken;
152 mHostWindowState = hostWindowState;
Vishnu Nairfca78472020-03-09 15:34:47 -0700153 mHostActivityRecord = (mHostWindowState != null) ? mHostWindowState.mActivityRecord
154 : null;
Vishnu Nair5cf253192019-11-07 15:33:20 -0800155 mOwnerUid = ownerUid;
156 mOwnerPid = ownerPid;
157 }
Evan Rosky680377e2020-01-10 19:12:10 -0800158
159 String getName() {
160 final String hostWindowName = (mHostWindowState != null)
161 ? mHostWindowState.getWindowTag().toString() : "Internal";
162 return "EmbeddedWindow{ u" + UserHandle.getUserId(mOwnerUid) + " " + hostWindowName
163 + "}";
164 }
165
166 InputApplicationHandle getApplicationHandle() {
167 if (mHostWindowState == null
168 || mHostWindowState.mInputWindowHandle.inputApplicationHandle == null) {
169 return null;
170 }
171 return new InputApplicationHandle(
172 mHostWindowState.mInputWindowHandle.inputApplicationHandle);
173 }
arthurhung03d65a72020-04-28 09:19:24 +0800174
175 InputChannel openInputChannel() {
176 final String name = getName();
177
178 final InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
179 mInputChannel = inputChannels[0];
180 final InputChannel clientChannel = inputChannels[1];
181 mWmService.mInputManager.registerInputChannel(mInputChannel);
182
183 if (mInputChannel.getToken() != clientChannel.getToken()) {
184 throw new IllegalStateException("Client and Server tokens are expected to"
185 + "be the same");
186 }
187
188 return clientChannel;
189 }
190
191 void onRemoved() {
192 if (mInputChannel != null) {
193 mWmService.mInputManager.unregisterInputChannel(mInputChannel);
194 mInputChannel.dispose();
195 mInputChannel = null;
196 }
197 }
Vishnu Nair5cf253192019-11-07 15:33:20 -0800198 }
199}