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 implements InputTarget { 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 169 @Override toString()170 public String toString() { 171 final String hostWindowName = (mHostWindowState != null) 172 ? mHostWindowState.getWindowTag().toString() : "Internal"; 173 return "EmbeddedWindow{ u" + UserHandle.getUserId(mOwnerUid) + " " + hostWindowName 174 + "}"; 175 } 176 getApplicationHandle()177 InputApplicationHandle getApplicationHandle() { 178 if (mHostWindowState == null 179 || mHostWindowState.mInputWindowHandle.getInputApplicationHandle() == null) { 180 return null; 181 } 182 return new InputApplicationHandle( 183 mHostWindowState.mInputWindowHandle.getInputApplicationHandle()); 184 } 185 openInputChannel()186 InputChannel openInputChannel() { 187 final String name = toString(); 188 mInputChannel = mWmService.mInputManager.createInputChannel(name); 189 return mInputChannel; 190 } 191 onRemoved()192 void onRemoved() { 193 if (mInputChannel != null) { 194 mWmService.mInputManager.removeInputChannel(mInputChannel.getToken()); 195 mInputChannel.dispose(); 196 mInputChannel = null; 197 } 198 } 199 200 @Override getWindowState()201 public WindowState getWindowState() { 202 return mHostWindowState; 203 } 204 205 @Override getDisplayId()206 public int getDisplayId() { 207 return mDisplayId; 208 } 209 210 @Override getIWindow()211 public IWindow getIWindow() { 212 return mClient; 213 } 214 215 @Override getPid()216 public int getPid() { 217 return mOwnerPid; 218 } 219 } 220 } 221