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.annotation.NonNull; 20 import android.annotation.SystemApi; 21 import android.annotation.UserIdInt; 22 import android.app.ActivityManager; 23 import android.app.ActivityOptions; 24 import android.app.ActivityTaskManager; 25 import android.app.ActivityTaskManager.RootTaskInfo; 26 import android.app.IActivityManager; 27 import android.app.IProcessObserver; 28 import android.car.builtin.annotation.AddedIn; 29 import android.car.builtin.annotation.PlatformVersion; 30 import android.car.builtin.util.Slogf; 31 import android.os.Bundle; 32 import android.os.RemoteException; 33 34 import java.util.concurrent.Callable; 35 36 /** 37 * Provide access to {@code android.app.IActivityManager} calls. 38 * @hide 39 */ 40 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) 41 public final class ActivityManagerHelper { 42 43 /** Invalid task ID. */ 44 @AddedIn(PlatformVersion.TIRAMISU_0) 45 public static final int INVALID_TASK_ID = ActivityTaskManager.INVALID_TASK_ID; 46 47 private static final String TAG = "CAR.AM"; // CarLog.TAG_AM 48 49 // Lazy initialization holder class idiom for static fields; See go/ej3e-83 for the detail. 50 private static class ActivityManagerHolder { 51 static final IActivityManager sAm = ActivityManager.getService(); 52 } 53 getActivityManager()54 private static IActivityManager getActivityManager() { 55 return ActivityManagerHolder.sAm; 56 } 57 ActivityManagerHelper()58 private ActivityManagerHelper() { 59 throw new UnsupportedOperationException("contains only static members"); 60 } 61 62 /** 63 * See {@code android.app.IActivityManager.startUserInBackground}. 64 * 65 * @throws IllegalStateException if ActivityManager binder throws RemoteException 66 */ 67 @AddedIn(PlatformVersion.TIRAMISU_0) startUserInBackground(@serIdInt int userId)68 public static boolean startUserInBackground(@UserIdInt int userId) { 69 return runRemotely(() -> getActivityManager().startUserInBackground(userId), 70 "error while startUserInBackground %d", userId); 71 } 72 73 /** 74 * See {@code android.app.IActivityManager.startUserInForegroundWithListener}. 75 * 76 * @throws IllegalStateException if ActivityManager binder throws RemoteException 77 */ 78 @AddedIn(PlatformVersion.TIRAMISU_0) startUserInForeground(@serIdInt int userId)79 public static boolean startUserInForeground(@UserIdInt int userId) { 80 return runRemotely( 81 () -> getActivityManager().startUserInForegroundWithListener( 82 userId, /* listener= */ null), 83 "error while startUserInForeground %d", userId); 84 } 85 86 /** 87 * See {@code android.app.IActivityManager.stopUserWithDelayedLocking}. 88 * 89 * @throws IllegalStateException if ActivityManager binder throws RemoteException 90 */ 91 @AddedIn(PlatformVersion.TIRAMISU_0) stopUserWithDelayedLocking(@serIdInt int userId, boolean force)92 public static int stopUserWithDelayedLocking(@UserIdInt int userId, boolean force) { 93 return runRemotely( 94 () -> getActivityManager().stopUserWithDelayedLocking( 95 userId, force, /* callback= */ null), 96 "error while stopUserWithDelayedLocking %d", userId); 97 } 98 99 /** 100 * Check {@code android.app.IActivityManager.unlockUser}. 101 * 102 * @throws IllegalStateException if ActivityManager binder throws RemoteException 103 */ 104 @AddedIn(PlatformVersion.TIRAMISU_0) unlockUser(@serIdInt int userId)105 public static boolean unlockUser(@UserIdInt int userId) { 106 return runRemotely(() -> getActivityManager().unlockUser(userId, 107 /* token= */ null, /* secret= */ null, /* listener= */ null), 108 "error while unlocking user %d", userId); 109 } 110 111 /** 112 * Stops all task for the user. 113 * 114 * @throws IllegalStateException if ActivityManager binder throws RemoteException 115 */ 116 @AddedIn(PlatformVersion.TIRAMISU_0) stopAllTasksForUser(@serIdInt int userId)117 public static void stopAllTasksForUser(@UserIdInt int userId) { 118 try { 119 IActivityManager am = getActivityManager(); 120 for (RootTaskInfo info : am.getAllRootTaskInfos()) { 121 for (int i = 0; i < info.childTaskIds.length; i++) { 122 if (info.childTaskUserIds[i] == userId) { 123 int taskId = info.childTaskIds[i]; 124 if (!am.removeTask(taskId)) { 125 Slogf.w(TAG, "could not remove task " + taskId); 126 } 127 } 128 } 129 } 130 } catch (RemoteException e) { 131 throw logAndReThrow(e, "could not get stack info for user %d", userId); 132 } 133 } 134 135 /** 136 * Creates an ActivityOptions from the Bundle generated from ActivityOptions. 137 */ 138 @NonNull 139 @AddedIn(PlatformVersion.TIRAMISU_0) createActivityOptions(@onNull Bundle bOptions)140 public static ActivityOptions createActivityOptions(@NonNull Bundle bOptions) { 141 return new ActivityOptions(bOptions); 142 } 143 runRemotely(Callable<T> callable, String format, Object...args)144 private static <T> T runRemotely(Callable<T> callable, String format, Object...args) { 145 try { 146 return callable.call(); 147 } catch (Exception e) { 148 throw logAndReThrow(e, format, args); 149 } 150 } 151 152 @SuppressWarnings("AnnotateFormatMethod") logAndReThrow(Exception e, String format, Object...args)153 private static RuntimeException logAndReThrow(Exception e, String format, Object...args) { 154 String msg = String.format(format, args); 155 Slogf.e(TAG, msg, e); 156 return new IllegalStateException(msg, e); 157 } 158 159 /** 160 * Makes the root task of the given taskId focused. 161 */ 162 @AddedIn(PlatformVersion.TIRAMISU_0) setFocusedRootTask(int taskId)163 public static void setFocusedRootTask(int taskId) { 164 try { 165 getActivityManager().setFocusedRootTask(taskId); 166 } catch (RemoteException e) { 167 Slogf.e(TAG, "Failed to setFocusedRootTask", e); 168 } 169 } 170 171 /** 172 * Removes the given task. 173 */ 174 @AddedIn(PlatformVersion.TIRAMISU_0) removeTask(int taskId)175 public static boolean removeTask(int taskId) { 176 try { 177 return getActivityManager().removeTask(taskId); 178 } catch (RemoteException e) { 179 Slogf.e(TAG, "Failed to removeTask", e); 180 } 181 return false; 182 } 183 184 /** 185 * Callback to monitor Processes in the system 186 */ 187 public abstract static class ProcessObserverCallback { 188 /** Called when the foreground Activities are changed. */ 189 @AddedIn(PlatformVersion.TIRAMISU_0) onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities)190 public void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) { 191 } 192 /** Called when the Process is died. */ 193 @AddedIn(PlatformVersion.TIRAMISU_0) onProcessDied(int pid, int uid)194 public void onProcessDied(int pid, int uid) {} 195 196 @AddedIn(PlatformVersion.TIRAMISU_0) 197 final IProcessObserver.Stub mIProcessObserver = new IProcessObserver.Stub() { 198 @Override 199 public void onForegroundActivitiesChanged( 200 int pid, int uid, boolean foregroundActivities) throws RemoteException { 201 ProcessObserverCallback.this.onForegroundActivitiesChanged( 202 pid, uid, foregroundActivities); 203 } 204 205 @Override 206 public void onForegroundServicesChanged(int pid, int uid, int fgServiceTypes) 207 throws RemoteException { 208 // Not used 209 } 210 211 @Override 212 public void onProcessDied(int pid, int uid) throws RemoteException { 213 ProcessObserverCallback.this.onProcessDied(pid, uid); 214 } 215 }; 216 } 217 218 /** 219 * Registers a callback to be invoked when the process states are changed. 220 * @param callback a callback to register 221 */ 222 @AddedIn(PlatformVersion.TIRAMISU_0) registerProcessObserverCallback(ProcessObserverCallback callback)223 public static void registerProcessObserverCallback(ProcessObserverCallback callback) { 224 try { 225 getActivityManager().registerProcessObserver(callback.mIProcessObserver); 226 } catch (RemoteException e) { 227 Slogf.e(TAG, "Failed to register ProcessObserver", e); 228 throw new RuntimeException(e); 229 } 230 } 231 232 /** 233 * Unregisters the given callback. 234 * @param callback a callback to unregister 235 */ 236 @AddedIn(PlatformVersion.TIRAMISU_0) unregisterProcessObserverCallback(ProcessObserverCallback callback)237 public static void unregisterProcessObserverCallback(ProcessObserverCallback callback) { 238 try { 239 getActivityManager().unregisterProcessObserver(callback.mIProcessObserver); 240 } catch (RemoteException e) { 241 Slogf.e(TAG, "Failed to unregister listener", e); 242 throw new RuntimeException(e); 243 } 244 } 245 246 /** 247 * Same as {@link ActivityManager#checkComponentPermission(String, int, int, boolean). 248 */ 249 @AddedIn(PlatformVersion.TIRAMISU_0) checkComponentPermission(@onNull String permission, int uid, int owningUid, boolean exported)250 public static int checkComponentPermission(@NonNull String permission, int uid, int owningUid, 251 boolean exported) { 252 return ActivityManager.checkComponentPermission(permission, uid, owningUid, exported); 253 } 254 } 255