summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java20
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityStartInterceptor.java95
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java12
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))