Loading api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -11399,6 +11399,7 @@ package android.content.pm { method @NonNull public CharSequence getProfileSwitchingLabel(@NonNull android.os.UserHandle); method @NonNull public java.util.List<android.os.UserHandle> getTargetUserProfiles(); 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"; } public final class FeatureGroupInfo implements android.os.Parcelable { core/java/android/content/pm/CrossProfileApps.java +45 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.app.AppOpsManager.Mode; import android.content.ComponentName; import android.content.Context; import android.content.Intent; Loading @@ -42,6 +43,18 @@ import java.util.Set; * use this class to start its main activity in managed profile. */ public class CrossProfileApps { /** * Broadcast signalling that the receiving app's ability to interact across profiles has * changed, as defined by the return value of {@link #canInteractAcrossProfiles()}. * * <p>Apps that have set the {@code android:crossProfile} manifest attribute to {@code true} * can receive this broadcast in manifest broadcast receivers. Otherwise, it can only be * received by dynamically-registered broadcast receivers. */ public static final String ACTION_CAN_INTERACT_ACROSS_PROFILES_CHANGED = "android.content.pm.action.CAN_INTERACT_ACROSS_PROFILES_CHANGED"; private final Context mContext; private final ICrossProfileApps mService; private final UserManager mUserManager; Loading Loading @@ -254,6 +267,38 @@ public class CrossProfileApps { return settingsIntent; } /** * Sets the app-op for {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES} that is * configurable by users in Settings. This configures it for the profile group of the calling * package. * * <p>Before calling, check {@link #canRequestInteractAcrossProfiles()} and do not call if it is * {@code false}. If presenting a user interface, do not allow the user to configure the app-op * in that case. * * <p>The underlying app-op {@link android.app.AppOpsManager#OP_INTERACT_ACROSS_PROFILES} should * never be set directly. This method ensures that the app-op is kept in sync for the app across * each user in the profile group and that those apps are sent a broadcast when their ability to * interact across profiles changes. * * <p>This method should be used whenever an app's ability to interact across profiles changes, * as defined by the return value of {@link #canInteractAcrossProfiles()}. This includes user * consent changes in Settings or during provisioning, plus changes to the admin or OEM consent * whitelists that make the current app-op value invalid. * * @hide */ @RequiresPermission( allOf={android.Manifest.permission.MANAGE_APP_OPS_MODES, android.Manifest.permission.INTERACT_ACROSS_USERS}) public void setInteractAcrossProfilesAppOp(@NonNull String packageName, @Mode int newMode) { try { mService.setInteractAcrossProfilesAppOp(packageName, newMode); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } } private void verifyCanAccessUser(UserHandle userHandle) { if (!getTargetUserProfiles().contains(userHandle)) { throw new SecurityException("Not allowed to access " + userHandle); Loading core/java/android/content/pm/ICrossProfileApps.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -32,4 +32,5 @@ interface ICrossProfileApps { List<UserHandle> getTargetUserProfiles(in String callingPackage); boolean canInteractAcrossProfiles(in String callingPackage); boolean canRequestInteractAcrossProfiles(in String callingPackage); void setInteractAcrossProfilesAppOp(in String packageName, int newMode); } No newline at end of file services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java +145 −15 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.server.pm; import static android.app.AppOpsManager.OP_INTERACT_ACROSS_PROFILES; import static android.content.Intent.FLAG_RECEIVER_REGISTERED_ONLY; import static android.content.pm.CrossProfileApps.ACTION_CAN_INTERACT_ACROSS_PROFILES_CHANGED; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; Loading @@ -26,6 +28,7 @@ import android.app.ActivityManagerInternal; import android.app.ActivityOptions; import android.app.AppGlobals; import android.app.AppOpsManager; import android.app.AppOpsManager.Mode; import android.app.IApplicationThread; import android.app.admin.DevicePolicyEventLogger; import android.app.admin.DevicePolicyManagerInternal; Loading Loading @@ -66,8 +69,6 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { private Context mContext; private Injector mInjector; private AppOpsService mAppOpsService; private final DevicePolicyManagerInternal mDpmi; private final IPackageManager mIpm; public CrossProfileAppsServiceImpl(Context context) { this(context, new InjectorImpl(context)); Loading @@ -77,8 +78,6 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { CrossProfileAppsServiceImpl(Context context, Injector injector) { mContext = context; mInjector = injector; mIpm = AppGlobals.getPackageManager(); mDpmi = LocalServices.getService(DevicePolicyManagerInternal.class); } @Override Loading Loading @@ -144,7 +143,7 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { // 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( final int permissionFlag = mInjector.checkComponentPermission( android.Manifest.permission.INTERACT_ACROSS_PROFILES, callingUid, -1, true); if (permissionFlag != PackageManager.PERMISSION_GRANTED Loading Loading @@ -172,23 +171,27 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { public boolean canRequestInteractAcrossProfiles(String callingPackage) { Objects.requireNonNull(callingPackage); verifyCallingPackage(callingPackage); final List<UserHandle> targetUserProfiles = getTargetUserProfilesUnchecked( return canRequestInteractAcrossProfilesUnchecked( callingPackage, mInjector.getCallingUserId()); } private boolean canRequestInteractAcrossProfilesUnchecked( String packageName, @UserIdInt int userId) { List<UserHandle> targetUserProfiles = getTargetUserProfilesUnchecked(packageName, userId); if (targetUserProfiles.isEmpty()) { return false; } if (!hasRequestedAppOpPermission( AppOpsManager.opToPermission(OP_INTERACT_ACROSS_PROFILES), callingPackage)) { AppOpsManager.opToPermission(OP_INTERACT_ACROSS_PROFILES), packageName)) { return false; } return isCrossProfilePackageWhitelisted(callingPackage); return isCrossProfilePackageWhitelisted(packageName); } private boolean hasRequestedAppOpPermission(String permission, String packageName) { try { String[] packages = mIpm.getAppOpPermissionPackages(permission); String[] packages = mInjector.getIPackageManager().getAppOpPermissionPackages(permission); return ArrayUtils.contains(packages, packageName); } catch (RemoteException exc) { Slog.e(TAG, "PackageManager dead. Cannot get permission info"); Loading @@ -206,7 +209,6 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { if (targetUserProfiles.isEmpty()) { return false; } final int callingUid = mInjector.getCallingUid(); return isPermissionGranted(Manifest.permission.INTERACT_ACROSS_USERS_FULL, callingUid) || isPermissionGranted(Manifest.permission.INTERACT_ACROSS_USERS, callingUid) Loading @@ -219,7 +221,8 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { private boolean isCrossProfilePackageWhitelisted(String packageName) { final long ident = mInjector.clearCallingIdentity(); try { return mDpmi.getAllCrossProfilePackages().contains(packageName); return mInjector.getDevicePolicyManagerInternal() .getAllCrossProfilePackages().contains(packageName); } finally { mInjector.restoreCallingIdentity(ident); } Loading Loading @@ -295,6 +298,104 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { } } @Override public void setInteractAcrossProfilesAppOp(String packageName, @Mode int newMode) { final int callingUid = mInjector.getCallingUid(); if (!isPermissionGranted(Manifest.permission.INTERACT_ACROSS_USERS_FULL, callingUid) && !isPermissionGranted(Manifest.permission.INTERACT_ACROSS_USERS, callingUid)) { throw new SecurityException( "INTERACT_ACROSS_USERS or INTERACT_ACROSS_USERS_FULL is required to set the" + " app-op for interacting across profiles."); } if (!isPermissionGranted(Manifest.permission.MANAGE_APP_OPS_MODES, callingUid)) { throw new SecurityException( "MANAGE_APP_OPS_MODES is required to set the app-op for interacting across" + " profiles."); } final int callingUserId = mInjector.getCallingUserId(); if (newMode == AppOpsManager.MODE_ALLOWED && !canRequestInteractAcrossProfilesUnchecked(packageName, callingUserId)) { // The user should not be prompted for apps that cannot request to interact across // profiles. However, we return early here if required to avoid race conditions. Slog.e(TAG, "Tried to turn on the appop for interacting across profiles for invalid" + " app " + packageName); return; } final int[] profileIds = mInjector.getUserManager().getProfileIds(callingUserId, /* enabledOnly= */ false); for (int profileId : profileIds) { if (!isPackageInstalled(packageName, profileId)) { continue; } setInteractAcrossProfilesAppOpForUser(packageName, newMode, profileId); } } private boolean isPackageInstalled(String packageName, @UserIdInt int userId) { final int callingUid = mInjector.getCallingUid(); final long identity = mInjector.clearCallingIdentity(); try { final PackageInfo info = mInjector.getPackageManagerInternal() .getPackageInfo( packageName, MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, callingUid, userId); return info != null; } finally { mInjector.restoreCallingIdentity(identity); } } private void setInteractAcrossProfilesAppOpForUser( String packageName, @Mode int newMode, @UserIdInt int userId) { try { setInteractAcrossProfilesAppOpForUserOrThrow(packageName, newMode, userId); } catch (PackageManager.NameNotFoundException e) { Slog.e(TAG, "Missing package " + packageName + " on user ID " + userId, e); } } private void setInteractAcrossProfilesAppOpForUserOrThrow( String packageName, @Mode int newMode, @UserIdInt int userId) throws PackageManager.NameNotFoundException { final int uid = mInjector.getPackageManager() .getPackageUidAsUser(packageName, /* flags= */ 0, userId); if (currentModeEquals(newMode, packageName, uid)) { Slog.w(TAG,"Attempt to set mode to existing value of " + newMode + " for " + packageName + " on user ID " + userId); return; } mInjector.getAppOpsManager() .setMode(OP_INTERACT_ACROSS_PROFILES, uid, packageName, newMode); sendCanInteractAcrossProfilesChangedBroadcast(packageName, uid, UserHandle.of(userId)); } private boolean currentModeEquals(@Mode int otherMode, String packageName, int uid) { final String op = AppOpsManager.permissionToOp(Manifest.permission.INTERACT_ACROSS_PROFILES); return otherMode == mInjector.getAppOpsManager().unsafeCheckOpNoThrow(op, uid, packageName); } private void sendCanInteractAcrossProfilesChangedBroadcast( String packageName, int uid, UserHandle userHandle) { final Intent intent = new Intent(ACTION_CAN_INTERACT_ACROSS_PROFILES_CHANGED) .setPackage(packageName); if (!appDeclaresCrossProfileAttribute(uid)) { intent.addFlags(FLAG_RECEIVER_REGISTERED_ONLY); } mInjector.sendBroadcastAsUser(intent, userHandle); } private boolean appDeclaresCrossProfileAttribute(int uid) { return mInjector.getPackageManagerInternal().getPackage(uid).isCrossProfile(); } private boolean isSameProfileGroup(@UserIdInt int callerUserId, @UserIdInt int userId) { final long ident = mInjector.clearCallingIdentity(); try { Loading @@ -311,8 +412,8 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { mInjector.getAppOpsManager().checkPackage(mInjector.getCallingUid(), callingPackage); } private static boolean isPermissionGranted(String permission, int uid) { return PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission( private boolean isPermissionGranted(String permission, int uid) { return PackageManager.PERMISSION_GRANTED == mInjector.checkComponentPermission( permission, uid, /* owningUid= */-1, /* exported= */ true); } Loading Loading @@ -376,6 +477,27 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { public ActivityTaskManagerInternal getActivityTaskManagerInternal() { return LocalServices.getService(ActivityTaskManagerInternal.class); } @Override public IPackageManager getIPackageManager() { return AppGlobals.getPackageManager(); } @Override public DevicePolicyManagerInternal getDevicePolicyManagerInternal() { return LocalServices.getService(DevicePolicyManagerInternal.class); } @Override public void sendBroadcastAsUser(Intent intent, UserHandle user) { mContext.sendBroadcastAsUser(intent, user); } @Override public int checkComponentPermission( String permission, int uid, int owningUid, boolean exported) { return ActivityManager.checkComponentPermission(permission, uid, owningUid, exported); } } @VisibleForTesting Loading @@ -401,5 +523,13 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { ActivityManagerInternal getActivityManagerInternal(); ActivityTaskManagerInternal getActivityTaskManagerInternal(); IPackageManager getIPackageManager(); DevicePolicyManagerInternal getDevicePolicyManagerInternal(); void sendBroadcastAsUser(Intent intent, UserHandle user); int checkComponentPermission(String permission, int uid, int owningUid, boolean exported); } } services/robotests/Android.bp +3 −0 Original line number Diff line number Diff line Loading @@ -43,6 +43,9 @@ android_robolectric_test { "platform-test-annotations", "testng", ], static_libs: [ "androidx.test.ext.truth", ], instrumentation_for: "FrameworksServicesLib", } Loading Loading
api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -11399,6 +11399,7 @@ package android.content.pm { method @NonNull public CharSequence getProfileSwitchingLabel(@NonNull android.os.UserHandle); method @NonNull public java.util.List<android.os.UserHandle> getTargetUserProfiles(); 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"; } public final class FeatureGroupInfo implements android.os.Parcelable {
core/java/android/content/pm/CrossProfileApps.java +45 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.app.AppOpsManager.Mode; import android.content.ComponentName; import android.content.Context; import android.content.Intent; Loading @@ -42,6 +43,18 @@ import java.util.Set; * use this class to start its main activity in managed profile. */ public class CrossProfileApps { /** * Broadcast signalling that the receiving app's ability to interact across profiles has * changed, as defined by the return value of {@link #canInteractAcrossProfiles()}. * * <p>Apps that have set the {@code android:crossProfile} manifest attribute to {@code true} * can receive this broadcast in manifest broadcast receivers. Otherwise, it can only be * received by dynamically-registered broadcast receivers. */ public static final String ACTION_CAN_INTERACT_ACROSS_PROFILES_CHANGED = "android.content.pm.action.CAN_INTERACT_ACROSS_PROFILES_CHANGED"; private final Context mContext; private final ICrossProfileApps mService; private final UserManager mUserManager; Loading Loading @@ -254,6 +267,38 @@ public class CrossProfileApps { return settingsIntent; } /** * Sets the app-op for {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES} that is * configurable by users in Settings. This configures it for the profile group of the calling * package. * * <p>Before calling, check {@link #canRequestInteractAcrossProfiles()} and do not call if it is * {@code false}. If presenting a user interface, do not allow the user to configure the app-op * in that case. * * <p>The underlying app-op {@link android.app.AppOpsManager#OP_INTERACT_ACROSS_PROFILES} should * never be set directly. This method ensures that the app-op is kept in sync for the app across * each user in the profile group and that those apps are sent a broadcast when their ability to * interact across profiles changes. * * <p>This method should be used whenever an app's ability to interact across profiles changes, * as defined by the return value of {@link #canInteractAcrossProfiles()}. This includes user * consent changes in Settings or during provisioning, plus changes to the admin or OEM consent * whitelists that make the current app-op value invalid. * * @hide */ @RequiresPermission( allOf={android.Manifest.permission.MANAGE_APP_OPS_MODES, android.Manifest.permission.INTERACT_ACROSS_USERS}) public void setInteractAcrossProfilesAppOp(@NonNull String packageName, @Mode int newMode) { try { mService.setInteractAcrossProfilesAppOp(packageName, newMode); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } } private void verifyCanAccessUser(UserHandle userHandle) { if (!getTargetUserProfiles().contains(userHandle)) { throw new SecurityException("Not allowed to access " + userHandle); Loading
core/java/android/content/pm/ICrossProfileApps.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -32,4 +32,5 @@ interface ICrossProfileApps { List<UserHandle> getTargetUserProfiles(in String callingPackage); boolean canInteractAcrossProfiles(in String callingPackage); boolean canRequestInteractAcrossProfiles(in String callingPackage); void setInteractAcrossProfilesAppOp(in String packageName, int newMode); } No newline at end of file
services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java +145 −15 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.server.pm; import static android.app.AppOpsManager.OP_INTERACT_ACROSS_PROFILES; import static android.content.Intent.FLAG_RECEIVER_REGISTERED_ONLY; import static android.content.pm.CrossProfileApps.ACTION_CAN_INTERACT_ACROSS_PROFILES_CHANGED; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; Loading @@ -26,6 +28,7 @@ import android.app.ActivityManagerInternal; import android.app.ActivityOptions; import android.app.AppGlobals; import android.app.AppOpsManager; import android.app.AppOpsManager.Mode; import android.app.IApplicationThread; import android.app.admin.DevicePolicyEventLogger; import android.app.admin.DevicePolicyManagerInternal; Loading Loading @@ -66,8 +69,6 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { private Context mContext; private Injector mInjector; private AppOpsService mAppOpsService; private final DevicePolicyManagerInternal mDpmi; private final IPackageManager mIpm; public CrossProfileAppsServiceImpl(Context context) { this(context, new InjectorImpl(context)); Loading @@ -77,8 +78,6 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { CrossProfileAppsServiceImpl(Context context, Injector injector) { mContext = context; mInjector = injector; mIpm = AppGlobals.getPackageManager(); mDpmi = LocalServices.getService(DevicePolicyManagerInternal.class); } @Override Loading Loading @@ -144,7 +143,7 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { // 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( final int permissionFlag = mInjector.checkComponentPermission( android.Manifest.permission.INTERACT_ACROSS_PROFILES, callingUid, -1, true); if (permissionFlag != PackageManager.PERMISSION_GRANTED Loading Loading @@ -172,23 +171,27 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { public boolean canRequestInteractAcrossProfiles(String callingPackage) { Objects.requireNonNull(callingPackage); verifyCallingPackage(callingPackage); final List<UserHandle> targetUserProfiles = getTargetUserProfilesUnchecked( return canRequestInteractAcrossProfilesUnchecked( callingPackage, mInjector.getCallingUserId()); } private boolean canRequestInteractAcrossProfilesUnchecked( String packageName, @UserIdInt int userId) { List<UserHandle> targetUserProfiles = getTargetUserProfilesUnchecked(packageName, userId); if (targetUserProfiles.isEmpty()) { return false; } if (!hasRequestedAppOpPermission( AppOpsManager.opToPermission(OP_INTERACT_ACROSS_PROFILES), callingPackage)) { AppOpsManager.opToPermission(OP_INTERACT_ACROSS_PROFILES), packageName)) { return false; } return isCrossProfilePackageWhitelisted(callingPackage); return isCrossProfilePackageWhitelisted(packageName); } private boolean hasRequestedAppOpPermission(String permission, String packageName) { try { String[] packages = mIpm.getAppOpPermissionPackages(permission); String[] packages = mInjector.getIPackageManager().getAppOpPermissionPackages(permission); return ArrayUtils.contains(packages, packageName); } catch (RemoteException exc) { Slog.e(TAG, "PackageManager dead. Cannot get permission info"); Loading @@ -206,7 +209,6 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { if (targetUserProfiles.isEmpty()) { return false; } final int callingUid = mInjector.getCallingUid(); return isPermissionGranted(Manifest.permission.INTERACT_ACROSS_USERS_FULL, callingUid) || isPermissionGranted(Manifest.permission.INTERACT_ACROSS_USERS, callingUid) Loading @@ -219,7 +221,8 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { private boolean isCrossProfilePackageWhitelisted(String packageName) { final long ident = mInjector.clearCallingIdentity(); try { return mDpmi.getAllCrossProfilePackages().contains(packageName); return mInjector.getDevicePolicyManagerInternal() .getAllCrossProfilePackages().contains(packageName); } finally { mInjector.restoreCallingIdentity(ident); } Loading Loading @@ -295,6 +298,104 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { } } @Override public void setInteractAcrossProfilesAppOp(String packageName, @Mode int newMode) { final int callingUid = mInjector.getCallingUid(); if (!isPermissionGranted(Manifest.permission.INTERACT_ACROSS_USERS_FULL, callingUid) && !isPermissionGranted(Manifest.permission.INTERACT_ACROSS_USERS, callingUid)) { throw new SecurityException( "INTERACT_ACROSS_USERS or INTERACT_ACROSS_USERS_FULL is required to set the" + " app-op for interacting across profiles."); } if (!isPermissionGranted(Manifest.permission.MANAGE_APP_OPS_MODES, callingUid)) { throw new SecurityException( "MANAGE_APP_OPS_MODES is required to set the app-op for interacting across" + " profiles."); } final int callingUserId = mInjector.getCallingUserId(); if (newMode == AppOpsManager.MODE_ALLOWED && !canRequestInteractAcrossProfilesUnchecked(packageName, callingUserId)) { // The user should not be prompted for apps that cannot request to interact across // profiles. However, we return early here if required to avoid race conditions. Slog.e(TAG, "Tried to turn on the appop for interacting across profiles for invalid" + " app " + packageName); return; } final int[] profileIds = mInjector.getUserManager().getProfileIds(callingUserId, /* enabledOnly= */ false); for (int profileId : profileIds) { if (!isPackageInstalled(packageName, profileId)) { continue; } setInteractAcrossProfilesAppOpForUser(packageName, newMode, profileId); } } private boolean isPackageInstalled(String packageName, @UserIdInt int userId) { final int callingUid = mInjector.getCallingUid(); final long identity = mInjector.clearCallingIdentity(); try { final PackageInfo info = mInjector.getPackageManagerInternal() .getPackageInfo( packageName, MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, callingUid, userId); return info != null; } finally { mInjector.restoreCallingIdentity(identity); } } private void setInteractAcrossProfilesAppOpForUser( String packageName, @Mode int newMode, @UserIdInt int userId) { try { setInteractAcrossProfilesAppOpForUserOrThrow(packageName, newMode, userId); } catch (PackageManager.NameNotFoundException e) { Slog.e(TAG, "Missing package " + packageName + " on user ID " + userId, e); } } private void setInteractAcrossProfilesAppOpForUserOrThrow( String packageName, @Mode int newMode, @UserIdInt int userId) throws PackageManager.NameNotFoundException { final int uid = mInjector.getPackageManager() .getPackageUidAsUser(packageName, /* flags= */ 0, userId); if (currentModeEquals(newMode, packageName, uid)) { Slog.w(TAG,"Attempt to set mode to existing value of " + newMode + " for " + packageName + " on user ID " + userId); return; } mInjector.getAppOpsManager() .setMode(OP_INTERACT_ACROSS_PROFILES, uid, packageName, newMode); sendCanInteractAcrossProfilesChangedBroadcast(packageName, uid, UserHandle.of(userId)); } private boolean currentModeEquals(@Mode int otherMode, String packageName, int uid) { final String op = AppOpsManager.permissionToOp(Manifest.permission.INTERACT_ACROSS_PROFILES); return otherMode == mInjector.getAppOpsManager().unsafeCheckOpNoThrow(op, uid, packageName); } private void sendCanInteractAcrossProfilesChangedBroadcast( String packageName, int uid, UserHandle userHandle) { final Intent intent = new Intent(ACTION_CAN_INTERACT_ACROSS_PROFILES_CHANGED) .setPackage(packageName); if (!appDeclaresCrossProfileAttribute(uid)) { intent.addFlags(FLAG_RECEIVER_REGISTERED_ONLY); } mInjector.sendBroadcastAsUser(intent, userHandle); } private boolean appDeclaresCrossProfileAttribute(int uid) { return mInjector.getPackageManagerInternal().getPackage(uid).isCrossProfile(); } private boolean isSameProfileGroup(@UserIdInt int callerUserId, @UserIdInt int userId) { final long ident = mInjector.clearCallingIdentity(); try { Loading @@ -311,8 +412,8 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { mInjector.getAppOpsManager().checkPackage(mInjector.getCallingUid(), callingPackage); } private static boolean isPermissionGranted(String permission, int uid) { return PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission( private boolean isPermissionGranted(String permission, int uid) { return PackageManager.PERMISSION_GRANTED == mInjector.checkComponentPermission( permission, uid, /* owningUid= */-1, /* exported= */ true); } Loading Loading @@ -376,6 +477,27 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { public ActivityTaskManagerInternal getActivityTaskManagerInternal() { return LocalServices.getService(ActivityTaskManagerInternal.class); } @Override public IPackageManager getIPackageManager() { return AppGlobals.getPackageManager(); } @Override public DevicePolicyManagerInternal getDevicePolicyManagerInternal() { return LocalServices.getService(DevicePolicyManagerInternal.class); } @Override public void sendBroadcastAsUser(Intent intent, UserHandle user) { mContext.sendBroadcastAsUser(intent, user); } @Override public int checkComponentPermission( String permission, int uid, int owningUid, boolean exported) { return ActivityManager.checkComponentPermission(permission, uid, owningUid, exported); } } @VisibleForTesting Loading @@ -401,5 +523,13 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { ActivityManagerInternal getActivityManagerInternal(); ActivityTaskManagerInternal getActivityTaskManagerInternal(); IPackageManager getIPackageManager(); DevicePolicyManagerInternal getDevicePolicyManagerInternal(); void sendBroadcastAsUser(Intent intent, UserHandle user); int checkComponentPermission(String permission, int uid, int owningUid, boolean exported); } }
services/robotests/Android.bp +3 −0 Original line number Diff line number Diff line Loading @@ -43,6 +43,9 @@ android_robolectric_test { "platform-test-annotations", "testng", ], static_libs: [ "androidx.test.ext.truth", ], instrumentation_for: "FrameworksServicesLib", } Loading