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
This commit is contained in:
Mohammed Rashidy
2022-12-06 18:47:28 +00:00
parent c4173db78f
commit f47192f8c3
9 changed files with 492 additions and 107 deletions

View File

@@ -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));
}
};

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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
*/
static final int LAST_ORDERED_ID = DREAM_MANAGER_ORDERED_ID;
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.
*/
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
*/
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;
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;
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;
/**
* @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.
*/
@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;
}
}
}

View File

@@ -23,6 +23,7 @@ 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;
@@ -33,7 +34,9 @@ import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED;
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
import static com.android.server.wm.ActivityInterceptorCallback.MAINLINE_SDK_SANDBOX_ORDER_ID;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityOptions;
import android.app.KeyguardManager;
@@ -226,13 +229,19 @@ class ActivityStartInterceptor {
getInterceptorInfo(null /* clearOptionsAnimation */);
for (int i = 0; i < callbacks.size(); i++) {
final int orderId = callbacks.keyAt(i);
if (!shouldInterceptActivityLaunch(orderId, interceptorInfo)) {
continue;
}
final ActivityInterceptorCallback callback = callbacks.valueAt(i);
final ActivityInterceptResult interceptResult = callback.intercept(interceptorInfo);
final ActivityInterceptResult interceptResult = callback.onInterceptActivityLaunch(
interceptorInfo);
if (interceptResult == null) {
continue;
}
mIntent = interceptResult.intent;
mActivityOptions = interceptResult.activityOptions;
mIntent = interceptResult.getIntent();
mActivityOptions = interceptResult.getActivityOptions();
mCallingPid = mRealCallingPid;
mCallingUid = mRealCallingUid;
mRInfo = mSupervisor.resolveIntent(mIntent, null, mUserId, 0, mRealCallingUid);
@@ -459,6 +468,11 @@ class ActivityStartInterceptor {
ActivityInterceptorCallback.ActivityInterceptorInfo info = getInterceptorInfo(
r::clearOptionsAnimationForSiblings);
for (int i = 0; i < callbacks.size(); i++) {
final int orderId = callbacks.keyAt(i);
if (!shouldNotifyOnActivityLaunch(orderId, info)) {
continue;
}
final ActivityInterceptorCallback callback = callbacks.valueAt(i);
callback.onActivityLaunched(taskInfo, r.info, info);
}
@@ -466,9 +480,33 @@ class ActivityStartInterceptor {
private ActivityInterceptorCallback.ActivityInterceptorInfo getInterceptorInfo(
@Nullable Runnable clearOptionsAnimation) {
return new ActivityInterceptorCallback.ActivityInterceptorInfo(mRealCallingUid,
mRealCallingPid, mUserId, mCallingPackage, mCallingFeatureId, mIntent,
mRInfo, mAInfo, mResolvedType, mCallingPid, mCallingUid,
mActivityOptions, clearOptionsAnimation);
return new ActivityInterceptorCallback.ActivityInterceptorInfo.Builder(mCallingUid,
mCallingPid, mRealCallingUid, mRealCallingPid, mUserId, mIntent, mRInfo, mAInfo)
.setResolvedType(mResolvedType)
.setCallingPackage(mCallingPackage)
.setCallingFeatureId(mCallingFeatureId)
.setCheckedOptions(mActivityOptions)
.setClearOptionsAnimationRunnable(clearOptionsAnimation)
.build();
}
private boolean shouldInterceptActivityLaunch(
@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 true;
}
private boolean shouldNotifyOnActivityLaunch(
@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 true;
}
}

View File

@@ -94,8 +94,10 @@ import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.Scr
import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.PACKAGE;
import static com.android.server.am.EventLogTags.writeBootProgressEnableScreen;
import static com.android.server.am.EventLogTags.writeConfigurationChanged;
import static com.android.server.wm.ActivityInterceptorCallback.FIRST_ORDERED_ID;
import static com.android.server.wm.ActivityInterceptorCallback.LAST_ORDERED_ID;
import static com.android.server.wm.ActivityInterceptorCallback.MAINLINE_FIRST_ORDERED_ID;
import static com.android.server.wm.ActivityInterceptorCallback.MAINLINE_LAST_ORDERED_ID;
import static com.android.server.wm.ActivityInterceptorCallback.SYSTEM_FIRST_ORDERED_ID;
import static com.android.server.wm.ActivityInterceptorCallback.SYSTEM_LAST_ORDERED_ID;
import static com.android.server.wm.ActivityRecord.State.PAUSING;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_ROOT_TASK;
@@ -6811,10 +6813,13 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
if (mActivityInterceptorCallbacks.contains(id)) {
throw new IllegalArgumentException("Duplicate id provided: " + id);
}
if (id > LAST_ORDERED_ID || id < FIRST_ORDERED_ID) {
if (!ActivityInterceptorCallback.isValidOrderId(id)) {
throw new IllegalArgumentException(
"Provided id " + id + " is not in range of valid ids ["
+ FIRST_ORDERED_ID + "," + LAST_ORDERED_ID + "]");
"Provided id " + id + " is not in range of valid ids for system "
+ "services [" + SYSTEM_FIRST_ORDERED_ID + ","
+ SYSTEM_LAST_ORDERED_ID + "] nor in range of valid ids for "
+ "mainline module services [" + MAINLINE_FIRST_ORDERED_ID + ","
+ MAINLINE_LAST_ORDERED_ID + "]");
}
mActivityInterceptorCallbacks.put(id, callback);
}

View File

@@ -0,0 +1,22 @@
/*
* Copyright (C) 2022 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.
*/
/**
* @hide
* TODO(b/146466118) remove this javadoc tag
*/
@android.annotation.Hide
package com.android.server.wm;

View File

@@ -16,6 +16,7 @@
package com.android.server.wm;
import static android.app.sdksandbox.SdkSandboxManager.ACTION_START_SANDBOXED_ACTIVITY;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED;
@@ -25,6 +26,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
import static com.android.server.wm.ActivityInterceptorCallback.MAINLINE_SDK_SANDBOX_ORDER_ID;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -33,7 +35,9 @@ import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManagerInternal;
import android.app.ActivityOptions;
@@ -68,6 +72,7 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
/**
@@ -356,13 +361,14 @@ public class ActivityStartInterceptorTest {
int size = mActivityInterceptorCallbacks.size();
mActivityInterceptorCallbacks.put(size, new ActivityInterceptorCallback() {
@Override
public ActivityInterceptResult intercept(ActivityInterceptorInfo info) {
public ActivityInterceptResult onInterceptActivityLaunch(@NonNull
ActivityInterceptorInfo info) {
if (intent == null && activityOptions == null) {
return null;
}
return new ActivityInterceptResult(
intent != null ? intent : info.intent,
activityOptions != null ? activityOptions : info.checkedOptions);
intent != null ? intent : info.getIntent(),
activityOptions != null ? activityOptions : info.getCheckedOptions());
}
});
}
@@ -405,4 +411,30 @@ public class ActivityStartInterceptorTest {
verify(callback, times(1)).onActivityLaunched(any(), any(), any());
}
@Test
public void testSandboxServiceInterceptionHappensToSandboxedActivityAction()
throws InterruptedException {
ActivityInterceptorCallback spyCallback = Mockito.spy(info -> null);
mActivityInterceptorCallbacks.put(MAINLINE_SDK_SANDBOX_ORDER_ID, spyCallback);
Intent intent = new Intent().setAction(ACTION_START_SANDBOXED_ACTIVITY);
mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null);
verify(spyCallback, times(1)).onInterceptActivityLaunch(
any(ActivityInterceptorCallback.ActivityInterceptorInfo.class));
}
@Test
public void testSandboxServiceInterceptionNotCalledForNotSandboxedActivityAction() {
ActivityInterceptorCallback spyCallback = Mockito.spy(info -> null);
mActivityInterceptorCallbacks.put(MAINLINE_SDK_SANDBOX_ORDER_ID, spyCallback);
Intent intent = new Intent();
mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null);
verify(spyCallback, never()).onInterceptActivityLaunch(
any(ActivityInterceptorCallback.ActivityInterceptorInfo.class));
}
}

View File

@@ -25,8 +25,9 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.server.wm.ActivityInterceptorCallback.FIRST_ORDERED_ID;
import static com.android.server.wm.ActivityInterceptorCallback.LAST_ORDERED_ID;
import static com.android.server.wm.ActivityInterceptorCallback.MAINLINE_FIRST_ORDERED_ID;
import static com.android.server.wm.ActivityInterceptorCallback.SYSTEM_FIRST_ORDERED_ID;
import static com.android.server.wm.ActivityInterceptorCallback.SYSTEM_LAST_ORDERED_ID;
import static com.android.server.wm.ActivityRecord.State.PAUSED;
import static com.android.server.wm.ActivityRecord.State.PAUSING;
import static com.android.server.wm.ActivityRecord.State.RESUMED;
@@ -45,6 +46,7 @@ import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.when;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityManager;
@@ -957,11 +959,12 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase {
@Test(expected = IllegalArgumentException.class)
public void testRegisterActivityStartInterceptor_IndexTooSmall() {
mAtm.mInternal.registerActivityStartInterceptor(FIRST_ORDERED_ID - 1,
mAtm.mInternal.registerActivityStartInterceptor(SYSTEM_FIRST_ORDERED_ID - 1,
new ActivityInterceptorCallback() {
@Nullable
@Override
public ActivityInterceptResult intercept(ActivityInterceptorInfo info) {
public ActivityInterceptResult onInterceptActivityLaunch(
@NonNull ActivityInterceptorInfo info) {
return null;
}
});
@@ -969,11 +972,12 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase {
@Test(expected = IllegalArgumentException.class)
public void testRegisterActivityStartInterceptor_IndexTooLarge() {
mAtm.mInternal.registerActivityStartInterceptor(LAST_ORDERED_ID + 1,
mAtm.mInternal.registerActivityStartInterceptor(SYSTEM_LAST_ORDERED_ID + 1,
new ActivityInterceptorCallback() {
@Nullable
@Override
public ActivityInterceptResult intercept(ActivityInterceptorInfo info) {
public ActivityInterceptResult onInterceptActivityLaunch(
@NonNull ActivityInterceptorInfo info) {
return null;
}
});
@@ -981,19 +985,21 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase {
@Test(expected = IllegalArgumentException.class)
public void testRegisterActivityStartInterceptor_DuplicateId() {
mAtm.mInternal.registerActivityStartInterceptor(FIRST_ORDERED_ID,
mAtm.mInternal.registerActivityStartInterceptor(SYSTEM_FIRST_ORDERED_ID,
new ActivityInterceptorCallback() {
@Nullable
@Override
public ActivityInterceptResult intercept(ActivityInterceptorInfo info) {
public ActivityInterceptResult onInterceptActivityLaunch(
@NonNull ActivityInterceptorInfo info) {
return null;
}
});
mAtm.mInternal.registerActivityStartInterceptor(FIRST_ORDERED_ID,
mAtm.mInternal.registerActivityStartInterceptor(SYSTEM_FIRST_ORDERED_ID,
new ActivityInterceptorCallback() {
@Nullable
@Override
public ActivityInterceptResult intercept(ActivityInterceptorInfo info) {
public ActivityInterceptResult onInterceptActivityLaunch(
@NonNull ActivityInterceptorInfo info) {
return null;
}
});
@@ -1003,16 +1009,22 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase {
public void testRegisterActivityStartInterceptor() {
assertEquals(0, mAtm.getActivityInterceptorCallbacks().size());
mAtm.mInternal.registerActivityStartInterceptor(FIRST_ORDERED_ID,
mAtm.mInternal.registerActivityStartInterceptor(SYSTEM_FIRST_ORDERED_ID,
new ActivityInterceptorCallback() {
@Nullable
@Override
public ActivityInterceptResult intercept(ActivityInterceptorInfo info) {
public ActivityInterceptResult onInterceptActivityLaunch(
@NonNull ActivityInterceptorInfo info) {
return null;
}
});
assertEquals(1, mAtm.getActivityInterceptorCallbacks().size());
assertTrue(mAtm.getActivityInterceptorCallbacks().contains(FIRST_ORDERED_ID));
assertTrue(mAtm.getActivityInterceptorCallbacks().contains(SYSTEM_FIRST_ORDERED_ID));
}
@Test
public void testSystemAndMainlineOrderIdsNotOverlapping() {
assertTrue(MAINLINE_FIRST_ORDERED_ID - SYSTEM_LAST_ORDERED_ID > 1);
}
}