Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1a735df7 authored by Nikhil Kumar's avatar Nikhil Kumar
Browse files

Extending systemUserOnly attribute to Providers and Services

systemUserOnly manifest attribute limits an android component to
be initialized and available only for the SYSTEM user. This is different from the singleUser attribute which instantiate the component on the SYSTEM user as a singleton and provides a proxy for other secondary users to access the SYSTEM user component.

Currently this attribute is only available for Activities and
Broadcast receivers, In the following change the attribute is extended to support Providers and Services as well.

Bug: 302354856
Test: atest PackageManagerShellCommandMultiUserTest#testInstallAppHavingSystemUserOnlyComponents -c
Test: manually tested by applying this attribute on a Service and a provider and making sure it isn't accessible and initialized when running on a Secondary user.

Change-Id: I3125bc0c336dfc11c40e327ce8992d5be3601922
parent 850a3f00
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1600,6 +1600,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
+30 −1
Original line number Diff line number Diff line
@@ -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);
    }
}
+9 −0
Original line number Diff line number Diff line
@@ -88,6 +88,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
+8 −0
Original line number Diff line number Diff line
@@ -99,6 +99,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
+8 −1
Original line number Diff line number Diff line
@@ -71,3 +71,10 @@ flag {
    description: "Add support for Private Space in resolver sheet"
    bug: "307515485"
}
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
}
Loading