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

Commit 00e1b197 authored by Anna Zhuravleva's avatar Anna Zhuravleva
Browse files

Restrict Launcher apis for hidden profiles

Restrict getProfiles, registerCallback and
getPackageInstallerSessions APIs.

Modify canAccessHiddenProfile to make it
reusable outside system context.

Test: atest LauncherAppsForHiddenProfileTest
Bug: 325248906
Change-Id: Ic0b8e830bd73d424f1d9f88aade391bb6d56e38e
parent a892df45
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -130,4 +130,6 @@ interface ILauncherApps {
    void unRegisterDumpCallback(IDumpCallback cb);

    void setArchiveCompatibilityOptions(boolean enableIconOverlay, boolean enableUnarchivalConfirmation);

    List<UserHandle> getUserProfiles();
}
+14 −3
Original line number Diff line number Diff line
@@ -693,12 +693,23 @@ public class LauncherApps {
     * Otherwise it'll return the same list as {@link UserManager#getUserProfiles()} would.
     */
    public List<UserHandle> getProfiles() {
        if (mUserManager.isManagedProfile()) {
            // If it's a managed profile, only return the current profile.
        if (mUserManager.isManagedProfile()
                || (android.multiuser.Flags.enableLauncherAppsHiddenProfileChecks()
                        && android.os.Flags.allowPrivateProfile()
                        && mUserManager.isPrivateProfile())) {
            // If it's a managed or private profile, only return the current profile.
            final List result = new ArrayList(1);
            result.add(android.os.Process.myUserHandle());
            return result;
        } else {
            if (android.multiuser.Flags.enableLauncherAppsHiddenProfileChecks()) {
                try {
                    return mService.getUserProfiles();
                } catch (RemoteException re) {
                    throw re.rethrowFromSystemServer();
                }
            }

            return mUserManager.getUserProfiles();
        }
    }
+120 −53
Original line number Diff line number Diff line
@@ -350,18 +350,50 @@ public class LauncherAppsService extends SystemService {
        public void registerPackageInstallerCallback(String callingPackage,
                IPackageInstallerCallback callback) {
            verifyCallingPackage(callingPackage);
            UserHandle callingIdUserHandle = new UserHandle(getCallingUserId());
            getPackageInstallerService().registerCallback(callback, eventUserId ->
                            isEnabledProfileOf(callingIdUserHandle,
                                    new UserHandle(eventUserId), "shouldReceiveEvent"));
            BroadcastCookie callerInfo =
                    new BroadcastCookie(
                            new UserHandle(getCallingUserId()),
                            callingPackage,
                            getCallingPid(),
                            getCallingUid());
            getPackageInstallerService()
                    .registerCallback(
                            callback,
                            eventUserId ->
                                    isEnabledProfileOf(
                                            callerInfo,
                                            new UserHandle(eventUserId),
                                            "shouldReceiveEvent"));
        }

        @Override
        public List<UserHandle> getUserProfiles() {
            int[] userIds;
            if (!canAccessHiddenProfile(getCallingUid(), getCallingPid())) {
                userIds = mUm.getProfileIdsExcludingHidden(getCallingUserId(), /* enabled= */ true);
            } else {
                userIds = mUm.getEnabledProfileIds(getCallingUserId());
            }
            final List<UserHandle> result = new ArrayList<>(userIds.length);
            for (int userId : userIds) {
                result.add(UserHandle.of(userId));
            }
            return result;
        }

        @Override
        public ParceledListSlice<SessionInfo> getAllSessions(String callingPackage) {
            verifyCallingPackage(callingPackage);
            List<SessionInfo> sessionInfos = new ArrayList<>();
            int[] userIds = mUm.getEnabledProfileIds(getCallingUserId());
            final int callingUid = Binder.getCallingUid();

            int[] userIds;
            if (!canAccessHiddenProfile(callingUid, Binder.getCallingPid())) {
                userIds = mUm.getProfileIdsExcludingHidden(getCallingUserId(), /* enabled= */ true);
            } else {
                userIds = mUm.getEnabledProfileIds(getCallingUserId());
            }

            final long token = Binder.clearCallingIdentity();
            try {
                for (int userId : userIds) {
@@ -389,7 +421,7 @@ public class LauncherAppsService extends SystemService {
                    mPackageInstallerService = ((PackageInstallerService) ((IPackageManager)
                            ServiceManager.getService("package")).getPackageInstaller());
                } catch (RemoteException e) {
                    Slog.wtf(TAG, "Error gettig IPackageInstaller", e);
                    Slog.wtf(TAG, "Error getting IPackageInstaller", e);
                }
            }
            return mPackageInstallerService;
@@ -470,33 +502,51 @@ public class LauncherAppsService extends SystemService {
                            + targetUserId + " from " + callingUserId + " not allowed");
                    return false;
                }

                if (areHiddenApisChecksEnabled()
                        && mUm.getUserProperties(UserHandle.of(targetUserId))
                                        .getProfileApiVisibility()
                                == UserProperties.PROFILE_API_VISIBILITY_HIDDEN
                        && !canAccessHiddenProfileInjected(callingUid, callingPid)) {
                    return false;
                }
            } finally {
                injectRestoreCallingIdentity(ident);
            }

            if (isHiddenProfile(UserHandle.of(targetUserId))
                    && !canAccessHiddenProfile(callingUid, callingPid)) {
                return false;
            }

            return mUserManagerInternal.isProfileAccessible(callingUserId, targetUserId,
                    message, true);
        }

        boolean areHiddenApisChecksEnabled() {
            return android.os.Flags.allowPrivateProfile()
                    && Flags.enableLauncherAppsHiddenProfileChecks()
                    && Flags.enablePermissionToAccessHiddenProfiles();
        private boolean isHiddenProfile(UserHandle targetUser) {
            if (!Flags.enableLauncherAppsHiddenProfileChecks()) {
                return false;
            }

            long identity = injectClearCallingIdentity();
            try {
                UserProperties properties = mUm.getUserProperties(targetUser);
                if (properties == null) {
                    return false;
                }

                return properties.getProfileApiVisibility()
                        == UserProperties.PROFILE_API_VISIBILITY_HIDDEN;
            } catch (IllegalArgumentException e) {
                return false;
            } finally {
                injectRestoreCallingIdentity(identity);
            }
        }

        private void verifyCallingPackage(String callingPackage) {
            verifyCallingPackage(callingPackage, injectBinderCallingUid());
        }

        boolean canAccessHiddenProfileInjected(int callingUid, int callingPid) {
        private boolean canAccessHiddenProfile(int callingUid, int callingPid) {
            if (!areHiddenApisChecksEnabled()) {
                return true;
            }

            long ident = injectClearCallingIdentity();
            try {
                AndroidPackage callingPackage = mPackageManagerInternal.getPackage(callingUid);
                if (callingPackage == null) {
                    return false;
@@ -508,9 +558,10 @@ public class LauncherAppsService extends SystemService {
                        .contains(callingPackage.getPackageName())) {
                    return false;
                }

                if (mContext.checkPermission(
                            Manifest.permission.ACCESS_HIDDEN_PROFILES_FULL, callingPid, callingUid)
                                Manifest.permission.ACCESS_HIDDEN_PROFILES_FULL,
                                callingPid,
                                callingUid)
                        == PackageManager.PERMISSION_GRANTED) {
                    return true;
                }
@@ -521,6 +572,16 @@ public class LauncherAppsService extends SystemService {
                                callingPid,
                                callingUid)
                        == PackageManager.PERMISSION_GRANTED;
            } finally {
                injectRestoreCallingIdentity(ident);
            }
        }

        private boolean areHiddenApisChecksEnabled() {
            return android.os.Flags.allowPrivateProfile()
                    && Flags.enableHidingProfiles()
                    && Flags.enableLauncherAppsHiddenProfileChecks()
                    && Flags.enablePermissionToAccessHiddenProfiles();
        }

        @VisibleForTesting // We override it in unit tests
@@ -2055,12 +2116,18 @@ public class LauncherAppsService extends SystemService {
                    });
        }

        /** Checks if user is a profile of or same as listeningUser.
         * and the user is enabled. */
        private boolean isEnabledProfileOf(UserHandle listeningUser, UserHandle user,
                String debugMsg) {
            return mUserManagerInternal.isProfileAccessible(listeningUser.getIdentifier(),
                    user.getIdentifier(), debugMsg, false);
        /**
         * Checks if user is a profile of or same as listeningUser and the target user is enabled
         * and accessible for caller.
         */
        private boolean isEnabledProfileOf(
                BroadcastCookie cookie, UserHandle user, String debugMsg) {
            if (isHiddenProfile(user)
                    && !canAccessHiddenProfile(cookie.callingUid, cookie.callingPid)) {
                return false;
            }
            return mUserManagerInternal.isProfileAccessible(
                    cookie.user.getIdentifier(), user.getIdentifier(), debugMsg, false);
        }

        /**
@@ -2292,7 +2359,7 @@ public class LauncherAppsService extends SystemService {
                                        mListeners.getBroadcastItem(i);
                                final BroadcastCookie cookie =
                                        (BroadcastCookie) mListeners.getBroadcastCookie(i);
                                if (!isEnabledProfileOf(cookie.user, user, "onPackageRemoved")) {
                                if (!isEnabledProfileOf(cookie, user, "onPackageRemoved")) {
                                    continue;
                                }
                                if (!isCallingAppIdAllowed(appIdAllowList, UserHandle.getAppId(
@@ -2331,7 +2398,7 @@ public class LauncherAppsService extends SystemService {
                    for (int i = 0; i < n; i++) {
                        IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
                        BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
                        if (!isEnabledProfileOf(cookie.user, user, "onPackageAdded")) {
                        if (!isEnabledProfileOf(cookie, user, "onPackageAdded")) {
                            continue;
                        }
                        if (!isPackageVisibleToListener(packageName, cookie, user)) {
@@ -2365,7 +2432,7 @@ public class LauncherAppsService extends SystemService {
                    for (int i = 0; i < n; i++) {
                        IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
                        BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
                        if (!isEnabledProfileOf(cookie.user, user, "onPackageModified")) {
                        if (!isEnabledProfileOf(cookie, user, "onPackageModified")) {
                            continue;
                        }
                        if (!isPackageVisibleToListener(packageName, cookie, user)) {
@@ -2390,7 +2457,7 @@ public class LauncherAppsService extends SystemService {
                    for (int i = 0; i < n; i++) {
                        IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
                        BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
                        if (!isEnabledProfileOf(cookie.user, user, "onPackagesAvailable")) {
                        if (!isEnabledProfileOf(cookie, user, "onPackagesAvailable")) {
                            continue;
                        }
                        final String[] filteredPackages =
@@ -2420,7 +2487,7 @@ public class LauncherAppsService extends SystemService {
                    for (int i = 0; i < n; i++) {
                        IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
                        BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
                        if (!isEnabledProfileOf(cookie.user, user, "onPackagesUnavailable")) {
                        if (!isEnabledProfileOf(cookie, user, "onPackagesUnavailable")) {
                            continue;
                        }
                        final String[] filteredPackages =
@@ -2464,7 +2531,7 @@ public class LauncherAppsService extends SystemService {
                    for (int i = 0; i < n; i++) {
                        IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
                        BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
                        if (!isEnabledProfileOf(cookie.user, user, "onPackagesSuspended")) {
                        if (!isEnabledProfileOf(cookie, user, "onPackagesSuspended")) {
                            continue;
                        }
                        final String[] filteredPackagesWithoutExtras =
@@ -2501,7 +2568,7 @@ public class LauncherAppsService extends SystemService {
                    for (int i = 0; i < n; i++) {
                        IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
                        BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
                        if (!isEnabledProfileOf(cookie.user, user, "onPackagesUnsuspended")) {
                        if (!isEnabledProfileOf(cookie, user, "onPackagesUnsuspended")) {
                            continue;
                        }
                        final String[] filteredPackages =
@@ -2538,7 +2605,7 @@ public class LauncherAppsService extends SystemService {
                    for (int i = 0; i < n; i++) {
                        IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
                        BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
                        if (!isEnabledProfileOf(cookie.user, user, "onShortcutChanged")) {
                        if (!isEnabledProfileOf(cookie, user, "onShortcutChanged")) {
                            continue;
                        }
                        if (!isPackageVisibleToListener(packageName, cookie, user)) {
@@ -2612,7 +2679,7 @@ public class LauncherAppsService extends SystemService {
                    for (int i = 0; i < n; i++) {
                        IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
                        BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
                        if (!isEnabledProfileOf(cookie.user, mUser, "onLoadingProgressChanged")) {
                        if (!isEnabledProfileOf(cookie, mUser, "onLoadingProgressChanged")) {
                            continue;
                        }
                        if (!isPackageVisibleToListener(mPackageName, cookie, mUser)) {