unplugged-system/packages/modules/Permission/service/java/com/android/safetycenter/UserProfileGroup.java

298 lines
11 KiB
Java

/*
* Copyright (C) 2022 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 com.android.safetycenter;
import static android.os.Build.VERSION_CODES.TIRAMISU;
import static java.util.Objects.requireNonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
import androidx.annotation.RequiresApi;
import com.android.permission.util.UserUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
/**
* A class that represent all the enabled profiles (profile parent and managed profile(s))
* associated with a user id.
*
* @hide
*/
@RequiresApi(TIRAMISU)
public final class UserProfileGroup {
private static final String TAG = "UserProfileGroup";
@UserIdInt private final int mProfileParentUserId;
private final int[] mManagedProfilesUserIds;
private final int[] mManagedRunningProfilesUserIds;
private UserProfileGroup(
@UserIdInt int profileParentUserId,
int[] managedProfilesUserIds,
int[] managedRunningProfilesUserIds) {
mProfileParentUserId = profileParentUserId;
mManagedProfilesUserIds = managedProfilesUserIds;
mManagedRunningProfilesUserIds = managedRunningProfilesUserIds;
}
/** Returns all the alive {@link UserProfileGroup}s. */
public static List<UserProfileGroup> getAllUserProfileGroups(Context context) {
List<UserProfileGroup> userProfileGroups = new ArrayList<>();
List<UserHandle> userHandles = UserUtils.getUserHandles(context);
for (int i = 0; i < userHandles.size(); i++) {
UserHandle userHandle = userHandles.get(i);
int userId = userHandle.getIdentifier();
if (userProfileGroupsContain(userProfileGroups, userId)) {
continue;
}
UserProfileGroup userProfileGroup = UserProfileGroup.fromUser(context, userId);
if (!userProfileGroup.contains(userId)) {
continue;
}
userProfileGroups.add(userProfileGroup);
}
return userProfileGroups;
}
private static boolean userProfileGroupsContain(
List<UserProfileGroup> userProfileGroups, @UserIdInt int userId) {
for (int i = 0; i < userProfileGroups.size(); i++) {
UserProfileGroup userProfileGroup = userProfileGroups.get(i);
if (userProfileGroup.contains(userId)) {
return true;
}
}
return false;
}
/**
* Returns the {@link UserProfileGroup} associated with the given {@code userId}.
*
* <p>The given {@code userId} could be related to the profile parent or any of its associated
* profile(s).
*
* <p>It is possible for the {@code userId} to not be contained within the returned {@link
* UserProfileGroup}. This can happen if the {@code userId} is a profile that is not managed or
* is disabled.
*/
public static UserProfileGroup fromUser(Context context, @UserIdInt int userId) {
UserManager userManager = getUserManagerForUser(userId, context);
List<UserHandle> userProfiles = getEnabledUserProfiles(userManager);
UserHandle profileParent = getProfileParent(userManager, userId);
int profileParentUserId = userId;
if (profileParent != null) {
profileParentUserId = profileParent.getIdentifier();
}
int[] managedProfilesUserIds = new int[userProfiles.size()];
int[] managedRunningProfilesUserIds = new int[userProfiles.size()];
int managedProfilesUserIdsLen = 0;
int managedRunningProfilesUserIdsLen = 0;
for (int i = 0; i < userProfiles.size(); i++) {
UserHandle userProfileHandle = userProfiles.get(i);
int userProfileId = userProfileHandle.getIdentifier();
if (UserUtils.isManagedProfile(userProfileId, context)) {
managedProfilesUserIds[managedProfilesUserIdsLen++] = userProfileId;
if (UserUtils.isProfileRunning(userProfileId, context)) {
managedRunningProfilesUserIds[managedRunningProfilesUserIdsLen++] =
userProfileId;
}
}
}
UserProfileGroup userProfileGroup =
new UserProfileGroup(
profileParentUserId,
Arrays.copyOf(managedProfilesUserIds, managedProfilesUserIdsLen),
Arrays.copyOf(
managedRunningProfilesUserIds, managedRunningProfilesUserIdsLen));
if (!userProfileGroup.contains(userId)) {
Log.w(
TAG,
"User id " + userId + " does not belong to " + userProfileGroup,
new Exception());
}
return userProfileGroup;
}
/** Returns whether the given {@code userId} is supported by {@link UserProfileGroup}. */
public static boolean isSupported(@UserIdInt int userId, Context context) {
if (!isProfile(userId, context)) {
return true;
}
return UserUtils.isManagedProfile(userId, context);
}
private static UserManager getUserManagerForUser(@UserIdInt int userId, Context context) {
Context userContext = getUserContext(context, UserHandle.of(userId));
return requireNonNull(userContext.getSystemService(UserManager.class));
}
private static Context getUserContext(Context context, UserHandle userHandle) {
if (Process.myUserHandle().equals(userHandle)) {
return context;
} else {
try {
return context.createPackageContextAsUser(context.getPackageName(), 0, userHandle);
} catch (PackageManager.NameNotFoundException doesNotHappen) {
throw new IllegalStateException(doesNotHappen);
}
}
}
private static boolean isProfile(@UserIdInt int userId, Context context) {
// This call requires the INTERACT_ACROSS_USERS permission.
final long callingId = Binder.clearCallingIdentity();
try {
UserManager userManager = getUserManagerForUser(userId, context);
return userManager.isProfile();
} finally {
Binder.restoreCallingIdentity(callingId);
}
}
private static List<UserHandle> getEnabledUserProfiles(UserManager userManager) {
// This call requires the QUERY_USERS permission.
final long callingId = Binder.clearCallingIdentity();
try {
return userManager.getUserProfiles();
} finally {
Binder.restoreCallingIdentity(callingId);
}
}
@Nullable
private static UserHandle getProfileParent(UserManager userManager, @UserIdInt int userId) {
// This call requires the INTERACT_ACROSS_USERS permission.
final long callingId = Binder.clearCallingIdentity();
try {
return userManager.getProfileParent(UserHandle.of(userId));
} finally {
Binder.restoreCallingIdentity(callingId);
}
}
/** Returns the profile parent user id of the {@link UserProfileGroup}. */
public int getProfileParentUserId() {
return mProfileParentUserId;
}
/** Returns the managed profile user ids of the {@link UserProfileGroup}. */
public int[] getManagedProfilesUserIds() {
return mManagedProfilesUserIds;
}
/** Returns the running managed profile user ids of the {@link UserProfileGroup}. */
public int[] getManagedRunningProfilesUserIds() {
return mManagedRunningProfilesUserIds;
}
/**
* Convenience method that combines the results of {@link
* UserProfileGroup#getProfileParentUserId()} and {@link
* UserProfileGroup#getManagedRunningProfilesUserIds()}.
*/
public int[] getProfileParentAndManagedRunningProfilesUserIds() {
int[] profileParentAndManagedRunningProfilesUserIds =
new int[mManagedRunningProfilesUserIds.length + 1];
profileParentAndManagedRunningProfilesUserIds[0] = mProfileParentUserId;
System.arraycopy(
mManagedRunningProfilesUserIds,
0,
profileParentAndManagedRunningProfilesUserIds,
1,
mManagedRunningProfilesUserIds.length);
return profileParentAndManagedRunningProfilesUserIds;
}
/** Returns whether the {@link UserProfileGroup} contains the given {@code userId}. */
public boolean contains(@UserIdInt int userId) {
if (userId == mProfileParentUserId) {
return true;
}
for (int i = 0; i < mManagedProfilesUserIds.length; i++) {
if (userId == mManagedProfilesUserIds[i]) {
return true;
}
}
return false;
}
/** Returns whether the given {@code userId} is associated with a running managed profile. */
boolean isManagedUserRunning(@UserIdInt int userId) {
for (int i = 0; i < mManagedRunningProfilesUserIds.length; i++) {
if (userId == mManagedRunningProfilesUserIds[i]) {
return true;
}
}
return false;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof UserProfileGroup)) return false;
UserProfileGroup that = (UserProfileGroup) o;
return mProfileParentUserId == that.mProfileParentUserId
&& Arrays.equals(mManagedProfilesUserIds, that.mManagedProfilesUserIds)
&& Arrays.equals(
mManagedRunningProfilesUserIds, that.mManagedRunningProfilesUserIds);
}
@Override
public int hashCode() {
return Objects.hash(
mProfileParentUserId,
Arrays.hashCode(mManagedProfilesUserIds),
Arrays.hashCode(mManagedRunningProfilesUserIds));
}
@Override
public String toString() {
return "UserProfileGroup{"
+ "mProfileParentUserId="
+ mProfileParentUserId
+ ", mManagedProfilesUserIds="
+ Arrays.toString(mManagedProfilesUserIds)
+ ", mManagedRunningProfilesUserIds="
+ Arrays.toString(mManagedRunningProfilesUserIds)
+ '}';
}
}