• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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.safetycenter;
18 
19 import static android.os.Build.VERSION_CODES.TIRAMISU;
20 
21 import static java.util.Objects.requireNonNull;
22 
23 import android.annotation.Nullable;
24 import android.annotation.UserIdInt;
25 import android.content.Context;
26 import android.content.pm.PackageManager;
27 import android.os.Binder;
28 import android.os.Process;
29 import android.os.UserHandle;
30 import android.os.UserManager;
31 import android.util.Log;
32 
33 import androidx.annotation.RequiresApi;
34 
35 import com.android.permission.util.UserUtils;
36 
37 import java.util.ArrayList;
38 import java.util.Arrays;
39 import java.util.List;
40 import java.util.Objects;
41 
42 /**
43  * A class that represent all the enabled profiles (profile parent and managed profile(s))
44  * associated with a user id.
45  *
46  * @hide
47  */
48 @RequiresApi(TIRAMISU)
49 public final class UserProfileGroup {
50 
51     private static final String TAG = "UserProfileGroup";
52 
53     @UserIdInt private final int mProfileParentUserId;
54     private final int[] mManagedProfilesUserIds;
55     private final int[] mManagedRunningProfilesUserIds;
56 
UserProfileGroup( @serIdInt int profileParentUserId, int[] managedProfilesUserIds, int[] managedRunningProfilesUserIds)57     private UserProfileGroup(
58             @UserIdInt int profileParentUserId,
59             int[] managedProfilesUserIds,
60             int[] managedRunningProfilesUserIds) {
61         mProfileParentUserId = profileParentUserId;
62         mManagedProfilesUserIds = managedProfilesUserIds;
63         mManagedRunningProfilesUserIds = managedRunningProfilesUserIds;
64     }
65 
66     /** Returns all the alive {@link UserProfileGroup}s. */
getAllUserProfileGroups(Context context)67     public static List<UserProfileGroup> getAllUserProfileGroups(Context context) {
68         List<UserProfileGroup> userProfileGroups = new ArrayList<>();
69         List<UserHandle> userHandles = UserUtils.getUserHandles(context);
70         for (int i = 0; i < userHandles.size(); i++) {
71             UserHandle userHandle = userHandles.get(i);
72             int userId = userHandle.getIdentifier();
73 
74             if (userProfileGroupsContain(userProfileGroups, userId)) {
75                 continue;
76             }
77 
78             UserProfileGroup userProfileGroup = UserProfileGroup.fromUser(context, userId);
79             if (!userProfileGroup.contains(userId)) {
80                 continue;
81             }
82 
83             userProfileGroups.add(userProfileGroup);
84         }
85         return userProfileGroups;
86     }
87 
userProfileGroupsContain( List<UserProfileGroup> userProfileGroups, @UserIdInt int userId)88     private static boolean userProfileGroupsContain(
89             List<UserProfileGroup> userProfileGroups, @UserIdInt int userId) {
90         for (int i = 0; i < userProfileGroups.size(); i++) {
91             UserProfileGroup userProfileGroup = userProfileGroups.get(i);
92 
93             if (userProfileGroup.contains(userId)) {
94                 return true;
95             }
96         }
97 
98         return false;
99     }
100 
101     /**
102      * Returns the {@link UserProfileGroup} associated with the given {@code userId}.
103      *
104      * <p>The given {@code userId} could be related to the profile parent or any of its associated
105      * profile(s).
106      *
107      * <p>It is possible for the {@code userId} to not be contained within the returned {@link
108      * UserProfileGroup}. This can happen if the {@code userId} is a profile that is not managed or
109      * is disabled.
110      */
fromUser(Context context, @UserIdInt int userId)111     public static UserProfileGroup fromUser(Context context, @UserIdInt int userId) {
112         UserManager userManager = getUserManagerForUser(userId, context);
113         List<UserHandle> userProfiles = getEnabledUserProfiles(userManager);
114         UserHandle profileParent = getProfileParent(userManager, userId);
115         int profileParentUserId = userId;
116         if (profileParent != null) {
117             profileParentUserId = profileParent.getIdentifier();
118         }
119 
120         int[] managedProfilesUserIds = new int[userProfiles.size()];
121         int[] managedRunningProfilesUserIds = new int[userProfiles.size()];
122         int managedProfilesUserIdsLen = 0;
123         int managedRunningProfilesUserIdsLen = 0;
124         for (int i = 0; i < userProfiles.size(); i++) {
125             UserHandle userProfileHandle = userProfiles.get(i);
126             int userProfileId = userProfileHandle.getIdentifier();
127 
128             if (UserUtils.isManagedProfile(userProfileId, context)) {
129                 managedProfilesUserIds[managedProfilesUserIdsLen++] = userProfileId;
130                 if (UserUtils.isProfileRunning(userProfileId, context)) {
131                     managedRunningProfilesUserIds[managedRunningProfilesUserIdsLen++] =
132                             userProfileId;
133                 }
134             }
135         }
136 
137         UserProfileGroup userProfileGroup =
138                 new UserProfileGroup(
139                         profileParentUserId,
140                         Arrays.copyOf(managedProfilesUserIds, managedProfilesUserIdsLen),
141                         Arrays.copyOf(
142                                 managedRunningProfilesUserIds, managedRunningProfilesUserIdsLen));
143         if (!userProfileGroup.contains(userId)) {
144             Log.w(
145                     TAG,
146                     "User id " + userId + " does not belong to " + userProfileGroup,
147                     new Exception());
148         }
149         return userProfileGroup;
150     }
151 
152     /** Returns whether the given {@code userId} is supported by {@link UserProfileGroup}. */
isSupported(@serIdInt int userId, Context context)153     public static boolean isSupported(@UserIdInt int userId, Context context) {
154         if (!isProfile(userId, context)) {
155             return true;
156         }
157         return UserUtils.isManagedProfile(userId, context);
158     }
159 
getUserManagerForUser(@serIdInt int userId, Context context)160     private static UserManager getUserManagerForUser(@UserIdInt int userId, Context context) {
161         Context userContext = getUserContext(context, UserHandle.of(userId));
162         return requireNonNull(userContext.getSystemService(UserManager.class));
163     }
164 
getUserContext(Context context, UserHandle userHandle)165     private static Context getUserContext(Context context, UserHandle userHandle) {
166         if (Process.myUserHandle().equals(userHandle)) {
167             return context;
168         } else {
169             try {
170                 return context.createPackageContextAsUser(context.getPackageName(), 0, userHandle);
171             } catch (PackageManager.NameNotFoundException doesNotHappen) {
172                 throw new IllegalStateException(doesNotHappen);
173             }
174         }
175     }
176 
isProfile(@serIdInt int userId, Context context)177     private static boolean isProfile(@UserIdInt int userId, Context context) {
178         // This call requires the INTERACT_ACROSS_USERS permission.
179         final long callingId = Binder.clearCallingIdentity();
180         try {
181             UserManager userManager = getUserManagerForUser(userId, context);
182             return userManager.isProfile();
183         } finally {
184             Binder.restoreCallingIdentity(callingId);
185         }
186     }
187 
getEnabledUserProfiles(UserManager userManager)188     private static List<UserHandle> getEnabledUserProfiles(UserManager userManager) {
189         // This call requires the QUERY_USERS permission.
190         final long callingId = Binder.clearCallingIdentity();
191         try {
192             return userManager.getUserProfiles();
193         } finally {
194             Binder.restoreCallingIdentity(callingId);
195         }
196     }
197 
198     @Nullable
getProfileParent(UserManager userManager, @UserIdInt int userId)199     private static UserHandle getProfileParent(UserManager userManager, @UserIdInt int userId) {
200         // This call requires the INTERACT_ACROSS_USERS permission.
201         final long callingId = Binder.clearCallingIdentity();
202         try {
203             return userManager.getProfileParent(UserHandle.of(userId));
204         } finally {
205             Binder.restoreCallingIdentity(callingId);
206         }
207     }
208 
209     /** Returns the profile parent user id of the {@link UserProfileGroup}. */
getProfileParentUserId()210     public int getProfileParentUserId() {
211         return mProfileParentUserId;
212     }
213 
214     /** Returns the managed profile user ids of the {@link UserProfileGroup}. */
getManagedProfilesUserIds()215     public int[] getManagedProfilesUserIds() {
216         return mManagedProfilesUserIds;
217     }
218 
219     /** Returns the running managed profile user ids of the {@link UserProfileGroup}. */
getManagedRunningProfilesUserIds()220     public int[] getManagedRunningProfilesUserIds() {
221         return mManagedRunningProfilesUserIds;
222     }
223 
224     /**
225      * Convenience method that combines the results of {@link
226      * UserProfileGroup#getProfileParentUserId()} and {@link
227      * UserProfileGroup#getManagedRunningProfilesUserIds()}.
228      */
getProfileParentAndManagedRunningProfilesUserIds()229     public int[] getProfileParentAndManagedRunningProfilesUserIds() {
230         int[] profileParentAndManagedRunningProfilesUserIds =
231                 new int[mManagedRunningProfilesUserIds.length + 1];
232         profileParentAndManagedRunningProfilesUserIds[0] = mProfileParentUserId;
233         System.arraycopy(
234                 mManagedRunningProfilesUserIds,
235                 0,
236                 profileParentAndManagedRunningProfilesUserIds,
237                 1,
238                 mManagedRunningProfilesUserIds.length);
239         return profileParentAndManagedRunningProfilesUserIds;
240     }
241 
242     /** Returns whether the {@link UserProfileGroup} contains the given {@code userId}. */
contains(@serIdInt int userId)243     public boolean contains(@UserIdInt int userId) {
244         if (userId == mProfileParentUserId) {
245             return true;
246         }
247 
248         for (int i = 0; i < mManagedProfilesUserIds.length; i++) {
249             if (userId == mManagedProfilesUserIds[i]) {
250                 return true;
251             }
252         }
253 
254         return false;
255     }
256 
257     /** Returns whether the given {@code userId} is associated with a running managed profile. */
isManagedUserRunning(@serIdInt int userId)258     boolean isManagedUserRunning(@UserIdInt int userId) {
259         for (int i = 0; i < mManagedRunningProfilesUserIds.length; i++) {
260             if (userId == mManagedRunningProfilesUserIds[i]) {
261                 return true;
262             }
263         }
264         return false;
265     }
266 
267     @Override
equals(Object o)268     public boolean equals(Object o) {
269         if (this == o) return true;
270         if (!(o instanceof UserProfileGroup)) return false;
271         UserProfileGroup that = (UserProfileGroup) o;
272         return mProfileParentUserId == that.mProfileParentUserId
273                 && Arrays.equals(mManagedProfilesUserIds, that.mManagedProfilesUserIds)
274                 && Arrays.equals(
275                         mManagedRunningProfilesUserIds, that.mManagedRunningProfilesUserIds);
276     }
277 
278     @Override
hashCode()279     public int hashCode() {
280         return Objects.hash(
281                 mProfileParentUserId,
282                 Arrays.hashCode(mManagedProfilesUserIds),
283                 Arrays.hashCode(mManagedRunningProfilesUserIds));
284     }
285 
286     @Override
toString()287     public String toString() {
288         return "UserProfileGroup{"
289                 + "mProfileParentUserId="
290                 + mProfileParentUserId
291                 + ", mManagedProfilesUserIds="
292                 + Arrays.toString(mManagedProfilesUserIds)
293                 + ", mManagedRunningProfilesUserIds="
294                 + Arrays.toString(mManagedRunningProfilesUserIds)
295                 + '}';
296     }
297 }
298