diff options
| author | 2025-03-05 19:06:25 -0800 | |
|---|---|---|
| committer | 2025-03-05 19:06:25 -0800 | |
| commit | ee0af51fb0666b489ad17174a117b4caf3bfe099 (patch) | |
| tree | a385c1b25715a218d47ac7a1e95ab2af5c76f98b | |
| parent | 3fb79a62ae618c403ad58dcd1d04a359afece5c4 (diff) | |
| parent | 17f72a6129f66d415e1ed86de065d576ca9dd8be (diff) | |
RESTRICT AUTOMERGE Normalize home intent am: 9472387c9c am: 17f72a6129
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/31738532
Change-Id: I8dd712e61afe171bebaabc04c4fa02a4847aac36
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
4 files changed, 109 insertions, 4 deletions
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index add27078b00f..323b64f00d2e 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -2926,7 +2926,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A reparent(newTaskFrag, position); } - private boolean isHomeIntent(Intent intent) { + static boolean isHomeIntent(Intent intent) { return ACTION_MAIN.equals(intent.getAction()) && (intent.hasCategory(CATEGORY_HOME) || intent.hasCategory(CATEGORY_SECONDARY_HOME)) diff --git a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java index 1eb56f1b7d1c..1c5865308594 100644 --- a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java +++ b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java @@ -24,6 +24,9 @@ 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.content.Context.KEYGUARD_SERVICE; +import static android.content.Intent.ACTION_MAIN; +import static android.content.Intent.CATEGORY_HOME; +import static android.content.Intent.CATEGORY_SECONDARY_HOME; import static android.content.Intent.EXTRA_INTENT; import static android.content.Intent.EXTRA_PACKAGE_NAME; import static android.content.Intent.EXTRA_TASK_ID; @@ -41,6 +44,7 @@ import android.app.ActivityOptions; import android.app.KeyguardManager; import android.app.TaskInfo; import android.app.admin.DevicePolicyManagerInternal; +import android.content.ComponentName; import android.content.Context; import android.content.IIntentSender; import android.content.Intent; @@ -55,6 +59,7 @@ import android.os.IBinder; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; +import android.util.Slog; import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; @@ -66,6 +71,7 @@ import com.android.server.LocalServices; import com.android.server.am.ActivityManagerService; import com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptResult; + /** * A class that contains activity intercepting logic for {@link ActivityStarter#execute()} * It's initialized via setStates and interception occurs via the intercept method. @@ -74,6 +80,7 @@ import com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptResult * is no guarantee that other system services are already present. */ class ActivityStartInterceptor { + private static final String TAG = "ActivityStartInterceptor"; private final ActivityTaskManagerService mService; private final ActivityTaskSupervisor mSupervisor; @@ -110,6 +117,11 @@ class ActivityStartInterceptor { TaskFragment mInTaskFragment; ActivityOptions mActivityOptions; + /** + * Whether the component is specified originally in the given Intent. + */ + boolean mComponentSpecified; + ActivityStartInterceptor( ActivityTaskManagerService service, ActivityTaskSupervisor supervisor) { this(service, supervisor, service.mRootWindowContainer, service.mContext); @@ -158,7 +170,6 @@ class ActivityStartInterceptor { return new IntentSender(target); } - /** * A helper function to obtain the targeted {@link TaskFragment} during * {@link #intercept(Intent, ResolveInfo, ActivityInfo, String, Task, TaskFragment, int, int, @@ -179,6 +190,14 @@ class ActivityStartInterceptor { return TaskFragment.fromTaskFragmentToken(taskFragToken, mService); } + // TODO: consolidate this method with the one below since this is used for test only. + boolean intercept(Intent intent, ResolveInfo rInfo, ActivityInfo aInfo, String resolvedType, + Task inTask, TaskFragment inTaskFragment, int callingPid, int callingUid, + ActivityOptions activityOptions) { + return intercept(intent, rInfo, aInfo, resolvedType, inTask, inTaskFragment, callingPid, + callingUid, activityOptions, false); + } + /** * Intercept the launch intent based on various signals. If an interception happened the * internal variables get assigned and need to be read explicitly by the caller. @@ -187,7 +206,7 @@ class ActivityStartInterceptor { */ boolean intercept(Intent intent, ResolveInfo rInfo, ActivityInfo aInfo, String resolvedType, Task inTask, TaskFragment inTaskFragment, int callingPid, int callingUid, - ActivityOptions activityOptions) { + ActivityOptions activityOptions, boolean componentSpecified) { mUserManager = UserManager.get(mServiceContext); mIntent = intent; @@ -199,6 +218,7 @@ class ActivityStartInterceptor { mInTask = inTask; mInTaskFragment = inTaskFragment; mActivityOptions = activityOptions; + mComponentSpecified = componentSpecified; if (interceptQuietProfileIfNeeded()) { // If work profile is turned off, skip the work challenge since the profile can only @@ -221,6 +241,10 @@ class ActivityStartInterceptor { if (interceptLockedManagedProfileIfNeeded()) { return true; } + if (interceptHomeIfNeeded()) { + // Replace primary home intents if the home intent is not in the correct format. + return true; + } final SparseArray<ActivityInterceptorCallback> callbacks = mService.getActivityInterceptorCallbacks(); @@ -481,6 +505,74 @@ class ActivityStartInterceptor { return dpmi == null || dpmi.isKeepProfilesRunningEnabled(); } + private boolean interceptHomeIfNeeded() { + if (mService.mRootWindowContainer == null) { + return false; + } + + boolean intercepted = false; + if (!ACTION_MAIN.equals(mIntent.getAction()) || (!mIntent.hasCategory(CATEGORY_HOME) + && !mIntent.hasCategory(CATEGORY_SECONDARY_HOME))) { + // not a home intent + return false; + } + + if (mComponentSpecified) { + final ComponentName homeComponent = mIntent.getComponent(); + final Intent homeIntent = mService.getHomeIntent(); + final ActivityInfo aInfo = mService.mRootWindowContainer.resolveHomeActivity( + mUserId, homeIntent); + if (!aInfo.getComponentName().equals(homeComponent)) { + // Do nothing if the intent is not for the default home component. + return false; + } + } + + if (!ActivityRecord.isHomeIntent(mIntent) || mComponentSpecified) { + // This is not a standard home intent, make it so if possible. + normalizeHomeIntent(); + intercepted = true; + } + + if (intercepted) { + mCallingPid = mRealCallingPid; + mCallingUid = mRealCallingUid; + mResolvedType = null; + + mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, /* flags= */ 0, + mRealCallingUid, mRealCallingPid); + mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, /*profilerInfo=*/ + null); + } + return intercepted; + } + + private void normalizeHomeIntent() { + Slog.w(TAG, "The home Intent is not correctly formatted"); + if (mIntent.getCategories().size() > 1) { + Slog.d(TAG, "Purge home intent categories"); + boolean isSecondaryHome = false; + final Object[] categories = mIntent.getCategories().toArray(); + for (int i = categories.length - 1; i >= 0; i--) { + final String category = (String) categories[i]; + if (CATEGORY_SECONDARY_HOME.equals(category)) { + isSecondaryHome = true; + } + mIntent.removeCategory(category); + } + mIntent.addCategory(isSecondaryHome ? CATEGORY_SECONDARY_HOME : CATEGORY_HOME); + } + if (mIntent.getType() != null || mIntent.getData() != null) { + Slog.d(TAG, "Purge home intent data/type"); + mIntent.setType(null); + } + if (mComponentSpecified) { + Slog.d(TAG, "Purge home intent component, " + mIntent.getComponent()); + mIntent.setComponent(null); + } + mIntent.addFlags(FLAG_ACTIVITY_NEW_TASK); + } + /** * Called when an activity is successfully launched. */ diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 3c650e32beb9..69660a2efa8d 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -1154,7 +1154,7 @@ class ActivityStarter { mInterceptor.setStates(userId, realCallingPid, realCallingUid, startFlags, callingPackage, callingFeatureId); if (mInterceptor.intercept(intent, rInfo, aInfo, resolvedType, inTask, inTaskFragment, - callingPid, callingUid, checkedOptions)) { + callingPid, callingUid, checkedOptions, request.componentSpecified)) { // activity start was intercepted, e.g. because the target user is currently in quiet // mode (turn off work) or the target application is suspended intent = mInterceptor.mIntent; 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 bcb0c6b5c269..1d4f13966d80 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java @@ -238,6 +238,19 @@ public class ActivityStartInterceptorTest { } @Test + public void testInterceptIncorrectHomeIntent() { + // Create a non-standard home intent + final Intent homeIntent = new Intent(Intent.ACTION_MAIN); + homeIntent.addCategory(Intent.CATEGORY_HOME); + homeIntent.addCategory(Intent.CATEGORY_LAUNCHER); + + // Ensure the intent is intercepted and normalized to standard home intent. + assertTrue(mInterceptor.intercept(homeIntent, null, mAInfo, null, null, null, 0, 0, null, + false)); + assertTrue(ActivityRecord.isHomeIntent(homeIntent)); + } + + @Test public void testInterceptLockTaskModeViolationPackage() { when(mLockTaskController.isActivityAllowed( TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_DEFAULT)) |