Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f47192f8 authored by Mohammed Rashidy's avatar Mohammed Rashidy
Browse files

Prepare ActivityInterceptorCallback to be unhidden to mainline modules.

AdServices mainline module need to register ActivityInterceptorCallback
as part of Activity Support in SDK Sandbox.

ActivityInterceptorCallback should be visible to mainline modules which
requires the package com.android.server.wm to tagged with Hide annotation,
that is why in this CL a file packge-info.java is added to the package.

This also add fixed to make the class follow go/android-api-guidelines

Test: atest com.android.server.wm.ActivityStartInterceptorTest && atest com.android.server.wm.ActivityTaskManagerServiceTests
Bug: 248531721
CTS-Coverage-Bug: 261596770
API-Coverage-Bug: 261596770
Change-Id: Ied9787c1fa691d609ee7625433dc088d79d11473
parent c4173db7
Loading
Loading
Loading
Loading
+6 −5
Original line number Diff line number Diff line
@@ -134,21 +134,22 @@ public class VirtualDeviceManagerService extends SystemService {

        @Nullable
        @Override
        public ActivityInterceptResult intercept(ActivityInterceptorInfo info) {
            if (info.callingPackage == null) {
        public ActivityInterceptResult onInterceptActivityLaunch(@NonNull
                ActivityInterceptorInfo info) {
            if (info.getCallingPackage() == null) {
                return null;
            }
            PendingTrampoline pt = mPendingTrampolines.remove(info.callingPackage);
            PendingTrampoline pt = mPendingTrampolines.remove(info.getCallingPackage());
            if (pt == null) {
                return null;
            }
            pt.mResultReceiver.send(VirtualDeviceManager.LAUNCH_SUCCESS, null);
            ActivityOptions options = info.checkedOptions;
            ActivityOptions options = info.getCheckedOptions();
            if (options == null) {
                options = ActivityOptions.makeBasic();
            }
            return new ActivityInterceptResult(
                    info.intent, options.setLaunchDisplayId(pt.mDisplayId));
                    info.getIntent(), options.setLaunchDisplayId(pt.mDisplayId));
        }
    };

+2 −1
Original line number Diff line number Diff line
@@ -147,7 +147,8 @@ public final class DreamManagerService extends SystemService {
            new ActivityInterceptorCallback() {
                @Nullable
                @Override
                public ActivityInterceptResult intercept(ActivityInterceptorInfo info) {
                public ActivityInterceptResult onInterceptActivityLaunch(@NonNull
                        ActivityInterceptorInfo info) {
                    return null;
                }

+11 −11
Original line number Diff line number Diff line
@@ -1130,18 +1130,18 @@ public final class PermissionPolicyService extends SystemService {
                new ActivityInterceptorCallback() {
                    @Nullable
                    @Override
                    public ActivityInterceptorCallback.ActivityInterceptResult intercept(
                            ActivityInterceptorInfo info) {
                    public ActivityInterceptorCallback.ActivityInterceptResult
                            onInterceptActivityLaunch(@NonNull ActivityInterceptorInfo info) {
                        return null;
                    }

                    @Override
                    public void onActivityLaunched(TaskInfo taskInfo, ActivityInfo activityInfo,
                            ActivityInterceptorInfo info) {
                        super.onActivityLaunched(taskInfo, activityInfo, info);
                        if (!shouldShowNotificationDialogOrClearFlags(taskInfo,
                                activityInfo.packageName, info.callingPackage, info.intent,
                                info.checkedOptions, activityInfo.name, true)
                                activityInfo.packageName, info.getCallingPackage(),
                                info.getIntent(), info.getCheckedOptions(), activityInfo.name,
                                true)
                                || isNoDisplayActivity(activityInfo)) {
                            return;
                        }
@@ -1318,12 +1318,12 @@ public final class PermissionPolicyService extends SystemService {
                    ACTION_REQUEST_PERMISSIONS_FOR_OTHER);
            grantPermission.putExtra(Intent.EXTRA_PACKAGE_NAME, pkgName);

            final boolean remoteAnimation = info != null && info.checkedOptions != null
                    && info.checkedOptions.getAnimationType() == ANIM_REMOTE_ANIMATION
                    && info.clearOptionsAnimation != null;
            final boolean remoteAnimation = info != null && info.getCheckedOptions() != null
                    && info.getCheckedOptions().getAnimationType() == ANIM_REMOTE_ANIMATION
                    && info.getClearOptionsAnimationRunnable() != null;
            ActivityOptions options = remoteAnimation ? ActivityOptions.makeRemoteAnimation(
                        info.checkedOptions.getRemoteAnimationAdapter(),
                        info.checkedOptions.getRemoteTransition())
                        info.getCheckedOptions().getRemoteAnimationAdapter(),
                        info.getCheckedOptions().getRemoteTransition())
                    : new ActivityOptions(new Bundle());
            options.setTaskOverlay(true, false);
            options.setLaunchTaskId(taskId);
@@ -1333,7 +1333,7 @@ public final class PermissionPolicyService extends SystemService {
                // animation from the intercepted activity and its siblings to prevent duplication.
                // This should trigger ActivityRecord#clearOptionsAnimationForSiblings for the
                // intercepted activity.
                info.clearOptionsAnimation.run();
                info.getClearOptionsAnimationRunnable().run();
            }
            try {
                mContext.startActivityAsUser(grantPermission, options.toBundle(), user);
+337 −63
Original line number Diff line number Diff line
@@ -31,119 +31,393 @@ 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
 */
public abstract class ActivityInterceptorCallback {
public interface ActivityInterceptorCallback {
    /**
     * Intercept the launch intent based on various signals. If an interception happened, returns
     * a new/existing non-null {@link ActivityInterceptResult} which may redirect to another
     * activity or with new {@link ActivityOptions}.
     * Called to allow intercepting activity launching based on the provided launch parameters and
     * intent resolution.
     *
     * @return null if no interception occurred, or a non-null result which replaces the existing
     * intent and activity options.
     * <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.
     */
    public abstract @Nullable ActivityInterceptResult intercept(ActivityInterceptorInfo info);
    @Nullable
    ActivityInterceptResult onInterceptActivityLaunch(@NonNull ActivityInterceptorInfo info);

    /**
     * Called when an activity is successfully launched. The intent included in the
     * ActivityInterceptorInfo may have changed from the one sent in
     * {@link #intercept(ActivityInterceptorInfo)}, due to the return from
     * {@link #intercept(ActivityInterceptorInfo)}.
     * 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)}.
     */
    public void onActivityLaunched(TaskInfo taskInfo, ActivityInfo activityInfo,
            ActivityInterceptorInfo info) {
    }
    default void onActivityLaunched(@NonNull TaskInfo taskInfo, @NonNull ActivityInfo activityInfo,
            @NonNull ActivityInterceptorInfo info) {}

    /**
     * The unique id of each interceptor which determines the order it will execute in.
     * 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 = {
            FIRST_ORDERED_ID,
            // Order Ids for system services
            SYSTEM_FIRST_ORDERED_ID,
            PERMISSION_POLICY_ORDERED_ID,
            VIRTUAL_DEVICE_SERVICE_ORDERED_ID,
            DREAM_MANAGER_ORDERED_ID,
            LAST_ORDERED_ID // Update this when adding new ids
            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)
    public @interface OrderedId {}
    @interface OrderedId {}

    /**
     * The first id, used by the framework to determine the valid range of ids.
     * @hide
     */
    static final int FIRST_ORDERED_ID = 0;
    int SYSTEM_FIRST_ORDERED_ID = 0;

    /**
     * The identifier for {@link com.android.server.policy.PermissionPolicyService} interceptor
     * @hide
     */
    public static final int PERMISSION_POLICY_ORDERED_ID = 1;
    int PERMISSION_POLICY_ORDERED_ID = 1;

    /**
     * The identifier for {@link com.android.server.companion.virtual.VirtualDeviceManagerService}
     * interceptor.
     * @hide
     */
    public static final int VIRTUAL_DEVICE_SERVICE_ORDERED_ID = 3;
    int VIRTUAL_DEVICE_SERVICE_ORDERED_ID = 3;

    /**
     * The identifier for {@link com.android.server.dreams.DreamManagerService} interceptor.
     * @hide
     */
    public static final int DREAM_MANAGER_ORDERED_ID = 4;
    int DREAM_MANAGER_ORDERED_ID = 4;

    /**
     * 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 = DREAM_MANAGER_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.
     */
    static final int LAST_ORDERED_ID = DREAM_MANAGER_ORDERED_ID;
    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
     */
    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(@NonNull String resolvedType) {
                mResolvedType = resolvedType;
                return this;
            }

            /**
             * Sets the value for the calling package.
             * @param callingPackage the calling package.
             */
    public static final class ActivityInterceptorInfo {
        public final int realCallingUid;
        public final int realCallingPid;
        public final int userId;
        public final String callingPackage;
        public final String callingFeatureId;
        public final Intent intent;
        public final ResolveInfo rInfo;
        public final ActivityInfo aInfo;
        public final String resolvedType;
        public final int callingPid;
        public final int callingUid;
        public final ActivityOptions checkedOptions;
        public final @Nullable Runnable clearOptionsAnimation;

        public ActivityInterceptorInfo(int realCallingUid, int realCallingPid, int userId,
                String callingPackage, String callingFeatureId, Intent intent,
                ResolveInfo rInfo, ActivityInfo aInfo, String resolvedType, int callingPid,
                int callingUid, ActivityOptions checkedOptions,
                @Nullable Runnable clearOptionsAnimation) {
            this.realCallingUid = realCallingUid;
            this.realCallingPid = realCallingPid;
            this.userId = userId;
            this.callingPackage = callingPackage;
            this.callingFeatureId = callingFeatureId;
            this.intent = intent;
            this.rInfo = rInfo;
            this.aInfo = aInfo;
            this.resolvedType = resolvedType;
            this.callingPid = callingPid;
            this.callingUid = callingUid;
            this.checkedOptions = checkedOptions;
            this.clearOptionsAnimation = clearOptionsAnimation;
            @NonNull
            public Builder setCallingPackage(@NonNull String callingPackage) {
                mCallingPackage = callingPackage;
                return this;
            }

            /**
             * Sets the value for the calling feature id.
             * @param callingFeatureId the calling feature id.
             */
            @NonNull
            public Builder setCallingFeatureId(@NonNull String callingFeatureId) {
                mCallingFeatureId = callingFeatureId;
                return this;
            }

            /**
             * Sets the value for the {@link ActivityOptions}.
             * @param checkedOptions the {@link ActivityOptions}.
             */
            @NonNull
            public Builder setCheckedOptions(@NonNull 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(@NonNull
                    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
     */
    public static final class ActivityInterceptResult {
        @NonNull public final Intent intent;
        @NonNull public final ActivityOptions activityOptions;
    final class ActivityInterceptResult {
        @NonNull
        private final Intent mIntent;

        @NonNull
        private final ActivityOptions mActivityOptions;

        /** Generates the result of intercepting launching the {@link android.app.Activity}
         *
         * @param intent is the modified {@link Intent} after interception.
         * @param activityOptions holds the {@link ActivityOptions} after interception.
         */
        public ActivityInterceptResult(
                @NonNull Intent intent,
                @NonNull ActivityOptions activityOptions) {
            this.intent = intent;
            this.activityOptions = activityOptions;
                @NonNull Intent intent, @NonNull ActivityOptions activityOptions) {
            this.mIntent = intent;
            this.mActivityOptions = activityOptions;
        }

        /** Returns the intercepted {@link Intent} */
        @SuppressWarnings("IntentBuilderName")
        @NonNull
        public Intent getIntent() {
            return mIntent;
        }

        /** Returns the intercepted {@link ActivityOptions} */
        @NonNull
        public ActivityOptions getActivityOptions() {
            return mActivityOptions;
        }
    }
}
+45 −7

File changed.

Preview size limit exceeded, changes collapsed.

Loading