diff options
6 files changed, 120 insertions, 13 deletions
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java index 5f03410c8d5d..6196dfaefc30 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java @@ -27,6 +27,7 @@ import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; +import android.content.pm.PackageInstaller.SessionInfo; import android.content.pm.PackageManager; import android.content.pm.ProviderInfo; import android.net.Uri; @@ -65,14 +66,15 @@ public class InstallStart extends Activity { // If the activity was started via a PackageInstaller session, we retrieve the calling // package from that session final int sessionId = (isSessionInstall - ? intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1) - : -1); - if (callingPackage == null && sessionId != -1) { - PackageInstaller packageInstaller = getPackageManager().getPackageInstaller(); + ? intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, SessionInfo.INVALID_ID) + : SessionInfo.INVALID_ID); + if (sessionId != SessionInfo.INVALID_ID) { + PackageInstaller packageInstaller = mPackageManager.getPackageInstaller(); PackageInstaller.SessionInfo sessionInfo = packageInstaller.getSessionInfo(sessionId); - callingPackage = (sessionInfo != null) ? sessionInfo.getInstallerPackageName() : null; - callingAttributionTag = - (sessionInfo != null) ? sessionInfo.getInstallerAttributionTag() : null; + if (sessionInfo != null) { + callingPackage = sessionInfo.getInstallerPackageName(); + callingAttributionTag = sessionInfo.getInstallerAttributionTag(); + } } final ApplicationInfo sourceInfo = getSourceInfo(callingPackage); @@ -173,7 +175,7 @@ public class InstallStart extends Activity { private ApplicationInfo getSourceInfo(@Nullable String callingPackage) { if (callingPackage != null) { try { - return getPackageManager().getApplicationInfo(callingPackage, 0); + return mPackageManager.getApplicationInfo(callingPackage, 0); } catch (PackageManager.NameNotFoundException ex) { // ignore } @@ -220,7 +222,7 @@ public class InstallStart extends Activity { } private boolean isSystemDownloadsProvider(int uid) { - final ProviderInfo downloadProviderPackage = getPackageManager().resolveContentProvider( + final ProviderInfo downloadProviderPackage = mPackageManager.resolveContentProvider( DOWNLOADS_AUTHORITY, 0); if (downloadProviderPackage == null) { // There seems to be no currently enabled downloads provider on the system. diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index d199a41a6d84..d3daed8eddca 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -13154,7 +13154,7 @@ public class ActivityManagerService extends IActivityManager.Stub + " (pid=" + Binder.getCallingPid() + ") when registering receiver " + receiver); } - if (callerApp.info.uid != SYSTEM_UID + if (!UserHandle.isCore(callerApp.info.uid) && !callerApp.getPkgList().containsKey(callerPackage)) { throw new SecurityException("Given caller package " + callerPackage + " is not running in process " + callerApp); diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 173a1a660ac8..53ce8f4534bc 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -2782,7 +2782,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 a452013bf42a..409108174852 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; @@ -39,6 +42,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; @@ -52,6 +56,7 @@ import android.os.Bundle; 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; @@ -63,6 +68,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#startActivityLocked} * It's initialized via setStates and interception occurs via the intercept method. @@ -71,6 +77,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; @@ -106,6 +113,11 @@ class ActivityStartInterceptor { Task mInTask; 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); @@ -144,6 +156,13 @@ class ActivityStartInterceptor { return new IntentSender(target); } + // 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, int callingPid, int callingUid, ActivityOptions activityOptions) { + return intercept(intent, rInfo, aInfo, resolvedType, inTask, 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. @@ -151,7 +170,8 @@ class ActivityStartInterceptor { * @return true if an interception occurred */ boolean intercept(Intent intent, ResolveInfo rInfo, ActivityInfo aInfo, String resolvedType, - Task inTask, int callingPid, int callingUid, ActivityOptions activityOptions) { + Task inTask, int callingPid, int callingUid, ActivityOptions activityOptions, + boolean componentSpecified) { mUserManager = UserManager.get(mServiceContext); mIntent = intent; @@ -162,6 +182,7 @@ class ActivityStartInterceptor { mResolvedType = resolvedType; mInTask = inTask; mActivityOptions = activityOptions; + mComponentSpecified = componentSpecified; if (interceptQuietProfileIfNeeded()) { // If work profile is turned off, skip the work challenge since the profile can only @@ -184,6 +205,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(); @@ -403,6 +428,74 @@ class ActivityStartInterceptor { return true; } + 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); + 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 4633e34f78f6..c9693e374de2 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -1057,7 +1057,7 @@ class ActivityStarter { mInterceptor.setStates(userId, realCallingPid, realCallingUid, startFlags, callingPackage, callingFeatureId); if (mInterceptor.intercept(intent, rInfo, aInfo, resolvedType, inTask, callingPid, - callingUid, checkedOptions)) { + 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 73e409abf0c1..9be165abbd80 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java @@ -229,6 +229,18 @@ 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, 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)) |