diff options
| author | 2024-01-10 14:04:21 +0000 | |
|---|---|---|
| committer | 2024-01-10 14:04:21 +0000 | |
| commit | 79dd61236e51a31d5f6557af37fdbd34e5771345 (patch) | |
| tree | f1d24aacca9d839c97123318285ee16fd6ea2191 | |
| parent | efaa309e0d5fc7f717e3882d7a4ef13b6c118465 (diff) | |
| parent | 1a735df717baef0740dbfecf8d2174d85b27674f (diff) | |
Merge "Extending systemUserOnly attribute to Providers and Services" into main
12 files changed, 102 insertions, 8 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 4156a78f1c70..af821b6e7333 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -1601,6 +1601,7 @@ package android { field public static final int switchTextOff = 16843628; // 0x101036c field public static final int switchTextOn = 16843627; // 0x101036b field public static final int syncable = 16842777; // 0x1010019 + field @FlaggedApi("android.multiuser.enable_system_user_only_for_services_and_providers") public static final int systemUserOnly; field public static final int tabStripEnabled = 16843453; // 0x10102bd field public static final int tabStripLeft = 16843451; // 0x10102bb field public static final int tabStripRight = 16843452; // 0x10102bc diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index c7a75ed5ea9c..e9b94c9f5791 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -41,6 +41,7 @@ import android.content.res.Configuration; import android.database.Cursor; import android.database.MatrixCursor; import android.database.SQLException; +import android.multiuser.Flags; import android.net.Uri; import android.os.AsyncTask; import android.os.Binder; @@ -146,6 +147,7 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall private boolean mExported; private boolean mNoPerms; private boolean mSingleUser; + private boolean mSystemUserOnly; private SparseBooleanArray mUsersRedirectedToOwnerForMedia = new SparseBooleanArray(); private ThreadLocal<AttributionSource> mCallingAttributionSource; @@ -377,7 +379,9 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall != PermissionChecker.PERMISSION_GRANTED && getContext().checkUriPermission(userUri, Binder.getCallingPid(), callingUid, Intent.FLAG_GRANT_READ_URI_PERMISSION) - != PackageManager.PERMISSION_GRANTED) { + != PackageManager.PERMISSION_GRANTED + && !deniedAccessSystemUserOnlyProvider(callingUserId, + mSystemUserOnly)) { FrameworkStatsLog.write(GET_TYPE_ACCESSED_WITHOUT_PERMISSION, enumCheckUriPermission, callingUid, uri.getAuthority(), type); @@ -865,6 +869,10 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall boolean checkUser(int pid, int uid, Context context) { final int callingUserId = UserHandle.getUserId(uid); + if (deniedAccessSystemUserOnlyProvider(callingUserId, mSystemUserOnly)) { + return false; + } + if (callingUserId == context.getUserId() || mSingleUser) { return true; } @@ -987,6 +995,9 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall // last chance, check against any uri grants final int callingUserId = UserHandle.getUserId(uid); + if (deniedAccessSystemUserOnlyProvider(callingUserId, mSystemUserOnly)) { + return PermissionChecker.PERMISSION_HARD_DENIED; + } final Uri userUri = (mSingleUser && !UserHandle.isSameUser(mMyUid, uid)) ? maybeAddUserId(uri, callingUserId) : uri; if (context.checkUriPermission(userUri, pid, uid, Intent.FLAG_GRANT_READ_URI_PERMISSION) @@ -2623,6 +2634,7 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall setPathPermissions(info.pathPermissions); mExported = info.exported; mSingleUser = (info.flags & ProviderInfo.FLAG_SINGLE_USER) != 0; + mSystemUserOnly = (info.flags & ProviderInfo.FLAG_SYSTEM_USER_ONLY) != 0; setAuthorities(info.authority); } if (Build.IS_DEBUGGABLE) { @@ -2756,6 +2768,11 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall String auth = uri.getAuthority(); if (!mSingleUser) { int userId = getUserIdFromAuthority(auth, UserHandle.USER_CURRENT); + if (deniedAccessSystemUserOnlyProvider(mContext.getUserId(), + mSystemUserOnly)) { + throw new SecurityException("Trying to query a SYSTEM user only content" + + " provider from user:" + mContext.getUserId()); + } if (userId != UserHandle.USER_CURRENT && userId != mContext.getUserId() // Since userId specified in content uri, the provider userId would be @@ -2929,4 +2946,16 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall Trace.traceBegin(traceTag, methodName + subInfo); } } + /** + * Return true if access to content provider is denied because it's a SYSTEM user only + * provider and the calling user is not the SYSTEM user. + * + * @param callingUserId UserId of the caller accessing the content provider. + * @param systemUserOnly true when the content provider is only available for the SYSTEM user. + */ + private static boolean deniedAccessSystemUserOnlyProvider(int callingUserId, + boolean systemUserOnly) { + return Flags.enableSystemUserOnlyForServicesAndProviders() + && (callingUserId != UserHandle.USER_SYSTEM && systemUserOnly); + } } diff --git a/core/java/android/content/pm/ProviderInfo.java b/core/java/android/content/pm/ProviderInfo.java index 9e553dbfb719..de33fa8b2328 100644 --- a/core/java/android/content/pm/ProviderInfo.java +++ b/core/java/android/content/pm/ProviderInfo.java @@ -89,6 +89,15 @@ public final class ProviderInfo extends ComponentInfo public static final int FLAG_VISIBLE_TO_INSTANT_APP = 0x100000; /** + * Bit in {@link #flags}: If set, this provider will only be available + * for the system user. + * Set from the android.R.attr#systemUserOnly attribute. + * In Sync with {@link ActivityInfo#FLAG_SYSTEM_USER_ONLY} + * @hide + */ + public static final int FLAG_SYSTEM_USER_ONLY = ActivityInfo.FLAG_SYSTEM_USER_ONLY; + + /** * Bit in {@link #flags}: If set, a single instance of the provider will * run for all users on the device. Set from the * {@link android.R.attr#singleUser} attribute. diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java index ae46c027505e..2b378b1f09d0 100644 --- a/core/java/android/content/pm/ServiceInfo.java +++ b/core/java/android/content/pm/ServiceInfo.java @@ -101,6 +101,14 @@ public class ServiceInfo extends ComponentInfo public static final int FLAG_VISIBLE_TO_INSTANT_APP = 0x100000; /** + * @hide Bit in {@link #flags}: If set, this service will only be available + * for the system user. + * Set from the android.R.attr#systemUserOnly attribute. + * In Sync with {@link ActivityInfo#FLAG_SYSTEM_USER_ONLY} + */ + public static final int FLAG_SYSTEM_USER_ONLY = ActivityInfo.FLAG_SYSTEM_USER_ONLY; + + /** * Bit in {@link #flags}: If set, a single instance of the service will * run for all users on the device. Set from the * {@link android.R.attr#singleUser} attribute. diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig index c7797c719e2c..10368653f0c4 100644 --- a/core/java/android/content/pm/multiuser.aconfig +++ b/core/java/android/content/pm/multiuser.aconfig @@ -70,4 +70,11 @@ flag { namespace: "profile_experiences" description: "Add support for Private Space in resolver sheet" bug: "307515485" -}
\ No newline at end of file +} +flag { + name: "enable_system_user_only_for_services_and_providers" + namespace: "multiuser" + description: "Enable systemUserOnly manifest attribute for services and providers." + bug: "302354856" + is_fixed_read_only: true +} diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedProviderUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedProviderUtils.java index 5d82d0469d56..12aff1c6669f 100644 --- a/core/java/com/android/internal/pm/pkg/component/ParsedProviderUtils.java +++ b/core/java/com/android/internal/pm/pkg/component/ParsedProviderUtils.java @@ -29,6 +29,7 @@ import android.content.pm.parsing.result.ParseResult; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; +import android.multiuser.Flags; import android.os.Build; import android.os.PatternMatcher; import android.util.Slog; @@ -126,6 +127,10 @@ public class ParsedProviderUtils { .setFlags(provider.getFlags() | flag(ProviderInfo.FLAG_SINGLE_USER, R.styleable.AndroidManifestProvider_singleUser, sa)); + if (Flags.enableSystemUserOnlyForServicesAndProviders()) { + provider.setFlags(provider.getFlags() | flag(ProviderInfo.FLAG_SYSTEM_USER_ONLY, + R.styleable.AndroidManifestProvider_systemUserOnly, sa)); + } visibleToEphemeral = sa.getBoolean( R.styleable.AndroidManifestProvider_visibleToInstantApps, false); if (visibleToEphemeral) { diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedServiceUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedServiceUtils.java index a1dd19a3bc90..4ac542f84226 100644 --- a/core/java/com/android/internal/pm/pkg/component/ParsedServiceUtils.java +++ b/core/java/com/android/internal/pm/pkg/component/ParsedServiceUtils.java @@ -29,6 +29,7 @@ import android.content.pm.parsing.result.ParseResult; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; +import android.multiuser.Flags; import android.os.Build; import com.android.internal.R; @@ -105,6 +106,11 @@ public class ParsedServiceUtils { | flag(ServiceInfo.FLAG_SINGLE_USER, R.styleable.AndroidManifestService_singleUser, sa))); + if (Flags.enableSystemUserOnlyForServicesAndProviders()) { + service.setFlags(service.getFlags() | flag(ServiceInfo.FLAG_SYSTEM_USER_ONLY, + R.styleable.AndroidManifestService_systemUserOnly, sa)); + } + visibleToEphemeral = sa.getBoolean( R.styleable.AndroidManifestService_visibleToInstantApps, false); if (visibleToEphemeral) { diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 8fae6db4114a..601952437650 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -506,6 +506,12 @@ receivers, and providers; it can not be used with activities. --> <attr name="singleUser" format="boolean" /> + <!-- If set to true, only a single instance of this component will + run and be available for the SYSTEM user. Non SYSTEM users will not be + allowed to access the component if this flag is enabled. + This flag can be used with services, receivers, providers and activities. --> + <attr name="systemUserOnly" format="boolean" /> + <!-- Specify a specific process that the associated code is to run in. Use with the application tag (to supply a default process for all application components), or with the activity, receiver, service, @@ -2859,6 +2865,7 @@ Context.createAttributionContext() using the first attribution tag contained here. --> <attr name="attributionTags" /> + <attr name="systemUserOnly" format="boolean" /> </declare-styleable> <!-- Attributes that can be supplied in an AndroidManifest.xml @@ -3017,6 +3024,7 @@ ignored when the process is bound into a shared isolated process by a client. --> <attr name="allowSharedIsolatedProcess" format="boolean" /> + <attr name="systemUserOnly" format="boolean" /> </declare-styleable> <!-- @hide The <code>apex-system-service</code> tag declares an apex system service @@ -3144,7 +3152,7 @@ <attr name="uiOptions" /> <attr name="parentActivityName" /> <attr name="singleUser" /> - <!-- @hide This broadcast receiver or activity will only receive broadcasts for the + <!-- This broadcast receiver or activity will only receive broadcasts for the system user--> <attr name="systemUserOnly" format="boolean" /> <attr name="persistableMode" /> diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml index 53b473e0ac1f..7b5c49c8d9aa 100644 --- a/core/res/res/values/public-staging.xml +++ b/core/res/res/values/public-staging.xml @@ -119,6 +119,8 @@ <public name="optional"/> <!-- @FlaggedApi("android.media.tv.flags.enable_ad_service_fw") --> <public name="adServiceTypes" /> + <!-- @FlaggedApi("android.multiuser.enable_system_user_only_for_services_and_providers") --> + <public name="systemUserOnly"/> </staging-public-group> <staging-public-group type="id" first-id="0x01bc0000"> diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 02f4485d5b40..7b14a02c9d3a 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -4464,6 +4464,12 @@ public final class ActiveServices { } } if (userId > 0) { + if (mAm.isSystemUserOnly(sInfo.flags)) { + Slog.w(TAG_SERVICE, service + " is only available for the SYSTEM user," + + " calling userId is: " + userId); + return null; + } + if (mAm.isSingleton(sInfo.processName, sInfo.applicationInfo, sInfo.name, sInfo.flags) && mAm.isValidSingletonCall(callingUid, sInfo.applicationInfo.uid)) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index fddb5707b78e..0c70bfe198ce 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -13747,6 +13747,11 @@ public class ActivityManagerService extends IActivityManager.Stub return result; } + boolean isSystemUserOnly(int flags) { + return android.multiuser.Flags.enableSystemUserOnlyForServicesAndProviders() + && (flags & ServiceInfo.FLAG_SYSTEM_USER_ONLY) != 0; + } + /** * Checks to see if the caller is in the same app as the singleton * component, or the component is in a special app. It allows special apps diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java index 095d907d7df6..30f21a65b5b1 100644 --- a/services/core/java/com/android/server/am/ContentProviderHelper.java +++ b/services/core/java/com/android/server/am/ContentProviderHelper.java @@ -1249,9 +1249,9 @@ public class ContentProviderHelper { ProviderInfo cpi = providers.get(i); boolean singleton = mService.isSingleton(cpi.processName, cpi.applicationInfo, cpi.name, cpi.flags); - if (singleton && app.userId != UserHandle.USER_SYSTEM) { - // This is a singleton provider, but a user besides the - // default user is asking to initialize a process it runs + if (isSingletonOrSystemUserOnly(cpi) && app.userId != UserHandle.USER_SYSTEM) { + // This is a singleton or a SYSTEM user only provider, but a user besides the + // SYSTEM user is asking to initialize a process it runs // in... well, no, it doesn't actually run in this process, // it runs in the process of the default user. Get rid of it. providers.remove(i); @@ -1398,8 +1398,7 @@ public class ContentProviderHelper { final boolean processMatch = Objects.equals(pi.processName, app.processName) || pi.multiprocess; - final boolean userMatch = !mService.isSingleton( - pi.processName, pi.applicationInfo, pi.name, pi.flags) + final boolean userMatch = !isSingletonOrSystemUserOnly(pi) || app.userId == UserHandle.USER_SYSTEM; final boolean isInstantApp = pi.applicationInfo.isInstantApp(); final boolean splitInstalled = pi.splitName == null @@ -1985,4 +1984,13 @@ public class ContentProviderHelper { return isAuthRedirected; } } + + /** + * Returns true if Provider is either singleUser or systemUserOnly provider. + */ + private boolean isSingletonOrSystemUserOnly(ProviderInfo pi) { + return (android.multiuser.Flags.enableSystemUserOnlyForServicesAndProviders() + && mService.isSystemUserOnly(pi.flags)) + || mService.isSingleton(pi.processName, pi.applicationInfo, pi.name, pi.flags); + } } |