Loading api/system-current.txt +5 −0 Original line number Diff line number Diff line Loading @@ -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"; Loading Loading @@ -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[]); Loading core/java/android/content/pm/CrossProfileApps.java +26 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); } Loading core/java/android/content/pm/ICrossProfileApps.aidl +1 −1 Original line number Diff line number Diff line Loading @@ -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 core/res/AndroidManifest.xml +7 −0 Original line number Diff line number Diff line Loading @@ -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. --> Loading services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java +43 −22 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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. Loading @@ -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( Loading Loading @@ -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 = Loading @@ -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 Loading
api/system-current.txt +5 −0 Original line number Diff line number Diff line Loading @@ -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"; Loading Loading @@ -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[]); Loading
core/java/android/content/pm/CrossProfileApps.java +26 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); } Loading
core/java/android/content/pm/ICrossProfileApps.aidl +1 −1 Original line number Diff line number Diff line Loading @@ -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
core/res/AndroidManifest.xml +7 −0 Original line number Diff line number Diff line Loading @@ -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. --> Loading
services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java +43 −22 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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. Loading @@ -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( Loading Loading @@ -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 = Loading @@ -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