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

Commit 831dd754 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Prevent shortcut access when user is locked" into nyc-mr1-dev

parents 7fd0752e 9c850012
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -492,6 +492,8 @@ public class LauncherApps {
     * If the calling launcher application contains pinned shortcuts, they will still work,
     * even though the caller no longer has the shortcut host permission.
     *
     * <p>Returns {@code false} when the user is locked.
     *
     * @see ShortcutManager
     */
    public boolean hasShortcutHostPermission() {
@@ -508,6 +510,9 @@ public class LauncherApps {
     * <p>Callers must be allowed to access the shortcut information, as defined in {@link
     * #hasShortcutHostPermission()}.
     *
     * <p>Returns am empty list when the user is locked, or when the {@code user} user
     * is locked or not running.
     *
     * @param query result includes shortcuts matching this query.
     * @param user The UserHandle of the profile.
     *
@@ -551,6 +556,9 @@ public class LauncherApps {
     * <p>The calling launcher application must be allowed to access the shortcut information,
     * as defined in {@link #hasShortcutHostPermission()}.
     *
     * <p>Call will be ignored when the user is locked, or when the {@code user} user
     * is locked or not running.
     *
     * @param packageName The target package name.
     * @param shortcutIds The IDs of the shortcut to be pinned.
     * @param user The UserHandle of the profile.
@@ -622,6 +630,9 @@ public class LauncherApps {
     * <p>The calling launcher application must be allowed to access the shortcut information,
     * as defined in {@link #hasShortcutHostPermission()}.
     *
     * <p>Returns {@code null} when the user is locked, or when the user owning the shortcut
     * is locked or not running.
     *
     * @param density The preferred density of the icon, zero for default density. Use
     * density DPI values from {@link DisplayMetrics}.
     *
@@ -670,6 +681,9 @@ public class LauncherApps {
     * <p>The calling launcher application must be allowed to access the shortcut information,
     * as defined in {@link #hasShortcutHostPermission()}.
     *
     * <p>Returns {@code 0} when the user is locked, or when the user owning the shortcut
     * is locked or not running.
     *
     * @param density Optional density for the icon, or 0 to use the default density. Use
     * @return A badged icon for the shortcut.
     *
@@ -690,6 +704,10 @@ public class LauncherApps {
     * <p>The calling launcher application must be allowed to access the shortcut information,
     * as defined in {@link #hasShortcutHostPermission()}.
     *
     * <p>Throws {@link android.content.ActivityNotFoundException}
     * when the user is locked, or when the {@code user} user
     * is locked or not running.
     *
     * @param packageName The target shortcut package name.
     * @param shortcutId The target shortcut ID.
     * @param sourceBounds The Rect containing the source bounds of the clicked icon.
@@ -712,6 +730,10 @@ public class LauncherApps {
     * <p>The calling launcher application must be allowed to access the shortcut information,
     * as defined in {@link #hasShortcutHostPermission()}.
     *
     * <p>Throws {@link android.content.ActivityNotFoundException}
     * when the user is locked, or when the user owning the shortcut
     * is locked or not running.
     *
     * @param shortcut The target shortcut.
     * @param sourceBounds The Rect containing the source bounds of the clicked icon.
     * @param startActivityOptions Options to pass to startActivity.
+32 −0
Original line number Diff line number Diff line
@@ -434,6 +434,12 @@ import java.util.List;
 * <h3>Launcher API</h3>
 *
 * The {@link LauncherApps} class provides APIs for launcher applications to access shortcuts.
 *
 *
 * <h3>Direct Boot and Shortcuts</h3>
 *
 * All shortcut information is stored in credential encrypted storage, so no shortcuts can be
 * accessed when the user is locked.
 */
public class ShortcutManager {
    private static final String TAG = "ShortcutManager";
@@ -469,6 +475,8 @@ public class ShortcutManager {
     *
     * @throws IllegalArgumentException if {@link #getMaxShortcutCountPerActivity()} is exceeded,
     * or when trying to update immutable shortcuts.
     *
     * @throws IllegalStateException when the user is locked.
     */
    public boolean setDynamicShortcuts(@NonNull List<ShortcutInfo> shortcutInfoList) {
        try {
@@ -481,6 +489,8 @@ public class ShortcutManager {

    /**
     * Return all dynamic shortcuts from the caller application.
     *
     * @throws IllegalStateException when the user is locked.
     */
    @NonNull
    public List<ShortcutInfo> getDynamicShortcuts() {
@@ -494,6 +504,8 @@ public class ShortcutManager {

    /**
     * Return all manifest shortcuts from the caller application.
     *
     * @throws IllegalStateException when the user is locked.
     */
    @NonNull
    public List<ShortcutInfo> getManifestShortcuts() {
@@ -515,6 +527,8 @@ public class ShortcutManager {
     *
     * @throws IllegalArgumentException if {@link #getMaxShortcutCountPerActivity()} is exceeded,
     * or when trying to update immutable shortcuts.
     *
     * @throws IllegalStateException when the user is locked.
     */
    public boolean addDynamicShortcuts(@NonNull List<ShortcutInfo> shortcutInfoList) {
        try {
@@ -527,6 +541,8 @@ public class ShortcutManager {

    /**
     * Delete dynamic shortcuts by ID.
     *
     * @throws IllegalStateException when the user is locked.
     */
    public void removeDynamicShortcuts(@NonNull List<String> shortcutIds) {
        try {
@@ -539,6 +555,8 @@ public class ShortcutManager {

    /**
     * Delete all dynamic shortcuts from the caller application.
     *
     * @throws IllegalStateException when the user is locked.
     */
    public void removeAllDynamicShortcuts() {
        try {
@@ -550,6 +568,8 @@ public class ShortcutManager {

    /**
     * Return all pinned shortcuts from the caller application.
     *
     * @throws IllegalStateException when the user is locked.
     */
    @NonNull
    public List<ShortcutInfo> getPinnedShortcuts() {
@@ -570,6 +590,8 @@ public class ShortcutManager {
     * @return {@code true} if the call has succeeded. {@code false} if the call is rate-limited.
     *
     * @throws IllegalArgumentException If trying to update immutable shortcuts.
     *
     * @throws IllegalStateException when the user is locked.
     */
    public boolean updateShortcuts(List<ShortcutInfo> shortcutInfoList) {
        try {
@@ -585,6 +607,8 @@ public class ShortcutManager {
     * class.
     *
     * @throws IllegalArgumentException If trying to disable immutable shortcuts.
     *
     * @throws IllegalStateException when the user is locked.
     */
    public void disableShortcuts(@NonNull List<String> shortcutIds) {
        try {
@@ -622,6 +646,8 @@ public class ShortcutManager {
     * For more details, see the Javadoc for the {@link ShortcutManager} class.
     *
     * @throws IllegalArgumentException If trying to disable immutable shortcuts.
     *
     * @throws IllegalStateException when the user is locked.
     */
    public void disableShortcuts(@NonNull List<String> shortcutIds, CharSequence disabledMessage) {
        try {
@@ -638,6 +664,8 @@ public class ShortcutManager {
     * already enabled, this method does nothing.
     *
     * @throws IllegalArgumentException If trying to enable immutable shortcuts.
     *
     * @throws IllegalStateException when the user is locked.
     */
    public void enableShortcuts(@NonNull List<String> shortcutIds) {
        try {
@@ -704,6 +732,8 @@ public class ShortcutManager {
     * Return {@code true} when rate-limiting is active for the caller application.
     *
     * <p>See the class level javadoc for details.
     *
     * @throws IllegalStateException when the user is locked.
     */
    public boolean isRateLimitingActive() {
        try {
@@ -747,6 +777,8 @@ public class ShortcutManager {
     * <p>The information is accessible via {@link UsageStatsManager#queryEvents}
     * Typically, launcher applications use this information to build a prediction model
     * so that they can promote the shortcuts that are likely to be used at the moment.
     *
     * @throws IllegalStateException when the user is locked.
     */
    public void reportShortcutUsed(String shortcutId) {
        try {
+1 −1
Original line number Diff line number Diff line
@@ -259,7 +259,7 @@ public class ShortcutParser {
                    continue;
                }

                ShortcutService.warnForInvalidTag(depth, tag);
                Log.w(TAG, String.format("Invalid tag '%s' found at depth %d", tag, depth));
            }
        } finally {
            if (parser != null) {
+78 −2
Original line number Diff line number Diff line
@@ -1037,6 +1037,24 @@ public class ShortcutService extends IShortcutService.Stub {
        }
    }

    private boolean isUserUnlocked(@UserIdInt int userId) {
        final long token = injectClearCallingIdentity();
        try {
            // Weird: when SystemService.onUnlockUser() is called, the user state is still
            // unlocking, as opposed to unlocked.  So we need to accept the "unlocking" state too.
            // We know when the user is unlocking, the CE storage is already unlocked.
            return mUserManager.isUserUnlockingOrUnlocked(userId);
        } finally {
            injectRestoreCallingIdentity(token);
        }
    }

    void throwIfUserLocked(@UserIdInt int userId) {
        if (!isUserUnlocked(userId)) {
            throw new IllegalStateException("User " + userId + " is locked or not running");
        }
    }

    @GuardedBy("mLock")
    @NonNull
    private boolean isUserLoadedLocked(@UserIdInt int userId) {
@@ -1047,6 +1065,11 @@ public class ShortcutService extends IShortcutService.Stub {
    @GuardedBy("mLock")
    @NonNull
    ShortcutUser getUserShortcutsLocked(@UserIdInt int userId) {
        if (!isUserUnlocked(userId)) {
            wtf("User still locked");
            return new ShortcutUser(this, userId);
        }

        ShortcutUser userPackages = mUsers.get(userId);
        if (userPackages == null) {
            userPackages = loadUserLocked(userId);
@@ -1535,6 +1558,7 @@ public class ShortcutService extends IShortcutService.Stub {
    public boolean setDynamicShortcuts(String packageName, ParceledListSlice shortcutInfoList,
            @UserIdInt int userId) {
        verifyCaller(packageName, userId);
        throwIfUserLocked(userId);

        final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList();
        final int size = newShortcuts.size();
@@ -1585,6 +1609,7 @@ public class ShortcutService extends IShortcutService.Stub {
    public boolean updateShortcuts(String packageName, ParceledListSlice shortcutInfoList,
            @UserIdInt int userId) {
        verifyCaller(packageName, userId);
        throwIfUserLocked(userId);

        final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList();
        final int size = newShortcuts.size();
@@ -1664,6 +1689,7 @@ public class ShortcutService extends IShortcutService.Stub {
    public boolean addDynamicShortcuts(String packageName, ParceledListSlice shortcutInfoList,
            @UserIdInt int userId) {
        verifyCaller(packageName, userId);
        throwIfUserLocked(userId);

        final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList();
        final int size = newShortcuts.size();
@@ -1715,6 +1741,7 @@ public class ShortcutService extends IShortcutService.Stub {
            CharSequence disabledMessage, int disabledMessageResId, @UserIdInt int userId) {
        verifyCaller(packageName, userId);
        Preconditions.checkNotNull(shortcutIds, "shortcutIds must be provided");
        throwIfUserLocked(userId);

        synchronized (mLock) {
            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
@@ -1743,6 +1770,7 @@ public class ShortcutService extends IShortcutService.Stub {
    public void enableShortcuts(String packageName, List shortcutIds, @UserIdInt int userId) {
        verifyCaller(packageName, userId);
        Preconditions.checkNotNull(shortcutIds, "shortcutIds must be provided");
        throwIfUserLocked(userId);

        synchronized (mLock) {
            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
@@ -1764,6 +1792,7 @@ public class ShortcutService extends IShortcutService.Stub {
            @UserIdInt int userId) {
        verifyCaller(packageName, userId);
        Preconditions.checkNotNull(shortcutIds, "shortcutIds must be provided");
        throwIfUserLocked(userId);

        synchronized (mLock) {
            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
@@ -1787,6 +1816,7 @@ public class ShortcutService extends IShortcutService.Stub {
    @Override
    public void removeAllDynamicShortcuts(String packageName, @UserIdInt int userId) {
        verifyCaller(packageName, userId);
        throwIfUserLocked(userId);

        synchronized (mLock) {
            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
@@ -1802,6 +1832,8 @@ public class ShortcutService extends IShortcutService.Stub {
    public ParceledListSlice<ShortcutInfo> getDynamicShortcuts(String packageName,
            @UserIdInt int userId) {
        verifyCaller(packageName, userId);
        throwIfUserLocked(userId);

        synchronized (mLock) {
            return getShortcutsWithQueryLocked(
                    packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR,
@@ -1813,6 +1845,8 @@ public class ShortcutService extends IShortcutService.Stub {
    public ParceledListSlice<ShortcutInfo> getManifestShortcuts(String packageName,
            @UserIdInt int userId) {
        verifyCaller(packageName, userId);
        throwIfUserLocked(userId);

        synchronized (mLock) {
            return getShortcutsWithQueryLocked(
                    packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR,
@@ -1824,6 +1858,8 @@ public class ShortcutService extends IShortcutService.Stub {
    public ParceledListSlice<ShortcutInfo> getPinnedShortcuts(String packageName,
            @UserIdInt int userId) {
        verifyCaller(packageName, userId);
        throwIfUserLocked(userId);

        synchronized (mLock) {
            return getShortcutsWithQueryLocked(
                    packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR,
@@ -1854,6 +1890,7 @@ public class ShortcutService extends IShortcutService.Stub {
    @Override
    public int getRemainingCallCount(String packageName, @UserIdInt int userId) {
        verifyCaller(packageName, userId);
        throwIfUserLocked(userId);

        synchronized (mLock) {
            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
@@ -1865,6 +1902,7 @@ public class ShortcutService extends IShortcutService.Stub {
    @Override
    public long getRateLimitResetTime(String packageName, @UserIdInt int userId) {
        verifyCaller(packageName, userId);
        throwIfUserLocked(userId);

        synchronized (mLock) {
            return getNextResetTimeLocked();
@@ -1883,6 +1921,7 @@ public class ShortcutService extends IShortcutService.Stub {
    @Override
    public void reportShortcutUsed(String packageName, String shortcutId, int userId) {
        verifyCaller(packageName, userId);
        throwIfUserLocked(userId);

        Preconditions.checkNotNull(shortcutId);

@@ -1951,6 +1990,10 @@ public class ShortcutService extends IShortcutService.Stub {
            Slog.d(TAG, "onApplicationActive: package=" + packageName + "  userid=" + userId);
        }
        enforceResetThrottlingPermission();
        if (!isUserUnlocked(userId)) {
            // This is called by system UI, so no need to throw.  Just ignore.
            return;
        }
        resetPackageThrottling(packageName, userId);
    }

@@ -1968,6 +2011,8 @@ public class ShortcutService extends IShortcutService.Stub {
    // even when hasShortcutPermission() is overridden.
    @VisibleForTesting
    boolean hasShortcutHostPermissionInner(@NonNull String callingPackage, int userId) {
        throwIfUserLocked(userId);

        synchronized (mLock) {
            final ShortcutUser user = getUserShortcutsLocked(userId);

@@ -2125,6 +2170,10 @@ public class ShortcutService extends IShortcutService.Stub {
                @Nullable ComponentName componentName,
                int queryFlags, int userId) {
            final ArrayList<ShortcutInfo> ret = new ArrayList<>();
            if (!isUserUnlocked(userId) || !isUserUnlocked(launcherUserId)) {
                return ret;
            }

            final boolean cloneKeyFieldOnly =
                    ((queryFlags & ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY) != 0);
            final int cloneFlag = cloneKeyFieldOnly ? ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO
@@ -2202,6 +2251,10 @@ public class ShortcutService extends IShortcutService.Stub {
            Preconditions.checkStringNotEmpty(packageName, "packageName");
            Preconditions.checkStringNotEmpty(shortcutId, "shortcutId");

            if (!isUserUnlocked(userId) || !isUserUnlocked(launcherUserId)) {
                return false;
            }

            synchronized (mLock) {
                getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
                        .attemptToRestoreIfNeededAndSave();
@@ -2218,6 +2271,10 @@ public class ShortcutService extends IShortcutService.Stub {
            Preconditions.checkStringNotEmpty(packageName, "packageName");
            Preconditions.checkStringNotEmpty(shortcutId, "shortcutId");

            if (!isUserUnlocked(userId) || !isUserUnlocked(launcherUserId)) {
                return null;
            }

            final ShortcutPackage p = getUserShortcutsLocked(userId)
                    .getPackageShortcutsIfExists(packageName);
            if (p == null) {
@@ -2239,6 +2296,10 @@ public class ShortcutService extends IShortcutService.Stub {
            Preconditions.checkStringNotEmpty(packageName, "packageName");
            Preconditions.checkNotNull(shortcutIds, "shortcutIds");

            if (!isUserUnlocked(userId) || !isUserUnlocked(launcherUserId)) {
                return;
            }

            synchronized (mLock) {
                final ShortcutLauncher launcher =
                        getLauncherShortcutsLocked(callingPackage, userId, launcherUserId);
@@ -2259,6 +2320,10 @@ public class ShortcutService extends IShortcutService.Stub {
            Preconditions.checkStringNotEmpty(packageName, "packageName can't be empty");
            Preconditions.checkStringNotEmpty(shortcutId, "shortcutId can't be empty");

            if (!isUserUnlocked(userId) || !isUserUnlocked(launcherUserId)) {
                return null;
            }

            synchronized (mLock) {
                getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
                        .attemptToRestoreIfNeededAndSave();
@@ -2289,6 +2354,10 @@ public class ShortcutService extends IShortcutService.Stub {
            Preconditions.checkNotNull(packageName, "packageName");
            Preconditions.checkNotNull(shortcutId, "shortcutId");

            if (!isUserUnlocked(userId) || !isUserUnlocked(launcherUserId)) {
                return 0;
            }

            synchronized (mLock) {
                getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
                        .attemptToRestoreIfNeededAndSave();
@@ -2313,6 +2382,10 @@ public class ShortcutService extends IShortcutService.Stub {
            Preconditions.checkNotNull(packageName, "packageName");
            Preconditions.checkNotNull(shortcutId, "shortcutId");

            if (!isUserUnlocked(userId) || !isUserUnlocked(launcherUserId)) {
                return null;
            }

            synchronized (mLock) {
                getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
                        .attemptToRestoreIfNeededAndSave();
@@ -2345,6 +2418,9 @@ public class ShortcutService extends IShortcutService.Stub {
        @Override
        public boolean hasShortcutHostPermission(int launcherUserId,
                @NonNull String callingPackage) {
            if (!isUserUnlocked(launcherUserId)) {
                return false;
            }
            return ShortcutService.this.hasShortcutHostPermission(callingPackage, launcherUserId);
        }
    }
@@ -2395,7 +2471,7 @@ public class ShortcutService extends IShortcutService.Stub {
            final long token = injectClearCallingIdentity();
            try {

                if (!mUserManager.isUserUnlocked(userId)) {
                if (!isUserUnlocked(userId)) {
                    if (DEBUG) {
                        Slog.d(TAG, "Ignoring package broadcast " + action
                                + " for locked/stopped user " + userId);
@@ -3208,7 +3284,7 @@ public class ShortcutService extends IShortcutService.Stub {
                    case "--user":
                        if (takeUser) {
                            mUserId = UserHandle.parseUserArg(getNextArgRequired());
                            if (!mUserManager.isUserUnlocked(mUserId)) {
                            if (!isUserUnlocked(mUserId)) {
                                throw new CommandException(
                                        "User " + mUserId + " is not running or locked");
                            }
+22 −10
Original line number Diff line number Diff line
@@ -687,19 +687,25 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {

        // Set up isUserRunning and isUserUnlocked.
        when(mMockUserManager.isUserRunning(anyInt())).thenAnswer(new AnswerWithSystemCheck<>(
                        inv -> mRunningUsers.get((Integer) inv.getArguments()[0])));
                        inv -> b(mRunningUsers.get((Integer) inv.getArguments()[0]))));

        when(mMockUserManager.isUserUnlocked(anyInt())).thenAnswer(new AnswerWithSystemCheck<>(
                        inv -> {
        when(mMockUserManager.isUserUnlocked(anyInt()))
                .thenAnswer(new AnswerWithSystemCheck<>(inv -> {
                    final int userId = (Integer) inv.getArguments()[0];
                            return mRunningUsers.get(userId) && mUnlockedUsers.get(userId);
                    return b(mRunningUsers.get(userId)) && b(mUnlockedUsers.get(userId));
                }));
        // isUserUnlockingOrUnlocked() return the same value as isUserUnlocked().
        when(mMockUserManager.isUserUnlockingOrUnlocked(anyInt()))
                .thenAnswer(new AnswerWithSystemCheck<>(inv -> {
                    final int userId = (Integer) inv.getArguments()[0];
                    return b(mRunningUsers.get(userId)) && b(mUnlockedUsers.get(userId));
                }));

        // User 0 is always running
        // User 0 and P0 are always running
        mRunningUsers.put(USER_0, true);
        mRunningUsers.put(USER_10, false);
        mRunningUsers.put(USER_11, false);
        mRunningUsers.put(USER_P0, false);
        mRunningUsers.put(USER_P0, true);

        // Unlock all users by default.
        mUnlockedUsers.put(USER_0, true);
@@ -715,6 +721,10 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
        setCaller(CALLING_PACKAGE_1);
    }

    private static boolean b(Boolean value) {
        return (value != null && value);
    }

    /**
     * Returns a boolean but also checks if the current UID is SYSTEM_UID.
     */
@@ -1726,6 +1736,8 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
    }

    protected void prepareCrossProfileDataSet() {
        mRunningUsers.put(USER_10, true); // this test needs user 10.

        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
            assertTrue(mManager.setDynamicShortcuts(list(
                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
Loading