Loading core/java/android/app/admin/DevicePolicyManagerInternal.java +18 −0 Original line number Diff line number Diff line Loading @@ -187,4 +187,22 @@ public abstract class DevicePolicyManagerInternal { * @hide */ public abstract List<String> getAllCrossProfilePackages(); /** * Sends the {@code intent} to the packages with cross profile capabilities. * * <p>This means the application must have the {@code crossProfile} property and the * corresponding permissions, defined by * {@link * android.content.pm.CrossProfileAppsInternal#verifyPackageHasInteractAcrossProfilePermission}. * * <p>Note: This method doesn't modify {@code intent} but copies it before use. * * @param intent Template for the intent sent to the package. * @param parentHandle Handle of the user that will receive the intents. * @param requiresPermission If false, all packages with the {@code crossProfile} property * will receive the intent. */ public abstract void broadcastIntentToCrossProfileManifestReceiversAsUser(Intent intent, UserHandle parentHandle, boolean requiresPermission); } core/java/android/content/pm/CrossProfileAppsInternal.java 0 → 100644 +55 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.content.pm; import android.annotation.UserIdInt; /** * Exposes internal methods from {@link com.android.server.pm.CrossProfileAppsServiceImpl} to other * system server classes. * * @hide Only for use within the system server. */ public abstract class CrossProfileAppsInternal { /** * Returns whether the package has the necessary permissions to communicate cross-profile. * * <p>This means having at least one of these conditions: * <ul> * <li>{@code Manifest.permission.INTERACT_ACROSS_USERS_FULL} granted. * <li>{@code Manifest.permission.INTERACT_ACROSS_USERS} granted. * <li>{@code Manifest.permission.INTERACT_ACROSS_PROFILES} granted, or the corresponding * AppOps {@code android:interact_across_profiles} is set to "allow". * </ul> */ public abstract boolean verifyPackageHasInteractAcrossProfilePermission(String packageName, @UserIdInt int userId) throws PackageManager.NameNotFoundException; /** * Returns whether the package has the necessary permissions to communicate cross-profile. * * <p>This means having at least one of these conditions: * <ul> * <li>{@code Manifest.permission.INTERACT_ACROSS_USERS_FULL} granted. * <li>{@code Manifest.permission.INTERACT_ACROSS_USERS} granted. * <li>{@code Manifest.permission.INTERACT_ACROSS_PROFILES} granted, or the corresponding * AppOps {@code android:interact_across_profiles} is set to "allow". * </ul> */ public abstract boolean verifyUidHasInteractAcrossProfilePermission(String packageName, int uid); } services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java +31 −2 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ import android.content.Context; import android.content.Intent; import android.content.PermissionChecker; import android.content.pm.ActivityInfo; import android.content.pm.CrossProfileAppsInternal; import android.content.pm.ICrossProfileApps; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; Loading Loading @@ -81,6 +82,8 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { CrossProfileAppsServiceImpl(Context context, Injector injector) { mContext = context; mInjector = injector; LocalServices.addService(CrossProfileAppsInternal.class, new LocalService()); } @Override Loading Loading @@ -255,8 +258,8 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { Objects.requireNonNull(callingPackage); verifyCallingPackage(callingPackage); final List<UserHandle> targetUserProfiles = getTargetUserProfilesUnchecked( callingPackage, mInjector.getCallingUserId()); final List<UserHandle> targetUserProfiles = getTargetUserProfilesUnchecked(callingPackage, mInjector.getCallingUserId()); if (targetUserProfiles.isEmpty()) { return false; } Loading Loading @@ -685,4 +688,30 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { int checkComponentPermission(String permission, int uid, int owningUid, boolean exported); } class LocalService extends CrossProfileAppsInternal { @Override public boolean verifyPackageHasInteractAcrossProfilePermission(String packageName, @UserIdInt int userId) throws PackageManager.NameNotFoundException { final int uid = Objects.requireNonNull( mInjector.getPackageManager().getApplicationInfoAsUser( Objects.requireNonNull(packageName), /* flags= */ 0, userId)).uid; return verifyUidHasInteractAcrossProfilePermission(packageName, uid); } @Override public boolean verifyUidHasInteractAcrossProfilePermission(String packageName, int uid) { Objects.requireNonNull(packageName); return isPermissionGranted(Manifest.permission.INTERACT_ACROSS_USERS_FULL, uid) || isPermissionGranted(Manifest.permission.INTERACT_ACROSS_USERS, uid) || isPermissionGranted(Manifest.permission.INTERACT_ACROSS_PROFILES, uid) || PermissionChecker.checkPermissionForPreflight( mContext, Manifest.permission.INTERACT_ACROSS_PROFILES, PermissionChecker.PID_UNKNOWN, uid, packageName) == PermissionChecker.PERMISSION_GRANTED; } } } services/core/java/com/android/server/pm/UserManagerService.java +43 −4 Original line number Diff line number Diff line Loading @@ -35,13 +35,16 @@ import android.app.IStopUserCallback; import android.app.KeyguardManager; import android.app.PendingIntent; import android.app.admin.DevicePolicyEventLogger; import android.app.admin.DevicePolicyManagerInternal; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.IntentSender; import android.content.pm.CrossProfileAppsInternal; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManagerInternal; import android.content.pm.ShortcutServiceInternal; import android.content.pm.UserInfo; import android.content.pm.UserInfo.UserInfoFlag; Loading Loading @@ -258,6 +261,10 @@ public class UserManagerService extends IUserManager.Stub { /** Installs system packages based on user-type. */ private final UserSystemPackageInstaller mSystemPackageInstaller; private PackageManagerInternal mPmInternal; private CrossProfileAppsInternal mCrossProfileAppsInternal; private DevicePolicyManagerInternal mDevicePolicyManagerInternal; /** * Internal non-parcelable wrapper for UserInfo that is not exposed to other system apps. */ Loading Loading @@ -944,6 +951,8 @@ public class UserManagerService extends IUserManager.Stub { intent.putExtra(Intent.EXTRA_QUIET_MODE, inQuietMode); intent.putExtra(Intent.EXTRA_USER, profileHandle); intent.putExtra(Intent.EXTRA_USER_HANDLE, profileHandle.getIdentifier()); getDevicePolicyManagerInternal().broadcastIntentToCrossProfileManifestReceiversAsUser( intent, parentHandle, /* requiresPermission= */ true); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); mContext.sendBroadcastAsUser(intent, parentHandle); } Loading Loading @@ -3845,11 +3854,15 @@ public class UserManagerService extends IUserManager.Stub { private void sendProfileRemovedBroadcast(int parentUserId, int removedUserId) { Intent managedProfileIntent = new Intent(Intent.ACTION_MANAGED_PROFILE_REMOVED); managedProfileIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); managedProfileIntent.putExtra(Intent.EXTRA_USER, new UserHandle(removedUserId)); managedProfileIntent.putExtra(Intent.EXTRA_USER_HANDLE, removedUserId); mContext.sendBroadcastAsUser(managedProfileIntent, new UserHandle(parentUserId), null); final UserHandle parentHandle = new UserHandle(parentUserId); getDevicePolicyManagerInternal().broadcastIntentToCrossProfileManifestReceiversAsUser( managedProfileIntent, parentHandle, /* requiresPermission= */ false); managedProfileIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); mContext.sendBroadcastAsUser(managedProfileIntent, parentHandle, /* receiverPermission= */null); } @Override Loading Loading @@ -5095,7 +5108,7 @@ public class UserManagerService extends IUserManager.Stub { } /** * Check if the calling package name matches with the calling UID, throw * Checks if the calling package name matches with the calling UID, throw * {@link SecurityException} if not. */ private void verifyCallingPackage(String callingPackage, int callingUid) { Loading @@ -5105,4 +5118,30 @@ public class UserManagerService extends IUserManager.Stub { + " does not match the calling uid " + callingUid); } } /** Retrieves the internal package manager interface. */ private PackageManagerInternal getPackageManagerInternal() { // Don't need to synchonize; worst-case scenario LocalServices will be called twice. if (mPmInternal == null) { mPmInternal = LocalServices.getService(PackageManagerInternal.class); } return mPmInternal; } /** Retrieve the internal cross profile apps interface. */ private CrossProfileAppsInternal getCrossProfileAppsInternal() { if (mCrossProfileAppsInternal == null) { mCrossProfileAppsInternal = LocalServices.getService(CrossProfileAppsInternal.class); } return mCrossProfileAppsInternal; } /** Returns the internal device policy manager interface. */ private DevicePolicyManagerInternal getDevicePolicyManagerInternal() { if (mDevicePolicyManagerInternal == null) { mDevicePolicyManagerInternal = LocalServices.getService(DevicePolicyManagerInternal.class); } return mDevicePolicyManagerInternal; } } services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +108 −1 Original line number Diff line number Diff line Loading @@ -81,6 +81,8 @@ import static android.app.admin.DevicePolicyManager.WIPE_EUICC; import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE; import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA; import static android.app.admin.DevicePolicyManager.WIPE_SILENTLY; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES; import static android.provider.Settings.Global.PRIVATE_DNS_MODE; import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER; Loading @@ -92,6 +94,7 @@ import static android.security.keystore.AttestationUtils.USE_INDIVIDUAL_ATTESTAT import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ENTRY_POINT_ADB; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW; import static com.android.server.am.ActivityManagerService.STOCK_PM_FLAGS; import static com.android.server.devicepolicy.TransferOwnershipMetadataManager.ADMIN_TYPE_DEVICE_OWNER; import static com.android.server.devicepolicy.TransferOwnershipMetadataManager.ADMIN_TYPE_PROFILE_OWNER; import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; Loading Loading @@ -162,6 +165,7 @@ import android.content.PermissionChecker; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.CrossProfileApps; import android.content.pm.CrossProfileAppsInternal; import android.content.pm.IPackageDataObserver; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; Loading @@ -174,6 +178,7 @@ import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.StringParceledListSlice; import android.content.pm.UserInfo; import android.content.pm.parsing.AndroidPackage; import android.content.res.Resources; import android.database.ContentObserver; import android.database.Cursor; Loading Loading @@ -8893,9 +8898,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { UserInfo parent = mUserManager.getProfileParent(userId); Intent intent = new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED); intent.putExtra(Intent.EXTRA_USER, new UserHandle(userId)); UserHandle parentHandle = new UserHandle(parent.id); mLocalService.broadcastIntentToCrossProfileManifestReceiversAsUser(intent, parentHandle, /* requiresPermission= */ true); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); mContext.sendBroadcastAsUser(intent, new UserHandle(parent.id)); mContext.sendBroadcastAsUser(intent, parentHandle); }); } } Loading Loading @@ -12257,6 +12265,105 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return DevicePolicyManagerService.this.getAllCrossProfilePackages(); } /** * Sends the {@code intent} to the packages with cross profile capabilities. * * <p>This means the application must have the {@code crossProfile} property and * and at least one of the following permissions: * * <ul> * <li>{@link android.Manifest.permission.INTERACT_ACROSS_PROFILES} * <li>{@link android.Manifest.permission.INTERACT_ACROSS_USERS} * <li>{@link android.Manifest.permission.INTERACT_ACROSS_USERS_FULL} permission or the * {@link AppOpsManager.OP_INTERACT_ACROSS_PROFILES} app operation authorization. * </ul> * * <p>Note: The intent itself is not modified but copied before use. * * @param intent Template for the intent sent to the packages. * @param parentHandle Handle of the user that will receive the intents. * @param requiresPermission If false, all packages with the {@code crossProfile} property * will receive the intent. */ @Override public void broadcastIntentToCrossProfileManifestReceiversAsUser(Intent intent, UserHandle parentHandle, boolean requiresPermission) { Objects.requireNonNull(intent); Objects.requireNonNull(parentHandle); final int userId = parentHandle.getIdentifier(); Slog.i(LOG_TAG, String.format("Sending %s broadcast to manifest receivers.", intent.getAction())); try { final List<ResolveInfo> receivers = mIPackageManager.queryIntentReceivers( intent, /* resolvedType= */ null, STOCK_PM_FLAGS, parentHandle.getIdentifier()).getList(); for (ResolveInfo receiver : receivers) { final String packageName = receiver.getComponentInfo().packageName; if (checkCrossProfilePackagePermissions(packageName, userId, requiresPermission)) { Slog.i(LOG_TAG, String.format("Sending %s broadcast to %s.", intent.getAction(), packageName)); final Intent packageIntent = new Intent(intent) .setComponent(receiver.getComponentInfo().getComponentName()) .addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); mContext.sendBroadcastAsUser(packageIntent, parentHandle); } } } catch (RemoteException ex) { Slog.w(LOG_TAG, String.format("Cannot get list of broadcast receivers for %s because: %s.", intent.getAction(), ex)); } } /** * Checks whether the package {@code packageName} has the required permissions to receive * cross-profile broadcasts on behalf of the user {@code userId}. */ private boolean checkCrossProfilePackagePermissions(String packageName, @UserIdInt int userId, boolean requiresPermission) { final PackageManagerInternal pmInternal = LocalServices.getService( PackageManagerInternal.class); final AndroidPackage androidPackage = pmInternal.getPackage(packageName); if (androidPackage == null || !androidPackage.isCrossProfile()) { return false; } if (!requiresPermission) { return true; } if (!isPackageEnabled(packageName, userId)) { return false; } try { final CrossProfileAppsInternal crossProfileAppsService = LocalServices.getService( CrossProfileAppsInternal.class); return crossProfileAppsService.verifyPackageHasInteractAcrossProfilePermission( packageName, userId); } catch (NameNotFoundException ex) { Slog.w(LOG_TAG, String.format("Cannot find the package %s to check for permissions.", packageName)); return false; } } private boolean isPackageEnabled(String packageName, @UserIdInt int userId) { final int callingUid = Binder.getCallingUid(); final long ident = Binder.clearCallingIdentity(); try { final PackageInfo info = mInjector.getPackageManagerInternal() .getPackageInfo( packageName, MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, callingUid, userId); return info != null && info.applicationInfo.enabled; } finally { Binder.restoreCallingIdentity(ident); } } } private Intent createShowAdminSupportIntent(ComponentName admin, int userId) { Loading
core/java/android/app/admin/DevicePolicyManagerInternal.java +18 −0 Original line number Diff line number Diff line Loading @@ -187,4 +187,22 @@ public abstract class DevicePolicyManagerInternal { * @hide */ public abstract List<String> getAllCrossProfilePackages(); /** * Sends the {@code intent} to the packages with cross profile capabilities. * * <p>This means the application must have the {@code crossProfile} property and the * corresponding permissions, defined by * {@link * android.content.pm.CrossProfileAppsInternal#verifyPackageHasInteractAcrossProfilePermission}. * * <p>Note: This method doesn't modify {@code intent} but copies it before use. * * @param intent Template for the intent sent to the package. * @param parentHandle Handle of the user that will receive the intents. * @param requiresPermission If false, all packages with the {@code crossProfile} property * will receive the intent. */ public abstract void broadcastIntentToCrossProfileManifestReceiversAsUser(Intent intent, UserHandle parentHandle, boolean requiresPermission); }
core/java/android/content/pm/CrossProfileAppsInternal.java 0 → 100644 +55 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.content.pm; import android.annotation.UserIdInt; /** * Exposes internal methods from {@link com.android.server.pm.CrossProfileAppsServiceImpl} to other * system server classes. * * @hide Only for use within the system server. */ public abstract class CrossProfileAppsInternal { /** * Returns whether the package has the necessary permissions to communicate cross-profile. * * <p>This means having at least one of these conditions: * <ul> * <li>{@code Manifest.permission.INTERACT_ACROSS_USERS_FULL} granted. * <li>{@code Manifest.permission.INTERACT_ACROSS_USERS} granted. * <li>{@code Manifest.permission.INTERACT_ACROSS_PROFILES} granted, or the corresponding * AppOps {@code android:interact_across_profiles} is set to "allow". * </ul> */ public abstract boolean verifyPackageHasInteractAcrossProfilePermission(String packageName, @UserIdInt int userId) throws PackageManager.NameNotFoundException; /** * Returns whether the package has the necessary permissions to communicate cross-profile. * * <p>This means having at least one of these conditions: * <ul> * <li>{@code Manifest.permission.INTERACT_ACROSS_USERS_FULL} granted. * <li>{@code Manifest.permission.INTERACT_ACROSS_USERS} granted. * <li>{@code Manifest.permission.INTERACT_ACROSS_PROFILES} granted, or the corresponding * AppOps {@code android:interact_across_profiles} is set to "allow". * </ul> */ public abstract boolean verifyUidHasInteractAcrossProfilePermission(String packageName, int uid); }
services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java +31 −2 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ import android.content.Context; import android.content.Intent; import android.content.PermissionChecker; import android.content.pm.ActivityInfo; import android.content.pm.CrossProfileAppsInternal; import android.content.pm.ICrossProfileApps; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; Loading Loading @@ -81,6 +82,8 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { CrossProfileAppsServiceImpl(Context context, Injector injector) { mContext = context; mInjector = injector; LocalServices.addService(CrossProfileAppsInternal.class, new LocalService()); } @Override Loading Loading @@ -255,8 +258,8 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { Objects.requireNonNull(callingPackage); verifyCallingPackage(callingPackage); final List<UserHandle> targetUserProfiles = getTargetUserProfilesUnchecked( callingPackage, mInjector.getCallingUserId()); final List<UserHandle> targetUserProfiles = getTargetUserProfilesUnchecked(callingPackage, mInjector.getCallingUserId()); if (targetUserProfiles.isEmpty()) { return false; } Loading Loading @@ -685,4 +688,30 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { int checkComponentPermission(String permission, int uid, int owningUid, boolean exported); } class LocalService extends CrossProfileAppsInternal { @Override public boolean verifyPackageHasInteractAcrossProfilePermission(String packageName, @UserIdInt int userId) throws PackageManager.NameNotFoundException { final int uid = Objects.requireNonNull( mInjector.getPackageManager().getApplicationInfoAsUser( Objects.requireNonNull(packageName), /* flags= */ 0, userId)).uid; return verifyUidHasInteractAcrossProfilePermission(packageName, uid); } @Override public boolean verifyUidHasInteractAcrossProfilePermission(String packageName, int uid) { Objects.requireNonNull(packageName); return isPermissionGranted(Manifest.permission.INTERACT_ACROSS_USERS_FULL, uid) || isPermissionGranted(Manifest.permission.INTERACT_ACROSS_USERS, uid) || isPermissionGranted(Manifest.permission.INTERACT_ACROSS_PROFILES, uid) || PermissionChecker.checkPermissionForPreflight( mContext, Manifest.permission.INTERACT_ACROSS_PROFILES, PermissionChecker.PID_UNKNOWN, uid, packageName) == PermissionChecker.PERMISSION_GRANTED; } } }
services/core/java/com/android/server/pm/UserManagerService.java +43 −4 Original line number Diff line number Diff line Loading @@ -35,13 +35,16 @@ import android.app.IStopUserCallback; import android.app.KeyguardManager; import android.app.PendingIntent; import android.app.admin.DevicePolicyEventLogger; import android.app.admin.DevicePolicyManagerInternal; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.IntentSender; import android.content.pm.CrossProfileAppsInternal; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManagerInternal; import android.content.pm.ShortcutServiceInternal; import android.content.pm.UserInfo; import android.content.pm.UserInfo.UserInfoFlag; Loading Loading @@ -258,6 +261,10 @@ public class UserManagerService extends IUserManager.Stub { /** Installs system packages based on user-type. */ private final UserSystemPackageInstaller mSystemPackageInstaller; private PackageManagerInternal mPmInternal; private CrossProfileAppsInternal mCrossProfileAppsInternal; private DevicePolicyManagerInternal mDevicePolicyManagerInternal; /** * Internal non-parcelable wrapper for UserInfo that is not exposed to other system apps. */ Loading Loading @@ -944,6 +951,8 @@ public class UserManagerService extends IUserManager.Stub { intent.putExtra(Intent.EXTRA_QUIET_MODE, inQuietMode); intent.putExtra(Intent.EXTRA_USER, profileHandle); intent.putExtra(Intent.EXTRA_USER_HANDLE, profileHandle.getIdentifier()); getDevicePolicyManagerInternal().broadcastIntentToCrossProfileManifestReceiversAsUser( intent, parentHandle, /* requiresPermission= */ true); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); mContext.sendBroadcastAsUser(intent, parentHandle); } Loading Loading @@ -3845,11 +3854,15 @@ public class UserManagerService extends IUserManager.Stub { private void sendProfileRemovedBroadcast(int parentUserId, int removedUserId) { Intent managedProfileIntent = new Intent(Intent.ACTION_MANAGED_PROFILE_REMOVED); managedProfileIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); managedProfileIntent.putExtra(Intent.EXTRA_USER, new UserHandle(removedUserId)); managedProfileIntent.putExtra(Intent.EXTRA_USER_HANDLE, removedUserId); mContext.sendBroadcastAsUser(managedProfileIntent, new UserHandle(parentUserId), null); final UserHandle parentHandle = new UserHandle(parentUserId); getDevicePolicyManagerInternal().broadcastIntentToCrossProfileManifestReceiversAsUser( managedProfileIntent, parentHandle, /* requiresPermission= */ false); managedProfileIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); mContext.sendBroadcastAsUser(managedProfileIntent, parentHandle, /* receiverPermission= */null); } @Override Loading Loading @@ -5095,7 +5108,7 @@ public class UserManagerService extends IUserManager.Stub { } /** * Check if the calling package name matches with the calling UID, throw * Checks if the calling package name matches with the calling UID, throw * {@link SecurityException} if not. */ private void verifyCallingPackage(String callingPackage, int callingUid) { Loading @@ -5105,4 +5118,30 @@ public class UserManagerService extends IUserManager.Stub { + " does not match the calling uid " + callingUid); } } /** Retrieves the internal package manager interface. */ private PackageManagerInternal getPackageManagerInternal() { // Don't need to synchonize; worst-case scenario LocalServices will be called twice. if (mPmInternal == null) { mPmInternal = LocalServices.getService(PackageManagerInternal.class); } return mPmInternal; } /** Retrieve the internal cross profile apps interface. */ private CrossProfileAppsInternal getCrossProfileAppsInternal() { if (mCrossProfileAppsInternal == null) { mCrossProfileAppsInternal = LocalServices.getService(CrossProfileAppsInternal.class); } return mCrossProfileAppsInternal; } /** Returns the internal device policy manager interface. */ private DevicePolicyManagerInternal getDevicePolicyManagerInternal() { if (mDevicePolicyManagerInternal == null) { mDevicePolicyManagerInternal = LocalServices.getService(DevicePolicyManagerInternal.class); } return mDevicePolicyManagerInternal; } }
services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +108 −1 Original line number Diff line number Diff line Loading @@ -81,6 +81,8 @@ import static android.app.admin.DevicePolicyManager.WIPE_EUICC; import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE; import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA; import static android.app.admin.DevicePolicyManager.WIPE_SILENTLY; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES; import static android.provider.Settings.Global.PRIVATE_DNS_MODE; import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER; Loading @@ -92,6 +94,7 @@ import static android.security.keystore.AttestationUtils.USE_INDIVIDUAL_ATTESTAT import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ENTRY_POINT_ADB; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW; import static com.android.server.am.ActivityManagerService.STOCK_PM_FLAGS; import static com.android.server.devicepolicy.TransferOwnershipMetadataManager.ADMIN_TYPE_DEVICE_OWNER; import static com.android.server.devicepolicy.TransferOwnershipMetadataManager.ADMIN_TYPE_PROFILE_OWNER; import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; Loading Loading @@ -162,6 +165,7 @@ import android.content.PermissionChecker; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.CrossProfileApps; import android.content.pm.CrossProfileAppsInternal; import android.content.pm.IPackageDataObserver; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; Loading @@ -174,6 +178,7 @@ import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.StringParceledListSlice; import android.content.pm.UserInfo; import android.content.pm.parsing.AndroidPackage; import android.content.res.Resources; import android.database.ContentObserver; import android.database.Cursor; Loading Loading @@ -8893,9 +8898,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { UserInfo parent = mUserManager.getProfileParent(userId); Intent intent = new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED); intent.putExtra(Intent.EXTRA_USER, new UserHandle(userId)); UserHandle parentHandle = new UserHandle(parent.id); mLocalService.broadcastIntentToCrossProfileManifestReceiversAsUser(intent, parentHandle, /* requiresPermission= */ true); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); mContext.sendBroadcastAsUser(intent, new UserHandle(parent.id)); mContext.sendBroadcastAsUser(intent, parentHandle); }); } } Loading Loading @@ -12257,6 +12265,105 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return DevicePolicyManagerService.this.getAllCrossProfilePackages(); } /** * Sends the {@code intent} to the packages with cross profile capabilities. * * <p>This means the application must have the {@code crossProfile} property and * and at least one of the following permissions: * * <ul> * <li>{@link android.Manifest.permission.INTERACT_ACROSS_PROFILES} * <li>{@link android.Manifest.permission.INTERACT_ACROSS_USERS} * <li>{@link android.Manifest.permission.INTERACT_ACROSS_USERS_FULL} permission or the * {@link AppOpsManager.OP_INTERACT_ACROSS_PROFILES} app operation authorization. * </ul> * * <p>Note: The intent itself is not modified but copied before use. * * @param intent Template for the intent sent to the packages. * @param parentHandle Handle of the user that will receive the intents. * @param requiresPermission If false, all packages with the {@code crossProfile} property * will receive the intent. */ @Override public void broadcastIntentToCrossProfileManifestReceiversAsUser(Intent intent, UserHandle parentHandle, boolean requiresPermission) { Objects.requireNonNull(intent); Objects.requireNonNull(parentHandle); final int userId = parentHandle.getIdentifier(); Slog.i(LOG_TAG, String.format("Sending %s broadcast to manifest receivers.", intent.getAction())); try { final List<ResolveInfo> receivers = mIPackageManager.queryIntentReceivers( intent, /* resolvedType= */ null, STOCK_PM_FLAGS, parentHandle.getIdentifier()).getList(); for (ResolveInfo receiver : receivers) { final String packageName = receiver.getComponentInfo().packageName; if (checkCrossProfilePackagePermissions(packageName, userId, requiresPermission)) { Slog.i(LOG_TAG, String.format("Sending %s broadcast to %s.", intent.getAction(), packageName)); final Intent packageIntent = new Intent(intent) .setComponent(receiver.getComponentInfo().getComponentName()) .addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); mContext.sendBroadcastAsUser(packageIntent, parentHandle); } } } catch (RemoteException ex) { Slog.w(LOG_TAG, String.format("Cannot get list of broadcast receivers for %s because: %s.", intent.getAction(), ex)); } } /** * Checks whether the package {@code packageName} has the required permissions to receive * cross-profile broadcasts on behalf of the user {@code userId}. */ private boolean checkCrossProfilePackagePermissions(String packageName, @UserIdInt int userId, boolean requiresPermission) { final PackageManagerInternal pmInternal = LocalServices.getService( PackageManagerInternal.class); final AndroidPackage androidPackage = pmInternal.getPackage(packageName); if (androidPackage == null || !androidPackage.isCrossProfile()) { return false; } if (!requiresPermission) { return true; } if (!isPackageEnabled(packageName, userId)) { return false; } try { final CrossProfileAppsInternal crossProfileAppsService = LocalServices.getService( CrossProfileAppsInternal.class); return crossProfileAppsService.verifyPackageHasInteractAcrossProfilePermission( packageName, userId); } catch (NameNotFoundException ex) { Slog.w(LOG_TAG, String.format("Cannot find the package %s to check for permissions.", packageName)); return false; } } private boolean isPackageEnabled(String packageName, @UserIdInt int userId) { final int callingUid = Binder.getCallingUid(); final long ident = Binder.clearCallingIdentity(); try { final PackageInfo info = mInjector.getPackageManagerInternal() .getPackageInfo( packageName, MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, callingUid, userId); return info != null && info.applicationInfo.enabled; } finally { Binder.restoreCallingIdentity(ident); } } } private Intent createShowAdminSupportIntent(ComponentName admin, int userId) {