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

Commit 27bd34d9 authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

Multi-user MTP.

The current MTP kernel driver at /dev/mtp_usb is exclusive, meaning
only one process can have it open. In addition, each MTP session
with a desktop requires unique object IDs, which doesn't hold true
across users on the device.

To solve these two issues, when switching users we cycle the USB host
stack to disconnect both local and remote MTP connections, giving the
new user's media process a chance to claim /dev/mtp_usb, and causing
the desktop to initiate a new MTP session.

This change also allows BroadcastReceivers to registerReceiver()
allow retrieval of a current sticky broadcast. Adds a system property
to override maximum users. Removes MOUNTED broadcasts for secondary
users. Allows INTERACT_ACROSS_USERS to getCurrentUser().

Bug: 6925114
Change-Id: I02b4a1b535af95fb2142655887b6d15a8068d18a
parent a4b0e559
Loading
Loading
Loading
Loading
+17 −16
Original line number Diff line number Diff line
@@ -129,32 +129,33 @@ class ReceiverRestrictedContext extends ContextWrapper {
    @Override
    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
            String broadcastPermission, Handler scheduler) {
        if (receiver == null) {
            // Allow retrieving current sticky broadcast; this is safe since we
            // aren't actually registering a receiver.
            return super.registerReceiver(null, filter, broadcastPermission, scheduler);
        } else {
            throw new ReceiverCallNotAllowedException(
                "IntentReceiver components are not allowed to register to receive intents");
        //ex.fillInStackTrace();
        //Log.e("IntentReceiver", ex.getMessage(), ex);
        //return mContext.registerReceiver(receiver, filter, broadcastPermission,
        //        scheduler);
                    "BroadcastReceiver components are not allowed to register to receive intents");
        }
    }

    @Override
    public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
            IntentFilter filter, String broadcastPermission, Handler scheduler) {
        if (receiver == null) {
            // Allow retrieving current sticky broadcast; this is safe since we
            // aren't actually registering a receiver.
            return super.registerReceiverAsUser(null, user, filter, broadcastPermission, scheduler);
        } else {
            throw new ReceiverCallNotAllowedException(
                "IntentReceiver components are not allowed to register to receive intents");
        //ex.fillInStackTrace();
        //Log.e("IntentReceiver", ex.getMessage(), ex);
        //return mContext.registerReceiver(receiver, filter, broadcastPermission,
        //        scheduler);
                    "BroadcastReceiver components are not allowed to register to receive intents");
        }
    }

    @Override
    public boolean bindService(Intent service, ServiceConnection conn, int flags) {
        throw new ReceiverCallNotAllowedException(
                "IntentReceiver components are not allowed to bind to services");
        //ex.fillInStackTrace();
        //Log.e("IntentReceiver", ex.getMessage(), ex);
        //return mContext.bindService(service, interfaceName, conn, flags);
                "BroadcastReceiver components are not allowed to bind to services");
    }
}

+4 −2
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ import com.android.internal.R;
import android.content.Context;
import android.content.pm.UserInfo;
import android.graphics.Bitmap;
import android.content.res.Resources;
import android.util.Log;

import java.util.List;
@@ -232,8 +233,9 @@ public class UserManager {
     * @hide
     * @return a value greater than or equal to 1 
     */
    public int getMaxSupportedUsers() {
        return mContext.getResources().getInteger(R.integer.config_multiuserMaximumUsers);
    public static int getMaxSupportedUsers() {
        return SystemProperties.getInt("fw.max_users",
                Resources.getSystem().getInteger(R.integer.config_multiuserMaximumUsers));
    }

    /**
+0 −32
Original line number Diff line number Diff line
@@ -549,34 +549,6 @@ class MountService extends IMountService.Stub
        }
    }

    private final BroadcastReceiver mBootReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
            if (userId == -1) return;
            final UserHandle user = new UserHandle(userId);

            Slog.d(TAG, "BOOT_COMPLETED for " + user);

            // Broadcast mounted volumes to newly booted user. This kicks off
            // media scanner when a user becomes active.
            synchronized (mVolumesLock) {
                for (StorageVolume volume : mVolumes) {
                    final UserHandle owner = volume.getOwner();
                    final boolean ownerMatch = owner == null
                            || owner.getIdentifier() == user.getIdentifier();

                    final String state = mVolumeStates.get(volume.getPath());

                    if (ownerMatch && (Environment.MEDIA_MOUNTED.equals(state)
                            || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state))) {
                        sendStorageIntent(Intent.ACTION_MEDIA_MOUNTED, volume, user);
                    }
                }
            }
        }
    };

    private final BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
@@ -1309,10 +1281,6 @@ class MountService extends IMountService.Stub
        mHandlerThread.start();
        mHandler = new MountServiceHandler(mHandlerThread.getLooper());

        // Watch for user boot completion
        mContext.registerReceiverAsUser(mBootReceiver, UserHandle.ALL,
                new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, mHandler);

        // Watch for user changes
        final IntentFilter userFilter = new IntentFilter();
        userFilter.addAction(Intent.ACTION_USER_ADDED);
+5 −3
Original line number Diff line number Diff line
@@ -14224,12 +14224,14 @@ public final class ActivityManagerService extends ActivityManagerNative
    @Override
    public UserInfo getCurrentUser() {
        if (checkCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
                != PackageManager.PERMISSION_GRANTED) {
        if ((checkCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
                != PackageManager.PERMISSION_GRANTED) && (
                checkCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
                != PackageManager.PERMISSION_GRANTED)) {
            String msg = "Permission Denial: getCurrentUser() from pid="
                    + Binder.getCallingPid()
                    + ", uid=" + Binder.getCallingUid()
                    + " requires " + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
                    + " requires " + android.Manifest.permission.INTERACT_ACROSS_USERS;
            Slog.w(TAG, msg);
            throw new SecurityException(msg);
        }
+2 −5
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.AtomicFile;
import android.util.Slog;
import android.util.SparseArray;
@@ -85,8 +86,6 @@ public class UserManagerService extends IUserManager.Stub {

    private SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>();

    private final int mUserLimit;

    private int[] mUserIds;
    private boolean mGuestEnabled;
    private int mNextSerialNumber;
@@ -129,8 +128,6 @@ public class UserManagerService extends IUserManager.Stub {
            mPm = pm;
            mInstallLock = installLock;
            mPackagesLock = packagesLock;
            mUserLimit = mContext.getResources().getInteger(
                    com.android.internal.R.integer.config_multiuserMaximumUsers);
            mUsersDir = new File(dataDir, USER_INFO_DIR);
            mUsersDir.mkdirs();
            // Make zeroth user directory, for services to migrate their files to that location
@@ -275,7 +272,7 @@ public class UserManagerService extends IUserManager.Stub {
     */
    private boolean isUserLimitReachedLocked() {
        int nUsers = mUsers.size();
        return nUsers >= mUserLimit;
        return nUsers >= UserManager.getMaxSupportedUsers();
    }

    /**
Loading