• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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.role;
18 
19 import android.Manifest;
20 import android.annotation.AnyThread;
21 import android.annotation.MainThread;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.annotation.UserIdInt;
25 import android.annotation.WorkerThread;
26 import android.app.AppOpsManager;
27 import android.app.role.IOnRoleHoldersChangedListener;
28 import android.app.role.IRoleManager;
29 import android.app.role.RoleControllerManager;
30 import android.app.role.RoleManager;
31 import android.content.BroadcastReceiver;
32 import android.content.Context;
33 import android.content.Intent;
34 import android.content.IntentFilter;
35 import android.content.pm.PackageManager;
36 import android.os.Binder;
37 import android.os.Build;
38 import android.os.Handler;
39 import android.os.ParcelFileDescriptor;
40 import android.os.Process;
41 import android.os.RemoteCallback;
42 import android.os.RemoteCallbackList;
43 import android.os.RemoteException;
44 import android.os.UserHandle;
45 import android.os.UserManager;
46 import android.text.TextUtils;
47 import android.util.ArraySet;
48 import android.util.IndentingPrintWriter;
49 import android.util.Log;
50 import android.util.SparseArray;
51 import android.util.proto.ProtoOutputStream;
52 
53 import androidx.annotation.RequiresApi;
54 
55 import com.android.internal.annotations.GuardedBy;
56 import com.android.internal.infra.AndroidFuture;
57 import com.android.internal.util.Preconditions;
58 import com.android.internal.util.dump.DualDumpOutputStream;
59 import com.android.permission.compat.UserHandleCompat;
60 import com.android.permission.util.ArrayUtils;
61 import com.android.permission.util.CollectionUtils;
62 import com.android.permission.util.ForegroundThread;
63 import com.android.permission.util.ThrottledRunnable;
64 import com.android.server.LocalManagerRegistry;
65 import com.android.server.SystemService;
66 import com.android.server.role.RoleServicePlatformHelper;
67 
68 import java.io.FileDescriptor;
69 import java.io.FileOutputStream;
70 import java.io.PrintWriter;
71 import java.util.ArrayList;
72 import java.util.Collections;
73 import java.util.List;
74 import java.util.Map;
75 import java.util.Objects;
76 import java.util.Set;
77 import java.util.concurrent.ExecutionException;
78 import java.util.concurrent.TimeUnit;
79 import java.util.concurrent.TimeoutException;
80 
81 /**
82  * Service for role management.
83  *
84  * @see RoleManager
85  */
86 @RequiresApi(Build.VERSION_CODES.S)
87 public class RoleService extends SystemService implements RoleUserState.Callback {
88     private static final String LOG_TAG = RoleService.class.getSimpleName();
89 
90     private static final boolean DEBUG = false;
91 
92     private static final long GRANT_DEFAULT_ROLES_INTERVAL_MILLIS = 1000;
93 
94     @NonNull
95     private final AppOpsManager mAppOpsManager;
96     @NonNull
97     private final UserManager mUserManager;
98 
99     @NonNull
100     private final Object mLock = new Object();
101 
102     @NonNull
103     private final RoleServicePlatformHelper mPlatformHelper;
104 
105     /**
106      * Maps user id to its state.
107      */
108     @GuardedBy("mLock")
109     @NonNull
110     private final SparseArray<RoleUserState> mUserStates = new SparseArray<>();
111 
112     /**
113      * Maps user id to its controller.
114      */
115     @GuardedBy("mLock")
116     @NonNull
117     private final SparseArray<RoleControllerManager> mControllers = new SparseArray<>();
118 
119     /**
120      * Maps user id to its list of listeners.
121      */
122     @GuardedBy("mLock")
123     @NonNull
124     private final SparseArray<RemoteCallbackList<IOnRoleHoldersChangedListener>> mListeners =
125             new SparseArray<>();
126 
127     @NonNull
128     private final Handler mListenerHandler = ForegroundThread.getHandler();
129 
130     @GuardedBy("mLock")
131     private boolean mBypassingRoleQualification;
132 
133     /**
134      * Maps user id to its throttled runnable for granting default roles.
135      */
136     @GuardedBy("mLock")
137     @NonNull
138     private final SparseArray<ThrottledRunnable> mGrantDefaultRolesThrottledRunnables =
139             new SparseArray<>();
140 
RoleService(@onNull Context context)141     public RoleService(@NonNull Context context) {
142         super(context);
143 
144         mPlatformHelper = LocalManagerRegistry.getManager(RoleServicePlatformHelper.class);
145 
146         RoleControllerManager.initializeRemoteServiceComponentName(context);
147 
148         mAppOpsManager = context.getSystemService(AppOpsManager.class);
149         mUserManager = context.getSystemService(UserManager.class);
150 
151         LocalManagerRegistry.addManager(RoleManagerLocal.class, new Local());
152 
153         registerUserRemovedReceiver();
154     }
155 
registerUserRemovedReceiver()156     private void registerUserRemovedReceiver() {
157         IntentFilter intentFilter = new IntentFilter();
158         intentFilter.addAction(Intent.ACTION_USER_REMOVED);
159         getContext().registerReceiverForAllUsers(new BroadcastReceiver() {
160             @Override
161             public void onReceive(@NonNull Context context, @NonNull Intent intent) {
162                 if (TextUtils.equals(intent.getAction(), Intent.ACTION_USER_REMOVED)) {
163                     int userId = intent.<UserHandle>getParcelableExtra(Intent.EXTRA_USER)
164                             .getIdentifier();
165                     onRemoveUser(userId);
166                 }
167             }
168         }, intentFilter, null, null);
169     }
170 
171     @Override
onStart()172     public void onStart() {
173         publishBinderService(Context.ROLE_SERVICE, new Stub());
174 
175         IntentFilter intentFilter = new IntentFilter();
176         intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
177         intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
178         intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
179         intentFilter.addDataScheme("package");
180         intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
181         getContext().registerReceiverForAllUsers(new BroadcastReceiver() {
182             @Override
183             public void onReceive(Context context, Intent intent) {
184                 int userId = UserHandleCompat.getUserId(intent.getIntExtra(Intent.EXTRA_UID, -1));
185                 if (DEBUG) {
186                     Log.i(LOG_TAG, "Packages changed - re-running initial grants for user "
187                             + userId);
188                 }
189                 if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
190                         && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
191                     // Package is being upgraded - we're about to get ACTION_PACKAGE_ADDED
192                     return;
193                 }
194                 maybeGrantDefaultRolesAsync(userId);
195             }
196         }, intentFilter, null, null);
197     }
198 
199     @Override
onUserStarting(@onNull TargetUser user)200     public void onUserStarting(@NonNull TargetUser user) {
201         maybeGrantDefaultRolesSync(user.getUserHandle().getIdentifier());
202     }
203 
204     @MainThread
maybeGrantDefaultRolesSync(@serIdInt int userId)205     private void maybeGrantDefaultRolesSync(@UserIdInt int userId) {
206         AndroidFuture<Void> future = maybeGrantDefaultRolesInternal(userId);
207         try {
208             future.get(30, TimeUnit.SECONDS);
209         } catch (InterruptedException | ExecutionException | TimeoutException e) {
210             Log.e(LOG_TAG, "Failed to grant default roles for user " + userId, e);
211         }
212     }
213 
maybeGrantDefaultRolesAsync(@serIdInt int userId)214     private void maybeGrantDefaultRolesAsync(@UserIdInt int userId) {
215         ThrottledRunnable runnable;
216         synchronized (mLock) {
217             runnable = mGrantDefaultRolesThrottledRunnables.get(userId);
218             if (runnable == null) {
219                 runnable = new ThrottledRunnable(ForegroundThread.getHandler(),
220                         GRANT_DEFAULT_ROLES_INTERVAL_MILLIS,
221                         () -> maybeGrantDefaultRolesInternal(userId));
222                 mGrantDefaultRolesThrottledRunnables.put(userId, runnable);
223             }
224         }
225         runnable.run();
226     }
227 
228     @AnyThread
229     @NonNull
maybeGrantDefaultRolesInternal(@serIdInt int userId)230     private AndroidFuture<Void> maybeGrantDefaultRolesInternal(@UserIdInt int userId) {
231         RoleUserState userState = getOrCreateUserState(userId);
232         String oldPackagesHash = userState.getPackagesHash();
233         String newPackagesHash = mPlatformHelper.computePackageStateHash(userId);
234         if (Objects.equals(oldPackagesHash, newPackagesHash)) {
235             if (DEBUG) {
236                 Log.i(LOG_TAG, "Already granted default roles for packages hash "
237                         + newPackagesHash);
238             }
239             return AndroidFuture.completedFuture(null);
240         }
241 
242         // Some package state has changed, so grant default roles again.
243         Log.i(LOG_TAG, "Granting default roles...");
244         AndroidFuture<Void> future = new AndroidFuture<>();
245         getOrCreateController(userId).grantDefaultRoles(ForegroundThread.getExecutor(),
246                 successful -> {
247                     if (successful) {
248                         userState.setPackagesHash(newPackagesHash);
249                         future.complete(null);
250                     } else {
251                         future.completeExceptionally(new RuntimeException());
252                     }
253                 });
254         return future;
255     }
256 
257     @NonNull
getOrCreateUserState(@serIdInt int userId)258     private RoleUserState getOrCreateUserState(@UserIdInt int userId) {
259         synchronized (mLock) {
260             RoleUserState userState = mUserStates.get(userId);
261             if (userState == null) {
262                 userState = new RoleUserState(userId, mPlatformHelper, this);
263                 mUserStates.put(userId, userState);
264             }
265             return userState;
266         }
267     }
268 
269     @NonNull
getOrCreateController(@serIdInt int userId)270     private RoleControllerManager getOrCreateController(@UserIdInt int userId) {
271         synchronized (mLock) {
272             RoleControllerManager controller = mControllers.get(userId);
273             if (controller == null) {
274                 Context systemContext = getContext();
275                 Context context;
276                 try {
277                     context = systemContext.createPackageContextAsUser(
278                             systemContext.getPackageName(), 0, UserHandle.of(userId));
279                 } catch (PackageManager.NameNotFoundException e) {
280                     throw new RuntimeException(e);
281                 }
282                 controller = RoleControllerManager.createWithInitializedRemoteServiceComponentName(
283                         ForegroundThread.getHandler(), context);
284                 mControllers.put(userId, controller);
285             }
286             return controller;
287         }
288     }
289 
290     @Nullable
getListeners(@serIdInt int userId)291     private RemoteCallbackList<IOnRoleHoldersChangedListener> getListeners(@UserIdInt int userId) {
292         synchronized (mLock) {
293             return mListeners.get(userId);
294         }
295     }
296 
297     @NonNull
getOrCreateListeners( @serIdInt int userId)298     private RemoteCallbackList<IOnRoleHoldersChangedListener> getOrCreateListeners(
299             @UserIdInt int userId) {
300         synchronized (mLock) {
301             RemoteCallbackList<IOnRoleHoldersChangedListener> listeners = mListeners.get(userId);
302             if (listeners == null) {
303                 listeners = new RemoteCallbackList<>();
304                 mListeners.put(userId, listeners);
305             }
306             return listeners;
307         }
308     }
309 
onRemoveUser(@serIdInt int userId)310     private void onRemoveUser(@UserIdInt int userId) {
311         RemoteCallbackList<IOnRoleHoldersChangedListener> listeners;
312         RoleUserState userState;
313         synchronized (mLock) {
314             mGrantDefaultRolesThrottledRunnables.remove(userId);
315             listeners = mListeners.get(userId);
316             mListeners.remove(userId);
317             mControllers.remove(userId);
318             userState = mUserStates.get(userId);
319             mUserStates.remove(userId);
320         }
321         if (listeners != null) {
322             listeners.kill();
323         }
324         if (userState != null) {
325             userState.destroy();
326         }
327     }
328 
329     @Override
onRoleHoldersChanged(@onNull String roleName, @UserIdInt int userId)330     public void onRoleHoldersChanged(@NonNull String roleName, @UserIdInt int userId) {
331         mListenerHandler.post(() -> notifyRoleHoldersChanged(roleName, userId));
332     }
333 
334     @WorkerThread
notifyRoleHoldersChanged(@onNull String roleName, @UserIdInt int userId)335     private void notifyRoleHoldersChanged(@NonNull String roleName, @UserIdInt int userId) {
336         RemoteCallbackList<IOnRoleHoldersChangedListener> listeners = getListeners(userId);
337         if (listeners != null) {
338             notifyRoleHoldersChangedForListeners(listeners, roleName, userId);
339         }
340 
341         RemoteCallbackList<IOnRoleHoldersChangedListener> allUsersListeners = getListeners(
342                 UserHandleCompat.USER_ALL);
343         if (allUsersListeners != null) {
344             notifyRoleHoldersChangedForListeners(allUsersListeners, roleName, userId);
345         }
346     }
347 
348     @WorkerThread
notifyRoleHoldersChangedForListeners( @onNull RemoteCallbackList<IOnRoleHoldersChangedListener> listeners, @NonNull String roleName, @UserIdInt int userId)349     private void notifyRoleHoldersChangedForListeners(
350             @NonNull RemoteCallbackList<IOnRoleHoldersChangedListener> listeners,
351             @NonNull String roleName, @UserIdInt int userId) {
352         int broadcastCount = listeners.beginBroadcast();
353         try {
354             for (int i = 0; i < broadcastCount; i++) {
355                 IOnRoleHoldersChangedListener listener = listeners.getBroadcastItem(i);
356                 try {
357                     listener.onRoleHoldersChanged(roleName, userId);
358                 } catch (RemoteException e) {
359                     Log.e(LOG_TAG, "Error calling OnRoleHoldersChangedListener", e);
360                 }
361             }
362         } finally {
363             listeners.finishBroadcast();
364         }
365     }
366 
367     private class Stub extends IRoleManager.Stub {
368 
369         @Override
isRoleAvailable(@onNull String roleName)370         public boolean isRoleAvailable(@NonNull String roleName) {
371             Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
372 
373             int userId = UserHandleCompat.getUserId(getCallingUid());
374             return getOrCreateUserState(userId).isRoleAvailable(roleName);
375         }
376 
377         @Override
isRoleHeld(@onNull String roleName, @NonNull String packageName)378         public boolean isRoleHeld(@NonNull String roleName, @NonNull String packageName) {
379             int callingUid = getCallingUid();
380             mAppOpsManager.checkPackage(callingUid, packageName);
381 
382             Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
383             Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
384 
385             int userId = UserHandleCompat.getUserId(callingUid);
386             ArraySet<String> roleHolders = getOrCreateUserState(userId).getRoleHolders(roleName);
387             if (roleHolders == null) {
388                 return false;
389             }
390             return roleHolders.contains(packageName);
391         }
392 
393         @NonNull
394         @Override
getRoleHoldersAsUser(@onNull String roleName, @UserIdInt int userId)395         public List<String> getRoleHoldersAsUser(@NonNull String roleName, @UserIdInt int userId) {
396             enforceCrossUserPermission(userId, false, "getRoleHoldersAsUser");
397             if (!isUserExistent(userId)) {
398                 Log.e(LOG_TAG, "user " + userId + " does not exist");
399                 return Collections.emptyList();
400             }
401 
402             getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
403                     "getRoleHoldersAsUser");
404 
405             Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
406 
407             ArraySet<String> roleHolders = getOrCreateUserState(userId).getRoleHolders(roleName);
408             if (roleHolders == null) {
409                 return Collections.emptyList();
410             }
411             return new ArrayList<>(roleHolders);
412         }
413 
414         @Override
addRoleHolderAsUser(@onNull String roleName, @NonNull String packageName, @RoleManager.ManageHoldersFlags int flags, @UserIdInt int userId, @NonNull RemoteCallback callback)415         public void addRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
416                 @RoleManager.ManageHoldersFlags int flags, @UserIdInt int userId,
417                 @NonNull RemoteCallback callback) {
418             enforceCrossUserPermission(userId, false, "addRoleHolderAsUser");
419             if (!isUserExistent(userId)) {
420                 Log.e(LOG_TAG, "user " + userId + " does not exist");
421                 return;
422             }
423 
424             getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
425                     "addRoleHolderAsUser");
426 
427             Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
428             Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
429             Objects.requireNonNull(callback, "callback cannot be null");
430 
431             getOrCreateController(userId).onAddRoleHolder(roleName, packageName, flags,
432                     callback);
433         }
434 
435         @Override
removeRoleHolderAsUser(@onNull String roleName, @NonNull String packageName, @RoleManager.ManageHoldersFlags int flags, @UserIdInt int userId, @NonNull RemoteCallback callback)436         public void removeRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
437                 @RoleManager.ManageHoldersFlags int flags, @UserIdInt int userId,
438                 @NonNull RemoteCallback callback) {
439             enforceCrossUserPermission(userId, false, "removeRoleHolderAsUser");
440             if (!isUserExistent(userId)) {
441                 Log.e(LOG_TAG, "user " + userId + " does not exist");
442                 return;
443             }
444 
445             getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
446                     "removeRoleHolderAsUser");
447 
448             Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
449             Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
450             Objects.requireNonNull(callback, "callback cannot be null");
451 
452             getOrCreateController(userId).onRemoveRoleHolder(roleName, packageName, flags,
453                     callback);
454         }
455 
456         @Override
clearRoleHoldersAsUser(@onNull String roleName, @RoleManager.ManageHoldersFlags int flags, @UserIdInt int userId, @NonNull RemoteCallback callback)457         public void clearRoleHoldersAsUser(@NonNull String roleName,
458                 @RoleManager.ManageHoldersFlags int flags, @UserIdInt int userId,
459                 @NonNull RemoteCallback callback) {
460             enforceCrossUserPermission(userId, false, "clearRoleHoldersAsUser");
461             if (!isUserExistent(userId)) {
462                 Log.e(LOG_TAG, "user " + userId + " does not exist");
463                 return;
464             }
465 
466             getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
467                     "clearRoleHoldersAsUser");
468 
469             Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
470             Objects.requireNonNull(callback, "callback cannot be null");
471 
472             getOrCreateController(userId).onClearRoleHolders(roleName, flags, callback);
473         }
474 
475         @Override
addOnRoleHoldersChangedListenerAsUser( @onNull IOnRoleHoldersChangedListener listener, @UserIdInt int userId)476         public void addOnRoleHoldersChangedListenerAsUser(
477                 @NonNull IOnRoleHoldersChangedListener listener, @UserIdInt int userId) {
478             enforceCrossUserPermission(userId, true, "addOnRoleHoldersChangedListenerAsUser");
479             if (userId != UserHandleCompat.USER_ALL && !isUserExistent(userId)) {
480                 Log.e(LOG_TAG, "user " + userId + " does not exist");
481                 return;
482             }
483 
484             getContext().enforceCallingOrSelfPermission(Manifest.permission.OBSERVE_ROLE_HOLDERS,
485                     "addOnRoleHoldersChangedListenerAsUser");
486 
487             Objects.requireNonNull(listener, "listener cannot be null");
488 
489             RemoteCallbackList<IOnRoleHoldersChangedListener> listeners = getOrCreateListeners(
490                     userId);
491             listeners.register(listener);
492         }
493 
494         @Override
removeOnRoleHoldersChangedListenerAsUser( @onNull IOnRoleHoldersChangedListener listener, @UserIdInt int userId)495         public void removeOnRoleHoldersChangedListenerAsUser(
496                 @NonNull IOnRoleHoldersChangedListener listener, @UserIdInt int userId) {
497             enforceCrossUserPermission(userId, true, "removeOnRoleHoldersChangedListenerAsUser");
498             if (userId != UserHandleCompat.USER_ALL && !isUserExistent(userId)) {
499                 Log.e(LOG_TAG, "user " + userId + " does not exist");
500                 return;
501             }
502 
503             getContext().enforceCallingOrSelfPermission(Manifest.permission.OBSERVE_ROLE_HOLDERS,
504                     "removeOnRoleHoldersChangedListenerAsUser");
505 
506             Objects.requireNonNull(listener, "listener cannot be null");
507 
508             RemoteCallbackList<IOnRoleHoldersChangedListener> listeners = getListeners(userId);
509             if (listener == null) {
510                 return;
511             }
512             listeners.unregister(listener);
513         }
514 
515         @Override
isBypassingRoleQualification()516         public boolean isBypassingRoleQualification() {
517             getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
518                     "isBypassingRoleQualification");
519             synchronized (mLock) {
520                 return mBypassingRoleQualification;
521             }
522         }
523 
524         @Override
setBypassingRoleQualification(boolean bypassRoleQualification)525         public void setBypassingRoleQualification(boolean bypassRoleQualification) {
526             getContext().enforceCallingOrSelfPermission(
527                     Manifest.permission.BYPASS_ROLE_QUALIFICATION, "setBypassingRoleQualification");
528             synchronized (mLock) {
529                 mBypassingRoleQualification = bypassRoleQualification;
530             }
531         }
532 
533         @Override
setRoleNamesFromController(@onNull List<String> roleNames)534         public void setRoleNamesFromController(@NonNull List<String> roleNames) {
535             getContext().enforceCallingOrSelfPermission(
536                     RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER,
537                     "setRoleNamesFromController");
538 
539             Objects.requireNonNull(roleNames, "roleNames cannot be null");
540 
541             int userId = UserHandleCompat.getUserId(Binder.getCallingUid());
542             getOrCreateUserState(userId).setRoleNames(roleNames);
543         }
544 
545         @Override
addRoleHolderFromController(@onNull String roleName, @NonNull String packageName)546         public boolean addRoleHolderFromController(@NonNull String roleName,
547                 @NonNull String packageName) {
548             getContext().enforceCallingOrSelfPermission(
549                     RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER,
550                     "addRoleHolderFromController");
551 
552             Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
553             Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
554 
555             int userId = UserHandleCompat.getUserId(Binder.getCallingUid());
556             return getOrCreateUserState(userId).addRoleHolder(roleName, packageName);
557         }
558 
559         @Override
removeRoleHolderFromController(@onNull String roleName, @NonNull String packageName)560         public boolean removeRoleHolderFromController(@NonNull String roleName,
561                 @NonNull String packageName) {
562             getContext().enforceCallingOrSelfPermission(
563                     RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER,
564                     "removeRoleHolderFromController");
565 
566             Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
567             Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
568 
569             int userId = UserHandleCompat.getUserId(Binder.getCallingUid());
570             return getOrCreateUserState(userId).removeRoleHolder(roleName, packageName);
571         }
572 
573         @Override
getHeldRolesFromController(@onNull String packageName)574         public List<String> getHeldRolesFromController(@NonNull String packageName) {
575             getContext().enforceCallingOrSelfPermission(
576                     RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER,
577                     "getRolesHeldFromController");
578 
579             Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
580 
581             int userId = UserHandleCompat.getUserId(Binder.getCallingUid());
582             return getOrCreateUserState(userId).getHeldRoles(packageName);
583         }
584 
isUserExistent(@serIdInt int userId)585         private boolean isUserExistent(@UserIdInt int userId) {
586             final long identity = Binder.clearCallingIdentity();
587             try {
588                 return mUserManager.getUserHandles(true).contains(UserHandle.of(userId));
589             } finally {
590                 Binder.restoreCallingIdentity(identity);
591             }
592         }
593 
enforceCrossUserPermission(@serIdInt int userId, boolean allowAll, @NonNull String message)594         private void enforceCrossUserPermission(@UserIdInt int userId, boolean allowAll,
595                 @NonNull String message) {
596             final int callingUid = Binder.getCallingUid();
597             final int callingUserId = UserHandleCompat.getUserId(callingUid);
598             if (userId == callingUserId) {
599                 return;
600             }
601             Preconditions.checkArgument(userId >= UserHandleCompat.USER_SYSTEM
602                     || (allowAll && userId == UserHandleCompat.USER_ALL), "Invalid user " + userId);
603             getContext().enforceCallingOrSelfPermission(
604                     android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
605             if (callingUid == Process.SHELL_UID && userId >= UserHandleCompat.USER_SYSTEM) {
606                 if (mUserManager.hasUserRestrictionForUser(UserManager.DISALLOW_DEBUGGING_FEATURES,
607                         UserHandle.of(userId))) {
608                     throw new SecurityException("Shell does not have permission to access user "
609                             + userId);
610                 }
611             }
612         }
613 
614         @Override
handleShellCommand(@onNull ParcelFileDescriptor in, @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err, @NonNull String[] args)615         public int handleShellCommand(@NonNull ParcelFileDescriptor in,
616                 @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err,
617                 @NonNull String[] args) {
618             return new RoleShellCommand(this).exec(this, in.getFileDescriptor(),
619                     out.getFileDescriptor(), err.getFileDescriptor(), args);
620         }
621 
622         @Nullable
623         @Override
getBrowserRoleHolder(@serIdInt int userId)624         public String getBrowserRoleHolder(@UserIdInt int userId) {
625             final int callingUid = Binder.getCallingUid();
626             if (UserHandleCompat.getUserId(callingUid) != userId) {
627                 getContext().enforceCallingOrSelfPermission(
628                         android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
629             }
630             if (isInstantApp(callingUid)) {
631                 return null;
632             }
633 
634             final long identity = Binder.clearCallingIdentity();
635             try {
636                 return CollectionUtils.firstOrNull(getRoleHoldersAsUser(RoleManager.ROLE_BROWSER,
637                         userId));
638             } finally {
639                 Binder.restoreCallingIdentity(identity);
640             }
641         }
642 
isInstantApp(int uid)643         private boolean isInstantApp(int uid) {
644             final long identity = Binder.clearCallingIdentity();
645             try {
646                 final UserHandle user = UserHandle.getUserHandleForUid(uid);
647                 final Context userContext = getContext().createContextAsUser(user, 0);
648                 final PackageManager userPackageManager = userContext.getPackageManager();
649                 // Instant apps can not have shared UID, so it's safe to check only the first
650                 // package name here.
651                 final String packageName = ArrayUtils.firstOrNull(
652                         userPackageManager.getPackagesForUid(uid));
653                 if (packageName == null) {
654                     return false;
655                 }
656                 return userPackageManager.isInstantApp(packageName);
657             } finally {
658                 Binder.restoreCallingIdentity(identity);
659             }
660         }
661 
662         @Override
setBrowserRoleHolder(@ullable String packageName, @UserIdInt int userId)663         public boolean setBrowserRoleHolder(@Nullable String packageName, @UserIdInt int userId) {
664             final Context context = getContext();
665             context.enforceCallingOrSelfPermission(
666                     android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
667             if (UserHandleCompat.getUserId(Binder.getCallingUid()) != userId) {
668                 context.enforceCallingOrSelfPermission(
669                         android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
670             }
671 
672             if (!isUserExistent(userId)) {
673                 return false;
674             }
675 
676             final AndroidFuture<Void> future = new AndroidFuture<>();
677             final RemoteCallback callback = new RemoteCallback(result -> {
678                 boolean successful = result != null;
679                 if (successful) {
680                     future.complete(null);
681                 } else {
682                     future.completeExceptionally(new RuntimeException());
683                 }
684             });
685             final long identity = Binder.clearCallingIdentity();
686             try {
687                 if (packageName != null) {
688                     addRoleHolderAsUser(RoleManager.ROLE_BROWSER, packageName, 0, userId, callback);
689                 } else {
690                     clearRoleHoldersAsUser(RoleManager.ROLE_BROWSER, 0, userId, callback);
691                 }
692                 try {
693                     future.get(5, TimeUnit.SECONDS);
694                 } catch (InterruptedException | ExecutionException | TimeoutException e) {
695                     Log.e(LOG_TAG, "Exception while setting default browser: " + packageName, e);
696                     return false;
697                 }
698             } finally {
699                 Binder.restoreCallingIdentity(identity);
700             }
701 
702             return true;
703         }
704 
705         @Override
getSmsRoleHolder(int userId)706         public String getSmsRoleHolder(int userId) {
707             enforceCrossUserPermission(userId, false, "getSmsRoleHolder");
708             if (!isUserExistent(userId)) {
709                 Log.e(LOG_TAG, "user " + userId + " does not exist");
710                 return null;
711             }
712 
713             final long identity = Binder.clearCallingIdentity();
714             try {
715                 return CollectionUtils.firstOrNull(getRoleHoldersAsUser(RoleManager.ROLE_SMS,
716                         userId));
717             } finally {
718                 Binder.restoreCallingIdentity(identity);
719             }
720         }
721 
722         @Override
dump(@onNull FileDescriptor fd, @NonNull PrintWriter fout, @Nullable String[] args)723         protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout,
724                 @Nullable String[] args) {
725             if (!checkDumpPermission("role", fout)) {
726                 return;
727             }
728 
729             boolean dumpAsProto = args != null && ArrayUtils.contains(args, "--proto");
730             DualDumpOutputStream dumpOutputStream;
731             if (dumpAsProto) {
732                 dumpOutputStream = new DualDumpOutputStream(new ProtoOutputStream(
733                         new FileOutputStream(fd)));
734             } else {
735                 fout.println("ROLE STATE (dumpsys role):");
736                 dumpOutputStream = new DualDumpOutputStream(new IndentingPrintWriter(fout, "  "));
737             }
738 
739             synchronized (mLock) {
740                 final int userStatesSize = mUserStates.size();
741                 for (int i = 0; i < userStatesSize; i++) {
742                     final RoleUserState userState = mUserStates.valueAt(i);
743 
744                     userState.dump(dumpOutputStream, "user_states",
745                             RoleServiceDumpProto.USER_STATES);
746                 }
747             }
748 
749             dumpOutputStream.flush();
750         }
751 
checkDumpPermission(@onNull String serviceName, @NonNull PrintWriter writer)752         private boolean checkDumpPermission(@NonNull String serviceName,
753                 @NonNull PrintWriter writer) {
754             if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
755                     != PackageManager.PERMISSION_GRANTED) {
756                 writer.println("Permission Denial: can't dump " + serviceName + " from from pid="
757                         + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
758                         + " due to missing " + android.Manifest.permission.DUMP + " permission");
759                 return false;
760             } else {
761                 return true;
762             }
763         }
764     }
765 
766     private class Local implements RoleManagerLocal {
767         @NonNull
768         @Override
getRolesAndHolders(@serIdInt int userId)769         public Map<String, Set<String>> getRolesAndHolders(@UserIdInt int userId) {
770             // Convert ArrayMap<String, ArraySet<String>> to Map<String, Set<String>> for the API.
771             //noinspection unchecked
772             return (Map<String, Set<String>>) (Map<String, ?>)
773                     getOrCreateUserState(userId).getRolesAndHolders();
774         }
775     }
776 }
777