1 /* 2 * Copyright (C) 2021 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 android.car.builtin.app; 18 19 import android.Manifest; 20 import android.annotation.NonNull; 21 import android.annotation.RequiresPermission; 22 import android.annotation.SystemApi; 23 import android.annotation.UserIdInt; 24 import android.app.Activity; 25 import android.app.ActivityManager; 26 import android.app.ActivityOptions; 27 import android.app.ActivityTaskManager; 28 import android.app.ActivityTaskManager.RootTaskInfo; 29 import android.app.IActivityManager; 30 import android.app.IProcessObserver; 31 import android.car.builtin.util.Slogf; 32 import android.os.Bundle; 33 import android.os.IBinder; 34 import android.os.RemoteException; 35 36 import java.util.List; 37 import java.util.concurrent.Callable; 38 39 /** 40 * Provide access to {@code android.app.IActivityManager} calls. 41 * @hide 42 */ 43 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) 44 public final class ActivityManagerHelper { 45 46 /** Invalid task ID. */ 47 public static final int INVALID_TASK_ID = ActivityTaskManager.INVALID_TASK_ID; 48 49 /** Persistent process flag */ 50 public static final int PROCESS_INFO_PERSISTENT_FLAG = 51 ActivityManager.RunningAppProcessInfo.FLAG_PERSISTENT; 52 53 private static final String TAG = "CAR.AM"; // CarLog.TAG_AM 54 55 // Lazy initialization holder class idiom for static fields; See go/ej3e-83 for the detail. 56 private static class ActivityManagerHolder { 57 static final IActivityManager sAm = ActivityManager.getService(); 58 } 59 getActivityManager()60 private static IActivityManager getActivityManager() { 61 return ActivityManagerHolder.sAm; 62 } 63 ActivityManagerHelper()64 private ActivityManagerHelper() { 65 throw new UnsupportedOperationException("contains only static members"); 66 } 67 68 /** 69 * See {@code android.app.IActivityManager.startUserInBackground}. 70 * 71 * @throws IllegalStateException if ActivityManager binder throws RemoteException 72 */ startUserInBackground(@serIdInt int userId)73 public static boolean startUserInBackground(@UserIdInt int userId) { 74 return runRemotely(() -> getActivityManager().startUserInBackground(userId), 75 "error while startUserInBackground %d", userId); 76 } 77 78 /** 79 * See {@code android.app.IActivityManager.startUserInBackgroundVisibleOnDisplay}. 80 * 81 * @throws IllegalStateException if ActivityManager binder throws RemoteException 82 */ startUserInBackgroundVisibleOnDisplay(@serIdInt int userId, int displayId)83 public static boolean startUserInBackgroundVisibleOnDisplay(@UserIdInt int userId, 84 int displayId) { 85 return runRemotely(() -> getActivityManager().startUserInBackgroundVisibleOnDisplay( 86 userId, displayId, /* unlockProgressListener= */ null), 87 "error while startUserInBackgroundVisibleOnDisplay userId:%d displayId:%d", 88 userId, displayId); 89 } 90 91 /** 92 * See {@code android.app.IActivityManager.startUserInForegroundWithListener}. 93 * 94 * @throws IllegalStateException if ActivityManager binder throws RemoteException 95 */ startUserInForeground(@serIdInt int userId)96 public static boolean startUserInForeground(@UserIdInt int userId) { 97 return runRemotely( 98 () -> getActivityManager().startUserInForegroundWithListener( 99 userId, /* listener= */ null), 100 "error while startUserInForeground %d", userId); 101 } 102 103 /** 104 * See {@code android.app.IActivityManager.stopUser}. 105 * 106 * @throws IllegalStateException if ActivityManager binder throws RemoteException 107 */ stopUser(@serIdInt int userId, boolean force)108 public static int stopUser(@UserIdInt int userId, boolean force) { 109 // Note that the value of force is irrelevant. Even historically, it never had any effect 110 // in this case, since it only even applied to profiles (which Car didn't support). 111 return runRemotely( 112 () -> getActivityManager().stopUserWithCallback(userId, /* callback= */ null), 113 "error while stopUser userId:%d force:%b", userId, force); 114 } 115 116 /** 117 * See {@code android.app.IActivityManager.stopUserWithDelayedLocking}. 118 * 119 * @throws IllegalStateException if ActivityManager binder throws RemoteException 120 */ stopUserWithDelayedLocking(@serIdInt int userId, boolean force)121 public static int stopUserWithDelayedLocking(@UserIdInt int userId, boolean force) { 122 // Note that the value of force is irrelevant. Even historically, it never had any effect 123 // in this case, since it only even applied to profiles (which Car didn't support). 124 return runRemotely( 125 () -> getActivityManager().stopUserWithDelayedLocking( 126 userId, /* callback= */ null), 127 "error while stopUserWithDelayedLocking userId:%d force:%b", userId, force); 128 } 129 130 /** 131 * Check {@code android.app.IActivityManager.unlockUser}. 132 * 133 * @throws IllegalStateException if ActivityManager binder throws RemoteException 134 */ unlockUser(@serIdInt int userId)135 public static boolean unlockUser(@UserIdInt int userId) { 136 return runRemotely(() -> getActivityManager().unlockUser2(userId, /* listener= */ null), 137 "error while unlocking user %d", userId); 138 } 139 140 /** 141 * Stops all task for the user. 142 * 143 * @throws IllegalStateException if ActivityManager binder throws RemoteException 144 */ stopAllTasksForUser(@serIdInt int userId)145 public static void stopAllTasksForUser(@UserIdInt int userId) { 146 try { 147 IActivityManager am = getActivityManager(); 148 for (RootTaskInfo info : am.getAllRootTaskInfos()) { 149 for (int i = 0; i < info.childTaskIds.length; i++) { 150 if (info.childTaskUserIds[i] == userId) { 151 int taskId = info.childTaskIds[i]; 152 if (!am.removeTask(taskId)) { 153 Slogf.w(TAG, "could not remove task " + taskId); 154 } 155 } 156 } 157 } 158 } catch (RemoteException e) { 159 throw logAndReThrow(e, "could not get stack info for user %d", userId); 160 } 161 } 162 163 /** 164 * Creates an ActivityOptions from the Bundle generated from ActivityOptions. 165 */ 166 @NonNull createActivityOptions(@onNull Bundle bOptions)167 public static ActivityOptions createActivityOptions(@NonNull Bundle bOptions) { 168 return new ActivityOptions(bOptions); 169 } 170 runRemotely(Callable<T> callable, String format, Object...args)171 private static <T> T runRemotely(Callable<T> callable, String format, Object...args) { 172 try { 173 return callable.call(); 174 } catch (Exception e) { 175 throw logAndReThrow(e, format, args); 176 } 177 } 178 179 @SuppressWarnings("AnnotateFormatMethod") logAndReThrow(Exception e, String format, Object...args)180 private static RuntimeException logAndReThrow(Exception e, String format, Object...args) { 181 String msg = String.format(format, args); 182 Slogf.e(TAG, msg, e); 183 return new IllegalStateException(msg, e); 184 } 185 186 /** 187 * Makes the task of the given taskId focused. 188 */ setFocusedTask(int taskId)189 public static void setFocusedTask(int taskId) { 190 try { 191 ActivityTaskManager.getService().setFocusedTask(taskId); 192 } catch (RemoteException e) { 193 Slogf.e(TAG, "Failed to setFocusedTask", e); 194 } 195 } 196 197 /** 198 * Removes the given task. 199 */ removeTask(int taskId)200 public static boolean removeTask(int taskId) { 201 try { 202 return getActivityManager().removeTask(taskId); 203 } catch (RemoteException e) { 204 Slogf.e(TAG, "Failed to removeTask", e); 205 } 206 return false; 207 } 208 209 /** 210 * Gets the flag values for the given {@link ActivityManager.RunningAppProcessInfo} 211 * 212 * @param appProcessInfo The {@link ActivityManager.RunningAppProcessInfo} 213 * @return The flags for the appProcessInfo 214 */ getFlagsForRunningAppProcessInfo( @onNull ActivityManager.RunningAppProcessInfo appProcessInfo)215 public static int getFlagsForRunningAppProcessInfo( 216 @NonNull ActivityManager.RunningAppProcessInfo appProcessInfo) { 217 return appProcessInfo.flags; 218 } 219 220 /** 221 * Gets all the running app process 222 * 223 * @return List of all the RunningAppProcessInfo 224 */ getRunningAppProcesses()225 public static List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() { 226 try { 227 return getActivityManager().getRunningAppProcesses(); 228 } catch (RemoteException e) { 229 Slogf.e(TAG, "Failed to removeTask", e); 230 } 231 return List.of(); 232 } 233 234 /** 235 * Callback to monitor Processes in the system 236 */ 237 public abstract static class ProcessObserverCallback { 238 /** Called when the foreground Activities are changed. */ onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities)239 public void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) { 240 } 241 /** Called when the Process is died. */ onProcessDied(int pid, int uid)242 public void onProcessDied(int pid, int uid) {} 243 244 final IProcessObserver.Stub mIProcessObserver = new IProcessObserver.Stub() { 245 @Override 246 public void onForegroundActivitiesChanged( 247 int pid, int uid, boolean foregroundActivities) throws RemoteException { 248 ProcessObserverCallback.this.onForegroundActivitiesChanged( 249 pid, uid, foregroundActivities); 250 } 251 252 @Override 253 public void onForegroundServicesChanged(int pid, int uid, int fgServiceTypes) 254 throws RemoteException { 255 // Not used 256 } 257 258 @Override 259 public void onProcessStarted(int pid, int processUid, int packageUid, 260 String packageName, String processName) { 261 // Not used 262 } 263 264 @Override 265 public void onProcessDied(int pid, int uid) throws RemoteException { 266 ProcessObserverCallback.this.onProcessDied(pid, uid); 267 } 268 }; 269 } 270 271 /** 272 * Registers a callback to be invoked when the process states are changed. 273 * @param callback a callback to register 274 */ registerProcessObserverCallback(ProcessObserverCallback callback)275 public static void registerProcessObserverCallback(ProcessObserverCallback callback) { 276 try { 277 getActivityManager().registerProcessObserver(callback.mIProcessObserver); 278 } catch (RemoteException e) { 279 Slogf.e(TAG, "Failed to register ProcessObserver", e); 280 throw new RuntimeException(e); 281 } 282 } 283 284 /** 285 * Unregisters the given callback. 286 * @param callback a callback to unregister 287 */ unregisterProcessObserverCallback(ProcessObserverCallback callback)288 public static void unregisterProcessObserverCallback(ProcessObserverCallback callback) { 289 try { 290 getActivityManager().unregisterProcessObserver(callback.mIProcessObserver); 291 } catch (RemoteException e) { 292 Slogf.e(TAG, "Failed to unregister listener", e); 293 throw new RuntimeException(e); 294 } 295 } 296 297 /** 298 * Same as {@link ActivityManager#checkComponentPermission(String, int, int, boolean). 299 */ checkComponentPermission(@onNull String permission, int uid, int owningUid, boolean exported)300 public static int checkComponentPermission(@NonNull String permission, int uid, int owningUid, 301 boolean exported) { 302 return ActivityManager.checkComponentPermission(permission, uid, owningUid, exported); 303 } 304 305 /** See {@link android.app.ActivityTaskManager#getTasks(int, boolean, boolean, int)} */ getTasks(int maxNum, boolean filterOnlyVisibleRecents, boolean keepIntentExtra, int displayId)306 public static List<ActivityManager.RunningTaskInfo> getTasks(int maxNum, 307 boolean filterOnlyVisibleRecents, boolean keepIntentExtra, int displayId) { 308 return ActivityTaskManager.getInstance().getTasks(maxNum, filterOnlyVisibleRecents, 309 keepIntentExtra, displayId); 310 } 311 312 /** 313 * Same as {@link ActivityManager#killAllBackgroundProcesses()} 314 */ killAllBackgroundProcesses()315 public static void killAllBackgroundProcesses() { 316 try { 317 getActivityManager().killAllBackgroundProcesses(); 318 } catch (RemoteException e) { 319 Slogf.e(TAG, "Failed to kill background apps", e); 320 throw new RuntimeException(e); 321 } 322 } 323 324 /** 325 * Same as {@link ActivityManager#killUid()} 326 */ killUid(int appId, int userId, String reason)327 public static void killUid(int appId, int userId, String reason) { 328 try { 329 getActivityManager().killUid(appId, userId, reason); 330 } catch (RemoteException e) { 331 Slogf.e(TAG, "Failed to call app : %d , userId: %d, kill reason: %s", appId, userId, 332 reason); 333 throw new RuntimeException(e); 334 } 335 } 336 337 /** See {@link Activity#getActivityToken()} */ getActivityToken(Activity activity)338 public static IBinder getActivityToken(Activity activity) { 339 return activity.getActivityToken(); 340 } 341 342 /** See {@link Activity#isVisibleForAutofill()} */ isVisible(Activity activity)343 public static boolean isVisible(Activity activity) { 344 return activity.isVisibleForAutofill(); 345 } 346 347 /** 348 * Moves the given {@code RootTask} to the specified {@code Display}. 349 * 350 * @param taskId the id of the target {@code RootTask} to move 351 * @param displayId the displayId to move the {@code RootTask} to 352 */ 353 @RequiresPermission(Manifest.permission.INTERNAL_SYSTEM_WINDOW) moveRootTaskToDisplay(int taskId, int displayId)354 public static void moveRootTaskToDisplay(int taskId, int displayId) { 355 try { 356 ActivityTaskManager.getService().moveRootTaskToDisplay(taskId, displayId); 357 } catch (RemoteException e) { 358 Slogf.e(TAG, "Error moving task %d to display %d", e, taskId, displayId); 359 throw new RuntimeException(e); 360 } 361 } 362 } 363