1 /*
2  * Copyright (C) 2022 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 android.annotation.NonNull;
20 import android.annotation.SystemApi;
21 import android.os.Binder;
22 import android.os.Process;
23 
24 import com.android.internal.annotations.VisibleForTesting;
25 import com.android.server.LocalServices;
26 
27 /**
28  * This class should be used by system services which are part of mainline modules to register
29  * {@link ActivityInterceptorCallback}. For other system services, this function should be used
30  * instead {@link ActivityTaskManagerInternal#registerActivityStartInterceptor(
31  * int, ActivityInterceptorCallback)}.
32  * @hide
33  */
34 @SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
35 public class ActivityInterceptorCallbackRegistry {
36 
37     private static final ActivityInterceptorCallbackRegistry sInstance =
38             new ActivityInterceptorCallbackRegistry();
39 
ActivityInterceptorCallbackRegistry()40     private ActivityInterceptorCallbackRegistry() {}
41 
42     /** Returns an already initialised singleton instance of this class. */
43     @NonNull
getInstance()44     public static ActivityInterceptorCallbackRegistry getInstance() {
45         return sInstance;
46     }
47 
48     /**
49      * Registers a callback which can intercept activity launching flow.
50      *
51      * <p>Only system services which are part of mainline modules should call this function.
52      *
53      * <p>To avoid Activity launch delays, the callbacks must execute quickly and avoid acquiring
54      * other system process locks.
55      *
56      * @param mainlineOrderId has to be one of the following [{@link
57      *                        ActivityInterceptorCallback#MAINLINE_FIRST_ORDERED_ID}].
58      * @param callback the {@link ActivityInterceptorCallback} to register.
59      * @throws IllegalArgumentException if duplicate ids are provided, the provided id is not the
60      * mainline module range or the provided {@code callback} is null.
61      */
62     // ExecutorRegistration is suppressed as the callback is called synchronously in the system
63     // server.
64     @SuppressWarnings("ExecutorRegistration")
registerActivityInterceptorCallback( @ctivityInterceptorCallback.OrderedId int mainlineOrderId, @NonNull ActivityInterceptorCallback callback)65     public void registerActivityInterceptorCallback(
66             @ActivityInterceptorCallback.OrderedId int mainlineOrderId,
67             @NonNull ActivityInterceptorCallback callback) {
68         if (getCallingUid() != Process.SYSTEM_UID) {
69             throw new SecurityException("Only system server can register "
70                     + "ActivityInterceptorCallback");
71         }
72         if (!ActivityInterceptorCallback.isValidMainlineOrderId(mainlineOrderId)) {
73             throw new IllegalArgumentException("id is not in the mainline modules range, please use"
74                     + "ActivityTaskManagerInternal.registerActivityStartInterceptor(OrderedId, "
75                     + "ActivityInterceptorCallback) instead.");
76         }
77         if (callback == null) {
78             throw new IllegalArgumentException("The passed ActivityInterceptorCallback can not be "
79                     + "null");
80         }
81         ActivityTaskManagerInternal activityTaskManagerInternal =
82                 LocalServices.getService(ActivityTaskManagerInternal.class);
83         activityTaskManagerInternal.registerActivityStartInterceptor(mainlineOrderId, callback);
84     }
85 
86     /**
87      * Unregisters an already registered {@link ActivityInterceptorCallback}.
88      *
89      * @param mainlineOrderId the order id of the {@link ActivityInterceptorCallback} should be
90      *                        unregistered, this callback should be registered before by calling
91      *                        {@link #registerActivityInterceptorCallback(int,
92      *                        ActivityInterceptorCallback)} using the same order id.
93      * @throws IllegalArgumentException if the provided id is not the mainline module range or is
94      * not registered
95      */
unregisterActivityInterceptorCallback( @ctivityInterceptorCallback.OrderedId int mainlineOrderId)96     public void unregisterActivityInterceptorCallback(
97             @ActivityInterceptorCallback.OrderedId int mainlineOrderId) {
98         if (getCallingUid() != Process.SYSTEM_UID) {
99             throw new SecurityException("Only system server can register "
100                     + "ActivityInterceptorCallback");
101         }
102         if (!ActivityInterceptorCallback.isValidMainlineOrderId(mainlineOrderId)) {
103             throw new IllegalArgumentException("id is not in the mainline modules range, please use"
104                     + "ActivityTaskManagerInternal.unregisterActivityStartInterceptor(OrderedId) "
105                     + "instead.");
106         }
107         ActivityTaskManagerInternal activityTaskManagerInternal =
108                 LocalServices.getService(ActivityTaskManagerInternal.class);
109         activityTaskManagerInternal.unregisterActivityStartInterceptor(mainlineOrderId);
110     }
111 
112     /**
113      * This hidden function is for unit tests as a way to behave like as if they are called from
114      * system server process uid by mocking it and returning {@link Process#SYSTEM_UID}.
115      * Do not make this {@code public} to apps as apps should not have a way to change the uid.
116      * @hide
117      */
118     @VisibleForTesting
getCallingUid()119     int getCallingUid() {
120         return Binder.getCallingUid();
121     }
122 }
123