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

Commit 3317d134 authored by Winson Chung's avatar Winson Chung
Browse files

5/ Validate and resolve shortcut & task activity infos

- Resolve shortcut activity infos
- Fix issue with resolving activity infos for restored tasks after reboot

Bug: 169894807
Test: atest DragDropControllerTests
Change-Id: I581de3ff31747e4a3369ef5b8c96cef132aa2bb5
parent 93fd63d0
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -74,8 +74,8 @@ public class ClipDescription implements Parcelable {

    /**
     * The MIME type for a shortcut. The ClipData must include intents with required extras
     * {@link #EXTRA_PENDING_INTENT} and {@link Intent#EXTRA_USER}, and an optional
     * {@link #EXTRA_ACTIVITY_OPTIONS}.
     * {@link Intent#EXTRA_SHORTCUT_ID}, {@link Intent#EXTRA_PACKAGE_NAME} and
     * {@link Intent#EXTRA_USER}, and an optional {@link #EXTRA_ACTIVITY_OPTIONS}.
     * @hide
     */
    public static final String MIMETYPE_APPLICATION_SHORTCUT = "application/vnd.android.shortcut";
+40 −13
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
import static android.content.Intent.EXTRA_PACKAGE_NAME;
import static android.content.Intent.EXTRA_SHORTCUT_ID;
import static android.content.Intent.EXTRA_TASK_ID;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -43,6 +44,7 @@ import android.content.ClipData;
import android.content.ClipDescription;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ShortcutServiceInternal;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
@@ -288,7 +290,8 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
    public IBinder performDrag(IWindow window, int flags, SurfaceControl surface, int touchSource,
            float touchX, float touchY, float thumbCenterX, float thumbCenterY, ClipData data) {
        // Validate and resolve ClipDescription data before clearing the calling identity
        validateAndResolveDragMimeTypeExtras(data, Binder.getCallingUid());
        validateAndResolveDragMimeTypeExtras(data, Binder.getCallingUid(), Binder.getCallingPid(),
                mPackageName);
        final long ident = Binder.clearCallingIdentity();
        try {
            return mDragDropController.performDrag(mPid, mUid, window, flags, surface, touchSource,
@@ -302,8 +305,9 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
     * Validates the given drag data.
     */
    @VisibleForTesting
    public void validateAndResolveDragMimeTypeExtras(ClipData data, int callingUid) {
        if (Binder.getCallingUid() == Process.SYSTEM_UID) {
    void validateAndResolveDragMimeTypeExtras(ClipData data, int callingUid, int callingPid,
            String callingPackage) {
        if (callingUid == Process.SYSTEM_UID) {
            throw new IllegalStateException("Need to validate before calling identify is cleared");
        }
        final ClipDescription desc = data != null ? data.getDescription() : null;
@@ -358,35 +362,58 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
                Binder.restoreCallingIdentity(origId);
            }
        } else if (hasShortcut) {
            // Restrict who can start a shortcut drag since it will start the shortcut as the
            // target shortcut package
            mService.mAtmService.enforceCallerIsRecentsOrHasPermission(START_TASKS_FROM_RECENTS,
                    "performDrag");
            for (int i = 0; i < data.getItemCount(); i++) {
                final Intent intent = data.getItemAt(i).getIntent();
                final ClipData.Item item = data.getItemAt(i);
                final Intent intent = item.getIntent();
                final String shortcutId = intent.getStringExtra(EXTRA_SHORTCUT_ID);
                final String packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME);
                final UserHandle user = intent.getParcelableExtra(Intent.EXTRA_USER);
                if (!intent.hasExtra(EXTRA_SHORTCUT_ID)
                        || TextUtils.isEmpty(intent.getStringExtra(EXTRA_SHORTCUT_ID))
                if (TextUtils.isEmpty(shortcutId)
                        || TextUtils.isEmpty(packageName)
                        || user == null) {
                    throw new IllegalArgumentException("Clip item must include the shortcut id and "
                            + "the user to launch for.");
                    throw new IllegalArgumentException("Clip item must include the package name, "
                            + "shortcut id, and the user to launch for.");
                }
                final ShortcutServiceInternal shortcutService =
                        LocalServices.getService(ShortcutServiceInternal.class);
                final Intent[] shortcutIntents = shortcutService.createShortcutIntents(
                        callingUid, callingPackage, packageName, shortcutId,
                        user.getIdentifier(), callingPid, callingUid);
                if (shortcutIntents == null || shortcutIntents.length == 0) {
                    throw new IllegalArgumentException("Invalid shortcut id");
                }
                // TODO(b/169894807): Validate and get activity info for shortcut as well
                final ActivityInfo info = mService.mAtmService.resolveActivityInfoForIntent(
                        shortcutIntents[0], null /* resolvedType */, user.getIdentifier(),
                        callingUid);
                item.setActivityInfo(info);
            }
        } else if (hasTask) {
            // TODO(b/169894807): Consider opening this up for tasks from the same app as the caller
            mService.mAtmService.enforceCallerIsRecentsOrHasPermission(START_TASKS_FROM_RECENTS,
                    "performDrag");
            for (int i = 0; i < data.getItemCount(); i++) {
                final ClipData.Item item = data.getItemAt(i);
                final Intent intent = data.getItemAt(i).getIntent();
                final Intent intent = item.getIntent();
                final int taskId = intent.getIntExtra(EXTRA_TASK_ID, INVALID_TASK_ID);
                if (taskId == INVALID_TASK_ID) {
                    throw new IllegalArgumentException("Clip item must include the task id.");
                }
                final Task task = mService.mRoot.anyTaskForId(taskId);
                final ActivityRecord rootActivity = task != null ? task.getRootActivity() : null;
                if (rootActivity == null) {
                if (task == null) {
                    throw new IllegalArgumentException("Invalid task id.");
                }
                item.setActivityInfo(rootActivity.info);
                if (task.getRootActivity() != null) {
                    item.setActivityInfo(task.getRootActivity().info);
                } else {
                    // Resolve the activity info manually if the task was restored after reboot
                    final ActivityInfo info = mService.mAtmService.resolveActivityInfoForIntent(
                            task.intent, null /* resolvedType */, task.mUserId, callingUid);
                    item.setActivityInfo(info);
                }
            }
        }
    }
+46 −15
Original line number Diff line number Diff line
@@ -83,6 +83,8 @@ import java.util.concurrent.TimeUnit;
public class DragDropControllerTests extends WindowTestsBase {
    private static final int TIMEOUT_MS = 3000;
    private static final int TEST_UID = 12345;
    private static final int TEST_PID = 67890;
    private static final String TEST_PACKAGE = "com.test.package";

    private TestDragDropController mTarget;
    private WindowState mWindow;
@@ -243,21 +245,16 @@ public class DragDropControllerTests extends WindowTestsBase {
        });
        try {
            session.validateAndResolveDragMimeTypeExtras(
                    createClipDataForActivity(null, null), 0);
            fail("Expected failure without pending intent and user");
        } catch (IllegalArgumentException e) {
            // Expected failure
        }
        try {
            session.validateAndResolveDragMimeTypeExtras(
                    createClipDataForActivity(mock(PendingIntent.class), null), 0);
                    createClipDataForActivity(mock(PendingIntent.class), null), TEST_UID, TEST_PID,
                    TEST_PACKAGE);
            fail("Expected failure without user");
        } catch (IllegalArgumentException e) {
            // Expected failure
        }
        try {
            session.validateAndResolveDragMimeTypeExtras(
                    createClipDataForActivity(null, mock(UserHandle.class)), 0);
                    createClipDataForActivity(null, mock(UserHandle.class)), TEST_UID, TEST_PID,
                    TEST_PACKAGE);
            fail("Expected failure without pending intent");
        } catch (IllegalArgumentException e) {
            // Expected failure
@@ -286,15 +283,48 @@ public class DragDropControllerTests extends WindowTestsBase {
            public void onAnimatorScaleChanged(float scale) {}
        });
        try {
            final ClipData clipData = new ClipData(
                    new ClipDescription("drag", new String[] { MIMETYPE_APPLICATION_SHORTCUT }),
                    new ClipData.Item(new Intent()));

            session.validateAndResolveDragMimeTypeExtras(clipData, TEST_UID);
            session.validateAndResolveDragMimeTypeExtras(
                    createClipDataForShortcut(null, "test_shortcut_id", mock(UserHandle.class)),
                    TEST_UID, TEST_PID, TEST_PACKAGE);
            fail("Expected failure without package name");
        } catch (IllegalArgumentException e) {
            // Expected failure
        }
        try {
            session.validateAndResolveDragMimeTypeExtras(
                    createClipDataForShortcut("test_package", null, mock(UserHandle.class)),
                    TEST_UID, TEST_PID, TEST_PACKAGE);
            fail("Expected failure without shortcut id");
        } catch (IllegalArgumentException e) {
            // Expected failure
        }
        try {
            session.validateAndResolveDragMimeTypeExtras(
                    createClipDataForShortcut("test_package", "test_shortcut_id", null),
                    TEST_UID, TEST_PID, TEST_PACKAGE);
            fail("Expected failure without package name");
        } catch (IllegalArgumentException e) {
            // Expected failure
        }
    }

    private ClipData createClipDataForShortcut(String packageName, String shortcutId,
            UserHandle user) {
        final Intent data = new Intent();
        if (packageName != null) {
            data.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
        }
        if (shortcutId != null) {
            data.putExtra(Intent.EXTRA_SHORTCUT_ID, shortcutId);
        }
        if (user != null) {
            data.putExtra(Intent.EXTRA_USER, user);
        }
        final ClipData clipData = new ClipData(
                new ClipDescription("drag", new String[] {
                        MIMETYPE_APPLICATION_SHORTCUT}),
                new ClipData.Item(data));
        return clipData;
    }

    @Test
@@ -308,7 +338,8 @@ public class DragDropControllerTests extends WindowTestsBase {
                    new ClipDescription("drag", new String[] { MIMETYPE_APPLICATION_TASK }),
                    new ClipData.Item(new Intent()));

            session.validateAndResolveDragMimeTypeExtras(clipData, TEST_UID);
            session.validateAndResolveDragMimeTypeExtras(clipData, TEST_UID, TEST_PID,
                    TEST_PACKAGE);
            fail("Expected failure without task id");
        } catch (IllegalArgumentException e) {
            // Expected failure