1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.permission.util; 18 19 import android.annotation.NonNull; 20 import android.annotation.UserIdInt; 21 import android.content.Context; 22 import android.os.Binder; 23 import android.os.Process; 24 import android.os.UserHandle; 25 import android.os.UserManager; 26 27 import com.android.internal.util.Preconditions; 28 import com.android.modules.utils.build.SdkLevel; 29 import com.android.permission.compat.UserHandleCompat; 30 import com.android.permission.flags.Flags; 31 32 import java.util.List; 33 34 /** Utility class to deal with Android users. */ 35 public final class UserUtils { 36 UserUtils()37 private UserUtils() {} 38 39 /** Enforces cross user permission for the calling UID and the given {@code userId}. */ enforceCrossUserPermission( @serIdInt int userId, boolean allowAll, @NonNull String message, @NonNull Context context)40 public static void enforceCrossUserPermission( 41 @UserIdInt int userId, 42 boolean allowAll, 43 @NonNull String message, 44 @NonNull Context context) { 45 final int callingUid = Binder.getCallingUid(); 46 final int callingUserId = UserHandleCompat.getUserId(callingUid); 47 if (userId == callingUserId) { 48 return; 49 } 50 Preconditions.checkArgument( 51 userId >= UserHandleCompat.USER_SYSTEM 52 || (allowAll && userId == UserHandleCompat.USER_ALL), 53 "Invalid user " + userId); 54 context.enforceCallingOrSelfPermission( 55 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, message); 56 if (callingUid != Process.SHELL_UID || userId < UserHandleCompat.USER_SYSTEM) { 57 return; 58 } 59 UserManager userManager = context.getSystemService(UserManager.class); 60 if (userManager.hasUserRestrictionForUser( 61 UserManager.DISALLOW_DEBUGGING_FEATURES, UserHandle.of(userId))) { 62 throw new SecurityException("Shell does not have permission to access user " + userId); 63 } 64 } 65 66 /** Returns whether a given {@code userId} corresponds to an existing user. */ isUserExistent(@serIdInt int userId, @NonNull Context context)67 public static boolean isUserExistent(@UserIdInt int userId, @NonNull Context context) { 68 return getUserHandles(context).contains(UserHandle.of(userId)); 69 } 70 71 /** Returns all the alive users on the device. */ 72 @NonNull getUserHandles(@onNull Context context)73 public static List<UserHandle> getUserHandles(@NonNull Context context) { 74 UserManager userManager = context.getSystemService(UserManager.class); 75 // This call requires the MANAGE_USERS permission. 76 final long identity = Binder.clearCallingIdentity(); 77 try { 78 return userManager.getUserHandles(true); 79 } finally { 80 Binder.restoreCallingIdentity(identity); 81 } 82 } 83 84 /** Returns whether a given {@code userId} corresponds to a managed profile. */ isManagedProfile(@serIdInt int userId, @NonNull Context context)85 public static boolean isManagedProfile(@UserIdInt int userId, @NonNull Context context) { 86 UserManager userManager = context.getSystemService(UserManager.class); 87 // This call requires the QUERY_USERS permission. 88 final long identity = Binder.clearCallingIdentity(); 89 try { 90 return userManager.isManagedProfile(userId); 91 } finally { 92 Binder.restoreCallingIdentity(identity); 93 } 94 } 95 96 /** 97 * Returns whether the given {@code userId} is a private profile. Note that private profiles are 98 * allowed from Android V+ only, so this method will return false on Sdk levels below that. 99 */ isPrivateProfile(@serIdInt int userId, @NonNull Context context)100 public static boolean isPrivateProfile(@UserIdInt int userId, @NonNull Context context) { 101 if (!isPrivateProfileSupported()) { 102 return false; 103 } 104 // It's needed to clear the calling identity because we are going to query the UserManager 105 // for isPrivateProfile() and Context for createContextAsUser, which requires one of the 106 // following permissions: 107 // MANAGE_USERS, QUERY_USERS, or INTERACT_ACROSS_USERS. 108 final long identity = Binder.clearCallingIdentity(); 109 try { 110 Context userContext = context 111 .createContextAsUser(UserHandle.of(userId), /* flags= */ 0); 112 UserManager userManager = userContext.getSystemService(UserManager.class); 113 return userManager != null && userManager.isPrivateProfile(); 114 } finally { 115 Binder.restoreCallingIdentity(identity); 116 } 117 } 118 119 120 /** 121 * Returns whether private profile's allowed to exist. This can be true iff the SdkLevel is at 122 * least V AND the permission module's private profile feature flag is enabled. 123 */ isPrivateProfileSupported()124 public static boolean isPrivateProfileSupported() { 125 //TODO(b/286539356) add the os feature flag protection when available. 126 return SdkLevel.isAtLeastV() && Flags.privateProfileSupported(); 127 } 128 129 /** 130 * Returns whether a given {@code userId} corresponds to a running managed profile, i.e. the 131 * user is running and the quiet mode is not enabled. 132 */ isProfileRunning(@serIdInt int userId, @NonNull Context context)133 public static boolean isProfileRunning(@UserIdInt int userId, @NonNull Context context) { 134 UserManager userManager = context.getSystemService(UserManager.class); 135 // This call requires the QUERY_USERS permission 136 final long identity = Binder.clearCallingIdentity(); 137 try { 138 return userManager.isUserRunning(UserHandle.of(userId)) 139 && !userManager.isQuietModeEnabled(UserHandle.of(userId)); 140 } finally { 141 Binder.restoreCallingIdentity(identity); 142 } 143 } 144 } 145