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

Commit c228e1d8 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add manifest broadcasts for profile (un-)available."

parents 0a7e4a21 1858482e
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -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);
}
+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);
}
+31 −2
Original line number Diff line number Diff line
@@ -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;
@@ -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
@@ -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;
        }
@@ -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;
        }
    }
}
+43 −4
Original line number Diff line number Diff line
@@ -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;
@@ -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.
     */
@@ -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);
    }
@@ -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
@@ -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) {
@@ -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;
    }
}
+108 −1
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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);
            });
        }
    }
@@ -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