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

Commit 0fb4f28f authored by Mohammed Rashidy's avatar Mohammed Rashidy
Browse files

Disable resolving while intercepting based on a flag

Adding a flag to ActivityInterceptResult which could disable resolving
if interception happened.

This flag is needed in case that SDK sandbox is intercepting the
activity starting flow, as it would modify ActivityInfo (not the intent),
so there is no need to resolve it again.

Test: atest WmTests:ActivityStartInterceptorTest
CTS-Coverage-Bug: 261605379
API-Coverage-Bug: 261605379
Bug: 248531721
Change-Id: Ie4b018d9fdf996bd10aa2e9a1350c6046f28fd14
parent 44036d20
Loading
Loading
Loading
Loading
+49 −0
Original line number Original line Diff line number Diff line
@@ -169,3 +169,52 @@ package com.android.server.wifi {


}
}


package com.android.server.wm {

  public interface ActivityInterceptorCallback {
    method public default void onActivityLaunched(@NonNull android.app.TaskInfo, @NonNull android.content.pm.ActivityInfo, @NonNull com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptorInfo);
    method @Nullable public com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptResult onInterceptActivityLaunch(@NonNull com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptorInfo);
    field public static final int MAINLINE_SDK_SANDBOX_ORDER_ID = 1001; // 0x3e9
  }

  public static final class ActivityInterceptorCallback.ActivityInterceptResult {
    ctor public ActivityInterceptorCallback.ActivityInterceptResult(@NonNull android.content.Intent, @NonNull android.app.ActivityOptions, boolean);
    method @NonNull public android.app.ActivityOptions getActivityOptions();
    method @NonNull public android.content.Intent getIntent();
    method public boolean isActivityResolved();
  }

  public static final class ActivityInterceptorCallback.ActivityInterceptorInfo {
    method @NonNull public android.content.pm.ActivityInfo getActivityInfo();
    method @Nullable public String getCallingFeatureId();
    method @Nullable public String getCallingPackage();
    method public int getCallingPid();
    method public int getCallingUid();
    method @Nullable public android.app.ActivityOptions getCheckedOptions();
    method @Nullable public Runnable getClearOptionsAnimationRunnable();
    method @NonNull public android.content.Intent getIntent();
    method public int getRealCallingPid();
    method public int getRealCallingUid();
    method @NonNull public android.content.pm.ResolveInfo getResolveInfo();
    method @Nullable public String getResolvedType();
    method public int getUserId();
  }

  public static final class ActivityInterceptorCallback.ActivityInterceptorInfo.Builder {
    ctor public ActivityInterceptorCallback.ActivityInterceptorInfo.Builder(int, int, int, int, int, @NonNull android.content.Intent, @NonNull android.content.pm.ResolveInfo, @NonNull android.content.pm.ActivityInfo);
    method @NonNull public com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptorInfo build();
    method @NonNull public com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptorInfo.Builder setCallingFeatureId(@NonNull String);
    method @NonNull public com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptorInfo.Builder setCallingPackage(@NonNull String);
    method @NonNull public com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptorInfo.Builder setCheckedOptions(@NonNull android.app.ActivityOptions);
    method @NonNull public com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptorInfo.Builder setClearOptionsAnimationRunnable(@NonNull Runnable);
    method @NonNull public com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptorInfo.Builder setResolvedType(@NonNull String);
  }

  public class ActivityInterceptorCallbackRegistry {
    method @NonNull public static com.android.server.wm.ActivityInterceptorCallbackRegistry getInstance();
    method public void registerActivityInterceptorCallback(int, @NonNull com.android.server.wm.ActivityInterceptorCallback);
    method public void unregisterActivityInterceptorCallback(int);
  }

}
+34 −3
Original line number Original line Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.server.wm;
import android.annotation.IntDef;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.app.ActivityOptions;
import android.app.ActivityOptions;
import android.app.TaskInfo;
import android.app.TaskInfo;
import android.content.Intent;
import android.content.Intent;
@@ -33,6 +34,7 @@ import java.lang.annotation.RetentionPolicy;
 * be called with the WindowManagerGlobalLock held.
 * be called with the WindowManagerGlobalLock held.
 * @hide
 * @hide
 */
 */
@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
public interface ActivityInterceptorCallback {
public interface ActivityInterceptorCallback {
    /**
    /**
     * Called to allow intercepting activity launching based on the provided launch parameters and
     * Called to allow intercepting activity launching based on the provided launch parameters and
@@ -165,6 +167,7 @@ public interface ActivityInterceptorCallback {
     * Data class for storing the various arguments needed for activity interception.
     * Data class for storing the various arguments needed for activity interception.
     * @hide
     * @hide
     */
     */
    @SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
    final class ActivityInterceptorInfo {
    final class ActivityInterceptorInfo {
        private final int mCallingUid;
        private final int mCallingUid;
        private final int mCallingPid;
        private final int mCallingPid;
@@ -389,6 +392,7 @@ public interface ActivityInterceptorCallback {
     * Data class for storing the intercept result.
     * Data class for storing the intercept result.
     * @hide
     * @hide
     */
     */
    @SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
    final class ActivityInterceptResult {
    final class ActivityInterceptResult {
        @NonNull
        @NonNull
        private final Intent mIntent;
        private final Intent mIntent;
@@ -396,15 +400,35 @@ public interface ActivityInterceptorCallback {
        @NonNull
        @NonNull
        private final ActivityOptions mActivityOptions;
        private final ActivityOptions mActivityOptions;


        /** Generates the result of intercepting launching the {@link android.app.Activity}
        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 intent is the modified {@link Intent} after interception.
         * @param activityOptions holds the {@link ActivityOptions} 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(
        public ActivityInterceptResult(@NonNull Intent intent,
                @NonNull Intent intent, @NonNull ActivityOptions activityOptions) {
                @NonNull ActivityOptions activityOptions, boolean activityResolved) {
            this.mIntent = intent;
            this.mIntent = intent;
            this.mActivityOptions = activityOptions;
            this.mActivityOptions = activityOptions;
            this.mActivityResolved = activityResolved;
        }
        }


        /** Returns the intercepted {@link Intent} */
        /** Returns the intercepted {@link Intent} */
@@ -419,5 +443,12 @@ public interface ActivityInterceptorCallback {
        public ActivityOptions getActivityOptions() {
        public ActivityOptions getActivityOptions() {
            return mActivityOptions;
            return mActivityOptions;
        }
        }

        /**
         * Returns if the {@link ActivityInfo} or {@link ResolveInfo} gets resolved.
         */
        public boolean isActivityResolved() {
            return mActivityResolved;
        }
    }
    }
}
}
+2 −0
Original line number Original line Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server.wm;
package com.android.server.wm;


import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.os.Binder;
import android.os.Binder;
import android.os.Process;
import android.os.Process;


@@ -30,6 +31,7 @@ import com.android.server.LocalServices;
 * int, ActivityInterceptorCallback)}.
 * int, ActivityInterceptorCallback)}.
 * @hide
 * @hide
 */
 */
@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
public class ActivityInterceptorCallbackRegistry {
public class ActivityInterceptorCallbackRegistry {


    private static final ActivityInterceptorCallbackRegistry sInstance =
    private static final ActivityInterceptorCallbackRegistry sInstance =
+3 −0
Original line number Original line Diff line number Diff line
@@ -244,6 +244,9 @@ class ActivityStartInterceptor {
            mActivityOptions = interceptResult.getActivityOptions();
            mActivityOptions = interceptResult.getActivityOptions();
            mCallingPid = mRealCallingPid;
            mCallingPid = mRealCallingPid;
            mCallingUid = mRealCallingUid;
            mCallingUid = mRealCallingUid;
            if (interceptResult.isActivityResolved()) {
                return true;
            }
            mRInfo = mSupervisor.resolveIntent(mIntent, null, mUserId, 0, mRealCallingUid);
            mRInfo = mSupervisor.resolveIntent(mIntent, null, mUserId, 0, mRealCallingUid);
            mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags,
            mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags,
                    null /*profilerInfo*/);
                    null /*profilerInfo*/);
+33 −1
Original line number Original line Diff line number Diff line
@@ -30,6 +30,7 @@ import static com.android.server.wm.ActivityInterceptorCallback.MAINLINE_SDK_SAN


import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.eq;
@@ -358,6 +359,12 @@ public class ActivityStartInterceptorTest {


    public void addMockInterceptorCallback(
    public void addMockInterceptorCallback(
            @Nullable Intent intent, @Nullable ActivityOptions activityOptions) {
            @Nullable Intent intent, @Nullable ActivityOptions activityOptions) {
        addMockInterceptorCallback(intent, activityOptions, false);
    }

    public void addMockInterceptorCallback(
            @Nullable Intent intent, @Nullable ActivityOptions activityOptions,
            boolean skipResolving) {
        int size = mActivityInterceptorCallbacks.size();
        int size = mActivityInterceptorCallbacks.size();
        mActivityInterceptorCallbacks.put(size, new ActivityInterceptorCallback() {
        mActivityInterceptorCallbacks.put(size, new ActivityInterceptorCallback() {
            @Override
            @Override
@@ -368,7 +375,8 @@ public class ActivityStartInterceptorTest {
                }
                }
                return new ActivityInterceptResult(
                return new ActivityInterceptResult(
                        intent != null ? intent : info.getIntent(),
                        intent != null ? intent : info.getIntent(),
                        activityOptions != null ? activityOptions : info.getCheckedOptions());
                        activityOptions != null ? activityOptions : info.getCheckedOptions(),
                        skipResolving);
            }
            }
        });
        });
    }
    }
@@ -400,6 +408,30 @@ public class ActivityStartInterceptorTest {
        assertEquals("android.test.second", mInterceptor.mIntent.getAction());
        assertEquals("android.test.second", mInterceptor.mIntent.getAction());
    }
    }


    @Test
    public void testInterceptionCallback_skipResolving() {
        addMockInterceptorCallback(
                new Intent("android.test.foo"),
                ActivityOptions.makeBasic().setLaunchDisplayId(3), true);
        ActivityInfo aInfo = mAInfo;
        assertTrue(mInterceptor.intercept(null, null, aInfo, null, null, null, 0, 0, null));
        assertEquals("android.test.foo", mInterceptor.mIntent.getAction());
        assertEquals(3, mInterceptor.mActivityOptions.getLaunchDisplayId());
        assertEquals(aInfo, mInterceptor.mAInfo); // mAInfo should not be resolved
    }

    @Test
    public void testInterceptionCallback_NoSkipResolving() throws InterruptedException {
        addMockInterceptorCallback(
                new Intent("android.test.foo"),
                ActivityOptions.makeBasic().setLaunchDisplayId(3));
        ActivityInfo aInfo = mAInfo;
        assertTrue(mInterceptor.intercept(null, null, aInfo, null, null, null, 0, 0, null));
        assertEquals("android.test.foo", mInterceptor.mIntent.getAction());
        assertEquals(3, mInterceptor.mActivityOptions.getLaunchDisplayId());
        assertNotEquals(aInfo, mInterceptor.mAInfo); // mAInfo should be resolved after intercept
    }

    @Test
    @Test
    public void testActivityLaunchedCallback_singleCallback() {
    public void testActivityLaunchedCallback_singleCallback() {
        addMockInterceptorCallback(null, null);
        addMockInterceptorCallback(null, null);