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.server.companion.utils;
18 
19 import static android.app.role.RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP;
20 
21 import android.annotation.NonNull;
22 import android.annotation.SuppressLint;
23 import android.annotation.UserIdInt;
24 import android.app.role.RoleManager;
25 import android.companion.AssociationInfo;
26 import android.content.Context;
27 import android.os.Binder;
28 import android.os.UserHandle;
29 import android.util.Slog;
30 
31 import java.util.List;
32 import java.util.function.Consumer;
33 
34 /** Utility methods for accessing {@link RoleManager} APIs. */
35 @SuppressLint("LongLogTag")
36 public final class RolesUtils {
37 
38     private static final String TAG = "CDM_RolesUtils";
39 
40     /**
41      * Check if the package holds the role.
42      */
isRoleHolder(@onNull Context context, @UserIdInt int userId, @NonNull String packageName, @NonNull String role)43     public static boolean isRoleHolder(@NonNull Context context, @UserIdInt int userId,
44             @NonNull String packageName, @NonNull String role) {
45         final RoleManager roleManager = context.getSystemService(RoleManager.class);
46         final List<String> roleHolders = roleManager.getRoleHoldersAsUser(
47                 role, UserHandle.of(userId));
48         return roleHolders.contains(packageName);
49     }
50 
51     /**
52      * Attempt to add the association's companion app as the role holder for the device profile
53      * specified in the association. If the association does not have any device profile specified,
54      * then the operation will always be successful as a no-op.
55      *
56      * @param context
57      * @param associationInfo the association for which the role should be granted to the app
58      * @param roleGrantResult the result callback for adding role holder. True if successful, and
59      *                        false if failed. If the association does not have any device profile
60      *                        specified, then the operation will always be successful as a no-op.
61      */
addRoleHolderForAssociation( @onNull Context context, @NonNull AssociationInfo associationInfo, @NonNull Consumer<Boolean> roleGrantResult)62     public static void addRoleHolderForAssociation(
63             @NonNull Context context, @NonNull AssociationInfo associationInfo,
64             @NonNull Consumer<Boolean> roleGrantResult) {
65         final String deviceProfile = associationInfo.getDeviceProfile();
66         if (deviceProfile == null) {
67             // If no device profile is specified, then no-op and resolve callback with success.
68             roleGrantResult.accept(true);
69             return;
70         }
71 
72         final RoleManager roleManager = context.getSystemService(RoleManager.class);
73 
74         final String packageName = associationInfo.getPackageName();
75         final int userId = associationInfo.getUserId();
76         final UserHandle userHandle = UserHandle.of(userId);
77 
78         roleManager.addRoleHolderAsUser(deviceProfile, packageName,
79                 MANAGE_HOLDERS_FLAG_DONT_KILL_APP, userHandle, context.getMainExecutor(),
80                 roleGrantResult);
81     }
82 
83     /**
84      * Remove the role for the package association.
85      */
removeRoleHolderForAssociation( @onNull Context context, int userId, String packageName, String deviceProfile)86     public static void removeRoleHolderForAssociation(
87             @NonNull Context context, int userId, String packageName, String deviceProfile) {
88         if (deviceProfile == null) return;
89 
90         final RoleManager roleManager = context.getSystemService(RoleManager.class);
91 
92         final UserHandle userHandle = UserHandle.of(userId);
93 
94         Slog.i(TAG, "Removing CDM role=" + deviceProfile
95                 + " for userId=" + userId + ", packageName=" + packageName);
96 
97         Binder.withCleanCallingIdentity(() ->
98             roleManager.removeRoleHolderAsUser(deviceProfile, packageName,
99                     MANAGE_HOLDERS_FLAG_DONT_KILL_APP, userHandle, context.getMainExecutor(),
100                     success -> {
101                         if (!success) {
102                             Slog.e(TAG, "Failed to remove userId=" + userId + ", packageName="
103                                     + packageName + " from the list of " + deviceProfile
104                                     + " holders.");
105                         }
106                     })
107         );
108     }
109 
RolesUtils()110     private RolesUtils() {}
111 }
112