android13/packages/modules/Permission/service/java/com/android/role/RoleService.java

786 lines
31 KiB
Java

/*
* Copyright (C) 2018 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.role;
import android.Manifest;
import android.annotation.AnyThread;
import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.annotation.WorkerThread;
import android.app.AppOpsManager;
import android.app.role.IOnRoleHoldersChangedListener;
import android.app.role.IRoleManager;
import android.app.role.RoleControllerManager;
import android.app.role.RoleManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.ParcelFileDescriptor;
import android.os.RemoteCallback;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import androidx.annotation.Keep;
import androidx.annotation.RequiresApi;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.util.Preconditions;
import com.android.internal.util.dump.DualDumpOutputStream;
import com.android.permission.compat.UserHandleCompat;
import com.android.permission.util.ArrayUtils;
import com.android.permission.util.CollectionUtils;
import com.android.permission.util.ForegroundThread;
import com.android.permission.util.PackageUtils;
import com.android.permission.util.PermissionUtils;
import com.android.permission.util.ThrottledRunnable;
import com.android.server.LocalManagerRegistry;
import com.android.server.SystemService;
import com.android.server.role.RoleServicePlatformHelper;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* Service for role management.
*
* @see RoleManager
*/
@Keep
@RequiresApi(Build.VERSION_CODES.S)
public class RoleService extends SystemService implements RoleUserState.Callback {
private static final String LOG_TAG = RoleService.class.getSimpleName();
private static final boolean DEBUG = false;
private static final long GRANT_DEFAULT_ROLES_INTERVAL_MILLIS = 1000;
@NonNull
private final AppOpsManager mAppOpsManager;
@NonNull
private final UserManager mUserManager;
@NonNull
private final Object mLock = new Object();
@NonNull
private final RoleServicePlatformHelper mPlatformHelper;
/**
* Maps user id to its state.
*/
@GuardedBy("mLock")
@NonNull
private final SparseArray<RoleUserState> mUserStates = new SparseArray<>();
/**
* Maps user id to its controller.
*/
@GuardedBy("mLock")
@NonNull
private final SparseArray<RoleControllerManager> mControllers = new SparseArray<>();
/**
* Maps user id to its list of listeners.
*/
@GuardedBy("mLock")
@NonNull
private final SparseArray<RemoteCallbackList<IOnRoleHoldersChangedListener>> mListeners =
new SparseArray<>();
@NonNull
private final Handler mListenerHandler = ForegroundThread.getHandler();
@GuardedBy("mLock")
private boolean mBypassingRoleQualification;
/**
* Maps user id to its throttled runnable for granting default roles.
*/
@GuardedBy("mLock")
@NonNull
private final SparseArray<ThrottledRunnable> mGrantDefaultRolesThrottledRunnables =
new SparseArray<>();
public RoleService(@NonNull Context context) {
super(context);
mPlatformHelper = LocalManagerRegistry.getManager(RoleServicePlatformHelper.class);
RoleControllerManager.initializeRemoteServiceComponentName(context);
mAppOpsManager = context.getSystemService(AppOpsManager.class);
mUserManager = context.getSystemService(UserManager.class);
LocalManagerRegistry.addManager(RoleManagerLocal.class, new Local());
registerUserRemovedReceiver();
}
private void registerUserRemovedReceiver() {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_USER_REMOVED);
getContext().registerReceiverForAllUsers(new BroadcastReceiver() {
@Override
public void onReceive(@NonNull Context context, @NonNull Intent intent) {
if (TextUtils.equals(intent.getAction(), Intent.ACTION_USER_REMOVED)) {
int userId = intent.<UserHandle>getParcelableExtra(Intent.EXTRA_USER)
.getIdentifier();
onRemoveUser(userId);
}
}
}, intentFilter, null, null);
}
@Override
public void onStart() {
publishBinderService(Context.ROLE_SERVICE, new Stub());
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
intentFilter.addDataScheme("package");
intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
getContext().registerReceiverForAllUsers(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
int userId = UserHandleCompat.getUserId(intent.getIntExtra(Intent.EXTRA_UID, -1));
if (DEBUG) {
Log.i(LOG_TAG, "Packages changed - re-running initial grants for user "
+ userId);
}
if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
&& intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
// Package is being upgraded - we're about to get ACTION_PACKAGE_ADDED
return;
}
maybeGrantDefaultRolesAsync(userId);
}
}, intentFilter, null, null);
}
@Override
public void onUserStarting(@NonNull TargetUser user) {
maybeGrantDefaultRolesSync(user.getUserHandle().getIdentifier());
}
@MainThread
private void maybeGrantDefaultRolesSync(@UserIdInt int userId) {
AndroidFuture<Void> future = maybeGrantDefaultRolesInternal(userId);
try {
future.get(30, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
Log.e(LOG_TAG, "Failed to grant default roles for user " + userId, e);
}
}
private void maybeGrantDefaultRolesAsync(@UserIdInt int userId) {
ThrottledRunnable runnable;
synchronized (mLock) {
runnable = mGrantDefaultRolesThrottledRunnables.get(userId);
if (runnable == null) {
runnable = new ThrottledRunnable(ForegroundThread.getHandler(),
GRANT_DEFAULT_ROLES_INTERVAL_MILLIS,
() -> maybeGrantDefaultRolesInternal(userId));
mGrantDefaultRolesThrottledRunnables.put(userId, runnable);
}
}
runnable.run();
}
@AnyThread
@NonNull
private AndroidFuture<Void> maybeGrantDefaultRolesInternal(@UserIdInt int userId) {
RoleUserState userState = getOrCreateUserState(userId);
String oldPackagesHash = userState.getPackagesHash();
String newPackagesHash = mPlatformHelper.computePackageStateHash(userId);
if (Objects.equals(oldPackagesHash, newPackagesHash)) {
if (DEBUG) {
Log.i(LOG_TAG, "Already granted default roles for packages hash "
+ newPackagesHash);
}
return AndroidFuture.completedFuture(null);
}
// Some package state has changed, so grant default roles again.
Log.i(LOG_TAG, "Granting default roles...");
AndroidFuture<Void> future = new AndroidFuture<>();
getOrCreateController(userId).grantDefaultRoles(ForegroundThread.getExecutor(),
successful -> {
if (successful) {
userState.setPackagesHash(newPackagesHash);
future.complete(null);
} else {
future.completeExceptionally(new RuntimeException());
}
});
return future;
}
@NonNull
private RoleUserState getOrCreateUserState(@UserIdInt int userId) {
synchronized (mLock) {
RoleUserState userState = mUserStates.get(userId);
if (userState == null) {
userState = new RoleUserState(userId, mPlatformHelper, this,
mBypassingRoleQualification);
mUserStates.put(userId, userState);
}
return userState;
}
}
@NonNull
private RoleControllerManager getOrCreateController(@UserIdInt int userId) {
synchronized (mLock) {
RoleControllerManager controller = mControllers.get(userId);
if (controller == null) {
Context systemContext = getContext();
Context context;
try {
context = systemContext.createPackageContextAsUser(
systemContext.getPackageName(), 0, UserHandle.of(userId));
} catch (PackageManager.NameNotFoundException e) {
throw new RuntimeException(e);
}
controller = RoleControllerManager.createWithInitializedRemoteServiceComponentName(
ForegroundThread.getHandler(), context);
mControllers.put(userId, controller);
}
return controller;
}
}
@Nullable
private RemoteCallbackList<IOnRoleHoldersChangedListener> getListeners(@UserIdInt int userId) {
synchronized (mLock) {
return mListeners.get(userId);
}
}
@NonNull
private RemoteCallbackList<IOnRoleHoldersChangedListener> getOrCreateListeners(
@UserIdInt int userId) {
synchronized (mLock) {
RemoteCallbackList<IOnRoleHoldersChangedListener> listeners = mListeners.get(userId);
if (listeners == null) {
listeners = new RemoteCallbackList<>();
mListeners.put(userId, listeners);
}
return listeners;
}
}
private void onRemoveUser(@UserIdInt int userId) {
RemoteCallbackList<IOnRoleHoldersChangedListener> listeners;
RoleUserState userState;
synchronized (mLock) {
mGrantDefaultRolesThrottledRunnables.remove(userId);
listeners = mListeners.get(userId);
mListeners.remove(userId);
mControllers.remove(userId);
userState = mUserStates.get(userId);
mUserStates.remove(userId);
}
if (listeners != null) {
listeners.kill();
}
if (userState != null) {
userState.destroy();
}
}
@Override
public void onRoleHoldersChanged(@NonNull String roleName, @UserIdInt int userId) {
mListenerHandler.post(() -> notifyRoleHoldersChanged(roleName, userId));
}
@WorkerThread
private void notifyRoleHoldersChanged(@NonNull String roleName, @UserIdInt int userId) {
RemoteCallbackList<IOnRoleHoldersChangedListener> listeners = getListeners(userId);
if (listeners != null) {
notifyRoleHoldersChangedForListeners(listeners, roleName, userId);
}
RemoteCallbackList<IOnRoleHoldersChangedListener> allUsersListeners = getListeners(
UserHandleCompat.USER_ALL);
if (allUsersListeners != null) {
notifyRoleHoldersChangedForListeners(allUsersListeners, roleName, userId);
}
}
@WorkerThread
private void notifyRoleHoldersChangedForListeners(
@NonNull RemoteCallbackList<IOnRoleHoldersChangedListener> listeners,
@NonNull String roleName, @UserIdInt int userId) {
int broadcastCount = listeners.beginBroadcast();
try {
for (int i = 0; i < broadcastCount; i++) {
IOnRoleHoldersChangedListener listener = listeners.getBroadcastItem(i);
try {
listener.onRoleHoldersChanged(roleName, userId);
} catch (RemoteException e) {
Log.e(LOG_TAG, "Error calling OnRoleHoldersChangedListener", e);
}
}
} finally {
listeners.finishBroadcast();
}
}
private class Stub extends IRoleManager.Stub {
@Override
public boolean isRoleAvailable(@NonNull String roleName) {
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
int userId = UserHandleCompat.getUserId(getCallingUid());
return getOrCreateUserState(userId).isRoleAvailable(roleName);
}
@Override
public boolean isRoleHeld(@NonNull String roleName, @NonNull String packageName) {
int callingUid = getCallingUid();
mAppOpsManager.checkPackage(callingUid, packageName);
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
int userId = UserHandleCompat.getUserId(callingUid);
ArraySet<String> roleHolders = getOrCreateUserState(userId).getRoleHolders(roleName);
if (roleHolders == null) {
return false;
}
return roleHolders.contains(packageName);
}
@NonNull
@Override
public List<String> getRoleHoldersAsUser(@NonNull String roleName, @UserIdInt int userId) {
PermissionUtils.enforceCrossUserPermission(userId, false, "getRoleHoldersAsUser",
getContext());
if (!isUserExistent(userId)) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
return Collections.emptyList();
}
getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
"getRoleHoldersAsUser");
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
ArraySet<String> roleHolders = getOrCreateUserState(userId).getRoleHolders(roleName);
if (roleHolders == null) {
return Collections.emptyList();
}
return new ArrayList<>(roleHolders);
}
@Override
public void addRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
@RoleManager.ManageHoldersFlags int flags, @UserIdInt int userId,
@NonNull RemoteCallback callback) {
PermissionUtils.enforceCrossUserPermission(userId, false, "addRoleHolderAsUser",
getContext());
if (!isUserExistent(userId)) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
return;
}
getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
"addRoleHolderAsUser");
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
Objects.requireNonNull(callback, "callback cannot be null");
getOrCreateController(userId).onAddRoleHolder(roleName, packageName, flags,
callback);
}
@Override
public void removeRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
@RoleManager.ManageHoldersFlags int flags, @UserIdInt int userId,
@NonNull RemoteCallback callback) {
PermissionUtils.enforceCrossUserPermission(userId, false, "removeRoleHolderAsUser",
getContext());
if (!isUserExistent(userId)) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
return;
}
getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
"removeRoleHolderAsUser");
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
Objects.requireNonNull(callback, "callback cannot be null");
getOrCreateController(userId).onRemoveRoleHolder(roleName, packageName, flags,
callback);
}
@Override
public void clearRoleHoldersAsUser(@NonNull String roleName,
@RoleManager.ManageHoldersFlags int flags, @UserIdInt int userId,
@NonNull RemoteCallback callback) {
PermissionUtils.enforceCrossUserPermission(userId, false, "clearRoleHoldersAsUser",
getContext());
if (!isUserExistent(userId)) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
return;
}
getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
"clearRoleHoldersAsUser");
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
Objects.requireNonNull(callback, "callback cannot be null");
getOrCreateController(userId).onClearRoleHolders(roleName, flags, callback);
}
@Override
public void addOnRoleHoldersChangedListenerAsUser(
@NonNull IOnRoleHoldersChangedListener listener, @UserIdInt int userId) {
PermissionUtils.enforceCrossUserPermission(userId, true,
"addOnRoleHoldersChangedListenerAsUser", getContext());
if (userId != UserHandleCompat.USER_ALL && !isUserExistent(userId)) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
return;
}
getContext().enforceCallingOrSelfPermission(Manifest.permission.OBSERVE_ROLE_HOLDERS,
"addOnRoleHoldersChangedListenerAsUser");
Objects.requireNonNull(listener, "listener cannot be null");
RemoteCallbackList<IOnRoleHoldersChangedListener> listeners = getOrCreateListeners(
userId);
listeners.register(listener);
}
@Override
public void removeOnRoleHoldersChangedListenerAsUser(
@NonNull IOnRoleHoldersChangedListener listener, @UserIdInt int userId) {
PermissionUtils.enforceCrossUserPermission(userId, true,
"removeOnRoleHoldersChangedListenerAsUser", getContext());
if (userId != UserHandleCompat.USER_ALL && !isUserExistent(userId)) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
return;
}
getContext().enforceCallingOrSelfPermission(Manifest.permission.OBSERVE_ROLE_HOLDERS,
"removeOnRoleHoldersChangedListenerAsUser");
Objects.requireNonNull(listener, "listener cannot be null");
RemoteCallbackList<IOnRoleHoldersChangedListener> listeners = getListeners(userId);
if (listener == null) {
return;
}
listeners.unregister(listener);
}
@Override
public boolean isBypassingRoleQualification() {
getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
"isBypassingRoleQualification");
synchronized (mLock) {
return mBypassingRoleQualification;
}
}
@Override
public void setBypassingRoleQualification(boolean bypassRoleQualification) {
getContext().enforceCallingOrSelfPermission(
Manifest.permission.BYPASS_ROLE_QUALIFICATION, "setBypassingRoleQualification");
synchronized (mLock) {
if (mBypassingRoleQualification == bypassRoleQualification) {
return;
}
mBypassingRoleQualification = bypassRoleQualification;
final int userStatesSize = mUserStates.size();
for (int i = 0; i < userStatesSize; i++) {
final RoleUserState userState = mUserStates.valueAt(i);
userState.setBypassingRoleQualification(bypassRoleQualification);
}
}
}
@Override
public void setRoleNamesFromController(@NonNull List<String> roleNames) {
getContext().enforceCallingOrSelfPermission(
RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER,
"setRoleNamesFromController");
Objects.requireNonNull(roleNames, "roleNames cannot be null");
int userId = UserHandleCompat.getUserId(Binder.getCallingUid());
getOrCreateUserState(userId).setRoleNames(roleNames);
}
@Override
public boolean addRoleHolderFromController(@NonNull String roleName,
@NonNull String packageName) {
getContext().enforceCallingOrSelfPermission(
RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER,
"addRoleHolderFromController");
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
int userId = UserHandleCompat.getUserId(Binder.getCallingUid());
return getOrCreateUserState(userId).addRoleHolder(roleName, packageName);
}
@Override
public boolean removeRoleHolderFromController(@NonNull String roleName,
@NonNull String packageName) {
getContext().enforceCallingOrSelfPermission(
RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER,
"removeRoleHolderFromController");
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
int userId = UserHandleCompat.getUserId(Binder.getCallingUid());
return getOrCreateUserState(userId).removeRoleHolder(roleName, packageName);
}
@Override
public List<String> getHeldRolesFromController(@NonNull String packageName) {
getContext().enforceCallingOrSelfPermission(
RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER,
"getRolesHeldFromController");
Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
int userId = UserHandleCompat.getUserId(Binder.getCallingUid());
return getOrCreateUserState(userId).getHeldRoles(packageName);
}
private boolean isUserExistent(@UserIdInt int userId) {
final long identity = Binder.clearCallingIdentity();
try {
return mUserManager.getUserHandles(true).contains(UserHandle.of(userId));
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
public int handleShellCommand(@NonNull ParcelFileDescriptor in,
@NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err,
@NonNull String[] args) {
return new RoleShellCommand(this).exec(this, in.getFileDescriptor(),
out.getFileDescriptor(), err.getFileDescriptor(), args);
}
@Nullable
@Override
public String getBrowserRoleHolder(@UserIdInt int userId) {
final int callingUid = Binder.getCallingUid();
if (UserHandleCompat.getUserId(callingUid) != userId) {
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
}
if (isInstantApp(callingUid)) {
return null;
}
final long identity = Binder.clearCallingIdentity();
try {
return CollectionUtils.firstOrNull(getRoleHoldersAsUser(RoleManager.ROLE_BROWSER,
userId));
} finally {
Binder.restoreCallingIdentity(identity);
}
}
private boolean isInstantApp(int uid) {
final long identity = Binder.clearCallingIdentity();
try {
final UserHandle user = UserHandle.getUserHandleForUid(uid);
final Context userContext = getContext().createContextAsUser(user, 0);
final PackageManager userPackageManager = userContext.getPackageManager();
// Instant apps can not have shared UID, so it's safe to check only the first
// package name here.
final String packageName = ArrayUtils.firstOrNull(
userPackageManager.getPackagesForUid(uid));
if (packageName == null) {
return false;
}
return userPackageManager.isInstantApp(packageName);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
public boolean setBrowserRoleHolder(@Nullable String packageName, @UserIdInt int userId) {
final Context context = getContext();
context.enforceCallingOrSelfPermission(
android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
if (UserHandleCompat.getUserId(Binder.getCallingUid()) != userId) {
context.enforceCallingOrSelfPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
}
if (!isUserExistent(userId)) {
return false;
}
final AndroidFuture<Void> future = new AndroidFuture<>();
final RemoteCallback callback = new RemoteCallback(result -> {
boolean successful = result != null;
if (successful) {
future.complete(null);
} else {
future.completeExceptionally(new RuntimeException());
}
});
final long identity = Binder.clearCallingIdentity();
try {
if (packageName != null) {
addRoleHolderAsUser(RoleManager.ROLE_BROWSER, packageName, 0, userId, callback);
} else {
clearRoleHoldersAsUser(RoleManager.ROLE_BROWSER, 0, userId, callback);
}
try {
future.get(5, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
Log.e(LOG_TAG, "Exception while setting default browser: " + packageName, e);
return false;
}
} finally {
Binder.restoreCallingIdentity(identity);
}
return true;
}
@Override
public String getSmsRoleHolder(int userId) {
final Context context = getContext();
PermissionUtils.enforceCrossUserPermission(userId, false, "getSmsRoleHolder", context);
if (!isUserExistent(userId)) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
return null;
}
final String packageName;
final long identity = Binder.clearCallingIdentity();
try {
packageName = CollectionUtils.firstOrNull(getRoleHoldersAsUser(RoleManager.ROLE_SMS,
userId));
} finally {
Binder.restoreCallingIdentity(identity);
}
if (packageName != null && !PackageUtils.canCallingOrSelfPackageQuery(packageName,
userId, context)) {
return null;
}
return packageName;
}
@Override
protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout,
@Nullable String[] args) {
if (!checkDumpPermission("role", fout)) {
return;
}
boolean dumpAsProto = args != null && ArrayUtils.contains(args, "--proto");
DualDumpOutputStream dumpOutputStream;
if (dumpAsProto) {
dumpOutputStream = new DualDumpOutputStream(new ProtoOutputStream(
new FileOutputStream(fd)));
} else {
fout.println("ROLE STATE (dumpsys role):");
dumpOutputStream = new DualDumpOutputStream(new IndentingPrintWriter(fout, " "));
}
synchronized (mLock) {
final int userStatesSize = mUserStates.size();
for (int i = 0; i < userStatesSize; i++) {
final RoleUserState userState = mUserStates.valueAt(i);
userState.dump(dumpOutputStream, "user_states",
RoleServiceDumpProto.USER_STATES);
}
}
dumpOutputStream.flush();
}
private boolean checkDumpPermission(@NonNull String serviceName,
@NonNull PrintWriter writer) {
if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
writer.println("Permission Denial: can't dump " + serviceName + " from from pid="
+ Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
+ " due to missing " + android.Manifest.permission.DUMP + " permission");
return false;
} else {
return true;
}
}
}
private class Local implements RoleManagerLocal {
@NonNull
@Override
public Map<String, Set<String>> getRolesAndHolders(@UserIdInt int userId) {
// Convert ArrayMap<String, ArraySet<String>> to Map<String, Set<String>> for the API.
//noinspection unchecked
return (Map<String, Set<String>>) (Map<String, ?>)
getOrCreateUserState(userId).getRolesAndHolders();
}
}
}