Vishnu Nair | 5cf25319 | 2019-11-07 15:33:20 -0800 | [diff] [blame] | 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 | |
Vishnu Nair | 5cf25319 | 2019-11-07 15:33:20 -0800 | [diff] [blame] | 19 | |
Vishnu Nair | fca7847 | 2020-03-09 15:34:47 -0700 | [diff] [blame] | 20 | import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; |
| 21 | import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; |
| 22 | |
Vishnu Nair | ddbd251 | 2019-11-12 14:39:43 -0800 | [diff] [blame] | 23 | import android.annotation.Nullable; |
Vishnu Nair | 5cf25319 | 2019-11-07 15:33:20 -0800 | [diff] [blame] | 24 | import android.os.IBinder; |
| 25 | import android.os.RemoteException; |
Evan Rosky | 680377e | 2020-01-10 19:12:10 -0800 | [diff] [blame] | 26 | import android.os.UserHandle; |
Vishnu Nair | 5cf25319 | 2019-11-07 15:33:20 -0800 | [diff] [blame] | 27 | import android.util.ArrayMap; |
Vishnu Nair | fca7847 | 2020-03-09 15:34:47 -0700 | [diff] [blame] | 28 | import android.util.Slog; |
Vishnu Nair | 5cf25319 | 2019-11-07 15:33:20 -0800 | [diff] [blame] | 29 | import android.view.IWindow; |
Evan Rosky | 680377e | 2020-01-10 19:12:10 -0800 | [diff] [blame] | 30 | import android.view.InputApplicationHandle; |
arthurhung | 03d65a7 | 2020-04-28 09:19:24 +0800 | [diff] [blame] | 31 | import android.view.InputChannel; |
Vishnu Nair | 5cf25319 | 2019-11-07 15:33:20 -0800 | [diff] [blame] | 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 { |
Vishnu Nair | fca7847 | 2020-03-09 15:34:47 -0700 | [diff] [blame] | 41 | private static final String TAG = TAG_WITH_CLASS_NAME ? "EmbeddedWindowController" : TAG_WM; |
Vishnu Nair | 5cf25319 | 2019-11-07 15:33:20 -0800 | [diff] [blame] | 42 | /* maps input token to an embedded window */ |
| 43 | private ArrayMap<IBinder /*input token */, EmbeddedWindow> mWindows = new ArrayMap<>(); |
Vishnu Nair | fca7847 | 2020-03-09 15:34:47 -0700 | [diff] [blame] | 44 | private final Object mGlobalLock; |
| 45 | private final ActivityTaskManagerService mAtmService; |
Vishnu Nair | 5cf25319 | 2019-11-07 15:33:20 -0800 | [diff] [blame] | 46 | |
Vishnu Nair | fca7847 | 2020-03-09 15:34:47 -0700 | [diff] [blame] | 47 | EmbeddedWindowController(ActivityTaskManagerService atmService) { |
| 48 | mAtmService = atmService; |
| 49 | mGlobalLock = atmService.getGlobalLock(); |
Vishnu Nair | 5cf25319 | 2019-11-07 15:33:20 -0800 | [diff] [blame] | 50 | } |
| 51 | |
Vishnu Nair | ddbd251 | 2019-11-12 14:39:43 -0800 | [diff] [blame] | 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. |
Vishnu Nair | fca7847 | 2020-03-09 15:34:47 -0700 | [diff] [blame] | 57 | * @param window An {@link EmbeddedWindow} object to add to this controller. |
Vishnu Nair | ddbd251 | 2019-11-12 14:39:43 -0800 | [diff] [blame] | 58 | */ |
Vishnu Nair | fca7847 | 2020-03-09 15:34:47 -0700 | [diff] [blame] | 59 | void add(IBinder inputToken, EmbeddedWindow window) { |
Vishnu Nair | 5cf25319 | 2019-11-07 15:33:20 -0800 | [diff] [blame] | 60 | try { |
Vishnu Nair | fca7847 | 2020-03-09 15:34:47 -0700 | [diff] [blame] | 61 | mWindows.put(inputToken, window); |
| 62 | updateProcessController(window); |
| 63 | window.mClient.asBinder().linkToDeath(()-> { |
| 64 | synchronized (mGlobalLock) { |
Vishnu Nair | 5cf25319 | 2019-11-07 15:33:20 -0800 | [diff] [blame] | 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 | |
Vishnu Nair | fca7847 | 2020-03-09 15:34:47 -0700 | [diff] [blame] | 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 | */ |
| 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 Nair | 5cf25319 | 2019-11-07 15:33:20 -0800 | [diff] [blame] | 91 | WindowState getHostWindow(IBinder inputToken) { |
| 92 | EmbeddedWindow embeddedWindow = mWindows.get(inputToken); |
| 93 | return embeddedWindow != null ? embeddedWindow.mHostWindowState : null; |
| 94 | } |
| 95 | |
Vishnu Nair | 5cf25319 | 2019-11-07 15:33:20 -0800 | [diff] [blame] | 96 | void remove(IWindow client) { |
Vishnu Nair | ddbd251 | 2019-11-12 14:39:43 -0800 | [diff] [blame] | 97 | for (int i = mWindows.size() - 1; i >= 0; i--) { |
| 98 | if (mWindows.valueAt(i).mClient.asBinder() == client.asBinder()) { |
arthurhung | 03d65a7 | 2020-04-28 09:19:24 +0800 | [diff] [blame] | 99 | mWindows.removeAt(i).onRemoved(); |
Vishnu Nair | 5cf25319 | 2019-11-07 15:33:20 -0800 | [diff] [blame] | 100 | return; |
| 101 | } |
| 102 | } |
| 103 | } |
| 104 | |
Vishnu Nair | fca7847 | 2020-03-09 15:34:47 -0700 | [diff] [blame] | 105 | void onWindowRemoved(WindowState host) { |
Vishnu Nair | ddbd251 | 2019-11-12 14:39:43 -0800 | [diff] [blame] | 106 | for (int i = mWindows.size() - 1; i >= 0; i--) { |
| 107 | if (mWindows.valueAt(i).mHostWindowState == host) { |
arthurhung | 03d65a7 | 2020-04-28 09:19:24 +0800 | [diff] [blame] | 108 | mWindows.removeAt(i).onRemoved(); |
Vishnu Nair | 5cf25319 | 2019-11-07 15:33:20 -0800 | [diff] [blame] | 109 | } |
| 110 | } |
| 111 | } |
| 112 | |
Vishnu Nair | ddbd251 | 2019-11-12 14:39:43 -0800 | [diff] [blame] | 113 | EmbeddedWindow get(IBinder inputToken) { |
| 114 | return mWindows.get(inputToken); |
| 115 | } |
| 116 | |
Vishnu Nair | fca7847 | 2020-03-09 15:34:47 -0700 | [diff] [blame] | 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 | |
Vishnu Nair | ddbd251 | 2019-11-12 14:39:43 -0800 | [diff] [blame] | 130 | static class EmbeddedWindow { |
Vishnu Nair | 5cf25319 | 2019-11-07 15:33:20 -0800 | [diff] [blame] | 131 | final IWindow mClient; |
Vishnu Nair | ddbd251 | 2019-11-12 14:39:43 -0800 | [diff] [blame] | 132 | @Nullable final WindowState mHostWindowState; |
Vishnu Nair | fca7847 | 2020-03-09 15:34:47 -0700 | [diff] [blame] | 133 | @Nullable final ActivityRecord mHostActivityRecord; |
Vishnu Nair | 5cf25319 | 2019-11-07 15:33:20 -0800 | [diff] [blame] | 134 | final int mOwnerUid; |
| 135 | final int mOwnerPid; |
arthurhung | 03d65a7 | 2020-04-28 09:19:24 +0800 | [diff] [blame] | 136 | final WindowManagerService mWmService; |
| 137 | InputChannel mInputChannel; |
Vishnu Nair | 5cf25319 | 2019-11-07 15:33:20 -0800 | [diff] [blame] | 138 | |
Evan Rosky | 680377e | 2020-01-10 19:12:10 -0800 | [diff] [blame] | 139 | /** |
| 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 | */ |
arthurhung | 03d65a7 | 2020-04-28 09:19:24 +0800 | [diff] [blame] | 148 | EmbeddedWindow(WindowManagerService service, IWindow clientToken, |
| 149 | WindowState hostWindowState, int ownerUid, int ownerPid) { |
| 150 | mWmService = service; |
Vishnu Nair | 5cf25319 | 2019-11-07 15:33:20 -0800 | [diff] [blame] | 151 | mClient = clientToken; |
| 152 | mHostWindowState = hostWindowState; |
Vishnu Nair | fca7847 | 2020-03-09 15:34:47 -0700 | [diff] [blame] | 153 | mHostActivityRecord = (mHostWindowState != null) ? mHostWindowState.mActivityRecord |
| 154 | : null; |
Vishnu Nair | 5cf25319 | 2019-11-07 15:33:20 -0800 | [diff] [blame] | 155 | mOwnerUid = ownerUid; |
| 156 | mOwnerPid = ownerPid; |
| 157 | } |
Evan Rosky | 680377e | 2020-01-10 19:12:10 -0800 | [diff] [blame] | 158 | |
| 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 | } |
arthurhung | 03d65a7 | 2020-04-28 09:19:24 +0800 | [diff] [blame] | 174 | |
| 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 Nair | 5cf25319 | 2019-11-07 15:33:20 -0800 | [diff] [blame] | 198 | } |
| 199 | } |