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

Commit 93d5e803 authored by Varun Shah's avatar Varun Shah Committed by Android (Google) Code Review
Browse files

Merge "Privileged apps can now launch their activities across profiles."

parents 62b6a1d0 acad138e
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -91,6 +91,7 @@ package android {
    field public static final java.lang.String INSTALL_PACKAGE_UPDATES = "android.permission.INSTALL_PACKAGE_UPDATES";
    field public static final java.lang.String INSTALL_SELF_UPDATES = "android.permission.INSTALL_SELF_UPDATES";
    field public static final java.lang.String INTENT_FILTER_VERIFICATION_AGENT = "android.permission.INTENT_FILTER_VERIFICATION_AGENT";
    field public static final java.lang.String INTERACT_ACROSS_PROFILES = "android.permission.INTERACT_ACROSS_PROFILES";
    field public static final java.lang.String INTERACT_ACROSS_USERS = "android.permission.INTERACT_ACROSS_USERS";
    field public static final java.lang.String INTERACT_ACROSS_USERS_FULL = "android.permission.INTERACT_ACROSS_USERS_FULL";
    field public static final java.lang.String INTERNAL_SYSTEM_WINDOW = "android.permission.INTERNAL_SYSTEM_WINDOW";
@@ -1141,6 +1142,10 @@ package android.content.pm {
    field public int targetSandboxVersion;
  }

  public class CrossProfileApps {
    method public void startAnyActivity(android.content.ComponentName, android.os.UserHandle);
  }

  public final class InstantAppInfo implements android.os.Parcelable {
    ctor public InstantAppInfo(android.content.pm.ApplicationInfo, java.lang.String[], java.lang.String[]);
    ctor public InstantAppInfo(java.lang.String, java.lang.CharSequence, java.lang.String[], java.lang.String[]);
+26 −1
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@
package android.content.pm;

import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.content.ComponentName;
import android.content.Context;
import android.content.res.Resources;
@@ -66,7 +68,30 @@ public class CrossProfileApps {
                    mContext.getIApplicationThread(),
                    mContext.getPackageName(),
                    component,
                    targetUser);
                    targetUser.getIdentifier(),
                    true);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
    }

    /**
     * Starts the specified activity of the caller package in the specified profile if the caller
     * has {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES} permission and
     * both the caller and target user profiles are in the same user group.
     *
     * @param component The ComponentName of the activity to launch. It must be exported.
     * @param targetUser The UserHandle of the profile, must be one of the users returned by
     *        {@link #getTargetUserProfiles()}, otherwise a {@link SecurityException} will
     *        be thrown.
     * @hide
     */
    @SystemApi
    @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_PROFILES)
    public void startAnyActivity(@NonNull ComponentName component, @NonNull UserHandle targetUser) {
        try {
            mService.startActivityAsUser(mContext.getIApplicationThread(),
                    mContext.getPackageName(), component, targetUser.getIdentifier(), false);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
+1 −1
Original line number Diff line number Diff line
@@ -28,6 +28,6 @@ import android.os.UserHandle;
 */
interface ICrossProfileApps {
    void startActivityAsUser(in IApplicationThread caller, in String callingPackage,
            in ComponentName component, in UserHandle user);
            in ComponentName component, int userId, boolean launchMainActivity);
    List<UserHandle> getTargetUserProfiles(in String callingPackage);
}
 No newline at end of file
+7 −0
Original line number Diff line number Diff line
@@ -2171,6 +2171,13 @@
    <permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"
        android:protectionLevel="signature|installer" />

    <!-- @SystemApi Allows an application to start an activity within its managed profile from
         the personal profile.
         This permission is not available to third party applications.
         @hide -->
    <permission android:name="android.permission.INTERACT_ACROSS_PROFILES"
        android:protectionLevel="signature|privileged" />

    <!-- @SystemApi @hide Allows an application to call APIs that allow it to query and manage
         users on the device. This permission is not available to
         third party applications. -->
+43 −22
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;

import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.ActivityOptions;
import android.app.AppOpsManager;
@@ -77,18 +78,20 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
            IApplicationThread caller,
            String callingPackage,
            ComponentName component,
            UserHandle user) throws RemoteException {
            @UserIdInt int userId,
            boolean launchMainActivity) throws RemoteException {
        Preconditions.checkNotNull(callingPackage);
        Preconditions.checkNotNull(component);
        Preconditions.checkNotNull(user);

        verifyCallingPackage(callingPackage);

        final int callerUserId = mInjector.getCallingUserId();
        final int callingUid = mInjector.getCallingUid();

        List<UserHandle> allowedTargetUsers = getTargetUserProfilesUnchecked(
                callingPackage, mInjector.getCallingUserId());
        if (!allowedTargetUsers.contains(user)) {
            throw new SecurityException(
                    callingPackage + " cannot access unrelated user " + user.getIdentifier());
                callingPackage, callerUserId);
        if (!allowedTargetUsers.contains(UserHandle.of(userId))) {
            throw new SecurityException(callingPackage + " cannot access unrelated user " + userId);
        }

        // Verify that caller package is starting activity in its own package.
@@ -98,25 +101,43 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
                            + component.getPackageName());
        }

        final int callingUid = mInjector.getCallingUid();

        // Verify that target activity does handle the intent with ACTION_MAIN and
        // CATEGORY_LAUNCHER as calling startActivityAsUser ignore them if component is present.
        final Intent launchIntent = new Intent(Intent.ACTION_MAIN);
        // Verify that target activity does handle the intent correctly.
        final Intent launchIntent = new Intent();
        if (launchMainActivity) {
            launchIntent.setAction(Intent.ACTION_MAIN);
            launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
            launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                    | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
        // Only package name is set here, as opposed to component name, because intent action and
        // category are ignored if component name is present while we are resolving intent.
            // Only package name is set here, as opposed to component name, because intent action
            // and category are ignored if component name is present while we are resolving intent.
            launchIntent.setPackage(component.getPackageName());
        verifyActivityCanHandleIntentAndExported(launchIntent, component, callingUid, user);
        } else {
            // If the main activity is not being launched and the users are different, the caller
            // must have the required permission and the users must be in the same profile group
            // in order to launch any of its own activities.
            if (callerUserId != userId) {
                final int permissionFlag = ActivityManager.checkComponentPermission(
                        android.Manifest.permission.INTERACT_ACROSS_PROFILES, callingUid,
                        -1, true);
                if (permissionFlag != PackageManager.PERMISSION_GRANTED
                        || !mInjector.getUserManager().isSameProfileGroup(callerUserId, userId)) {
                    throw new SecurityException("Attempt to launch activity without required "
                            + android.Manifest.permission.INTERACT_ACROSS_PROFILES + " permission"
                            + " or target user is not in the same profile group.");
                }
            }
            launchIntent.setComponent(component);
        }
        verifyActivityCanHandleIntentAndExported(launchIntent, component, callingUid, userId);

        launchIntent.setPackage(null);
        launchIntent.setComponent(component);
        mInjector.getActivityTaskManagerInternal().startActivityAsUser(
                caller, callingPackage, launchIntent,
                ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle(),
                user.getIdentifier());
                launchMainActivity
                        ? ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle()
                        : null,
                userId);
    }

    private List<UserHandle> getTargetUserProfilesUnchecked(
@@ -163,7 +184,7 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
     * activity is exported.
     */
    private void verifyActivityCanHandleIntentAndExported(
            Intent launchIntent, ComponentName component, int callingUid, UserHandle user) {
            Intent launchIntent, ComponentName component, int callingUid, @UserIdInt int userId) {
        final long ident = mInjector.clearCallingIdentity();
        try {
            final List<ResolveInfo> apps =
@@ -171,7 +192,7 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
                            launchIntent,
                            MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
                            callingUid,
                            user.getIdentifier());
                            userId);
            final int size = apps.size();
            for (int i = 0; i < size; ++i) {
                final ActivityInfo activityInfo = apps.get(i).activityInfo;
Loading