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