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