diff options
7 files changed, 153 insertions, 2 deletions
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 182b0a3e5149..ee25a7033879 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -4208,13 +4208,23 @@ public class ActivityManager { } }*/ + /** @hide + * Determines whether the given UID can access unexported components + * @param uid the calling UID + * @return true if the calling UID is ROOT or SYSTEM + */ + public static boolean canAccessUnexportedComponents(int uid) { + final int appId = UserHandle.getAppId(uid); + return (appId == Process.ROOT_UID || appId == Process.SYSTEM_UID); + } + /** @hide */ @UnsupportedAppUsage public static int checkComponentPermission(String permission, int uid, int owningUid, boolean exported) { // Root, system server get to do everything. final int appId = UserHandle.getAppId(uid); - if (appId == Process.ROOT_UID || appId == Process.SYSTEM_UID) { + if (canAccessUnexportedComponents(uid)) { return PackageManager.PERMISSION_GRANTED; } // Isolated processes don't get any permissions. diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java index 3d8dc148b7e2..0ce49d0baa97 100644 --- a/services/core/java/android/content/pm/PackageManagerInternal.java +++ b/services/core/java/android/content/pm/PackageManagerInternal.java @@ -578,6 +578,14 @@ public abstract class PackageManagerInternal { int filterCallingUid); /** + * Resolves an exported activity intent, allowing instant apps to be resolved. + */ + public abstract ResolveInfo resolveIntentExported(Intent intent, String resolvedType, + @PackageManager.ResolveInfoFlagsBits long flags, + @PrivateResolveFlags long privateResolveFlags, int userId, boolean resolveForStart, + int filterCallingUid); + + /** * Resolves a service intent, allowing instant apps to be resolved. */ public abstract ResolveInfo resolveService(Intent intent, String resolvedType, diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index a0c2ad57241b..31d8049936c4 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -214,6 +214,7 @@ import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetManagerInternal; import android.compat.annotation.ChangeId; import android.compat.annotation.Disabled; +import android.compat.annotation.EnabledAfter; import android.content.AttributionSource; import android.content.AutofillOptions; import android.content.BroadcastReceiver; @@ -583,6 +584,17 @@ public class ActivityManagerService extends IActivityManager.Stub private static final long DYNAMIC_RECEIVER_EXPLICIT_EXPORT_REQUIRED = 161145287L; /** + * Apps targeting Android U and above will need to export components in order to invoke them + * through implicit intents. + * + * If a component is not exported and invoked, it will be removed from the list of receivers. + * This applies specifically to activities and broadcasts. + */ + @ChangeId + @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) + public static final long IMPLICIT_INTENTS_ONLY_MATCH_EXPORTED_COMPONENTS = 229362273; + + /** * The maximum number of bytes that {@link #setProcessStateSummary} accepts. * * @see {@link android.app.ActivityManager#setProcessStateSummary(byte[])} @@ -12346,6 +12358,58 @@ public class ActivityManagerService extends IActivityManager.Stub } /** + * Filters out non-exported components in a given list of broadcast filters + * @param intent the original intent + * @param callingUid the calling UID + * @param query the list of broadcast filters + * @param platformCompat the instance of platform compat + */ + private static void filterNonExportedComponents(Intent intent, int callingUid, + List query, PlatformCompat platformCompat, String callerPackage) { + if (query == null + || intent.getPackage() != null + || intent.getComponent() != null + || ActivityManager.canAccessUnexportedComponents(callingUid)) { + return; + } + for (int i = query.size() - 1; i >= 0; i--) { + String componentInfo; + ResolveInfo resolveInfo; + BroadcastFilter broadcastFilter; + if (query.get(i) instanceof ResolveInfo) { + resolveInfo = (ResolveInfo) query.get(i); + if (resolveInfo.getComponentInfo().exported) { + continue; + } + componentInfo = resolveInfo.getComponentInfo() + .getComponentName().flattenToShortString(); + } else if (query.get(i) instanceof BroadcastFilter) { + broadcastFilter = (BroadcastFilter) query.get(i); + if (broadcastFilter.exported) { + continue; + } + componentInfo = broadcastFilter.packageName; + } else { + continue; + } + if (!platformCompat.isChangeEnabledByUid( + IMPLICIT_INTENTS_ONLY_MATCH_EXPORTED_COMPONENTS, callingUid)) { + Slog.w(TAG, "Non-exported component not filtered out " + + "(will be filtered out once the app targets U+)- intent: " + + intent.getAction() + ", component: " + + componentInfo + ", sender: " + + callerPackage); + return; + } + Slog.w(TAG, "Non-exported component filtered out - intent: " + + intent.getAction() + ", component: " + + componentInfo + ", sender: " + + callerPackage); + query.remove(i); + } + } + + /** * Main code for cleaning up a process when it has gone away. This is * called both as a result of the process dying, or directly when stopping * a process when running in single process mode. @@ -14229,6 +14293,8 @@ public class ActivityManagerService extends IActivityManager.Stub } } + filterNonExportedComponents(intent, callingUid, registeredReceivers, + mPlatformCompat, callerPackage); int NR = registeredReceivers != null ? registeredReceivers.size() : 0; if (!ordered && NR > 0) { // If we are not serializing this broadcast, then send the @@ -14331,6 +14397,8 @@ public class ActivityManagerService extends IActivityManager.Stub if ((receivers != null && receivers.size() > 0) || resultTo != null) { BroadcastQueue queue = broadcastQueueForIntent(intent); + filterNonExportedComponents(intent, callingUid, receivers, + mPlatformCompat, callerPackage); BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage, callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType, requiredPermissions, excludedPermissions, excludedPackages, appOp, brOptions, diff --git a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java index e969d93465f8..8f255fa266e5 100644 --- a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java +++ b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java @@ -466,6 +466,20 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal { filterCallingUid); } + /** + * @deprecated similar to {@link resolveIntent} but limits the matches to exported components. + */ + @Override + @Deprecated + public final ResolveInfo resolveIntentExported(Intent intent, String resolvedType, + @PackageManager.ResolveInfoFlagsBits long flags, + @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, int userId, + boolean resolveForStart, int filterCallingUid) { + return getResolveIntentHelper().resolveIntentInternal(snapshot(), + intent, resolvedType, flags, privateResolveFlags, userId, resolveForStart, + filterCallingUid, true); + } + @Override @Deprecated public final ResolveInfo resolveService(Intent intent, String resolvedType, diff --git a/services/core/java/com/android/server/pm/ResolveIntentHelper.java b/services/core/java/com/android/server/pm/ResolveIntentHelper.java index 24ed6216f7fe..2c01d7a21d5f 100644 --- a/services/core/java/com/android/server/pm/ResolveIntentHelper.java +++ b/services/core/java/com/android/server/pm/ResolveIntentHelper.java @@ -52,6 +52,7 @@ import android.util.Slog; import com.android.internal.app.ResolverActivity; import com.android.internal.util.ArrayUtils; +import com.android.server.am.ActivityManagerService; import com.android.server.compat.PlatformCompat; import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.pm.pkg.PackageStateInternal; @@ -100,6 +101,36 @@ final class ResolveIntentHelper { mInstantAppInstallerActivitySupplier = instantAppInstallerActivitySupplier; } + private static void filterNonExportedComponents(Intent intent, int filterCallingUid, + List<ResolveInfo> query, PlatformCompat platformCompat, String callerPackage) { + if (query == null + || intent.getPackage() != null + || intent.getComponent() != null + || ActivityManager.canAccessUnexportedComponents(filterCallingUid)) { + return; + } + for (int i = query.size() - 1; i >= 0; i--) { + if (!query.get(i).getComponentInfo().exported) { + if (!platformCompat.isChangeEnabledByUid( + ActivityManagerService.IMPLICIT_INTENTS_ONLY_MATCH_EXPORTED_COMPONENTS, + filterCallingUid)) { + Slog.w(TAG, "Non-exported component not filtered out " + + "(will be filtered out once the app targets U+)- intent: " + + intent.getAction() + ", component: " + + query.get(i).getComponentInfo() + .getComponentName().flattenToShortString() + + ", starter: " + callerPackage); + return; + } + Slog.w(TAG, "Non-exported component filtered out - intent: " + + intent.getAction() + ", component: " + + query.get(i).getComponentInfo().getComponentName().flattenToShortString() + + ", starter: " + callerPackage); + query.remove(i); + } + } + } + /** * Normally instant apps can only be resolved when they're visible to the caller. * However, if {@code resolveForStart} is {@code true}, all instant apps are visible @@ -109,6 +140,20 @@ final class ResolveIntentHelper { @PackageManager.ResolveInfoFlagsBits long flags, @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, int userId, boolean resolveForStart, int filterCallingUid) { + return resolveIntentInternal(computer, intent, resolvedType, flags, + privateResolveFlags, userId, resolveForStart, filterCallingUid, false); + } + + /** + * Normally instant apps can only be resolved when they're visible to the caller. + * However, if {@code resolveForStart} is {@code true}, all instant apps are visible + * since we need to allow the system to start any installed application. + * Allows picking exported components only. + */ + public ResolveInfo resolveIntentInternal(Computer computer, Intent intent, String resolvedType, + @PackageManager.ResolveInfoFlagsBits long flags, + @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, int userId, + boolean resolveForStart, int filterCallingUid, boolean exportedComponentsOnly) { try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveIntent"); @@ -124,6 +169,10 @@ final class ResolveIntentHelper { final List<ResolveInfo> query = computer.queryIntentActivitiesInternal(intent, resolvedType, flags, privateResolveFlags, filterCallingUid, userId, resolveForStart, true /*allowDynamicSplits*/); + if (exportedComponentsOnly) { + filterNonExportedComponents(intent, filterCallingUid, query, + mPlatformCompat, computer.getPackage(filterCallingUid).getPackageName()); + } Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); final boolean queryMayBeFiltered = diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java index dc91c1597128..28cd0016b019 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java @@ -744,7 +744,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { // (e.g. AMS.startActivityAsUser). final long token = Binder.clearCallingIdentity(); try { - return mService.getPackageManagerInternalLocked().resolveIntent( + return mService.getPackageManagerInternalLocked().resolveIntentExported( intent, resolvedType, modifiedFlags, privateResolveFlags, userId, true, filterCallingUid); } finally { diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java index cd087e69bb0c..017de0f159e3 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -371,6 +371,8 @@ public class ActivityStarterTests extends WindowTestsBase { doReturn(false).when(mMockPackageManager).isInstantAppInstallerComponent(any()); doReturn(null).when(mMockPackageManager).resolveIntent(any(), any(), anyLong(), anyLong(), anyInt(), anyBoolean(), anyInt()); + doReturn(null).when(mMockPackageManager).resolveIntentExported(any(), any(), + anyLong(), anyLong(), anyInt(), anyBoolean(), anyInt()); doReturn(new ComponentName("", "")).when(mMockPackageManager).getSystemUiServiceComponent(); // Never review permissions |