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

Commit 58b684f1 authored by Makoto Onuki's avatar Makoto Onuki
Browse files

[split system] Tentatively support running DO on meat user

- setDeviceOwner() now takes a user ID.  (We can infer it from Binder, but
we still need it for the dpm command.)

- Change broadcast target UID for DO to the DO user

- Start the DO user on boot complete.
TODO Investigate whether this is actually the good timing.

TODO Prevent the DO user from being killed

Bug 23827706

Change-Id: I227dbd444f1f4e94d98c317489d151554fe79d91
parent 3403b744
Loading
Loading
Loading
Loading
+8 −7
Original line number Diff line number Diff line
@@ -51,7 +51,8 @@ public final class Dpm extends BaseCommand {
        out.println(
                "usage: dpm [subcommand] [options]\n" +
                "usage: dpm set-active-admin [ --user <USER_ID> ] <COMPONENT>\n" +
                "usage: dpm set-device-owner <COMPONENT>\n" +
                // STOPSHIP Finalize it
                "usage: dpm set-device-owner [ --user <USER_ID> *EXPERIMENTAL* ] <COMPONENT>\n" +
                "usage: dpm set-profile-owner [ --user <USER_ID> ] <COMPONENT>\n" +
                "\n" +
                "dpm set-active-admin: Sets the given component as active admin" +
@@ -106,22 +107,22 @@ public final class Dpm extends BaseCommand {
    }

    private void runSetDeviceOwner() throws RemoteException {
        ComponentName component = parseComponentName(nextArgRequired());
        mDevicePolicyManager.setActiveAdmin(component, true /*refreshing*/, UserHandle.USER_SYSTEM);
        parseArgs(true);
        mDevicePolicyManager.setActiveAdmin(mComponent, true /*refreshing*/, mUserId);

        String packageName = component.getPackageName();
        String packageName = mComponent.getPackageName();
        try {
            if (!mDevicePolicyManager.setDeviceOwner(packageName, null /*ownerName*/)) {
            if (!mDevicePolicyManager.setDeviceOwner(packageName, null /*ownerName*/, mUserId)) {
                throw new RuntimeException(
                        "Can't set package " + packageName + " as device owner.");
            }
        } catch (Exception e) {
            // Need to remove the admin that we just added.
            mDevicePolicyManager.removeActiveAdmin(component, UserHandle.USER_SYSTEM);
            mDevicePolicyManager.removeActiveAdmin(mComponent, UserHandle.USER_SYSTEM);
            throw e;
        }
        System.out.println("Success: Device owner set to package " + packageName);
        System.out.println("Active admin set to component " + component.toShortString());
        System.out.println("Active admin set to component " + mComponent.toShortString());
    }

    private void runSetProfileOwner() throws RemoteException {
+18 −4
Original line number Diff line number Diff line
@@ -2684,11 +2684,24 @@ public class DevicePolicyManager {
     * @throws IllegalArgumentException if the package name is null or invalid
     * @throws IllegalStateException If the preconditions mentioned are not met.
     */
    public boolean setDeviceOwner(String packageName) throws IllegalArgumentException,
            IllegalStateException {
    public boolean setDeviceOwner(String packageName) {
        return setDeviceOwner(packageName, null);
    }

    /**
     * @hide
     */
    public boolean setDeviceOwner(String packageName, int userId)  {
        return setDeviceOwner(packageName, null, userId);
    }

    /**
     * @hide
     */
    public boolean setDeviceOwner(String packageName, String ownerName) {
        return setDeviceOwner(packageName, ownerName, UserHandle.USER_SYSTEM);
    }

    /**
     * @hide
     * Sets the given package as the device owner. The package must already be installed. There
@@ -2699,15 +2712,16 @@ public class DevicePolicyManager {
     * the caller is the shell uid, and there are no additional users and no accounts.
     * @param packageName the package name of the application to be registered as the device owner.
     * @param ownerName the human readable name of the institution that owns this device.
     * @param userId ID of the user on which the device owner runs.
     * @return whether the package was successfully registered as the device owner.
     * @throws IllegalArgumentException if the package name is null or invalid
     * @throws IllegalStateException If the preconditions mentioned are not met.
     */
    public boolean setDeviceOwner(String packageName, String ownerName)
    public boolean setDeviceOwner(String packageName, String ownerName, int userId)
            throws IllegalArgumentException, IllegalStateException {
        if (mService != null) {
            try {
                return mService.setDeviceOwner(packageName, ownerName);
                return mService.setDeviceOwner(packageName, ownerName, userId);
            } catch (RemoteException re) {
                Log.w(TAG, "Failed to set device owner");
            }
+1 −1
Original line number Diff line number Diff line
@@ -113,7 +113,7 @@ interface IDevicePolicyManager {
    void reportFailedPasswordAttempt(int userHandle);
    void reportSuccessfulPasswordAttempt(int userHandle);

    boolean setDeviceOwner(String packageName, String ownerName);
    boolean setDeviceOwner(String packageName, String ownerName, int userId);
    boolean isDeviceOwner(String packageName);
    String getDeviceOwner();
    String getDeviceOwnerName();
+77 −35
Original line number Diff line number Diff line
@@ -303,9 +303,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {

        @Override
        public void onBootPhase(int phase) {
            if (phase == PHASE_LOCK_SETTINGS_READY) {
                mService.systemReady();
            }
            mService.systemReady(phase);
        }
    }

@@ -1776,10 +1774,21 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        }
    }

    public void systemReady() {
    public void systemReady(int phase) {
        if (!mHasFeature) {
            return;
        }
        switch (phase) {
            case SystemService.PHASE_LOCK_SETTINGS_READY:
                onLockSettingsReady();
                break;
            case SystemService.PHASE_BOOT_COMPLETED:
                ensureDeviceOwnerUserStarted(); // TODO Consider better place to do this.
                break;
        }
    }

    private void onLockSettingsReady() {
        getUserData(UserHandle.USER_OWNER);
        loadDeviceOwner();
        cleanUpOldUsers();
@@ -1798,6 +1807,26 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        }
    }

    private void ensureDeviceOwnerUserStarted() {
        if (mOwners.hasDeviceOwner()) {
            final IActivityManager am = ActivityManagerNative.getDefault();
            final int userId = mOwners.getDeviceOwnerUserId();
            if (VERBOSE_LOG) {
                Log.v(LOG_TAG, "Starting non-system DO user: " + userId);
            }
            if (userId != UserHandle.USER_SYSTEM) {
                try {
                    am.startUserInBackground(userId);

                    // STOPSHIP Prevent the DO user from being killed.

                } catch (RemoteException e) {
                    Slog.w(LOG_TAG, "Exception starting user", e);
                }
            }
        }
    }

    private void cleanUpOldUsers() {
        // This is needed in case the broadcast {@link Intent.ACTION_USER_REMOVED} was not handled
        // before reboot
@@ -4110,17 +4139,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    }

    @Override
    public boolean setDeviceOwner(String packageName, String ownerName) {
    public boolean setDeviceOwner(String packageName, String ownerName, int userId) {
        if (!mHasFeature) {
            return false;
        }
        if (packageName == null
                || !Owners.isInstalled(packageName, mContext.getPackageManager())) {
                || !Owners.isInstalledForUser(packageName, userId)) {
            throw new IllegalArgumentException("Invalid package name " + packageName
                    + " for device owner");
        }
        synchronized (this) {
            enforceCanSetDeviceOwner();
            enforceCanSetDeviceOwner(userId);

            // Shutting down backup manager service permanently.
            long ident = Binder.clearCallingIdentity();
@@ -4134,14 +4163,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                Binder.restoreCallingIdentity(ident);
            }

            mOwners.setDeviceOwner(packageName, ownerName);
            mOwners.setDeviceOwner(packageName, ownerName, userId);
            mOwners.writeDeviceOwner();
            updateDeviceOwnerLocked();
            Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED);

            ident = Binder.clearCallingIdentity();
            try {
                mContext.sendBroadcastAsUser(intent, UserHandle.OWNER);
                // TODO Send to system too?
                mContext.sendBroadcastAsUser(intent, new UserHandle(userId));
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
@@ -4242,10 +4272,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        if (!mHasFeature) {
            return false;
        }
        if (initializer == null || !Owners.isInstalled(
                initializer.getPackageName(), mContext.getPackageManager())) {
        if (initializer == null ||
                !mOwners.hasDeviceOwner() ||
                !Owners.isInstalledForUser(initializer.getPackageName(),
                        mOwners.getDeviceOwnerUserId())) {
            throw new IllegalArgumentException("Invalid component name " + initializer
                    + " for device initializer");
                    + " for device initializer or no device owner set");
        }
        boolean isInitializerSystemApp;
        try {
@@ -4268,7 +4300,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {

            mOwners.setDeviceInitializer(initializer);

            addDeviceInitializerToLockTaskPackagesLocked(UserHandle.USER_OWNER);
            addDeviceInitializerToLockTaskPackagesLocked(mOwners.getDeviceOwnerUserId());
            mOwners.writeDeviceOwner();
            return true;
        }
@@ -4278,7 +4310,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        if (who == null) {
            mContext.enforceCallingOrSelfPermission(
                    android.Manifest.permission.MANAGE_DEVICE_ADMINS, null);
            if (hasUserSetupCompleted(UserHandle.USER_OWNER)) {
            if (hasUserSetupCompleted(UserHandle.USER_SYSTEM)) {
                throw new IllegalStateException(
                        "Trying to set device initializer but device is already provisioned.");
            }
@@ -4648,33 +4680,48 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
     * The device owner can only be set before the setup phase of the primary user has completed,
     * except for adb if no accounts or additional users are present on the device.
     */
    private void enforceCanSetDeviceOwner() {
        if (mOwners != null && mOwners.hasDeviceOwner()) {
    private void enforceCanSetDeviceOwner(int userId) {
        if (mOwners.hasDeviceOwner()) {
            throw new IllegalStateException("Trying to set the device owner, but device owner "
                    + "is already set.");
        }
        // STOPSHIP Make sure the DO user is running
        int callingUid = Binder.getCallingUid();
        if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
            if (!hasUserSetupCompleted(UserHandle.USER_OWNER)) {
                return;
            }
            // STOPSHIP Do proper check in split user mode
            if (!UserManager.isSplitSystemUser()) {
                if (mUserManager.getUserCount() > 1) {
                throw new IllegalStateException("Not allowed to set the device owner because there "
                    throw new IllegalStateException(
                            "Not allowed to set the device owner because there "
                                    + "are already several users on the device");
                }
                if (AccountManager.get(mContext).getAccounts().length > 0) {
                throw new IllegalStateException("Not allowed to set the device owner because there "
                    throw new IllegalStateException(
                            "Not allowed to set the device owner because there "
                                    + "are already some accounts on the device");
                }
            }
            return;
        } else {
            // STOPSHIP check the caller UID with userId
        }
        if (mUserManager.isUserRunning(new UserHandle(userId))) {
            throw new IllegalStateException("User not running: " + userId);
        }

        mContext.enforceCallingOrSelfPermission(
                android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null);
        // STOPSHIP Do proper check in split user mode
        if (!UserManager.isSplitSystemUser()) {
            if (hasUserSetupCompleted(UserHandle.USER_OWNER)) {
                throw new IllegalStateException("Cannot set the device owner if the device is "
                        + "already set-up");
            }
        }
    }

    private void enforceCrossUserPermission(int userHandle) {
        if (userHandle < 0) {
@@ -4689,12 +4736,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        }
    }

    private void enforceSystemProcess(String message) {
        if (Binder.getCallingUid() != Process.SYSTEM_UID) {
            throw new SecurityException(message);
        }
    }

    private void enforceNotManagedProfile(int userHandle, String message) {
        if(isManagedProfile(userHandle)) {
            throw new SecurityException("You can not " + message + " for a managed profile. ");
@@ -6318,7 +6359,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        }
        mContext.sendBroadcastAsUser(
                new Intent(DevicePolicyManager.ACTION_SYSTEM_UPDATE_POLICY_CHANGED),
                UserHandle.OWNER);
                UserHandle.SYSTEM);
    }

    @Override
@@ -6368,6 +6409,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
            if (deviceOwnerPackage == null) {
                return;
            }
            final UserHandle deviceOwnerUser = new UserHandle(mOwners.getDeviceOwnerUserId());

            ActivityInfo[] receivers = null;
            try {
@@ -6383,7 +6425,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                        if (permission.BIND_DEVICE_ADMIN.equals(receivers[i].permission)) {
                            intent.setComponent(new ComponentName(deviceOwnerPackage,
                                    receivers[i].name));
                            mContext.sendBroadcastAsUser(intent, UserHandle.OWNER);
                            mContext.sendBroadcastAsUser(intent, deviceOwnerUser);
                        }
                    }
                } finally {
+43 −16
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.UserInfo;
import android.os.Environment;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.ArrayMap;
import android.util.AtomicFile;
@@ -71,6 +72,8 @@ class Owners {
    private static final String TAG_DEVICE_OWNER = "device-owner";
    private static final String TAG_DEVICE_INITIALIZER = "device-initializer";
    private static final String TAG_PROFILE_OWNER = "profile-owner";
    // Holds "context" for device-owner, this must not be show up before device-owner.
    private static final String TAG_DEVICE_OWNER_CONTEXT = "device-owner-context";

    private static final String ATTR_NAME = "name";
    private static final String ATTR_PACKAGE = "package";
@@ -85,6 +88,8 @@ class Owners {
    // Internal state for the device owner package.
    private OwnerInfo mDeviceOwner;

    private int mDeviceOwnerUserId = UserHandle.USER_NULL;

    // Internal state for the device initializer package.
    private OwnerInfo mDeviceInitializer;

@@ -140,16 +145,26 @@ class Owners {
        return mDeviceOwner != null ? mDeviceOwner.packageName : null;
    }

    int getDeviceOwnerUserId() {
        return mDeviceOwnerUserId;
    }

    String getDeviceOwnerName() {
        return mDeviceOwner != null ? mDeviceOwner.name : null;
    }

    void setDeviceOwner(String packageName, String ownerName) {
    void setDeviceOwner(String packageName, String ownerName, int userId) {
        if (userId < 0) {
            Slog.e(TAG, "Invalid user id for device owner user: " + userId);
            return;
        }
        mDeviceOwner = new OwnerInfo(ownerName, packageName);
        mDeviceOwnerUserId = userId;
    }

    void clearDeviceOwner() {
        mDeviceOwner = null;
        mDeviceOwnerUserId = UserHandle.USER_NULL;
    }

    ComponentName getDeviceInitializerComponent() {
@@ -215,20 +230,6 @@ class Owners {
        return mDeviceOwner != null;
    }

    static boolean isInstalled(String packageName, PackageManager pm) {
        try {
            PackageInfo pi;
            if ((pi = pm.getPackageInfo(packageName, 0)) != null) {
                if ((pi.applicationInfo.flags) != 0) {
                    return true;
                }
            }
        } catch (NameNotFoundException nnfe) {
            Slog.w(TAG, "Device Owner package " + packageName + " not installed.");
        }
        return false;
    }

    static boolean isInstalledForUser(String packageName, int userHandle) {
        try {
            PackageInfo pi = (AppGlobals.getPackageManager())
@@ -263,6 +264,7 @@ class Owners {
                    String name = parser.getAttributeValue(null, ATTR_NAME);
                    String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
                    mDeviceOwner = new OwnerInfo(name, packageName);
                    mDeviceOwnerUserId = UserHandle.USER_SYSTEM;
                } else if (tag.equals(TAG_DEVICE_INITIALIZER)) {
                    String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
                    String initializerComponentStr =
@@ -464,7 +466,11 @@ class Owners {
        void writeInner(XmlSerializer out) throws IOException {
            if (mDeviceOwner != null) {
                mDeviceOwner.writeToXml(out, TAG_DEVICE_OWNER);
                out.startTag(null, TAG_DEVICE_OWNER_CONTEXT);
                out.attribute(null, ATTR_USERID, String.valueOf(mDeviceOwnerUserId));
                out.endTag(null, TAG_DEVICE_OWNER_CONTEXT);
            }

            if (mDeviceInitializer != null) {
                mDeviceInitializer.writeToXml(out, TAG_DEVICE_INITIALIZER);
            }
@@ -483,7 +489,18 @@ class Owners {
            switch (tag) {
                case TAG_DEVICE_OWNER:
                    mDeviceOwner = OwnerInfo.readFromXml(parser);
                    mDeviceOwnerUserId = UserHandle.USER_SYSTEM; // Set default
                    break;
                case TAG_DEVICE_OWNER_CONTEXT: {
                    final String userIdString =
                            parser.getAttributeValue(null, ATTR_USERID);
                    try {
                        mDeviceOwnerUserId = Integer.parseInt(userIdString);
                    } catch (NumberFormatException e) {
                        Slog.e(TAG, "Error parsing user-id " + userIdString);
                    }
                    break;
                }
                case TAG_DEVICE_INITIALIZER:
                    mDeviceInitializer = OwnerInfo.readFromXml(parser);
                    break;
@@ -594,7 +611,6 @@ class Owners {
            pw.println(prefix + "admin=" + admin);
            pw.println(prefix + "name=" + name);
            pw.println(prefix + "package=" + packageName);
            pw.println();
        }
    }

@@ -602,6 +618,17 @@ class Owners {
        if (mDeviceOwner != null) {
            pw.println(prefix + "Device Owner: ");
            mDeviceOwner.dump(prefix + "  ", pw);
            pw.println(prefix + "  User ID: " + mDeviceOwnerUserId);
            pw.println();
        }
        if (mDeviceInitializer != null) {
            pw.println(prefix + "Device Initializer: ");
            mDeviceInitializer.dump(prefix + "  ", pw);
            pw.println();
        }
        if (mSystemUpdatePolicy != null) {
            pw.println(prefix + "System Update Policy: " + mSystemUpdatePolicy);
            pw.println();
        }
        if (mProfileOwners != null) {
            for (Map.Entry<Integer, OwnerInfo> entry : mProfileOwners.entrySet()) {
Loading