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