1 /*
2  * Copyright (C) 2019 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 android.app.role;
18 
19 import android.Manifest;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.SystemApi;
23 import android.annotation.WorkerThread;
24 import android.app.Service;
25 import android.content.Intent;
26 import android.os.Binder;
27 import android.os.Bundle;
28 import android.os.Handler;
29 import android.os.HandlerThread;
30 import android.os.IBinder;
31 import android.os.Process;
32 import android.os.RemoteCallback;
33 import android.os.UserHandle;
34 
35 import com.android.internal.util.Preconditions;
36 
37 import java.util.Objects;
38 import java.util.concurrent.Executor;
39 
40 /**
41  * Abstract base class for the role controller service.
42  * <p>
43  * Subclass should implement the business logic for role management, including enforcing role
44  * requirements and granting or revoking relevant privileges of roles. This class can only be
45  * implemented by the permission controller app which is registered in {@code PackageManager}.
46  *
47  * @deprecated The role controller service is an internal implementation detail inside role, and it
48  *             may be replaced by other mechanisms in the future and no longer be called.
49  *
50  * @hide
51  */
52 @Deprecated
53 @SystemApi
54 public abstract class RoleControllerService extends Service {
55 
56     /**
57      * The {@link Intent} that must be declared as handled by the service.
58      */
59     public static final String SERVICE_INTERFACE = "android.app.role.RoleControllerService";
60 
61     private HandlerThread mWorkerThread;
62     private Handler mWorkerHandler;
63 
64     @Override
65     public void onCreate() {
66         super.onCreate();
67 
68         mWorkerThread = new HandlerThread(RoleControllerService.class.getSimpleName());
69         mWorkerThread.start();
70         mWorkerHandler = new Handler(mWorkerThread.getLooper());
71     }
72 
73     @Override
74     public void onDestroy() {
75         super.onDestroy();
76 
77         mWorkerThread.quitSafely();
78     }
79 
80     @Nullable
81     @Override
82     public final IBinder onBind(@Nullable Intent intent) {
83         return new IRoleController.Stub() {
84 
85             @Override
86             public void grantDefaultRoles(RemoteCallback callback) {
87                 enforceCallerSystemUid("grantDefaultRoles");
88 
89                 Objects.requireNonNull(callback, "callback cannot be null");
90 
91                 mWorkerHandler.post(() -> RoleControllerService.this.grantDefaultRoles(callback));
92             }
93 
94             @Override
95             public void onAddRoleHolder(String roleName, String packageName, int flags,
96                     RemoteCallback callback) {
97                 enforceCallerSystemUid("onAddRoleHolder");
98 
99                 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
100                 Preconditions.checkStringNotEmpty(packageName,
101                         "packageName cannot be null or empty");
102                 Objects.requireNonNull(callback, "callback cannot be null");
103 
104                 mWorkerHandler.post(() -> RoleControllerService.this.onAddRoleHolder(roleName,
105                         packageName, flags, callback));
106             }
107 
108             @Override
109             public void onRemoveRoleHolder(String roleName, String packageName, int flags,
110                     RemoteCallback callback) {
111                 enforceCallerSystemUid("onRemoveRoleHolder");
112 
113                 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
114                 Preconditions.checkStringNotEmpty(packageName,
115                         "packageName cannot be null or empty");
116                 Objects.requireNonNull(callback, "callback cannot be null");
117 
118                 mWorkerHandler.post(() -> RoleControllerService.this.onRemoveRoleHolder(roleName,
119                         packageName, flags, callback));
120             }
121 
122             @Override
123             public void onClearRoleHolders(String roleName, int flags, RemoteCallback callback) {
124                 enforceCallerSystemUid("onClearRoleHolders");
125 
126                 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
127                 Objects.requireNonNull(callback, "callback cannot be null");
128 
129                 mWorkerHandler.post(() -> RoleControllerService.this.onClearRoleHolders(roleName,
130                         flags, callback));
131             }
132 
133             private void enforceCallerSystemUid(@NonNull String methodName) {
134                 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
135                     throw new SecurityException("Only the system process can call " + methodName
136                             + "()");
137                 }
138             }
139 
140             @Override
141             public void isApplicationQualifiedForRole(String roleName, String packageName,
142                     RemoteCallback callback) {
143                 enforceCallingPermission(Manifest.permission.MANAGE_ROLE_HOLDERS, null);
144 
145                 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
146                 Preconditions.checkStringNotEmpty(packageName,
147                         "packageName cannot be null or empty");
148                 Objects.requireNonNull(callback, "callback cannot be null");
149 
150                 boolean qualified = onIsApplicationQualifiedForRole(roleName, packageName);
151                 callback.sendResult(qualified ? Bundle.EMPTY : null);
152             }
153 
154             @Override
155             public void isApplicationVisibleForRole(String roleName, String packageName,
156                     RemoteCallback callback) {
157                 enforceCallingPermission(Manifest.permission.MANAGE_ROLE_HOLDERS, null);
158 
159                 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
160                 Preconditions.checkStringNotEmpty(packageName,
161                         "packageName cannot be null or empty");
162                 Objects.requireNonNull(callback, "callback cannot be null");
163 
164                 boolean visible = onIsApplicationVisibleForRole(roleName, packageName);
165                 callback.sendResult(visible ? Bundle.EMPTY : null);
166             }
167 
168             @Override
169             public void isRoleVisible(String roleName, RemoteCallback callback) {
170                 enforceCallingPermission(Manifest.permission.MANAGE_ROLE_HOLDERS, null);
171 
172                 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
173                 Objects.requireNonNull(callback, "callback cannot be null");
174 
175                 boolean visible = onIsRoleVisible(roleName);
176                 callback.sendResult(visible ? Bundle.EMPTY : null);
177             }
178         };
179     }
180 
181     private void grantDefaultRoles(@NonNull RemoteCallback callback) {
182         boolean successful = onGrantDefaultRoles();
183         callback.sendResult(successful ? Bundle.EMPTY : null);
184     }
185 
186     private void onAddRoleHolder(@NonNull String roleName, @NonNull String packageName,
187             @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
188         boolean successful = onAddRoleHolder(roleName, packageName, flags);
189         callback.sendResult(successful ? Bundle.EMPTY : null);
190     }
191 
192     private void onRemoveRoleHolder(@NonNull String roleName, @NonNull String packageName,
193             @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
194         boolean successful = onRemoveRoleHolder(roleName, packageName, flags);
195         callback.sendResult(successful ? Bundle.EMPTY : null);
196     }
197 
198     private void onClearRoleHolders(@NonNull String roleName,
199             @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
200         boolean successful = onClearRoleHolders(roleName, flags);
201         callback.sendResult(successful ? Bundle.EMPTY : null);
202     }
203 
204     /**
205      * Called by system to grant default permissions and roles.
206      * <p>
207      * This is typically when creating a new user or upgrading either system or
208      * permission controller package
209      *
210      * @return whether this call was successful
211      */
212     @WorkerThread
213     public abstract boolean onGrantDefaultRoles();
214 
215     /**
216      * Add a specific application to the holders of a role. If the role is exclusive, the previous
217      * holder will be replaced.
218      * <p>
219      * Implementation should enforce the role requirements and grant or revoke the relevant
220      * privileges of roles.
221      *
222      * @param roleName the name of the role to add the role holder for
223      * @param packageName the package name of the application to add to the role holders
224      * @param flags optional behavior flags
225      *
226      * @return whether this call was successful
227      *
228      * @see RoleManager#addRoleHolderAsUser(String, String, int, UserHandle, Executor,
229      *      RemoteCallback)
230      */
231     @WorkerThread
232     public abstract boolean onAddRoleHolder(@NonNull String roleName, @NonNull String packageName,
233             @RoleManager.ManageHoldersFlags int flags);
234 
235     /**
236      * Remove a specific application from the holders of a role.
237      *
238      * @param roleName the name of the role to remove the role holder for
239      * @param packageName the package name of the application to remove from the role holders
240      * @param flags optional behavior flags
241      *
242      * @return whether this call was successful
243      *
244      * @see RoleManager#removeRoleHolderAsUser(String, String, int, UserHandle, Executor,
245      *      RemoteCallback)
246      */
247     @WorkerThread
248     public abstract boolean onRemoveRoleHolder(@NonNull String roleName,
249             @NonNull String packageName, @RoleManager.ManageHoldersFlags int flags);
250 
251     /**
252      * Remove all holders of a role.
253      *
254      * @param roleName the name of the role to remove role holders for
255      * @param flags optional behavior flags
256      *
257      * @return whether this call was successful
258      *
259      * @see RoleManager#clearRoleHoldersAsUser(String, int, UserHandle, Executor, RemoteCallback)
260      */
261     @WorkerThread
262     public abstract boolean onClearRoleHolders(@NonNull String roleName,
263             @RoleManager.ManageHoldersFlags int flags);
264 
265     /**
266      * Check whether an application is qualified for a role.
267      *
268      * @param roleName name of the role to check for
269      * @param packageName package name of the application to check for
270      *
271      * @return whether the application is qualified for the role
272      *
273      * @deprecated Implement {@link #onIsApplicationVisibleForRole(String, String)} instead.
274      */
275     @Deprecated
276     public abstract boolean onIsApplicationQualifiedForRole(@NonNull String roleName,
277             @NonNull String packageName);
278 
279     /**
280      * Check whether an application is visible for a role.
281      *
282      * While an application can be qualified for a role, it can still stay hidden from user (thus
283      * not visible). If an application is visible for a role, we may show things related to the role
284      * for it, e.g. showing an entry pointing to the role settings in its application info page.
285      *
286      * @param roleName name of the role to check for
287      * @param packageName package name of the application to check for
288      *
289      * @return whether the application is visible for the role
290      */
291     public boolean onIsApplicationVisibleForRole(@NonNull String roleName,
292             @NonNull String packageName) {
293         return onIsApplicationQualifiedForRole(roleName, packageName);
294     }
295 
296     /**
297      * Check whether a role should be visible to user.
298      *
299      * @param roleName name of the role to check for
300      *
301      * @return whether the role should be visible to user
302      */
303     public abstract boolean onIsRoleVisible(@NonNull String roleName);
304 }
305