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