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

Commit 22d88574 authored by Vladimir Komsiyski's avatar Vladimir Komsiyski
Browse files

Allow clipboard on virtual devices when the default device is locked.

Clipboard access is currently blocked on virtual devices if the default
device is locked, even if the virtual device is "always unlocked".

Virtual devices are considered insecure by default and there's already
an attempt to return false from isDeviceLocked/isDeviceSecure based on
whether the display belongs to a virtual device.

However, when the KeyguardManager is created from the system context,
its displayId association is always the default display, so this is
broken. Adding new overloads in KeyguardManager that explicitly take
the deviceId fixes the problem with the clipboard. Also changing the
existing displayId argument to deviceId to avoid an unnecessary call
into VDM to determine the device. When this was added, deviceId wasn't
available from Context.

Fix: 306620764
Bug: 300402201
Test: see CTS in topic
Change-Id: I7aedd47c13d3acd8d2954f99fa5ea671a1b888e7
parent 15c2cf07
Loading
Loading
Loading
Loading
+23 −4
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.annotation.UserIdInt;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManager.PasswordComplexity;
import android.app.admin.PasswordMetrics;
@@ -736,7 +737,7 @@ public class KeyguardManager {
     * @see #isKeyguardLocked()
     */
    public boolean isDeviceLocked() {
        return isDeviceLocked(mContext.getUserId());
        return isDeviceLocked(mContext.getUserId(), mContext.getDeviceId());
    }

    /**
@@ -746,8 +747,17 @@ public class KeyguardManager {
     */
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
    public boolean isDeviceLocked(int userId) {
        return isDeviceLocked(userId, mContext.getDeviceId());
    }

    /**
     * Per-user per-device version of {@link #isDeviceLocked()}.
     *
     * @hide
     */
    public boolean isDeviceLocked(@UserIdInt int userId, int deviceId) {
        try {
            return mTrustManager.isDeviceLocked(userId, mContext.getAssociatedDisplayId());
            return mTrustManager.isDeviceLocked(userId, deviceId);
        } catch (RemoteException e) {
            return false;
        }
@@ -769,7 +779,7 @@ public class KeyguardManager {
     * @see #isKeyguardSecure()
     */
    public boolean isDeviceSecure() {
        return isDeviceSecure(mContext.getUserId());
        return isDeviceSecure(mContext.getUserId(), mContext.getDeviceId());
    }

    /**
@@ -779,8 +789,17 @@ public class KeyguardManager {
     */
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public boolean isDeviceSecure(int userId) {
        return isDeviceSecure(userId, mContext.getDeviceId());
    }

    /**
     * Per-user per-device version of {@link #isDeviceSecure()}.
     *
     * @hide
     */
    public boolean isDeviceSecure(@UserIdInt int userId, int deviceId) {
        try {
            return mTrustManager.isDeviceSecure(userId, mContext.getAssociatedDisplayId());
            return mTrustManager.isDeviceSecure(userId, deviceId);
        } catch (RemoteException e) {
            return false;
        }
+2 −2
Original line number Diff line number Diff line
@@ -34,8 +34,8 @@ interface ITrustManager {
    void unregisterTrustListener(in ITrustListener trustListener);
    void reportKeyguardShowingChanged();
    void setDeviceLockedForUser(int userId, boolean locked);
    boolean isDeviceLocked(int userId, int displayId);
    boolean isDeviceSecure(int userId, int displayId);
    boolean isDeviceLocked(int userId, int deviceId);
    boolean isDeviceSecure(int userId, int deviceId);
    @EnforcePermission("TRUST_LISTENER")
    boolean isTrustUsuallyManaged(int userId);
    void unlockedByBiometricForUser(int userId, in BiometricSourceType source);
+1 −1
Original line number Diff line number Diff line
@@ -108,7 +108,7 @@ class PreAuthInfo {
        final boolean credentialRequested = Utils.isCredentialRequested(promptInfo);

        final boolean credentialAvailable = trustManager.isDeviceSecure(userId,
                context.getAssociatedDisplayId());
                context.getDeviceId());

        // Assuming that biometric authenticators are listed in priority-order, the rest of this
        // function will attempt to find the first authenticator that's as strong or stronger than
+7 −7
Original line number Diff line number Diff line
@@ -646,7 +646,7 @@ public class ClipboardService extends SystemService {
                            intendingUid,
                            intendingUserId,
                            intendingDeviceId)
                    || isDeviceLocked(intendingUserId)) {
                    || isDeviceLocked(intendingUserId, deviceId)) {
                return null;
            }
            synchronized (mLock) {
@@ -686,7 +686,7 @@ public class ClipboardService extends SystemService {
                            intendingUserId,
                            intendingDeviceId,
                            false)
                    || isDeviceLocked(intendingUserId)) {
                    || isDeviceLocked(intendingUserId, deviceId)) {
                return null;
            }
            synchronized (mLock) {
@@ -710,7 +710,7 @@ public class ClipboardService extends SystemService {
                            intendingUserId,
                            intendingDeviceId,
                            false)
                    || isDeviceLocked(intendingUserId)) {
                    || isDeviceLocked(intendingUserId, deviceId)) {
                return false;
            }
            synchronized (mLock) {
@@ -785,7 +785,7 @@ public class ClipboardService extends SystemService {
                            intendingUserId,
                            intendingDeviceId,
                            false)
                    || isDeviceLocked(intendingUserId)) {
                    || isDeviceLocked(intendingUserId, deviceId)) {
                return false;
            }
            synchronized (mLock) {
@@ -814,7 +814,7 @@ public class ClipboardService extends SystemService {
                            intendingUserId,
                            intendingDeviceId,
                            false)
                    || isDeviceLocked(intendingUserId)) {
                    || isDeviceLocked(intendingUserId, deviceId)) {
                return null;
            }
            synchronized (mLock) {
@@ -1150,12 +1150,12 @@ public class ClipboardService extends SystemService {
                && text.equals(clipboard.primaryClip.getItemAt(0).getText());
    }

    private boolean isDeviceLocked(@UserIdInt int userId) {
    private boolean isDeviceLocked(@UserIdInt int userId, int deviceId) {
        final long token = Binder.clearCallingIdentity();
        try {
            final KeyguardManager keyguardManager = getContext().getSystemService(
                    KeyguardManager.class);
            return keyguardManager != null && keyguardManager.isDeviceLocked(userId);
            return keyguardManager != null && keyguardManager.isDeviceLocked(userId, deviceId);
        } finally {
            Binder.restoreCallingIdentity(token);
        }
+8 −57
Original line number Diff line number Diff line
@@ -70,7 +70,6 @@ import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.Xml;
import android.view.Display;
import android.view.IWindowManager;
import android.view.WindowManagerGlobal;

@@ -79,7 +78,6 @@ import com.android.internal.content.PackageMonitor;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.util.DumpUtils;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.companion.virtual.VirtualDeviceManagerInternal;

@@ -1523,57 +1521,13 @@ public class TrustManagerService extends SystemService {
            mHandler.obtainMessage(MSG_UNREGISTER_LISTENER, trustListener).sendToTarget();
        }

        /**
         * @param uid: uid of the calling app (obtained via getCallingUid())
         * @param displayId: the id of a Display
         * @return Returns true if both of the following conditions hold -
         * 1) the uid belongs to an app instead of a system core component; and
         * 2) either the uid is running on a virtual device or the displayId
         *    is owned by a virtual device
         */
        private boolean isAppOrDisplayOnAnyVirtualDevice(int uid, int displayId) {
            if (UserHandle.isCore(uid)) {
                return false;
            }

            if (mVirtualDeviceManager == null) {
                mVirtualDeviceManager = LocalServices.getService(
                        VirtualDeviceManagerInternal.class);
                if (mVirtualDeviceManager == null) {
                    // VirtualDeviceManager service may not have been published
                    return false;
                }
            }

            switch (displayId) {
                case Display.INVALID_DISPLAY:
                    // There is no Display object associated with the Context of the calling app.
                    if (mVirtualDeviceManager.isAppRunningOnAnyVirtualDevice(uid)) {
                        return true;
                    }
                    break;
                case Display.DEFAULT_DISPLAY:
                    // The DEFAULT_DISPLAY is by definition not virtual.
                    break;
                default:
                    // Other display IDs can belong to logical displays created for other purposes.
                    if (mVirtualDeviceManager.isDisplayOwnedByAnyVirtualDevice(displayId)) {
                        return true;
                    }
                    break;
            }
            return false;
        }

        @Override
        public boolean isDeviceLocked(int userId, int displayId) throws RemoteException {
            int uid = getCallingUid();
            if (isAppOrDisplayOnAnyVirtualDevice(uid, displayId)) {
                // Virtual displays are considered insecure because they may be used for streaming
                // to other devices.
        public boolean isDeviceLocked(int userId, int deviceId) throws RemoteException {
            if (deviceId != Context.DEVICE_ID_DEFAULT) {
                // Virtual devices are considered insecure.
                return false;
            }
            userId = ActivityManager.handleIncomingUser(getCallingPid(), uid, userId,
            userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,
                    false /* allowAll */, true /* requireFull */, "isDeviceLocked", null);

            final long token = Binder.clearCallingIdentity();
@@ -1588,15 +1542,12 @@ public class TrustManagerService extends SystemService {
        }

        @Override
        public boolean isDeviceSecure(int userId, int displayId) throws RemoteException {
            int uid = getCallingUid();
            if (isAppOrDisplayOnAnyVirtualDevice(uid, displayId)) {
                // Virtual displays are considered insecure because they may be used for streaming
                // to other devices.
        public boolean isDeviceSecure(int userId, int deviceId) throws RemoteException {
            if (deviceId != Context.DEVICE_ID_DEFAULT) {
                // Virtual devices are considered insecure.
                return false;
            }

            userId = ActivityManager.handleIncomingUser(getCallingPid(), uid, userId,
            userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,
                    false /* allowAll */, true /* requireFull */, "isDeviceSecure", null);

            final long token = Binder.clearCallingIdentity();