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

Commit e220722b authored by Makoto Onuki's avatar Makoto Onuki Committed by android-build-merger
Browse files

Merge \"Don\'t take the DPMS lock in DPMI.createPackageSuspendedDialogIntent\" into nyc-dev

am: 5e94a16b

Change-Id: I7e4d1044616bdb6e88c96dc1f79ab683b760bc5a
parents 2c95fb07 5e94a16b
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -47,6 +47,8 @@ public abstract class DevicePolicyManagerInternal {
     * Gets the packages whose widget providers are white-listed to be
     * available in the parent user.
     *
     * <p>This takes the DPMS lock.  DO NOT call from PM/UM/AM with their lock held.
     *
     * @param profileId The profile id.
     * @return The list of packages if such or empty list if there are
     *    no white-listed packages or the profile id is not a managed
@@ -58,6 +60,8 @@ public abstract class DevicePolicyManagerInternal {
     * Adds a listener for changes in the white-listed packages to show
     * cross-profile app widgets.
     *
     * <p>This takes the DPMS lock.  DO NOT call from PM/UM/AM with their lock held.
     *
     * @param listener The listener to add.
     */
    public abstract void addOnCrossProfileWidgetProvidersChangeListener(
@@ -66,6 +70,9 @@ public abstract class DevicePolicyManagerInternal {
    /**
     * Checks if an app with given uid is an active device admin of its user and has the policy
     * specified.
     *
     * <p>This takes the DPMS lock.  DO NOT call from PM/UM/AM with their lock held.
     *
     * @param uid App uid.
     * @param reqPolicy Required policy, for policies see {@link DevicePolicyManager}.
     * @return true if the uid is an active admin with the given policy.
@@ -77,6 +84,8 @@ public abstract class DevicePolicyManagerInternal {
     * suspended by the admin. This assumes that {@param packageName} is suspended by the
     * device/profile owner. The caller should check if the package is suspended or not.
     *
     * <p>This method does not take the DPMS lock.  Safe to be called from anywhere.
     *
     * @param packageName The package that is suspended
     * @param userId The user having the suspended package.
     * @return The intent to trigger the admin support dialog.
+3 −0
Original line number Diff line number Diff line
@@ -147,6 +147,9 @@ class ActivityStartInterceptor {
        }
        DevicePolicyManagerInternal devicePolicyManager = LocalServices.getService(
                DevicePolicyManagerInternal.class);
        if (devicePolicyManager == null) {
            return false;
        }
        mIntent = devicePolicyManager.createPackageSuspendedDialogIntent(
                mAInfo.packageName, mUserId);
        mCallingPid = mRealCallingPid;
+15 −13
Original line number Diff line number Diff line
@@ -8139,21 +8139,23 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
            Intent intent = new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS);
            intent.putExtra(Intent.EXTRA_USER_ID, userId);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            synchronized (DevicePolicyManagerService.this) {

            // This method is called from AM with its lock held, so don't take the DPMS lock.
            // b/29242568

            ComponentName profileOwner = mOwners.getProfileOwnerComponent(userId);
            if (profileOwner != null) {
                intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, profileOwner);
                return intent;
            }

                if (mOwners.getDeviceOwnerUserId() == userId) {
                    ComponentName deviceOwner = mOwners.getDeviceOwnerComponent();
                    if (deviceOwner != null) {
                        intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, deviceOwner);
            final Pair<Integer, ComponentName> deviceOwner =
                    mOwners.getDeviceOwnerUserIdAndComponent();
            if (deviceOwner != null && deviceOwner.first == userId) {
                intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, deviceOwner.second);
                return intent;
            }
                }
            }

            // We're not specifying the device admin because there isn't one.
            return intent;
        }
+160 −92
Original line number Diff line number Diff line
@@ -16,9 +16,9 @@

package com.android.server.devicepolicy;

import android.annotation.Nullable;
import android.app.admin.SystemUpdatePolicy;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManagerInternal;
import android.content.pm.UserInfo;
import android.os.Environment;
@@ -28,6 +28,7 @@ import android.os.UserManagerInternal;
import android.util.ArrayMap;
import android.util.AtomicFile;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.Xml;
@@ -54,8 +55,8 @@ import libcore.io.IoUtils;
 * Stores and restores state for the Device and Profile owners. By definition there can be
 * only one device owner, but there may be a profile owner for each user.
 *
 * <p>This class is not thread safe.  (i.e. access to this class must always be synchronized
 * in the caller side.)
 * <p>This class is thread safe, so individual methods can safely be called without locking.
 * However, caller must still synchronize on their side to ensure integrity between multiple calls.
 */
class Owners {
    private static final String TAG = "DevicePolicyManagerService";
@@ -101,6 +102,8 @@ class Owners {
    // Local system update policy controllable by device owner.
    private SystemUpdatePolicy mSystemUpdatePolicy;

    private final Object mLock = new Object();

    public Owners(UserManager userManager,
            UserManagerInternal userManagerInternal,
            PackageManagerInternal packageManagerInternal) {
@@ -113,12 +116,13 @@ class Owners {
     * Load configuration from the disk.
     */
    void load() {
        synchronized (mLock) {
            // First, try to read from the legacy file.
            final File legacy = getLegacyConfigFileWithTestOverride();

            final List<UserInfo> users = mUserManager.getUsers();

        if (readLegacyOwnerFile(legacy)) {
            if (readLegacyOwnerFileLocked(legacy)) {
                if (DEBUG) {
                    Log.d(TAG, "Legacy config file found.");
                }
@@ -150,10 +154,11 @@ class Owners {
                Slog.w(TAG, String.format("User %d has both DO and PO, which is not supported",
                        getDeviceOwnerUserId()));
            }
        pushToPackageManager();
            pushToPackageManagerLocked();
        }
    }

    private void pushToPackageManager() {
    private void pushToPackageManagerLocked() {
        final SparseArray<String> po = new SparseArray<>();
        for (int i = mProfileOwners.size() - 1; i >= 0; i--) {
            po.put(mProfileOwners.keyAt(i), mProfileOwners.valueAt(i).packageName);
@@ -164,160 +169,223 @@ class Owners {
    }

    String getDeviceOwnerPackageName() {
        synchronized (mLock) {
            return mDeviceOwner != null ? mDeviceOwner.packageName : null;
        }
    }

    int getDeviceOwnerUserId() {
        synchronized (mLock) {
            return mDeviceOwnerUserId;
        }
    }

    @Nullable
    Pair<Integer, ComponentName> getDeviceOwnerUserIdAndComponent() {
        synchronized (mLock) {
            if (mDeviceOwner == null) {
                return null;
            } else {
                return Pair.create(mDeviceOwnerUserId, mDeviceOwner.admin);
            }
        }
    }

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

    ComponentName getDeviceOwnerComponent() {
        synchronized (mLock) {
            return mDeviceOwner != null ? mDeviceOwner.admin : null;
        }
    }

    String getDeviceOwnerRemoteBugreportUri() {
        synchronized (mLock) {
            return mDeviceOwner != null ? mDeviceOwner.remoteBugreportUri : null;
        }
    }

    String getDeviceOwnerRemoteBugreportHash() {
        synchronized (mLock) {
            return mDeviceOwner != null ? mDeviceOwner.remoteBugreportHash : null;
        }
    }

    void setDeviceOwner(ComponentName admin, String ownerName, int userId) {
        if (userId < 0) {
            Slog.e(TAG, "Invalid user id for device owner user: " + userId);
            return;
        }
        synchronized (mLock) {
            // For a newly set DO, there's no need for migration.
            setDeviceOwnerWithRestrictionsMigrated(admin, ownerName, userId,
                    /* userRestrictionsMigrated =*/ true);
        }
    }

    // Note this should be only called during migration.  Normally when DO is set,
    // userRestrictionsMigrated should always be true.
    void setDeviceOwnerWithRestrictionsMigrated(ComponentName admin, String ownerName, int userId,
            boolean userRestrictionsMigrated) {
        synchronized (mLock) {
            mDeviceOwner = new OwnerInfo(ownerName, admin, userRestrictionsMigrated,
                    /* remoteBugreportUri =*/ null, /* remoteBugreportHash =*/ null);
            mDeviceOwnerUserId = userId;

            mUserManagerInternal.setDeviceManaged(true);
        pushToPackageManager();
            pushToPackageManagerLocked();
        }
    }

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

            mUserManagerInternal.setDeviceManaged(false);
        pushToPackageManager();
            pushToPackageManagerLocked();
        }
    }

    void setProfileOwner(ComponentName admin, String ownerName, int userId) {
        synchronized (mLock) {
            // For a newly set PO, there's no need for migration.
            mProfileOwners.put(userId, new OwnerInfo(ownerName, admin,
                    /* userRestrictionsMigrated =*/ true, /* remoteBugreportUri =*/ null,
                    /* remoteBugreportHash =*/ null));
            mUserManagerInternal.setUserManaged(userId, true);
        pushToPackageManager();
            pushToPackageManagerLocked();
        }
    }

    void removeProfileOwner(int userId) {
        synchronized (mLock) {
            mProfileOwners.remove(userId);
            mUserManagerInternal.setUserManaged(userId, false);
        pushToPackageManager();
            pushToPackageManagerLocked();
        }
    }

    ComponentName getProfileOwnerComponent(int userId) {
        synchronized (mLock) {
            OwnerInfo profileOwner = mProfileOwners.get(userId);
            return profileOwner != null ? profileOwner.admin : null;
        }
    }

    String getProfileOwnerName(int userId) {
        synchronized (mLock) {
            OwnerInfo profileOwner = mProfileOwners.get(userId);
            return profileOwner != null ? profileOwner.name : null;
        }
    }

    String getProfileOwnerPackage(int userId) {
        synchronized (mLock) {
            OwnerInfo profileOwner = mProfileOwners.get(userId);
            return profileOwner != null ? profileOwner.packageName : null;
        }
    }

    Set<Integer> getProfileOwnerKeys() {
        synchronized (mLock) {
            return mProfileOwners.keySet();
        }
    }

    SystemUpdatePolicy getSystemUpdatePolicy() {
        synchronized (mLock) {
            return mSystemUpdatePolicy;
        }
    }

    void setSystemUpdatePolicy(SystemUpdatePolicy systemUpdatePolicy) {
        synchronized (mLock) {
            mSystemUpdatePolicy = systemUpdatePolicy;
        }
    }

    void clearSystemUpdatePolicy() {
        synchronized (mLock) {
            mSystemUpdatePolicy = null;
        }
    }

    boolean hasDeviceOwner() {
        synchronized (mLock) {
            return mDeviceOwner != null;
        }
    }

    boolean isDeviceOwnerUserId(int userId) {
        synchronized (mLock) {
            return mDeviceOwner != null && mDeviceOwnerUserId == userId;
        }
    }

    boolean hasProfileOwner(int userId) {
        synchronized (mLock) {
            return getProfileOwnerComponent(userId) != null;
        }
    }

    /**
     * @return true if user restrictions need to be migrated for DO.
     */
    boolean getDeviceOwnerUserRestrictionsNeedsMigration() {
        synchronized (mLock) {
            return mDeviceOwner != null && !mDeviceOwner.userRestrictionsMigrated;
        }
    }

    /**
     * @return true if user restrictions need to be migrated for PO.
     */
    boolean getProfileOwnerUserRestrictionsNeedsMigration(int userId) {
        synchronized (mLock) {
            OwnerInfo profileOwner = mProfileOwners.get(userId);
            return profileOwner != null && !profileOwner.userRestrictionsMigrated;
        }
    }

    /** Sets the user restrictions migrated flag, and also writes to the file. */
    void setDeviceOwnerUserRestrictionsMigrated() {
        synchronized (mLock) {
            if (mDeviceOwner != null) {
                mDeviceOwner.userRestrictionsMigrated = true;
            }
            writeDeviceOwner();
        }
    }

    /** Sets the remote bugreport uri and hash, and also writes to the file. */
    void setDeviceOwnerRemoteBugreportUriAndHash(String remoteBugreportUri,
            String remoteBugreportHash) {
        synchronized (mLock) {
            if (mDeviceOwner != null) {
                mDeviceOwner.remoteBugreportUri = remoteBugreportUri;
                mDeviceOwner.remoteBugreportHash = remoteBugreportHash;
            }
            writeDeviceOwner();
        }
    }

    /** Sets the user restrictions migrated flag, and also writes to the file.  */
    void setProfileOwnerUserRestrictionsMigrated(int userId) {
        synchronized (mLock) {
            OwnerInfo profileOwner = mProfileOwners.get(userId);
            if (profileOwner != null) {
                profileOwner.userRestrictionsMigrated = true;
            }
            writeProfileOwner(userId);
        }
    }

    private boolean readLegacyOwnerFile(File file) {
    private boolean readLegacyOwnerFileLocked(File file) {
        if (!file.exists()) {
            // Already migrated or the device has no owners.
            return false;
@@ -383,7 +451,7 @@ class Owners {
    }

    void writeDeviceOwner() {
        synchronized (this) {
        synchronized (mLock) {
            if (DEBUG) {
                Log.d(TAG, "Writing to device owner file");
            }
@@ -392,7 +460,7 @@ class Owners {
    }

    void writeProfileOwner(int userId) {
        synchronized (this) {
        synchronized (mLock) {
            if (DEBUG) {
                Log.d(TAG, "Writing to profile owner file for user " + userId);
            }