• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 import static com.android.server.wm.ActivityStarter.Request;
20 
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.annotation.UserIdInt;
24 import android.app.ActivityOptions;
25 import android.app.ActivityTaskManager;
26 import android.content.Context;
27 import android.content.pm.ActivityInfo;
28 import android.hardware.display.DisplayManager;
29 import android.os.Handler;
30 import android.os.Looper;
31 import android.util.Pair;
32 import android.view.Display;
33 
34 import com.android.server.LocalServices;
35 import com.android.server.pm.UserManagerInternal;
36 
37 import java.util.ArrayList;
38 import java.util.List;
39 
40 /**
41  * Class to control the assignment of a display for Car while launching a Activity.
42  *
43  * <p>This one controls which displays users are allowed to launch.
44  * The policy should be passed from car service through
45  * {@link com.android.internal.car.ICarServiceHelper} binder interfaces. If no policy is set,
46  * this module will not change anything for launch process.</p>
47  *
48  * <p> The policy can only affect which display passenger users can use. Current user, assumed
49  * to be a driver user, is allowed to launch any display always.</p>
50  *
51  * @hide
52  */
53 public final class CarLaunchParamsModifier implements LaunchParamsController.LaunchParamsModifier {
54 
55     private final Context mContext;
56 
57     private DisplayManager mDisplayManager;  // set only from init()
58     private ActivityTaskManagerService mAtm;  // set only from init()
59 
60     private CarLaunchParamsModifierUpdatable mUpdatable;
61 
62     // getFallbackDisplayAreasForActivity() can return the most 3 {@link TaskDisplayAreaWrapper}.
63     private final ArrayList<TaskDisplayAreaWrapper> mFallBackDisplayAreaList = new ArrayList<>(3);
64 
65     /** Constructor. Can be constructed any time. */
CarLaunchParamsModifier(Context context)66     public CarLaunchParamsModifier(Context context) {
67         // This can be very early stage. So postpone interaction with other system until init.
68         mContext = context;
69     }
70 
setUpdatable(CarLaunchParamsModifierUpdatable updatable)71     public void setUpdatable(CarLaunchParamsModifierUpdatable updatable) {
72         mUpdatable = updatable;
73     }
74 
getBuiltinInterface()75     public CarLaunchParamsModifierInterface getBuiltinInterface() {
76         return mBuiltinInterface;
77     }
78 
79     /**
80      * Initializes all internal stuffs. This should be called only after ATMS, DisplayManagerService
81      * are ready.
82      */
init()83     public void init() {
84         mAtm = (ActivityTaskManagerService) ActivityTaskManager.getService();
85         LaunchParamsController controller = mAtm.mTaskSupervisor.getLaunchParamsController();
86         controller.registerModifier(this);
87         mDisplayManager = mContext.getSystemService(DisplayManager.class);
88         mDisplayManager.registerDisplayListener(mUpdatable.getDisplayListener(),
89                 new Handler(Looper.getMainLooper()));
90     }
91 
92     /** Notifies user visibility changed. */
handleUserVisibilityChanged(int userId, boolean visible)93     public void handleUserVisibilityChanged(int userId, boolean visible) {
94         mUpdatable.handleUserVisibilityChanged(userId, visible);
95     }
96 
97     /** Notifies user switching. */
handleUserStarting(@serIdInt int startingUserId)98     public void handleUserStarting(@UserIdInt int startingUserId) {
99         mUpdatable.handleUserStarting(startingUserId);
100     }
101 
102     /** Notifies user switching. */
handleCurrentUserSwitching(@serIdInt int newUserId)103     public void handleCurrentUserSwitching(@UserIdInt int newUserId) {
104         mUpdatable.handleCurrentUserSwitching(newUserId);
105     }
106 
107     /** Notifies user stopped. */
handleUserStopped(@serIdInt int stoppedUser)108     public void handleUserStopped(@UserIdInt int stoppedUser) {
109         mUpdatable.handleUserStopped(stoppedUser);
110     }
111 
112     /**
113      * Decides display to assign while an Activity is launched.
114      *
115      * <p>For current user (=driver), launching to any display is allowed as long as system
116      * allows it.</p>
117      *
118      * <p>For private display, do not change anything as private display has its own logic.</p>
119      *
120      * <p>For passenger displays, only run in allowed displays. If requested display is not
121      * allowed, change to the 1st allowed display.</p>
122      */
123     @Override
124     @Result
onCalculate(@ullable Task task, @Nullable ActivityInfo.WindowLayout layout, @Nullable ActivityRecord activity, @Nullable ActivityRecord source, ActivityOptions options, @Nullable Request request, int phase, LaunchParamsController.LaunchParams currentParams, LaunchParamsController.LaunchParams outParams)125     public int onCalculate(@Nullable Task task, @Nullable ActivityInfo.WindowLayout layout,
126             @Nullable ActivityRecord activity, @Nullable ActivityRecord source,
127             ActivityOptions options, @Nullable Request request, int phase,
128             LaunchParamsController.LaunchParams currentParams,
129             LaunchParamsController.LaunchParams outParams) {
130         CalculateParams params = CalculateParams.create(task, layout, activity, source,
131                 options, request, phase, currentParams, outParams, mAtm.mSupportsMultiDisplay);
132         return mUpdatable.calculate(params);
133     }
134 
135     @Nullable
getDefaultTaskDisplayAreaOnDisplay(int displayId)136     private TaskDisplayAreaWrapper getDefaultTaskDisplayAreaOnDisplay(int displayId) {
137         if (displayId == Display.INVALID_DISPLAY) {
138             return null;
139         }
140         DisplayContent dc = mAtm.mRootWindowContainer.getDisplayContentOrCreate(displayId);
141         if (dc == null) {
142             return null;
143         }
144         return TaskDisplayAreaWrapper.create(dc.getDefaultTaskDisplayArea());
145     }
146 
147     /**
148      * Calculates the default {@link TaskDisplayAreaWrapper} for a task. We attempt to put
149      * the activity within the same display area if possible. The strategy is to find the display
150      * in the following order:
151      *
152      * <ol>
153      *     <li>The display area of the top activity from the launching process will be used</li>
154      *     <li>The display area of the top activity from the real launching process will be used
155      *     </li>
156      *     <li>Default display area from the associated root window container.</li>
157      * </ol>
158      * @param activityRecordWrapper the activity being started
159      * @param requestWrapper optional {@link RequestWrapper} made to start the activity record
160      * @return the list of {@link TaskDisplayAreaWrapper} to house the task
161      */
getFallbackDisplayAreasForActivity( @onNull ActivityRecordWrapper activityRecordWrapper, @Nullable RequestWrapper requestWrapper)162     private List<TaskDisplayAreaWrapper> getFallbackDisplayAreasForActivity(
163             @NonNull ActivityRecordWrapper activityRecordWrapper,
164             @Nullable RequestWrapper requestWrapper) {
165         ActivityRecord activityRecord = activityRecordWrapper.getActivityRecord();
166         Request request = requestWrapper != null ? requestWrapper.getRequest() : null;
167         mFallBackDisplayAreaList.clear();
168 
169         WindowProcessController controllerFromLaunchingRecord = mAtm.getProcessController(
170                 activityRecord.getLaunchedFromPid(), activityRecord.getLaunchedFromUid());
171         TaskDisplayArea displayAreaForLaunchingRecord = controllerFromLaunchingRecord == null
172                 ? null : controllerFromLaunchingRecord.getTopActivityDisplayArea();
173         if (displayAreaForLaunchingRecord != null) {
174             mFallBackDisplayAreaList.add(
175                     TaskDisplayAreaWrapper.create(displayAreaForLaunchingRecord));
176         }
177 
178         WindowProcessController controllerFromProcess = mAtm.getProcessController(
179                 activityRecord.getProcessName(), activityRecord.getUid());
180         TaskDisplayArea displayAreaForRecord = controllerFromProcess == null ? null
181                 : controllerFromProcess.getTopActivityDisplayArea();
182         if (displayAreaForRecord != null) {
183             mFallBackDisplayAreaList.add(TaskDisplayAreaWrapper.create(displayAreaForRecord));
184         }
185 
186         WindowProcessController controllerFromRequest =
187                 request == null ? null : mAtm.getProcessController(request.realCallingPid,
188                         request.realCallingUid);
189         TaskDisplayArea displayAreaFromSourceProcess = controllerFromRequest == null ? null
190                 : controllerFromRequest.getTopActivityDisplayArea();
191         if (displayAreaFromSourceProcess != null) {
192             mFallBackDisplayAreaList.add(
193                     TaskDisplayAreaWrapper.create(displayAreaFromSourceProcess));
194         }
195         return mFallBackDisplayAreaList;
196     }
197 
198     @Nullable
findTaskDisplayArea(int displayId, int featureId)199     private TaskDisplayAreaWrapper findTaskDisplayArea(int displayId, int featureId) {
200         DisplayContent display = mAtm.mRootWindowContainer.getDisplayContent(displayId);
201         if (display == null) {
202             return null;
203         }
204         TaskDisplayArea tda = display.getItemFromTaskDisplayAreas(
205                 displayArea -> displayArea.mFeatureId == featureId ? displayArea : null);
206         return TaskDisplayAreaWrapper.create(tda);
207     }
208 
209     private final CarLaunchParamsModifierInterface mBuiltinInterface =
210             new CarLaunchParamsModifierInterface() {
211         @Nullable
212         @Override
213         public TaskDisplayAreaWrapper findTaskDisplayArea(int displayId, int featureId) {
214             return CarLaunchParamsModifier.this.findTaskDisplayArea(displayId, featureId);
215         }
216 
217         @Nullable
218         @Override
219         public TaskDisplayAreaWrapper getDefaultTaskDisplayAreaOnDisplay(int displayId) {
220             return CarLaunchParamsModifier.this.getDefaultTaskDisplayAreaOnDisplay(displayId);
221         }
222 
223         @NonNull
224         @Override
225         public List<TaskDisplayAreaWrapper> getFallbackDisplayAreasForActivity(
226                 @NonNull ActivityRecordWrapper activityRecord, @Nullable RequestWrapper request) {
227             return CarLaunchParamsModifier.this.getFallbackDisplayAreasForActivity(
228                     activityRecord, request);
229         }
230 
231         @NonNull
232         @Override
233         public Pair<Integer, Integer> getCurrentAndTargetUserIds() {
234             return mAtm.mAmInternal.getCurrentAndTargetUserIds();
235         }
236 
237         @Override
238         public int getUserAssignedToDisplay(int displayId) {
239             UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class);
240             int userId = umi.getUserAssignedToDisplay(displayId);
241             return userId;
242         }
243 
244         @Override
245         public int getMainDisplayAssignedToUser(int userId) {
246             UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class);
247             int displayId = umi.getMainDisplayAssignedToUser(userId);
248             return displayId;
249         }
250     };
251 }
252