Add CrossProfileApps#startActivity which takes an Intent.
Test: atest com.android.cts.devicepolicy.CrossProfileAppsHostSideTest Bug: 136249261 Change-Id: I2735dc480126daf457cc1fd09bbeae243d4e3db0
This commit is contained in:
@@ -11464,6 +11464,7 @@ package android.content.pm {
|
||||
method @NonNull public android.graphics.drawable.Drawable getProfileSwitchingIconDrawable(@NonNull android.os.UserHandle);
|
||||
method @NonNull public CharSequence getProfileSwitchingLabel(@NonNull android.os.UserHandle);
|
||||
method @NonNull public java.util.List<android.os.UserHandle> getTargetUserProfiles();
|
||||
method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_PROFILES, "android.permission.INTERACT_ACROSS_USERS"}) public void startActivity(@NonNull android.content.Intent, @NonNull android.os.UserHandle);
|
||||
method public void startMainActivity(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle);
|
||||
field public static final String ACTION_CAN_INTERACT_ACROSS_PROFILES_CHANGED = "android.content.pm.action.CAN_INTERACT_ACROSS_PROFILES_CHANGED";
|
||||
}
|
||||
|
||||
@@ -93,6 +93,32 @@ public class CrossProfileApps {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the specified activity of the caller package in the specified profile.
|
||||
*
|
||||
* <p>The caller must have the {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES}
|
||||
* permission and both the caller and target user profiles must be in the same profile group.
|
||||
*
|
||||
* @param intent The intent to launch. A component in the caller package must be specified.
|
||||
* @param targetUser The {@link UserHandle} of the profile; must be one of the users returned by
|
||||
* {@link #getTargetUserProfiles()} if different to the calling user, otherwise a
|
||||
* {@link SecurityException} will be thrown.
|
||||
*/
|
||||
@RequiresPermission(anyOf = {
|
||||
android.Manifest.permission.INTERACT_ACROSS_PROFILES,
|
||||
android.Manifest.permission.INTERACT_ACROSS_USERS})
|
||||
public void startActivity(@NonNull Intent intent, @NonNull UserHandle targetUser) {
|
||||
try {
|
||||
mService.startActivityAsUserByIntent(
|
||||
mContext.getIApplicationThread(),
|
||||
mContext.getPackageName(),
|
||||
intent,
|
||||
targetUser.getIdentifier());
|
||||
} catch (RemoteException ex) {
|
||||
throw ex.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the specified activity of the caller package in the specified profile. Unlike
|
||||
* {@link #startMainActivity}, this can start any activity of the caller package, not just
|
||||
|
||||
@@ -29,6 +29,8 @@ import android.os.UserHandle;
|
||||
interface ICrossProfileApps {
|
||||
void startActivityAsUser(in IApplicationThread caller, in String callingPackage,
|
||||
in ComponentName component, int userId, boolean launchMainActivity);
|
||||
void startActivityAsUserByIntent(in IApplicationThread caller, in String callingPackage,
|
||||
in Intent intent, int userId);
|
||||
List<UserHandle> getTargetUserProfiles(in String callingPackage);
|
||||
boolean canInteractAcrossProfiles(in String callingPackage);
|
||||
boolean canRequestInteractAcrossProfiles(in String callingPackage);
|
||||
|
||||
@@ -167,6 +167,50 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
|
||||
userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startActivityAsUserByIntent(
|
||||
IApplicationThread caller,
|
||||
String callingPackage,
|
||||
Intent intent,
|
||||
@UserIdInt int userId) throws RemoteException {
|
||||
Objects.requireNonNull(callingPackage);
|
||||
Objects.requireNonNull(intent);
|
||||
Objects.requireNonNull(intent.getComponent(), "The intent must have a Component set");
|
||||
|
||||
verifyCallingPackage(callingPackage);
|
||||
|
||||
final int callerUserId = mInjector.getCallingUserId();
|
||||
final int callingUid = mInjector.getCallingUid();
|
||||
|
||||
List<UserHandle> allowedTargetUsers = getTargetUserProfilesUnchecked(
|
||||
callingPackage, callerUserId);
|
||||
if (callerUserId != userId && !allowedTargetUsers.contains(UserHandle.of(userId))) {
|
||||
throw new SecurityException(callingPackage + " cannot access unrelated user " + userId);
|
||||
}
|
||||
|
||||
Intent launchIntent = new Intent(intent);
|
||||
launchIntent.setPackage(callingPackage);
|
||||
|
||||
if (!callingPackage.equals(launchIntent.getComponent().getPackageName())) {
|
||||
throw new SecurityException(
|
||||
callingPackage + " attempts to start an activity in other package - "
|
||||
+ launchIntent.getComponent().getPackageName());
|
||||
}
|
||||
|
||||
if (callerUserId != userId) {
|
||||
if (!hasInteractAcrossProfilesPermission(callingPackage)) {
|
||||
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.");
|
||||
}
|
||||
}
|
||||
|
||||
verifyActivityCanHandleIntent(launchIntent, callingUid, userId);
|
||||
|
||||
mInjector.getActivityTaskManagerInternal().startActivityAsUser(
|
||||
caller, callingPackage, launchIntent, /* options= */ null, userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRequestInteractAcrossProfiles(String callingPackage) {
|
||||
Objects.requireNonNull(callingPackage);
|
||||
@@ -209,6 +253,11 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
|
||||
if (targetUserProfiles.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return hasInteractAcrossProfilesPermission(callingPackage);
|
||||
}
|
||||
|
||||
private boolean hasInteractAcrossProfilesPermission(String callingPackage) {
|
||||
final int callingUid = mInjector.getCallingUid();
|
||||
return isPermissionGranted(Manifest.permission.INTERACT_ACROSS_USERS_FULL, callingUid)
|
||||
|| isPermissionGranted(Manifest.permission.INTERACT_ACROSS_USERS, callingUid)
|
||||
@@ -267,6 +316,27 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyActivityCanHandleIntent(
|
||||
Intent launchIntent, int callingUid, @UserIdInt int userId) {
|
||||
final long ident = mInjector.clearCallingIdentity();
|
||||
try {
|
||||
final List<ResolveInfo> activities =
|
||||
mInjector.getPackageManagerInternal().queryIntentActivities(
|
||||
launchIntent,
|
||||
launchIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
|
||||
MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
|
||||
callingUid,
|
||||
userId);
|
||||
|
||||
if (!activities.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
throw new SecurityException("Activity cannot handle intent");
|
||||
} finally {
|
||||
mInjector.restoreCallingIdentity(ident);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the specified intent does resolved to the specified component and the resolved
|
||||
* activity is exported.
|
||||
|
||||
Reference in New Issue
Block a user