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