1 /* 2 * Copyright (C) 2020 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 import static android.window.DisplayAreaOrganizer.FEATURE_RUNTIME_TASK_CONTAINER_FIRST; 20 21 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER; 22 import static com.android.server.wm.DisplayArea.Type.ANY; 23 24 import android.annotation.Nullable; 25 import android.content.pm.ParceledListSlice; 26 import android.os.Binder; 27 import android.os.IBinder; 28 import android.os.RemoteException; 29 import android.util.Slog; 30 import android.view.SurfaceControl; 31 import android.window.DisplayAreaAppearedInfo; 32 import android.window.IDisplayAreaOrganizer; 33 import android.window.IDisplayAreaOrganizerController; 34 import android.window.WindowContainerToken; 35 36 import com.android.internal.protolog.common.ProtoLog; 37 38 import java.util.ArrayList; 39 import java.util.HashMap; 40 import java.util.List; 41 42 public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerController.Stub { 43 private static final String TAG = "DisplayAreaOrganizerController"; 44 45 /** 46 * Next available feature id for a runtime task display area. 47 * @see #createTaskDisplayArea(IDisplayAreaOrganizer organizer, int, int, String) 48 */ 49 private int mNextTaskDisplayAreaFeatureId = FEATURE_RUNTIME_TASK_CONTAINER_FIRST; 50 51 final ActivityTaskManagerService mService; 52 private final WindowManagerGlobalLock mGlobalLock; 53 private final HashMap<Integer, DisplayAreaOrganizerState> mOrganizersByFeatureIds = 54 new HashMap(); 55 56 private class DeathRecipient implements IBinder.DeathRecipient { 57 int mFeature; 58 IDisplayAreaOrganizer mOrganizer; 59 DeathRecipient(IDisplayAreaOrganizer organizer, int feature)60 DeathRecipient(IDisplayAreaOrganizer organizer, int feature) { 61 mOrganizer = organizer; 62 mFeature = feature; 63 } 64 65 @Override binderDied()66 public void binderDied() { 67 synchronized (mGlobalLock) { 68 mOrganizersByFeatureIds.remove(mFeature).destroy(); 69 } 70 } 71 } 72 73 private class DisplayAreaOrganizerState { 74 private final IDisplayAreaOrganizer mOrganizer; 75 private final DeathRecipient mDeathRecipient; 76 DisplayAreaOrganizerState(IDisplayAreaOrganizer organizer, int feature)77 DisplayAreaOrganizerState(IDisplayAreaOrganizer organizer, int feature) { 78 mOrganizer = organizer; 79 mDeathRecipient = new DeathRecipient(organizer, feature); 80 try { 81 organizer.asBinder().linkToDeath(mDeathRecipient, 0); 82 } catch (RemoteException e) { 83 // Oh well... 84 } 85 } 86 destroy()87 void destroy() { 88 IBinder organizerBinder = mOrganizer.asBinder(); 89 mService.mRootWindowContainer.forAllDisplayAreas((da) -> { 90 if (da.mOrganizer != null && da.mOrganizer.asBinder().equals(organizerBinder)) { 91 if (da.isTaskDisplayArea() && da.asTaskDisplayArea().mCreatedByOrganizer) { 92 // Delete the organizer created TDA when unregister. 93 deleteTaskDisplayArea(da.asTaskDisplayArea()); 94 } else { 95 da.setOrganizer(null); 96 } 97 } 98 }); 99 organizerBinder.unlinkToDeath(mDeathRecipient, 0); 100 } 101 } 102 DisplayAreaOrganizerController(ActivityTaskManagerService atm)103 DisplayAreaOrganizerController(ActivityTaskManagerService atm) { 104 mService = atm; 105 mGlobalLock = atm.mGlobalLock; 106 } 107 enforceTaskPermission(String func)108 private void enforceTaskPermission(String func) { 109 mService.enforceTaskPermission(func); 110 } 111 112 @Nullable getOrganizerByFeature(int featureId)113 IDisplayAreaOrganizer getOrganizerByFeature(int featureId) { 114 final DisplayAreaOrganizerState state = mOrganizersByFeatureIds.get(featureId); 115 return state != null ? state.mOrganizer : null; 116 } 117 118 @Override registerOrganizer( IDisplayAreaOrganizer organizer, int feature)119 public ParceledListSlice<DisplayAreaAppearedInfo> registerOrganizer( 120 IDisplayAreaOrganizer organizer, int feature) { 121 enforceTaskPermission("registerOrganizer()"); 122 final long uid = Binder.getCallingUid(); 123 final long origId = Binder.clearCallingIdentity(); 124 try { 125 synchronized (mGlobalLock) { 126 ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Register display organizer=%s uid=%d", 127 organizer.asBinder(), uid); 128 if (mOrganizersByFeatureIds.get(feature) != null) { 129 if (mOrganizersByFeatureIds.get(feature).mOrganizer.asBinder() 130 .isBinderAlive()) { 131 throw new IllegalStateException( 132 "Replacing existing organizer currently unsupported"); 133 } 134 135 mOrganizersByFeatureIds.remove(feature).destroy(); 136 Slog.d(TAG, "Replacing dead organizer for feature=" + feature); 137 } 138 139 final DisplayAreaOrganizerState state = new DisplayAreaOrganizerState(organizer, 140 feature); 141 final List<DisplayAreaAppearedInfo> displayAreaInfos = new ArrayList<>(); 142 mService.mRootWindowContainer.forAllDisplays(dc -> { 143 if (!dc.isTrusted()) { 144 ProtoLog.w(WM_DEBUG_WINDOW_ORGANIZER, 145 "Don't organize or trigger events for untrusted displayId=%d", 146 dc.getDisplayId()); 147 return; 148 } 149 dc.forAllDisplayAreas((da) -> { 150 if (da.mFeatureId != feature) return; 151 displayAreaInfos.add(organizeDisplayArea(organizer, da, 152 "DisplayAreaOrganizerController.registerOrganizer")); 153 }); 154 }); 155 156 mOrganizersByFeatureIds.put(feature, state); 157 return new ParceledListSlice<>(displayAreaInfos); 158 } 159 } finally { 160 Binder.restoreCallingIdentity(origId); 161 } 162 } 163 164 @Override unregisterOrganizer(IDisplayAreaOrganizer organizer)165 public void unregisterOrganizer(IDisplayAreaOrganizer organizer) { 166 enforceTaskPermission("unregisterTaskOrganizer()"); 167 final long uid = Binder.getCallingUid(); 168 final long origId = Binder.clearCallingIdentity(); 169 try { 170 synchronized (mGlobalLock) { 171 ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Unregister display organizer=%s uid=%d", 172 organizer.asBinder(), uid); 173 mOrganizersByFeatureIds.entrySet().removeIf((entry) -> { 174 final boolean matches = entry.getValue().mOrganizer.asBinder() 175 == organizer.asBinder(); 176 if (matches) { 177 entry.getValue().destroy(); 178 } 179 return matches; 180 }); 181 } 182 } finally { 183 Binder.restoreCallingIdentity(origId); 184 } 185 } 186 187 @Override createTaskDisplayArea(IDisplayAreaOrganizer organizer, int displayId, int parentFeatureId, String name)188 public DisplayAreaAppearedInfo createTaskDisplayArea(IDisplayAreaOrganizer organizer, 189 int displayId, int parentFeatureId, String name) { 190 enforceTaskPermission("createTaskDisplayArea()"); 191 final long uid = Binder.getCallingUid(); 192 final long origId = Binder.clearCallingIdentity(); 193 try { 194 synchronized (mGlobalLock) { 195 ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Create TaskDisplayArea uid=%d", uid); 196 197 final DisplayContent display = 198 mService.mRootWindowContainer.getDisplayContent(displayId); 199 if (display == null) { 200 throw new IllegalArgumentException("createTaskDisplayArea unknown displayId=" 201 + displayId); 202 } 203 if (!display.isTrusted()) { 204 throw new IllegalArgumentException("createTaskDisplayArea untrusted displayId=" 205 + displayId); 206 } 207 208 // The parentFeatureId can be either a RootDisplayArea or a TaskDisplayArea. 209 // Check if there is a RootDisplayArea with the given parentFeatureId. 210 final RootDisplayArea parentRoot = display.getItemFromDisplayAreas(da -> 211 da.asRootDisplayArea() != null && da.mFeatureId == parentFeatureId 212 ? da.asRootDisplayArea() 213 : null); 214 final TaskDisplayArea parentTda; 215 if (parentRoot == null) { 216 // There is no RootDisplayArea matching the parentFeatureId. 217 // Check if there is a TaskDisplayArea with the given parentFeatureId. 218 parentTda = display.getItemFromTaskDisplayAreas(taskDisplayArea -> 219 taskDisplayArea.mFeatureId == parentFeatureId 220 ? taskDisplayArea 221 : null); 222 } else { 223 parentTda = null; 224 } 225 if (parentRoot == null && parentTda == null) { 226 throw new IllegalArgumentException( 227 "Can't find a parent DisplayArea with featureId=" + parentFeatureId); 228 } 229 230 final int taskDisplayAreaFeatureId = mNextTaskDisplayAreaFeatureId++; 231 final DisplayAreaOrganizerState state = new DisplayAreaOrganizerState(organizer, 232 taskDisplayAreaFeatureId); 233 234 final TaskDisplayArea tda = parentRoot != null 235 ? createTaskDisplayArea(parentRoot, name, taskDisplayAreaFeatureId) 236 : createTaskDisplayArea(parentTda, name, taskDisplayAreaFeatureId); 237 final DisplayAreaAppearedInfo tdaInfo = organizeDisplayArea(organizer, tda, 238 "DisplayAreaOrganizerController.createTaskDisplayArea"); 239 mOrganizersByFeatureIds.put(taskDisplayAreaFeatureId, state); 240 return tdaInfo; 241 } 242 } finally { 243 Binder.restoreCallingIdentity(origId); 244 } 245 } 246 247 @Override deleteTaskDisplayArea(WindowContainerToken token)248 public void deleteTaskDisplayArea(WindowContainerToken token) { 249 enforceTaskPermission("deleteTaskDisplayArea()"); 250 final long uid = Binder.getCallingUid(); 251 final long origId = Binder.clearCallingIdentity(); 252 try { 253 synchronized (mGlobalLock) { 254 ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Delete TaskDisplayArea uid=%d", uid); 255 256 final WindowContainer wc = WindowContainer.fromBinder(token.asBinder()); 257 if (wc == null || wc.asTaskDisplayArea() == null) { 258 throw new IllegalArgumentException("Can't resolve TaskDisplayArea from token"); 259 } 260 final TaskDisplayArea taskDisplayArea = wc.asTaskDisplayArea(); 261 if (!taskDisplayArea.mCreatedByOrganizer) { 262 throw new IllegalArgumentException( 263 "Attempt to delete TaskDisplayArea not created by organizer " 264 + "TaskDisplayArea=" + taskDisplayArea); 265 } 266 267 mOrganizersByFeatureIds.remove(taskDisplayArea.mFeatureId).destroy(); 268 } 269 } finally { 270 Binder.restoreCallingIdentity(origId); 271 } 272 } 273 onDisplayAreaAppeared(IDisplayAreaOrganizer organizer, DisplayArea da)274 void onDisplayAreaAppeared(IDisplayAreaOrganizer organizer, DisplayArea da) { 275 ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "DisplayArea appeared name=%s", da.getName()); 276 try { 277 SurfaceControl outSurfaceControl = new SurfaceControl(da.getSurfaceControl(), 278 "DisplayAreaOrganizerController.onDisplayAreaAppeared"); 279 organizer.onDisplayAreaAppeared(da.getDisplayAreaInfo(), outSurfaceControl); 280 } catch (RemoteException e) { 281 // Oh well... 282 } 283 } 284 onDisplayAreaVanished(IDisplayAreaOrganizer organizer, DisplayArea da)285 void onDisplayAreaVanished(IDisplayAreaOrganizer organizer, DisplayArea da) { 286 ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "DisplayArea vanished name=%s", da.getName()); 287 if (!organizer.asBinder().isBinderAlive()) { 288 Slog.d(TAG, "Organizer died before sending onDisplayAreaVanished"); 289 return; 290 } 291 try { 292 organizer.onDisplayAreaVanished(da.getDisplayAreaInfo()); 293 } catch (RemoteException e) { 294 // Oh well... 295 } 296 } 297 onDisplayAreaInfoChanged(IDisplayAreaOrganizer organizer, DisplayArea da)298 void onDisplayAreaInfoChanged(IDisplayAreaOrganizer organizer, DisplayArea da) { 299 ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "DisplayArea info changed name=%s", da.getName()); 300 try { 301 organizer.onDisplayAreaInfoChanged(da.getDisplayAreaInfo()); 302 } catch (RemoteException e) { 303 // Oh well... 304 } 305 } 306 organizeDisplayArea(IDisplayAreaOrganizer organizer, DisplayArea displayArea, String callsite)307 private DisplayAreaAppearedInfo organizeDisplayArea(IDisplayAreaOrganizer organizer, 308 DisplayArea displayArea, String callsite) { 309 displayArea.setOrganizer(organizer, true /* skipDisplayAreaAppeared */); 310 return new DisplayAreaAppearedInfo(displayArea.getDisplayAreaInfo(), 311 new SurfaceControl(displayArea.getSurfaceControl(), callsite)); 312 } 313 314 /** 315 * Creates a {@link TaskDisplayArea} as the topmost TDA below the given {@link RootDisplayArea}. 316 */ createTaskDisplayArea(RootDisplayArea root, String name, int taskDisplayAreaFeatureId)317 private TaskDisplayArea createTaskDisplayArea(RootDisplayArea root, String name, 318 int taskDisplayAreaFeatureId) { 319 final TaskDisplayArea taskDisplayArea = new TaskDisplayArea(root.mDisplayContent, 320 root.mWmService, name, taskDisplayAreaFeatureId, true /* createdByOrganizer */); 321 322 // Find the top most DA that can contain Task (either a TDA or a DisplayAreaGroup). 323 final DisplayArea topTaskContainer = root.getItemFromDisplayAreas(da -> { 324 if (da.mType != ANY) { 325 return null; 326 } 327 328 final RootDisplayArea rootDA = da.getRootDisplayArea(); 329 if (rootDA == root || rootDA == da) { 330 // Either it is the top TDA below the root or it is a DisplayAreaGroup. 331 return da; 332 } 333 return null; 334 }); 335 if (topTaskContainer == null) { 336 throw new IllegalStateException("Root must either contain TDA or DAG root=" + root); 337 } 338 339 // Insert the TaskDisplayArea as the top Task container. 340 final WindowContainer parent = topTaskContainer.getParent(); 341 final int index = parent.mChildren.indexOf(topTaskContainer) + 1; 342 parent.addChild(taskDisplayArea, index); 343 344 return taskDisplayArea; 345 } 346 347 /** 348 * Creates a {@link TaskDisplayArea} as the topmost child of the given {@link TaskDisplayArea}. 349 */ createTaskDisplayArea(TaskDisplayArea parentTda, String name, int taskDisplayAreaFeatureId)350 private TaskDisplayArea createTaskDisplayArea(TaskDisplayArea parentTda, String name, 351 int taskDisplayAreaFeatureId) { 352 final TaskDisplayArea taskDisplayArea = new TaskDisplayArea(parentTda.mDisplayContent, 353 parentTda.mWmService, name, taskDisplayAreaFeatureId, 354 true /* createdByOrganizer */); 355 356 // Insert the TaskDisplayArea on the top. 357 parentTda.addChild(taskDisplayArea, WindowContainer.POSITION_TOP); 358 359 return taskDisplayArea; 360 } 361 deleteTaskDisplayArea(TaskDisplayArea taskDisplayArea)362 private void deleteTaskDisplayArea(TaskDisplayArea taskDisplayArea) { 363 taskDisplayArea.setOrganizer(null); 364 mService.mRootWindowContainer.mTaskSupervisor.beginDeferResume(); 365 366 // TaskDisplayArea#remove() move the stacks to the default TaskDisplayArea. 367 Task lastReparentedRootTask; 368 try { 369 lastReparentedRootTask = taskDisplayArea.remove(); 370 } finally { 371 mService.mRootWindowContainer.mTaskSupervisor.endDeferResume(); 372 } 373 374 taskDisplayArea.removeImmediately(); 375 376 // Only update focus/visibility for the last one because there may be many root tasks are 377 // reparented and the intermediate states are unnecessary. 378 if (lastReparentedRootTask != null) { 379 lastReparentedRootTask.resumeNextFocusAfterReparent(); 380 } 381 } 382 } 383