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 com.android.server.wm;
18 
19 import android.annotation.IntDef;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.SystemApi;
23 import android.app.ActivityOptions;
24 import android.app.TaskInfo;
25 import android.content.Intent;
26 import android.content.pm.ActivityInfo;
27 import android.content.pm.ResolveInfo;
28 
29 import java.lang.annotation.Retention;
30 import java.lang.annotation.RetentionPolicy;
31 
32 /**
33  * Callback to intercept activity starts and possibly block/redirect them. The callback methods will
34  * be called with the WindowManagerGlobalLock held.
35  * @hide
36  */
37 @SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
38 public interface ActivityInterceptorCallback {
39     /**
40      * Called to allow intercepting activity launching based on the provided launch parameters and
41      * intent resolution.
42      *
43      * <p>If the interceptor decides to change the {@link Intent} or return different {@link
44      * ActivityOptions}, it should return a non-{@code null} {@link ActivityInterceptResult} which
45      * may redirect to another activity or use new {@link ActivityOptions}. Otherwise, the
46      * interceptor should return {@code null} to indicate that passed {@link Intent} should not be
47      * changed.
48      *
49      * @param info the information about the {@link Intent} that is being intercepted to launch an
50      *             {@link android.app.Activity}.
51      * @return {@code null} if the interceptor decides not to change the existing intent, or a non-
52      * {@code null} result which replaces the existing intent and activity options.
53      */
54     @Nullable
onInterceptActivityLaunch(@onNull ActivityInterceptorInfo info)55     ActivityInterceptResult onInterceptActivityLaunch(@NonNull ActivityInterceptorInfo info);
56 
57     /**
58      * Called when an activity is successfully launched.
59      *
60      * <p>The intent included in the ActivityInterceptorInfo may have changed from the one sent in
61      * {@link #onInterceptActivityLaunch(ActivityInterceptorInfo)}, due to the changes might applied
62      * during internception.
63      *
64      * <p>There is no callback in case that the {@link android.app.Activity} is failed to launch,
65      * and this is not necessary to be added for the known use-cases.
66      *
67      * @param taskInfo the information about the @{@link Task} holds the launched
68      *                 {@link android.app.Activity}.
69      * @param activityInfo the information about the launched {@link android.app.Activity}.
70      * @param info the information about the {@link Intent} after calling {@link
71      *             #onInterceptActivityLaunch(ActivityInterceptorInfo)}.
72      */
onActivityLaunched(@onNull TaskInfo taskInfo, @NonNull ActivityInfo activityInfo, @NonNull ActivityInterceptorInfo info)73     default void onActivityLaunched(@NonNull TaskInfo taskInfo, @NonNull ActivityInfo activityInfo,
74             @NonNull ActivityInterceptorInfo info) {}
75 
76     /**
77      * The unique id of each interceptor registered by a system service which determines the order
78      * it will execute in.
79      * @hide
80      */
81     @IntDef(suffix = { "_ORDERED_ID" }, value = {
82             // Order Ids for system services
83             SYSTEM_FIRST_ORDERED_ID,
84             PERMISSION_POLICY_ORDERED_ID,
85             VIRTUAL_DEVICE_SERVICE_ORDERED_ID,
86             DREAM_MANAGER_ORDERED_ID,
87             PRODUCT_ORDERED_ID,
88             SYSTEM_LAST_ORDERED_ID, // Update this when adding new ids
89             // Order Ids for mainline module services
90             MAINLINE_FIRST_ORDERED_ID,
91             MAINLINE_SDK_SANDBOX_ORDER_ID,
92             MAINLINE_LAST_ORDERED_ID  // Update this when adding new mainline module ids
93     })
94     @Retention(RetentionPolicy.SOURCE)
95     @interface OrderedId {}
96 
97     /**
98      * The first id, used by the framework to determine the valid range of ids.
99      * @hide
100      */
101     int SYSTEM_FIRST_ORDERED_ID = 0;
102 
103     /**
104      * The identifier for {@link com.android.server.policy.PermissionPolicyService} interceptor
105      * @hide
106      */
107     int PERMISSION_POLICY_ORDERED_ID = 1;
108 
109     /**
110      * The identifier for {@link com.android.server.companion.virtual.VirtualDeviceManagerService}
111      * interceptor.
112      * @hide
113      */
114     int VIRTUAL_DEVICE_SERVICE_ORDERED_ID = 3;
115 
116     /**
117      * The identifier for {@link com.android.server.dreams.DreamManagerService} interceptor.
118      * @hide
119      */
120     int DREAM_MANAGER_ORDERED_ID = 4;
121 
122     /**
123      * The identifier for an interceptor which is specific to the type of android product like
124      * automotive, wear, TV etc.
125      * @hide
126      */
127     int PRODUCT_ORDERED_ID = 5;
128 
129     /**
130      * The final id, used by the framework to determine the valid range of ids. Update this when
131      * adding new ids.
132      * @hide
133      */
134     int SYSTEM_LAST_ORDERED_ID = PRODUCT_ORDERED_ID;
135 
136     /**
137      * The first mainline module id, used by the framework to determine the valid range of ids
138      * could be used by mainline modules.
139      * @hide
140      */
141     int MAINLINE_FIRST_ORDERED_ID = 1000;
142 
143     /**
144      * The identifier for {@link com.android.server.sdksandbox.SdkSandboxManagerService.Lifecycle}
145      * interceptor.
146      */
147     int MAINLINE_SDK_SANDBOX_ORDER_ID = 1001;
148 
149     /**
150      * The final mainline module id, used by the framework to determine the valid range of ids
151      * could be used by mainline modules. Update this when adding new ids for mainline modules.
152      * @hide
153      */
154     int MAINLINE_LAST_ORDERED_ID = MAINLINE_SDK_SANDBOX_ORDER_ID;
155 
156     /**
157      * Returns {@code true} if the id is in the range of valid system services including mainline
158      * module services.
159      * @hide
160      */
isValidOrderId(int id)161     static boolean isValidOrderId(int id) {
162         return isValidMainlineOrderId(id)
163                 || (id >= SYSTEM_FIRST_ORDERED_ID && id <= SYSTEM_LAST_ORDERED_ID);
164     }
165 
166     /**
167      * Returns {@code true} if the id is in the range of valid mainline module services.
168      * @hide
169      */
isValidMainlineOrderId(int id)170     static boolean isValidMainlineOrderId(int id) {
171         return id >= MAINLINE_FIRST_ORDERED_ID && id <= MAINLINE_LAST_ORDERED_ID;
172     }
173 
174     /**
175      * Data class for storing the various arguments needed for activity interception.
176      * @hide
177      */
178     @SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
179     final class ActivityInterceptorInfo {
180         private final int mCallingUid;
181         private final int mCallingPid;
182         private final int mRealCallingUid;
183         private final int mRealCallingPid;
184         private final int mUserId;
185         private final Intent mIntent;
186         @NonNull
187         private final ResolveInfo mResolveInfo;
188         @NonNull
189         private final ActivityInfo mActivityInfo;
190         @Nullable
191         private final String mResolvedType;
192         @Nullable
193         private final String mCallingPackage;
194         @Nullable
195         private final String mCallingFeatureId;
196         @Nullable
197         private final ActivityOptions mCheckedOptions;
198         @Nullable
199         private final Runnable mClearOptionsAnimation;
200 
201         /**
202          * @hide
203          */
ActivityInterceptorInfo(Builder builder)204         public ActivityInterceptorInfo(Builder builder) {
205             this.mCallingUid = builder.mCallingUid;
206             this.mCallingPid = builder.mCallingPid;
207             this.mRealCallingUid = builder.mRealCallingUid;
208             this.mRealCallingPid = builder.mRealCallingPid;
209             this.mUserId = builder.mUserId;
210             this.mIntent = builder.mIntent;
211             this.mResolveInfo = builder.mResolveInfo;
212             this.mActivityInfo = builder.mActivityInfo;
213             this.mResolvedType = builder.mResolvedType;
214             this.mCallingPackage = builder.mCallingPackage;
215             this.mCallingFeatureId = builder.mCallingFeatureId;
216             this.mCheckedOptions = builder.mCheckedOptions;
217             this.mClearOptionsAnimation = builder.mClearOptionsAnimation;
218         }
219 
220         /**
221          * Builder class to build instances of {@link ActivityInterceptorInfo}.
222          */
223         public static final class Builder {
224             private final int mCallingUid;
225             private final int mCallingPid;
226             private final int mRealCallingUid;
227             private final int mRealCallingPid;
228             private final int mUserId;
229             private final Intent mIntent;
230             @NonNull
231             private final ResolveInfo mResolveInfo;
232             @NonNull
233             private final ActivityInfo mActivityInfo;
234             @Nullable
235             private String mResolvedType;
236             @Nullable
237             private String mCallingPackage = null;
238             @Nullable
239             private String mCallingFeatureId = null;
240             @Nullable
241             private ActivityOptions mCheckedOptions = null;
242             @Nullable
243             private Runnable mClearOptionsAnimation = null;
244 
245             /**
246              * Constructor of {@link ActivityInterceptorInfo.Builder}.
247              */
Builder(int callingUid, int callingPid, int realCallingUid, int realCallingPid, int userId, @NonNull Intent intent, @NonNull ResolveInfo rInfo, @NonNull ActivityInfo aInfo)248             public Builder(int callingUid, int callingPid, int realCallingUid,
249                     int realCallingPid, int userId, @NonNull Intent intent,
250                     @NonNull ResolveInfo rInfo, @NonNull ActivityInfo aInfo) {
251                 this.mCallingUid = callingUid;
252                 this.mCallingPid = callingPid;
253                 this.mRealCallingUid = realCallingUid;
254                 this.mRealCallingPid = realCallingPid;
255                 this.mUserId = userId;
256                 this.mIntent = intent;
257                 this.mResolveInfo = rInfo;
258                 this.mActivityInfo = aInfo;
259             }
260 
261             /**
262              * Returns a new instance of {@link ActivityInterceptorInfo} based on the {@link
263              * Builder} fields.
264              *
265              * @return a new instance of {@link ActivityInterceptorInfo}.
266              */
267             @NonNull
build()268             public ActivityInterceptorInfo build() {
269                 return new ActivityInterceptorInfo(this);
270             }
271 
272             /**
273              * Sets the value for the resolved type.
274              * @param resolvedType the resolved type.
275              */
276             @NonNull
setResolvedType(@ullable String resolvedType)277             public Builder setResolvedType(@Nullable String resolvedType) {
278                 mResolvedType = resolvedType;
279                 return this;
280             }
281 
282             /**
283              * Sets the value for the calling package.
284              * @param callingPackage the calling package.
285              */
286             @NonNull
setCallingPackage(@ullable String callingPackage)287             public Builder setCallingPackage(@Nullable String callingPackage) {
288                 mCallingPackage = callingPackage;
289                 return this;
290             }
291 
292             /**
293              * Sets the value for the calling feature id.
294              * @param callingFeatureId the calling feature id.
295              */
296             @NonNull
setCallingFeatureId(@ullable String callingFeatureId)297             public Builder setCallingFeatureId(@Nullable String callingFeatureId) {
298                 mCallingFeatureId = callingFeatureId;
299                 return this;
300             }
301 
302             /**
303              * Sets the value for the {@link ActivityOptions}.
304              * @param checkedOptions the {@link ActivityOptions}.
305              */
306             @NonNull
setCheckedOptions(@ullable ActivityOptions checkedOptions)307             public Builder setCheckedOptions(@Nullable ActivityOptions checkedOptions) {
308                 mCheckedOptions = checkedOptions;
309                 return this;
310             }
311 
312             /**
313              * Sets the value for the {@link Runnable} object to clear options Animation.
314              * @param clearOptionsAnimationRunnable the calling package.
315              */
316             @NonNull
setClearOptionsAnimationRunnable(@ullable Runnable clearOptionsAnimationRunnable)317             public Builder setClearOptionsAnimationRunnable(@Nullable
318                     Runnable clearOptionsAnimationRunnable) {
319                 mClearOptionsAnimation = clearOptionsAnimationRunnable;
320                 return this;
321             }
322         }
323 
324         /** Returns the calling uid. */
getCallingUid()325         public int getCallingUid() {
326             return mCallingUid;
327         }
328 
329         /** Returns the calling pid. */
getCallingPid()330         public int getCallingPid() {
331             return mCallingPid;
332         }
333 
334         /** Returns the real calling uid. */
getRealCallingUid()335         public int getRealCallingUid() {
336             return mRealCallingUid;
337         }
338 
339         /** Returns the real calling pid. */
getRealCallingPid()340         public int getRealCallingPid() {
341             return mRealCallingPid;
342         }
343 
344         /** Returns the user id. */
getUserId()345         public int getUserId() {
346             return mUserId;
347         }
348 
349         /** Returns the {@link Intent}. */
350         @SuppressWarnings("IntentBuilderName")
351         @NonNull
getIntent()352         public Intent getIntent() {
353             return mIntent;
354         }
355 
356         /** Returns the {@link ResolveInfo}. */
357         @NonNull
getResolveInfo()358         public ResolveInfo getResolveInfo() {
359             return mResolveInfo;
360         }
361 
362         /** Returns the {@link ActivityInfo}. */
363         @NonNull
getActivityInfo()364         public ActivityInfo getActivityInfo() {
365             return mActivityInfo;
366         }
367 
368         /** Returns the real resolved type. */
369         @Nullable
getResolvedType()370         public String getResolvedType() {
371             return mResolvedType;
372         }
373 
374         /** Returns the calling package. */
375         @Nullable
getCallingPackage()376         public String getCallingPackage() {
377             return mCallingPackage;
378         }
379 
380         /** Returns the calling feature id. */
381         @Nullable
getCallingFeatureId()382         public String getCallingFeatureId() {
383             return mCallingFeatureId;
384         }
385 
386         /** Returns the {@link ActivityOptions}. */
387         @Nullable
getCheckedOptions()388         public ActivityOptions getCheckedOptions() {
389             return mCheckedOptions;
390         }
391 
392         /**
393          * Returns the {@link Runnable} object to clear options Animation. Note that the runnable
394          * should not be executed inside a lock because the implementation of runnable holds window
395          * manager's lock.
396          */
397         @Nullable
getClearOptionsAnimationRunnable()398         public Runnable getClearOptionsAnimationRunnable() {
399             return mClearOptionsAnimation;
400         }
401     }
402 
403     /**
404      * Data class for storing the intercept result.
405      * @hide
406      */
407     @SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
408     final class ActivityInterceptResult {
409         @NonNull
410         private final Intent mIntent;
411 
412         @NonNull
413         private final ActivityOptions mActivityOptions;
414 
415         private final boolean mActivityResolved;
416 
417         /**
418          * This constructor should only be used if both {@link ActivityInfo} and {@link ResolveInfo}
419          * did not get resolved while interception.
420          * @hide
421          */
ActivityInterceptResult(@onNull Intent intent, @NonNull ActivityOptions activityOptions)422         public ActivityInterceptResult(@NonNull Intent intent,
423                 @NonNull ActivityOptions activityOptions) {
424             this(intent, activityOptions, false /* activityResolved */);
425         }
426 
427         /**
428          * Generates the result of intercepting launching the {@link android.app.Activity}
429          *
430          * <p>Interceptor should return non-{@code null} result when {@link
431          * #onInterceptActivityLaunch(ActivityInterceptorInfo)} gets called as an indicator that
432          * interception has happened.
433          *
434          * @param intent is the modified {@link Intent} after interception.
435          * @param activityOptions holds the {@link ActivityOptions} after interception.
436          * @param activityResolved should be {@code true} only if {@link ActivityInfo} or {@link
437          *                         ResolveInfo} gets resolved, otherwise should be {@code false}.
438          */
ActivityInterceptResult(@onNull Intent intent, @NonNull ActivityOptions activityOptions, boolean activityResolved)439         public ActivityInterceptResult(@NonNull Intent intent,
440                 @NonNull ActivityOptions activityOptions, boolean activityResolved) {
441             this.mIntent = intent;
442             this.mActivityOptions = activityOptions;
443             this.mActivityResolved = activityResolved;
444         }
445 
446         /** Returns the intercepted {@link Intent} */
447         @SuppressWarnings("IntentBuilderName")
448         @NonNull
getIntent()449         public Intent getIntent() {
450             return mIntent;
451         }
452 
453         /** Returns the intercepted {@link ActivityOptions} */
454         @NonNull
getActivityOptions()455         public ActivityOptions getActivityOptions() {
456             return mActivityOptions;
457         }
458 
459         /**
460          * Returns if the {@link ActivityInfo} or {@link ResolveInfo} gets resolved.
461          */
isActivityResolved()462         public boolean isActivityResolved() {
463             return mActivityResolved;
464         }
465     }
466 }
467