| /* |
| * Copyright (C) 2021 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.server.wm; |
| |
| import android.annotation.IntDef; |
| import android.annotation.NonNull; |
| import android.annotation.Nullable; |
| import android.annotation.SystemApi; |
| import android.app.ActivityOptions; |
| import android.app.TaskInfo; |
| import android.content.Intent; |
| import android.content.pm.ActivityInfo; |
| import android.content.pm.ResolveInfo; |
| |
| import java.lang.annotation.Retention; |
| import java.lang.annotation.RetentionPolicy; |
| |
| /** |
| * Callback to intercept activity starts and possibly block/redirect them. The callback methods will |
| * be called with the WindowManagerGlobalLock held. |
| * @hide |
| */ |
| @SystemApi(client = SystemApi.Client.SYSTEM_SERVER) |
| public interface ActivityInterceptorCallback { |
| /** |
| * Called to allow intercepting activity launching based on the provided launch parameters and |
| * intent resolution. |
| * |
| * <p>If the interceptor decides to change the {@link Intent} or return different {@link |
| * ActivityOptions}, it should return a non-{@code null} {@link ActivityInterceptResult} which |
| * may redirect to another activity or use new {@link ActivityOptions}. Otherwise, the |
| * interceptor should return {@code null} to indicate that passed {@link Intent} should not be |
| * changed. |
| * |
| * @param info the information about the {@link Intent} that is being intercepted to launch an |
| * {@link android.app.Activity}. |
| * @return {@code null} if the interceptor decides not to change the existing intent, or a non- |
| * {@code null} result which replaces the existing intent and activity options. |
| */ |
| @Nullable |
| ActivityInterceptResult onInterceptActivityLaunch(@NonNull ActivityInterceptorInfo info); |
| |
| /** |
| * Called when an activity is successfully launched. |
| * |
| * <p>The intent included in the ActivityInterceptorInfo may have changed from the one sent in |
| * {@link #onInterceptActivityLaunch(ActivityInterceptorInfo)}, due to the changes might applied |
| * during internception. |
| * |
| * <p>There is no callback in case that the {@link android.app.Activity} is failed to launch, |
| * and this is not necessary to be added for the known use-cases. |
| * |
| * @param taskInfo the information about the @{@link Task} holds the launched |
| * {@link android.app.Activity}. |
| * @param activityInfo the information about the launched {@link android.app.Activity}. |
| * @param info the information about the {@link Intent} after calling {@link |
| * #onInterceptActivityLaunch(ActivityInterceptorInfo)}. |
| */ |
| default void onActivityLaunched(@NonNull TaskInfo taskInfo, @NonNull ActivityInfo activityInfo, |
| @NonNull ActivityInterceptorInfo info) {} |
| |
| /** |
| * The unique id of each interceptor registered by a system service which determines the order |
| * it will execute in. |
| * @hide |
| */ |
| @IntDef(suffix = { "_ORDERED_ID" }, value = { |
| // Order Ids for system services |
| SYSTEM_FIRST_ORDERED_ID, |
| PERMISSION_POLICY_ORDERED_ID, |
| VIRTUAL_DEVICE_SERVICE_ORDERED_ID, |
| DREAM_MANAGER_ORDERED_ID, |
| PRODUCT_ORDERED_ID, |
| SYSTEM_LAST_ORDERED_ID, // Update this when adding new ids |
| // Order Ids for mainline module services |
| MAINLINE_FIRST_ORDERED_ID, |
| MAINLINE_SDK_SANDBOX_ORDER_ID, |
| MAINLINE_LAST_ORDERED_ID // Update this when adding new mainline module ids |
| }) |
| @Retention(RetentionPolicy.SOURCE) |
| @interface OrderedId {} |
| |
| /** |
| * The first id, used by the framework to determine the valid range of ids. |
| * @hide |
| */ |
| int SYSTEM_FIRST_ORDERED_ID = 0; |
| |
| /** |
| * The identifier for {@link com.android.server.policy.PermissionPolicyService} interceptor |
| * @hide |
| */ |
| int PERMISSION_POLICY_ORDERED_ID = 1; |
| |
| /** |
| * The identifier for {@link com.android.server.companion.virtual.VirtualDeviceManagerService} |
| * interceptor. |
| * @hide |
| */ |
| int VIRTUAL_DEVICE_SERVICE_ORDERED_ID = 3; |
| |
| /** |
| * The identifier for {@link com.android.server.dreams.DreamManagerService} interceptor. |
| * @hide |
| */ |
| int DREAM_MANAGER_ORDERED_ID = 4; |
| |
| /** |
| * The identifier for an interceptor which is specific to the type of android product like |
| * automotive, wear, TV etc. |
| * @hide |
| */ |
| int PRODUCT_ORDERED_ID = 5; |
| |
| /** |
| * The final id, used by the framework to determine the valid range of ids. Update this when |
| * adding new ids. |
| * @hide |
| */ |
| int SYSTEM_LAST_ORDERED_ID = PRODUCT_ORDERED_ID; |
| |
| /** |
| * The first mainline module id, used by the framework to determine the valid range of ids |
| * could be used by mainline modules. |
| * @hide |
| */ |
| int MAINLINE_FIRST_ORDERED_ID = 1000; |
| |
| /** |
| * The identifier for {@link com.android.server.sdksandbox.SdkSandboxManagerService.Lifecycle} |
| * interceptor. |
| */ |
| int MAINLINE_SDK_SANDBOX_ORDER_ID = 1001; |
| |
| /** |
| * The final mainline module id, used by the framework to determine the valid range of ids |
| * could be used by mainline modules. Update this when adding new ids for mainline modules. |
| * @hide |
| */ |
| int MAINLINE_LAST_ORDERED_ID = MAINLINE_SDK_SANDBOX_ORDER_ID; |
| |
| /** |
| * Returns {@code true} if the id is in the range of valid system services including mainline |
| * module services. |
| * @hide |
| */ |
| static boolean isValidOrderId(int id) { |
| return isValidMainlineOrderId(id) |
| || (id >= SYSTEM_FIRST_ORDERED_ID && id <= SYSTEM_LAST_ORDERED_ID); |
| } |
| |
| /** |
| * Returns {@code true} if the id is in the range of valid mainline module services. |
| * @hide |
| */ |
| static boolean isValidMainlineOrderId(int id) { |
| return id >= MAINLINE_FIRST_ORDERED_ID && id <= MAINLINE_LAST_ORDERED_ID; |
| } |
| |
| /** |
| * Data class for storing the various arguments needed for activity interception. |
| * @hide |
| */ |
| @SystemApi(client = SystemApi.Client.SYSTEM_SERVER) |
| final class ActivityInterceptorInfo { |
| private final int mCallingUid; |
| private final int mCallingPid; |
| private final int mRealCallingUid; |
| private final int mRealCallingPid; |
| private final int mUserId; |
| private final Intent mIntent; |
| @NonNull |
| private final ResolveInfo mResolveInfo; |
| @NonNull |
| private final ActivityInfo mActivityInfo; |
| @Nullable |
| private final String mResolvedType; |
| @Nullable |
| private final String mCallingPackage; |
| @Nullable |
| private final String mCallingFeatureId; |
| @Nullable |
| private final ActivityOptions mCheckedOptions; |
| @Nullable |
| private final Runnable mClearOptionsAnimation; |
| |
| /** |
| * @hide |
| */ |
| public ActivityInterceptorInfo(Builder builder) { |
| this.mCallingUid = builder.mCallingUid; |
| this.mCallingPid = builder.mCallingPid; |
| this.mRealCallingUid = builder.mRealCallingUid; |
| this.mRealCallingPid = builder.mRealCallingPid; |
| this.mUserId = builder.mUserId; |
| this.mIntent = builder.mIntent; |
| this.mResolveInfo = builder.mResolveInfo; |
| this.mActivityInfo = builder.mActivityInfo; |
| this.mResolvedType = builder.mResolvedType; |
| this.mCallingPackage = builder.mCallingPackage; |
| this.mCallingFeatureId = builder.mCallingFeatureId; |
| this.mCheckedOptions = builder.mCheckedOptions; |
| this.mClearOptionsAnimation = builder.mClearOptionsAnimation; |
| } |
| |
| /** |
| * Builder class to build instances of {@link ActivityInterceptorInfo}. |
| */ |
| public static final class Builder { |
| private final int mCallingUid; |
| private final int mCallingPid; |
| private final int mRealCallingUid; |
| private final int mRealCallingPid; |
| private final int mUserId; |
| private final Intent mIntent; |
| @NonNull |
| private final ResolveInfo mResolveInfo; |
| @NonNull |
| private final ActivityInfo mActivityInfo; |
| @Nullable |
| private String mResolvedType; |
| @Nullable |
| private String mCallingPackage = null; |
| @Nullable |
| private String mCallingFeatureId = null; |
| @Nullable |
| private ActivityOptions mCheckedOptions = null; |
| @Nullable |
| private Runnable mClearOptionsAnimation = null; |
| |
| /** |
| * Constructor of {@link ActivityInterceptorInfo.Builder}. |
| */ |
| public Builder(int callingUid, int callingPid, int realCallingUid, |
| int realCallingPid, int userId, @NonNull Intent intent, |
| @NonNull ResolveInfo rInfo, @NonNull ActivityInfo aInfo) { |
| this.mCallingUid = callingUid; |
| this.mCallingPid = callingPid; |
| this.mRealCallingUid = realCallingUid; |
| this.mRealCallingPid = realCallingPid; |
| this.mUserId = userId; |
| this.mIntent = intent; |
| this.mResolveInfo = rInfo; |
| this.mActivityInfo = aInfo; |
| } |
| |
| /** |
| * Returns a new instance of {@link ActivityInterceptorInfo} based on the {@link |
| * Builder} fields. |
| * |
| * @return a new instance of {@link ActivityInterceptorInfo}. |
| */ |
| @NonNull |
| public ActivityInterceptorInfo build() { |
| return new ActivityInterceptorInfo(this); |
| } |
| |
| /** |
| * Sets the value for the resolved type. |
| * @param resolvedType the resolved type. |
| */ |
| @NonNull |
| public Builder setResolvedType(@Nullable String resolvedType) { |
| mResolvedType = resolvedType; |
| return this; |
| } |
| |
| /** |
| * Sets the value for the calling package. |
| * @param callingPackage the calling package. |
| */ |
| @NonNull |
| public Builder setCallingPackage(@Nullable String callingPackage) { |
| mCallingPackage = callingPackage; |
| return this; |
| } |
| |
| /** |
| * Sets the value for the calling feature id. |
| * @param callingFeatureId the calling feature id. |
| */ |
| @NonNull |
| public Builder setCallingFeatureId(@Nullable String callingFeatureId) { |
| mCallingFeatureId = callingFeatureId; |
| return this; |
| } |
| |
| /** |
| * Sets the value for the {@link ActivityOptions}. |
| * @param checkedOptions the {@link ActivityOptions}. |
| */ |
| @NonNull |
| public Builder setCheckedOptions(@Nullable ActivityOptions checkedOptions) { |
| mCheckedOptions = checkedOptions; |
| return this; |
| } |
| |
| /** |
| * Sets the value for the {@link Runnable} object to clear options Animation. |
| * @param clearOptionsAnimationRunnable the calling package. |
| */ |
| @NonNull |
| public Builder setClearOptionsAnimationRunnable(@Nullable |
| Runnable clearOptionsAnimationRunnable) { |
| mClearOptionsAnimation = clearOptionsAnimationRunnable; |
| return this; |
| } |
| } |
| |
| /** Returns the calling uid. */ |
| public int getCallingUid() { |
| return mCallingUid; |
| } |
| |
| /** Returns the calling pid. */ |
| public int getCallingPid() { |
| return mCallingPid; |
| } |
| |
| /** Returns the real calling uid. */ |
| public int getRealCallingUid() { |
| return mRealCallingUid; |
| } |
| |
| /** Returns the real calling pid. */ |
| public int getRealCallingPid() { |
| return mRealCallingPid; |
| } |
| |
| /** Returns the user id. */ |
| public int getUserId() { |
| return mUserId; |
| } |
| |
| /** Returns the {@link Intent}. */ |
| @SuppressWarnings("IntentBuilderName") |
| @NonNull |
| public Intent getIntent() { |
| return mIntent; |
| } |
| |
| /** Returns the {@link ResolveInfo}. */ |
| @NonNull |
| public ResolveInfo getResolveInfo() { |
| return mResolveInfo; |
| } |
| |
| /** Returns the {@link ActivityInfo}. */ |
| @NonNull |
| public ActivityInfo getActivityInfo() { |
| return mActivityInfo; |
| } |
| |
| /** Returns the real resolved type. */ |
| @Nullable |
| public String getResolvedType() { |
| return mResolvedType; |
| } |
| |
| /** Returns the calling package. */ |
| @Nullable |
| public String getCallingPackage() { |
| return mCallingPackage; |
| } |
| |
| /** Returns the calling feature id. */ |
| @Nullable |
| public String getCallingFeatureId() { |
| return mCallingFeatureId; |
| } |
| |
| /** Returns the {@link ActivityOptions}. */ |
| @Nullable |
| public ActivityOptions getCheckedOptions() { |
| return mCheckedOptions; |
| } |
| |
| /** Returns the {@link Runnable} object to clear options Animation. */ |
| @Nullable |
| public Runnable getClearOptionsAnimationRunnable() { |
| return mClearOptionsAnimation; |
| } |
| } |
| |
| /** |
| * Data class for storing the intercept result. |
| * @hide |
| */ |
| @SystemApi(client = SystemApi.Client.SYSTEM_SERVER) |
| final class ActivityInterceptResult { |
| @NonNull |
| private final Intent mIntent; |
| |
| @NonNull |
| private final ActivityOptions mActivityOptions; |
| |
| private final boolean mActivityResolved; |
| |
| /** |
| * This constructor should only be used if both {@link ActivityInfo} and {@link ResolveInfo} |
| * did not get resolved while interception. |
| * @hide |
| */ |
| public ActivityInterceptResult(@NonNull Intent intent, |
| @NonNull ActivityOptions activityOptions) { |
| this(intent, activityOptions, false /* activityResolved */); |
| } |
| |
| /** |
| * Generates the result of intercepting launching the {@link android.app.Activity} |
| * |
| * <p>Interceptor should return non-{@code null} result when {@link |
| * #onInterceptActivityLaunch(ActivityInterceptorInfo)} gets called as an indicator that |
| * interception has happened. |
| * |
| * @param intent is the modified {@link Intent} after interception. |
| * @param activityOptions holds the {@link ActivityOptions} after interception. |
| * @param activityResolved should be {@code true} only if {@link ActivityInfo} or {@link |
| * ResolveInfo} gets resolved, otherwise should be {@code false}. |
| */ |
| public ActivityInterceptResult(@NonNull Intent intent, |
| @NonNull ActivityOptions activityOptions, boolean activityResolved) { |
| this.mIntent = intent; |
| this.mActivityOptions = activityOptions; |
| this.mActivityResolved = activityResolved; |
| } |
| |
| /** Returns the intercepted {@link Intent} */ |
| @SuppressWarnings("IntentBuilderName") |
| @NonNull |
| public Intent getIntent() { |
| return mIntent; |
| } |
| |
| /** Returns the intercepted {@link ActivityOptions} */ |
| @NonNull |
| public ActivityOptions getActivityOptions() { |
| return mActivityOptions; |
| } |
| |
| /** |
| * Returns if the {@link ActivityInfo} or {@link ResolveInfo} gets resolved. |
| */ |
| public boolean isActivityResolved() { |
| return mActivityResolved; |
| } |
| } |
| } |