• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.CallbackExecutor;
21 import android.annotation.NonNull;
22 import android.annotation.RequiresPermission;
23 import android.annotation.SystemService;
24 import android.annotation.UserIdInt;
25 import android.app.ActivityThread;
26 import android.content.ComponentName;
27 import android.content.Context;
28 import android.content.Intent;
29 import android.content.pm.PackageManager;
30 import android.content.pm.ResolveInfo;
31 import android.os.Binder;
32 import android.os.Handler;
33 import android.os.IBinder;
34 import android.os.RemoteCallback;
35 import android.os.RemoteException;
36 import android.util.Log;
37 import android.util.SparseArray;
38 
39 import com.android.internal.annotations.GuardedBy;
40 import com.android.internal.infra.AbstractMultiplePendingRequestsRemoteService;
41 import com.android.internal.infra.AbstractRemoteService;
42 
43 import java.util.concurrent.Executor;
44 import java.util.function.Consumer;
45 
46 /**
47  * Interface for communicating with the role controller.
48  *
49  * @hide
50  */
51 @SystemService(Context.ROLE_CONTROLLER_SERVICE)
52 public class RoleControllerManager {
53 
54     private static final String LOG_TAG = RoleControllerManager.class.getSimpleName();
55 
56     private static volatile ComponentName sRemoteServiceComponentName;
57 
58     private static final Object sRemoteServicesLock = new Object();
59 
60     /**
61      * Global remote services (per user) used by all {@link RoleControllerManager managers}.
62      */
63     @GuardedBy("sRemoteServicesLock")
64     private static final SparseArray<RemoteService> sRemoteServices = new SparseArray<>();
65 
66     @NonNull
67     private final RemoteService mRemoteService;
68 
69     /**
70      * Initialize the remote service component name once so that we can avoid acquiring the
71      * PackageManagerService lock in constructor.
72      *
73      * @see #createWithInitializedRemoteServiceComponentName(Handler, Context)
74      */
initializeRemoteServiceComponentName(@onNull Context context)75     public static void initializeRemoteServiceComponentName(@NonNull Context context) {
76         sRemoteServiceComponentName = getRemoteServiceComponentName(context);
77     }
78 
79     /**
80      * Create a {@link RoleControllerManager} instance with the initialized remote service component
81      * name so that we can avoid acquiring the PackageManagerService lock in constructor.
82      *
83      * @see #initializeRemoteServiceComponentName(Context)
84      */
85     @NonNull
createWithInitializedRemoteServiceComponentName( @onNull Handler handler, @NonNull Context context)86     public static RoleControllerManager createWithInitializedRemoteServiceComponentName(
87             @NonNull Handler handler, @NonNull Context context) {
88         return new RoleControllerManager(sRemoteServiceComponentName, handler, context);
89     }
90 
RoleControllerManager(@onNull ComponentName remoteServiceComponentName, @NonNull Handler handler, @NonNull Context context)91     private RoleControllerManager(@NonNull ComponentName remoteServiceComponentName,
92             @NonNull Handler handler, @NonNull Context context) {
93         synchronized (sRemoteServicesLock) {
94             int userId = context.getUserId();
95             RemoteService remoteService = sRemoteServices.get(userId);
96             if (remoteService == null) {
97                 remoteService = new RemoteService(ActivityThread.currentApplication(),
98                         remoteServiceComponentName, handler, userId);
99                 sRemoteServices.put(userId, remoteService);
100             }
101             mRemoteService = remoteService;
102         }
103     }
104 
RoleControllerManager(@onNull Context context)105     public RoleControllerManager(@NonNull Context context) {
106         this(getRemoteServiceComponentName(context), context.getMainThreadHandler(), context);
107     }
108 
109     @NonNull
getRemoteServiceComponentName(@onNull Context context)110     private static ComponentName getRemoteServiceComponentName(@NonNull Context context) {
111         Intent intent = new Intent(RoleControllerService.SERVICE_INTERFACE);
112         PackageManager packageManager = context.getPackageManager();
113         intent.setPackage(packageManager.getPermissionControllerPackageName());
114         ResolveInfo resolveInfo = packageManager.resolveService(intent, 0);
115         return resolveInfo.getComponentInfo().getComponentName();
116     }
117 
118     /**
119      * @see RoleControllerService#onGrantDefaultRoles()
120      */
grantDefaultRoles(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Boolean> callback)121     public void grantDefaultRoles(@NonNull @CallbackExecutor Executor executor,
122             @NonNull Consumer<Boolean> callback) {
123         mRemoteService.scheduleRequest(new GrantDefaultRolesRequest(mRemoteService, executor,
124                 callback));
125     }
126 
127     /**
128      * @see RoleControllerService#onAddRoleHolder(String, String, int)
129      */
onAddRoleHolder(@onNull String roleName, @NonNull String packageName, @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback)130     public void onAddRoleHolder(@NonNull String roleName, @NonNull String packageName,
131             @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
132         mRemoteService.scheduleRequest(new OnAddRoleHolderRequest(mRemoteService, roleName,
133                 packageName, flags, callback));
134     }
135 
136     /**
137      * @see RoleControllerService#onRemoveRoleHolder(String, String, int)
138      */
onRemoveRoleHolder(@onNull String roleName, @NonNull String packageName, @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback)139     public void onRemoveRoleHolder(@NonNull String roleName, @NonNull String packageName,
140             @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
141         mRemoteService.scheduleRequest(new OnRemoveRoleHolderRequest(mRemoteService, roleName,
142                 packageName, flags, callback));
143     }
144 
145     /**
146      * @see RoleControllerService#onClearRoleHolders(String, int)
147      */
onClearRoleHolders(@onNull String roleName, @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback)148     public void onClearRoleHolders(@NonNull String roleName,
149             @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
150         mRemoteService.scheduleRequest(new OnClearRoleHoldersRequest(mRemoteService, roleName,
151                 flags, callback));
152     }
153 
154     /**
155      * @see RoleControllerService#onIsApplicationQualifiedForRole(String, String)
156      */
157     @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
isApplicationQualifiedForRole(@onNull String roleName, @NonNull String packageName, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback)158     public void isApplicationQualifiedForRole(@NonNull String roleName, @NonNull String packageName,
159             @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) {
160         mRemoteService.scheduleRequest(new IsApplicationQualifiedForRoleRequest(mRemoteService,
161                 roleName, packageName, executor, callback));
162     }
163 
164     /**
165      * @see RoleControllerService#onIsRoleVisible(String)
166      */
167     @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
isRoleVisible(@onNull String roleName, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback)168     public void isRoleVisible(@NonNull String roleName,
169             @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) {
170         mRemoteService.scheduleRequest(new IsRoleVisibleRequest(mRemoteService, roleName, executor,
171                 callback));
172     }
173 
174     /**
175      * Connection to the remote service.
176      */
177     private static final class RemoteService extends AbstractMultiplePendingRequestsRemoteService<
178             RemoteService, IRoleController> {
179 
180         private static final long UNBIND_DELAY_MILLIS = 15 * 1000;
181         private static final long REQUEST_TIMEOUT_MILLIS = 15 * 1000;
182 
183         /**
184          * Create a connection to the remote service
185          *
186          * @param context the context to use
187          * @param componentName the component of the service to connect to
188          * @param handler the handler for binding service and callbacks
189          * @param userId the user whom remote service should be connected as
190          */
RemoteService(@onNull Context context, @NonNull ComponentName componentName, @NonNull Handler handler, @UserIdInt int userId)191         RemoteService(@NonNull Context context, @NonNull ComponentName componentName,
192                 @NonNull Handler handler, @UserIdInt int userId) {
193             super(context, RoleControllerService.SERVICE_INTERFACE, componentName, userId,
194                     service -> Log.e(LOG_TAG, "RemoteService " + service + " died"), handler, 0,
195                     false, 1);
196         }
197 
198         /**
199          * @return The default handler used by this service.
200          */
201         @NonNull
getHandler()202         public Handler getHandler() {
203             return mHandler;
204         }
205 
206         @Override
getServiceInterface(@onNull IBinder binder)207         protected @NonNull IRoleController getServiceInterface(@NonNull IBinder binder) {
208             return IRoleController.Stub.asInterface(binder);
209         }
210 
211         @Override
getTimeoutIdleBindMillis()212         protected long getTimeoutIdleBindMillis() {
213             return UNBIND_DELAY_MILLIS;
214         }
215 
216         @Override
getRemoteRequestMillis()217         protected long getRemoteRequestMillis() {
218             return REQUEST_TIMEOUT_MILLIS;
219         }
220 
221         @Override
scheduleRequest( @onNull BasePendingRequest<RemoteService, IRoleController> pendingRequest)222         public void scheduleRequest(
223                 @NonNull BasePendingRequest<RemoteService, IRoleController> pendingRequest) {
224             super.scheduleRequest(pendingRequest);
225         }
226 
227         @Override
scheduleAsyncRequest(@onNull AsyncRequest<IRoleController> request)228         public void scheduleAsyncRequest(@NonNull AsyncRequest<IRoleController> request) {
229             super.scheduleAsyncRequest(request);
230         }
231     }
232 
233     /**
234      * Request for {@link #grantDefaultRoles(Executor, Consumer)}.
235      */
236     private static final class GrantDefaultRolesRequest
237             extends AbstractRemoteService.PendingRequest<RemoteService, IRoleController> {
238 
239         @NonNull
240         private final Executor mExecutor;
241         @NonNull
242         private final Consumer<Boolean> mCallback;
243 
244         @NonNull
245         private final RemoteCallback mRemoteCallback;
246 
GrantDefaultRolesRequest(@onNull RemoteService service, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback)247         private GrantDefaultRolesRequest(@NonNull RemoteService service,
248                 @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) {
249             super(service);
250 
251             mExecutor = executor;
252             mCallback = callback;
253 
254             mRemoteCallback = new RemoteCallback(result -> mExecutor.execute(() -> {
255                 long token = Binder.clearCallingIdentity();
256                 try {
257                     boolean successful = result != null;
258                     mCallback.accept(successful);
259                 } finally {
260                     Binder.restoreCallingIdentity(token);
261                     finish();
262                 }
263             }));
264         }
265 
266         @Override
onTimeout(@onNull RemoteService remoteService)267         protected void onTimeout(@NonNull RemoteService remoteService) {
268             mExecutor.execute(() -> mCallback.accept(false));
269         }
270 
271         @Override
run()272         public void run() {
273             try {
274                 getService().getServiceInterface().grantDefaultRoles(mRemoteCallback);
275             } catch (RemoteException e) {
276                 Log.e(LOG_TAG, "Error calling grantDefaultRoles()", e);
277             }
278         }
279 
280         @Override
onFailed()281         protected void onFailed() {
282             mRemoteCallback.sendResult(null);
283         }
284     }
285 
286     /**
287      * Request for {@link #onAddRoleHolder(String, String, int, RemoteCallback)}.
288      */
289     private static final class OnAddRoleHolderRequest
290             extends AbstractRemoteService.PendingRequest<RemoteService, IRoleController> {
291 
292         @NonNull
293         private final String mRoleName;
294         @NonNull
295         private final String mPackageName;
296         @RoleManager.ManageHoldersFlags
297         private final int mFlags;
298         @NonNull
299         private final RemoteCallback mCallback;
300 
301         @NonNull
302         private final RemoteCallback mRemoteCallback;
303 
OnAddRoleHolderRequest(@onNull RemoteService service, @NonNull String roleName, @NonNull String packageName, @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback)304         private OnAddRoleHolderRequest(@NonNull RemoteService service, @NonNull String roleName,
305                 @NonNull String packageName, @RoleManager.ManageHoldersFlags int flags,
306                 @NonNull RemoteCallback callback) {
307             super(service);
308 
309             mRoleName = roleName;
310             mPackageName = packageName;
311             mFlags = flags;
312             mCallback = callback;
313 
314             mRemoteCallback = new RemoteCallback(result -> {
315                 long token = Binder.clearCallingIdentity();
316                 try {
317                     mCallback.sendResult(result);
318                 } finally {
319                     Binder.restoreCallingIdentity(token);
320                     finish();
321                 }
322             });
323         }
324 
325         @Override
onTimeout(@onNull RemoteService remoteService)326         protected void onTimeout(@NonNull RemoteService remoteService) {
327             mCallback.sendResult(null);
328         }
329 
330         @Override
run()331         public void run() {
332             try {
333                 getService().getServiceInterface().onAddRoleHolder(mRoleName, mPackageName, mFlags,
334                         mRemoteCallback);
335             } catch (RemoteException e) {
336                 Log.e(LOG_TAG, "Error calling onAddRoleHolder()", e);
337             }
338         }
339     }
340 
341     /**
342      * Request for {@link #onRemoveRoleHolder(String, String, int, RemoteCallback)}.
343      */
344     private static final class OnRemoveRoleHolderRequest
345             extends AbstractRemoteService.PendingRequest<RemoteService, IRoleController> {
346 
347         @NonNull
348         private final String mRoleName;
349         @NonNull
350         private final String mPackageName;
351         @RoleManager.ManageHoldersFlags
352         private final int mFlags;
353         @NonNull
354         private final RemoteCallback mCallback;
355 
356         @NonNull
357         private final RemoteCallback mRemoteCallback;
358 
OnRemoveRoleHolderRequest(@onNull RemoteService service, @NonNull String roleName, @NonNull String packageName, @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback)359         private OnRemoveRoleHolderRequest(@NonNull RemoteService service, @NonNull String roleName,
360                 @NonNull String packageName, @RoleManager.ManageHoldersFlags int flags,
361                 @NonNull RemoteCallback callback) {
362             super(service);
363 
364             mRoleName = roleName;
365             mPackageName = packageName;
366             mFlags = flags;
367             mCallback = callback;
368 
369             mRemoteCallback = new RemoteCallback(result -> {
370                 long token = Binder.clearCallingIdentity();
371                 try {
372                     mCallback.sendResult(result);
373                 } finally {
374                     Binder.restoreCallingIdentity(token);
375                     finish();
376                 }
377             });
378         }
379 
380         @Override
onTimeout(@onNull RemoteService remoteService)381         protected void onTimeout(@NonNull RemoteService remoteService) {
382             mCallback.sendResult(null);
383         }
384 
385         @Override
run()386         public void run() {
387             try {
388                 getService().getServiceInterface().onRemoveRoleHolder(mRoleName, mPackageName,
389                         mFlags, mRemoteCallback);
390             } catch (RemoteException e) {
391                 Log.e(LOG_TAG, "Error calling onRemoveRoleHolder()", e);
392             }
393         }
394     }
395 
396     /**
397      * Request for {@link #onClearRoleHolders(String, int, RemoteCallback)}.
398      */
399     private static final class OnClearRoleHoldersRequest
400             extends AbstractRemoteService.PendingRequest<RemoteService, IRoleController> {
401 
402         @NonNull
403         private final String mRoleName;
404         @RoleManager.ManageHoldersFlags
405         private final int mFlags;
406         @NonNull
407         private final RemoteCallback mCallback;
408 
409         @NonNull
410         private final RemoteCallback mRemoteCallback;
411 
OnClearRoleHoldersRequest(@onNull RemoteService service, @NonNull String roleName, @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback)412         private OnClearRoleHoldersRequest(@NonNull RemoteService service, @NonNull String roleName,
413                 @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
414             super(service);
415 
416             mRoleName = roleName;
417             mFlags = flags;
418             mCallback = callback;
419 
420             mRemoteCallback = new RemoteCallback(result -> {
421                 long token = Binder.clearCallingIdentity();
422                 try {
423                     mCallback.sendResult(result);
424                 } finally {
425                     Binder.restoreCallingIdentity(token);
426                     finish();
427                 }
428             });
429         }
430 
431         @Override
onTimeout(@onNull RemoteService remoteService)432         protected void onTimeout(@NonNull RemoteService remoteService) {
433             mCallback.sendResult(null);
434         }
435 
436         @Override
run()437         public void run() {
438             try {
439                 getService().getServiceInterface().onClearRoleHolders(mRoleName, mFlags,
440                         mRemoteCallback);
441             } catch (RemoteException e) {
442                 Log.e(LOG_TAG, "Error calling onClearRoleHolders()", e);
443             }
444         }
445     }
446 
447     /**
448      * Request for {@link #isApplicationQualifiedForRole(String, String, Executor, Consumer)}
449      */
450     private static final class IsApplicationQualifiedForRoleRequest extends
451             AbstractRemoteService.PendingRequest<RemoteService, IRoleController> {
452 
453         @NonNull
454         private final String mRoleName;
455         @NonNull
456         private final String mPackageName;
457         @NonNull
458         private final Executor mExecutor;
459         @NonNull
460         private final Consumer<Boolean> mCallback;
461 
462         @NonNull
463         private final RemoteCallback mRemoteCallback;
464 
IsApplicationQualifiedForRoleRequest(@onNull RemoteService service, @NonNull String roleName, @NonNull String packageName, @CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback)465         private IsApplicationQualifiedForRoleRequest(@NonNull RemoteService service,
466                 @NonNull String roleName, @NonNull String packageName,
467                 @CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback) {
468             super(service);
469 
470             mRoleName = roleName;
471             mPackageName = packageName;
472             mExecutor = executor;
473             mCallback = callback;
474 
475             mRemoteCallback = new RemoteCallback(result -> mExecutor.execute(() -> {
476                 long token = Binder.clearCallingIdentity();
477                 try {
478                     boolean qualified = result != null;
479                     mCallback.accept(qualified);
480                 } finally {
481                     Binder.restoreCallingIdentity(token);
482                     finish();
483                 }
484             }));
485         }
486 
487         @Override
onTimeout(RemoteService remoteService)488         protected void onTimeout(RemoteService remoteService) {
489             mExecutor.execute(() -> mCallback.accept(false));
490         }
491 
492         @Override
run()493         public void run() {
494             try {
495                 getService().getServiceInterface().isApplicationQualifiedForRole(mRoleName,
496                         mPackageName, mRemoteCallback);
497             } catch (RemoteException e) {
498                 Log.e(LOG_TAG, "Error calling isApplicationQualifiedForRole()", e);
499             }
500         }
501     }
502 
503     /**
504      * Request for {@link #isRoleVisible(String, Executor, Consumer)}
505      */
506     private static final class IsRoleVisibleRequest
507             extends AbstractRemoteService.PendingRequest<RemoteService, IRoleController> {
508 
509         @NonNull
510         private final String mRoleName;
511         @NonNull
512         private final Executor mExecutor;
513         @NonNull
514         private final Consumer<Boolean> mCallback;
515 
516         @NonNull
517         private final RemoteCallback mRemoteCallback;
518 
IsRoleVisibleRequest(@onNull RemoteService service, @NonNull String roleName, @CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback)519         private IsRoleVisibleRequest(@NonNull RemoteService service, @NonNull String roleName,
520                 @CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback) {
521             super(service);
522 
523             mRoleName = roleName;
524             mExecutor = executor;
525             mCallback = callback;
526 
527             mRemoteCallback = new RemoteCallback(result -> mExecutor.execute(() -> {
528                 long token = Binder.clearCallingIdentity();
529                 try {
530                     boolean visible = result != null;
531                     mCallback.accept(visible);
532                 } finally {
533                     Binder.restoreCallingIdentity(token);
534                     finish();
535                 }
536             }));
537         }
538 
539         @Override
onTimeout(RemoteService remoteService)540         protected void onTimeout(RemoteService remoteService) {
541             mExecutor.execute(() -> mCallback.accept(false));
542         }
543 
544         @Override
run()545         public void run() {
546             try {
547                 getService().getServiceInterface().isRoleVisible(mRoleName, mRemoteCallback);
548             } catch (RemoteException e) {
549                 Log.e(LOG_TAG, "Error calling isRoleVisible()", e);
550             }
551         }
552     }
553 }
554