From bfb2141e2d41f654845c0b55386b7648f582c5aa Mon Sep 17 00:00:00 2001 From: Mohammed Rashidy Date: Sat, 15 Apr 2023 04:11:56 +0100 Subject: [PATCH] Add package and component checks to intercept sandbox activity intent Apply sandbox activity checks and interception if the intent is related to the sandbox activities by any way, for that package and component checks are added. In case the intent's package or component refer to the sandbox activity, sandbox service will be called. Bug: 274592326 Test: com.android.server.wm.ActivityStartInterceptorTest Change-Id: I2bcb62f76211243e53a1ac7208351d3f31843660 --- core/java/android/content/Intent.java | 16 +++++ .../server/wm/ActivityStartInterceptor.java | 7 +- .../server/wm/ActivityTaskManagerService.java | 5 +- .../wm/ActivityStartInterceptorTest.java | 68 +++++++++++++++++-- 4 files changed, 83 insertions(+), 13 deletions(-) diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 154068eb9e092..74a69a6237905 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -16,6 +16,7 @@ package android.content; +import static android.app.sdksandbox.SdkSandboxManager.ACTION_START_SANDBOXED_ACTIVITY; import static android.content.ContentProvider.maybeAddUserId; import android.Manifest; @@ -12463,4 +12464,19 @@ public class Intent implements Parcelable, Cloneable { public boolean isDocument() { return (mFlags & FLAG_ACTIVITY_NEW_DOCUMENT) == FLAG_ACTIVITY_NEW_DOCUMENT; } + + /** @hide */ + public boolean isSandboxActivity(@NonNull Context context) { + if (mAction != null && mAction.equals(ACTION_START_SANDBOXED_ACTIVITY)) { + return true; + } + final String sandboxPackageName = context.getPackageManager().getSdkSandboxPackageName(); + if (mPackage != null && mPackage.equals(sandboxPackageName)) { + return true; + } + if (mComponent != null && mComponent.getPackageName().equals(sandboxPackageName)) { + return true; + } + return false; + } } diff --git a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java index 1944b3f8e6d3b..90af4c6236aa3 100644 --- a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java +++ b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java @@ -23,7 +23,6 @@ import static android.app.PendingIntent.FLAG_IMMUTABLE; import static android.app.PendingIntent.FLAG_ONE_SHOT; import static android.app.admin.DevicePolicyManager.EXTRA_RESTRICTION; import static android.app.admin.DevicePolicyManager.POLICY_SUSPEND_PACKAGES; -import static android.app.sdksandbox.SdkSandboxManager.ACTION_START_SANDBOXED_ACTIVITY; import static android.content.Context.KEYGUARD_SERVICE; import static android.content.Intent.EXTRA_INTENT; import static android.content.Intent.EXTRA_PACKAGE_NAME; @@ -503,8 +502,7 @@ class ActivityStartInterceptor { @ActivityInterceptorCallback.OrderedId int orderId, @NonNull ActivityInterceptorCallback.ActivityInterceptorInfo info) { if (orderId == MAINLINE_SDK_SANDBOX_ORDER_ID) { - return info.getIntent() != null && info.getIntent().getAction() != null - && info.getIntent().getAction().equals(ACTION_START_SANDBOXED_ACTIVITY); + return info.getIntent() != null && info.getIntent().isSandboxActivity(mServiceContext); } return true; } @@ -513,8 +511,7 @@ class ActivityStartInterceptor { @ActivityInterceptorCallback.OrderedId int orderId, @NonNull ActivityInterceptorCallback.ActivityInterceptorInfo info) { if (orderId == MAINLINE_SDK_SANDBOX_ORDER_ID) { - return info.getIntent() != null && info.getIntent().getAction() != null - && info.getIntent().getAction().equals(ACTION_START_SANDBOXED_ACTIVITY); + return info.getIntent() != null && info.getIntent().isSandboxActivity(mServiceContext); } return true; } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 401c16f7f76ac..abf66bc7ccc03 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -38,7 +38,6 @@ import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.ActivityTaskManager.RESIZE_MODE_PRESERVE_WINDOW; import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; -import static android.app.sdksandbox.SdkSandboxManager.ACTION_START_SANDBOXED_ACTIVITY; import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; @@ -1244,9 +1243,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { assertPackageMatchesCallingUid(callingPackage); enforceNotIsolatedCaller("startActivityAsUser"); - boolean isSandboxedActivity = (intent != null && intent.getAction() != null - && intent.getAction().equals(ACTION_START_SANDBOXED_ACTIVITY)); - if (isSandboxedActivity) { + if (intent != null && intent.isSandboxActivity(mContext)) { SdkSandboxManagerLocal sdkSandboxManagerLocal = LocalManagerRegistry.getManager( SdkSandboxManagerLocal.class); sdkSandboxManagerLocal.enforceAllowedToHostSandboxedActivity( diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java index 7d16fb2e02554..4890f3e6cbf15 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java @@ -44,11 +44,13 @@ import android.app.ActivityManagerInternal; import android.app.ActivityOptions; import android.app.KeyguardManager; import android.app.admin.DevicePolicyManagerInternal; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; +import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.SuspendDialogInfo; import android.content.pm.UserInfo; @@ -445,12 +447,15 @@ public class ActivityStartInterceptorTest { } @Test - public void testSandboxServiceInterceptionHappensToSandboxedActivityAction() - throws InterruptedException { - + public void testSandboxServiceInterceptionHappensToIntentWithSandboxActivityAction() { ActivityInterceptorCallback spyCallback = Mockito.spy(info -> null); mActivityInterceptorCallbacks.put(MAINLINE_SDK_SANDBOX_ORDER_ID, spyCallback); + PackageManager packageManagerMock = mock(PackageManager.class); + String sandboxPackageNameMock = "com.sandbox.mock"; + when(mContext.getPackageManager()).thenReturn(packageManagerMock); + when(packageManagerMock.getSdkSandboxPackageName()).thenReturn(sandboxPackageNameMock); + Intent intent = new Intent().setAction(ACTION_START_SANDBOXED_ACTIVITY); mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null); @@ -459,13 +464,68 @@ public class ActivityStartInterceptorTest { } @Test - public void testSandboxServiceInterceptionNotCalledForNotSandboxedActivityAction() { + public void testSandboxServiceInterceptionHappensToIntentWithSandboxPackage() { ActivityInterceptorCallback spyCallback = Mockito.spy(info -> null); mActivityInterceptorCallbacks.put(MAINLINE_SDK_SANDBOX_ORDER_ID, spyCallback); + PackageManager packageManagerMock = mock(PackageManager.class); + String sandboxPackageNameMock = "com.sandbox.mock"; + when(mContext.getPackageManager()).thenReturn(packageManagerMock); + when(packageManagerMock.getSdkSandboxPackageName()).thenReturn(sandboxPackageNameMock); + + Intent intent = new Intent().setPackage(sandboxPackageNameMock); + mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null); + + verify(spyCallback, times(1)).onInterceptActivityLaunch( + any(ActivityInterceptorCallback.ActivityInterceptorInfo.class)); + } + + @Test + public void testSandboxServiceInterceptionHappensToIntentWithComponentNameWithSandboxPackage() { + ActivityInterceptorCallback spyCallback = Mockito.spy(info -> null); + mActivityInterceptorCallbacks.put(MAINLINE_SDK_SANDBOX_ORDER_ID, spyCallback); + + PackageManager packageManagerMock = mock(PackageManager.class); + String sandboxPackageNameMock = "com.sandbox.mock"; + when(mContext.getPackageManager()).thenReturn(packageManagerMock); + when(packageManagerMock.getSdkSandboxPackageName()).thenReturn(sandboxPackageNameMock); + + Intent intent = new Intent().setComponent(new ComponentName(sandboxPackageNameMock, "")); + mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null); + + verify(spyCallback, times(1)).onInterceptActivityLaunch( + any(ActivityInterceptorCallback.ActivityInterceptorInfo.class)); + } + + @Test + public void testSandboxServiceInterceptionNotCalledWhenIntentNotRelatedToSandbox() { + ActivityInterceptorCallback spyCallback = Mockito.spy(info -> null); + mActivityInterceptorCallbacks.put(MAINLINE_SDK_SANDBOX_ORDER_ID, spyCallback); + + PackageManager packageManagerMock = mock(PackageManager.class); + String sandboxPackageNameMock = "com.sandbox.mock"; + when(mContext.getPackageManager()).thenReturn(packageManagerMock); + when(packageManagerMock.getSdkSandboxPackageName()).thenReturn(sandboxPackageNameMock); + + // Intent: null + mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null); + + // Action: null, Package: null, ComponentName: null Intent intent = new Intent(); mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null); + // Wrong Action + intent = new Intent().setAction(Intent.ACTION_VIEW); + mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null); + + // Wrong Package + intent = new Intent().setPackage("Random"); + mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null); + + // Wrong ComponentName's package + intent = new Intent().setComponent(new ComponentName("Random", "")); + mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null); + verify(spyCallback, never()).onInterceptActivityLaunch( any(ActivityInterceptorCallback.ActivityInterceptorInfo.class)); }