Merge "Prepare role code for modularization."

This commit is contained in:
Hai Zhang
2021-01-23 02:02:36 +00:00
committed by Android (Google) Code Review
18 changed files with 555 additions and 144 deletions

View File

@@ -21,8 +21,6 @@ import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.os.Looper;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@@ -40,8 +38,7 @@ import java.lang.annotation.Target;
* </code>
* </pre>
*
* @memberDoc This method must be called from the
* {@linkplain Looper#getMainLooper() main thread} of your app.
* @memberDoc This method must be called from the main thread of your app.
* @hide
*/
@Retention(SOURCE)

View File

@@ -31,7 +31,7 @@ import android.app.contentsuggestions.IContentSuggestionsManager;
import android.app.job.JobSchedulerFrameworkInitializer;
import android.app.people.PeopleManager;
import android.app.prediction.AppPredictionManager;
import android.app.role.RoleManager;
import android.app.role.RoleFrameworkInitializer;
import android.app.search.SearchUiManager;
import android.app.slice.SliceManager;
import android.app.time.TimeManager;
@@ -1320,14 +1320,6 @@ public final class SystemServiceRegistry {
ctx.getMainThreadHandler());
}});
registerService(Context.ROLE_SERVICE, RoleManager.class,
new CachedServiceFetcher<RoleManager>() {
@Override
public RoleManager createService(ContextImpl ctx)
throws ServiceNotFoundException {
return new RoleManager(ctx.getOuterContext());
}});
registerService(Context.DYNAMIC_SYSTEM_SERVICE, DynamicSystemManager.class,
new CachedServiceFetcher<DynamicSystemManager>() {
@Override
@@ -1423,6 +1415,7 @@ public final class SystemServiceRegistry {
RollbackManagerFrameworkInitializer.initialize();
MediaFrameworkPlatformInitializer.registerServiceWrappers();
MediaFrameworkInitializer.registerServiceWrappers();
RoleFrameworkInitializer.registerServiceWrappers();
} finally {
// If any of the above code throws, we're in a pretty bad shape and the process
// will likely crash, but we'll reset it just in case there's an exception handler...

View File

@@ -20,15 +20,15 @@ import android.Manifest;
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.app.ActivityThread;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteCallback;
import android.util.Log;
import android.util.SparseArray;
@@ -95,11 +95,10 @@ public class RoleControllerManager {
private RoleControllerManager(@NonNull ComponentName remoteServiceComponentName,
@NonNull Handler handler, @NonNull Context context) {
synchronized (sRemoteServicesLock) {
int userId = context.getUserId();
int userId = context.getUser().getIdentifier();
ServiceConnector<IRoleController> remoteService = sRemoteServices.get(userId);
if (remoteService == null) {
remoteService = new ServiceConnector.Impl<IRoleController>(
ActivityThread.currentApplication(),
remoteService = new ServiceConnector.Impl<IRoleController>(context,
new Intent(RoleControllerService.SERVICE_INTERFACE)
.setComponent(remoteServiceComponentName),
0 /* bindingFlags */, userId, IRoleController.Stub::asInterface) {
@@ -119,7 +118,7 @@ public class RoleControllerManager {
* @hide
*/
public RoleControllerManager(@NonNull Context context) {
this(getRemoteServiceComponentName(context), context.getMainThreadHandler(), context);
this(getRemoteServiceComponentName(context), new Handler(Looper.getMainLooper()), context);
}
@NonNull
@@ -127,8 +126,8 @@ public class RoleControllerManager {
Intent intent = new Intent(RoleControllerService.SERVICE_INTERFACE);
PackageManager packageManager = context.getPackageManager();
intent.setPackage(packageManager.getPermissionControllerPackageName());
ResolveInfo resolveInfo = packageManager.resolveService(intent, 0);
return resolveInfo.getComponentInfo().getComponentName();
ServiceInfo serviceInfo = packageManager.resolveService(intent, 0).serviceInfo;
return new ComponentName(serviceInfo.packageName, serviceInfo.name);
}
/**

View File

@@ -33,7 +33,6 @@ import android.os.RemoteCallback;
import android.os.UserHandle;
import com.android.internal.util.Preconditions;
import com.android.internal.util.function.pooled.PooledLambda;
import java.util.Objects;
import java.util.concurrent.Executor;
@@ -85,9 +84,7 @@ public abstract class RoleControllerService extends Service {
Objects.requireNonNull(callback, "callback cannot be null");
mWorkerHandler.sendMessage(PooledLambda.obtainMessage(
RoleControllerService::grantDefaultRoles, RoleControllerService.this,
callback));
mWorkerHandler.post(() -> RoleControllerService.this.grantDefaultRoles(callback));
}
@Override
@@ -100,9 +97,8 @@ public abstract class RoleControllerService extends Service {
"packageName cannot be null or empty");
Objects.requireNonNull(callback, "callback cannot be null");
mWorkerHandler.sendMessage(PooledLambda.obtainMessage(
RoleControllerService::onAddRoleHolder, RoleControllerService.this,
roleName, packageName, flags, callback));
mWorkerHandler.post(() -> RoleControllerService.this.onAddRoleHolder(roleName,
packageName, flags, callback));
}
@Override
@@ -115,9 +111,8 @@ public abstract class RoleControllerService extends Service {
"packageName cannot be null or empty");
Objects.requireNonNull(callback, "callback cannot be null");
mWorkerHandler.sendMessage(PooledLambda.obtainMessage(
RoleControllerService::onRemoveRoleHolder, RoleControllerService.this,
roleName, packageName, flags, callback));
mWorkerHandler.post(() -> RoleControllerService.this.onRemoveRoleHolder(roleName,
packageName, flags, callback));
}
@Override
@@ -127,9 +122,8 @@ public abstract class RoleControllerService extends Service {
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
Objects.requireNonNull(callback, "callback cannot be null");
mWorkerHandler.sendMessage(PooledLambda.obtainMessage(
RoleControllerService::onClearRoleHolders, RoleControllerService.this,
roleName, flags, callback));
mWorkerHandler.post(() -> RoleControllerService.this.onClearRoleHolders(roleName,
flags, callback));
}
private void enforceCallerSystemUid(@NonNull String methodName) {
@@ -274,6 +268,7 @@ public abstract class RoleControllerService extends Service {
*
* @deprecated Implement {@link #onIsApplicationVisibleForRole(String, String)} instead.
*/
@Deprecated
public abstract boolean onIsApplicationQualifiedForRole(@NonNull String roleName,
@NonNull String packageName);

View File

@@ -0,0 +1,43 @@
/*
* Copyright (C) 2021 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 android.app.role;
import android.app.SystemServiceRegistry;
import android.content.Context;
/**
* Class holding initialization code for role in the permission module.
*
* @hide
*/
//@SystemApi
public class RoleFrameworkInitializer {
private RoleFrameworkInitializer() {}
/**
* Called by {@link SystemServiceRegistry}'s static initializer and registers
* {@link RoleManager} to {@link Context}, so that {@link Context#getSystemService} can return
* it.
*
* <p>If this is called from other places, it throws a {@link IllegalStateException).
*/
public static void registerServiceWrappers() {
SystemServiceRegistry.registerContextAwareService(Context.ROLE_SERVICE, RoleManager.class,
(context, serviceBinder) -> new RoleManager(context,
IRoleManager.Stub.asInterface(serviceBinder)));
}
}

View File

@@ -32,14 +32,12 @@ import android.os.Binder;
import android.os.Process;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
import com.android.internal.util.function.pooled.PooledLambda;
import java.util.List;
import java.util.Objects;
@@ -180,12 +178,16 @@ public final class RoleManager {
private final Object mRoleControllerManagerLock = new Object();
/**
* Create a new instance of this class.
*
* @param context the {@link Context}
* @param service the {@link IRoleManager} service
*
* @hide
*/
public RoleManager(@NonNull Context context) throws ServiceManager.ServiceNotFoundException {
public RoleManager(@NonNull Context context, @NonNull IRoleManager service) {
mContext = context;
mService = IRoleManager.Stub.asInterface(ServiceManager.getServiceOrThrow(
Context.ROLE_SERVICE));
mService = service;
}
/**
@@ -747,9 +749,8 @@ public final class RoleManager {
public void onRoleHoldersChanged(@NonNull String roleName, @UserIdInt int userId) {
final long token = Binder.clearCallingIdentity();
try {
mExecutor.execute(PooledLambda.obtainRunnable(
OnRoleHoldersChangedListener::onRoleHoldersChanged, mListener, roleName,
UserHandle.of(userId)));
mExecutor.execute(() ->
mListener.onRoleHoldersChanged(roleName, UserHandle.of(userId)));
} finally {
Binder.restoreCallingIdentity(token);
}

View File

@@ -9,4 +9,4 @@
]
}
]
}
}

View File

@@ -18,14 +18,17 @@ package com.android.server.role;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.util.ArrayMap;
import android.util.ArraySet;
import java.util.Map;
import java.util.Set;
/**
* Internal calls into {@link RoleManagerService}.
* Internal calls into {@link RoleService}.
*
* @hide
*/
public abstract class RoleManagerInternal {
//@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
public interface RoleManagerLocal {
/**
* Get all roles and their holders.
*
@@ -34,6 +37,5 @@ public abstract class RoleManagerInternal {
* @return The roles and their holders
*/
@NonNull
public abstract ArrayMap<String, ArraySet<String>> getRolesAndHolders(
@UserIdInt int userId);
Map<String, Set<String>> getRolesAndHolders(@UserIdInt int userId);
}

View File

@@ -43,25 +43,23 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.IndentingPrintWriter;
import android.util.Slog;
import android.util.Log;
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.infra.ThrottledRunnable;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.Preconditions;
import com.android.internal.util.dump.DualDumpOutputStream;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.LocalManagerRegistry;
import com.android.server.SystemService;
import com.android.server.pm.UserManagerInternal;
import com.android.server.role.compat.UserHandleCompat;
import com.android.server.role.util.ArrayUtils;
import com.android.server.role.util.CollectionUtils;
import com.android.server.role.util.ForegroundThread;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
@@ -69,7 +67,9 @@ 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;
@@ -79,8 +79,8 @@ import java.util.concurrent.TimeoutException;
*
* @see RoleManager
*/
public class RoleManagerService extends SystemService implements RoleUserState.Callback {
private static final String LOG_TAG = RoleManagerService.class.getSimpleName();
public class RoleService extends SystemService implements RoleUserState.Callback {
private static final String LOG_TAG = RoleService.class.getSimpleName();
private static final boolean DEBUG = false;
@@ -89,7 +89,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
@NonNull
private final AppOpsManager mAppOpsManager;
@NonNull
private final UserManagerInternal mUserManagerInternal;
private final UserManager mUserManager;
@NonNull
private final Object mLock = new Object();
@@ -120,7 +120,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
new SparseArray<>();
@NonNull
private final Handler mListenerHandler = FgThread.getHandler();
private final Handler mListenerHandler = ForegroundThread.getHandler();
/**
* Maps user id to its throttled runnable for granting default roles.
@@ -130,18 +130,17 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
private final SparseArray<ThrottledRunnable> mGrantDefaultRolesThrottledRunnables =
new SparseArray<>();
public RoleManagerService(@NonNull Context context,
@NonNull RoleServicePlatformHelper platformHelper) {
public RoleService(@NonNull Context context) {
super(context);
mPlatformHelper = platformHelper;
mPlatformHelper = LocalManagerRegistry.getManager(RoleServicePlatformHelper.class);
RoleControllerManager.initializeRemoteServiceComponentName(context);
mAppOpsManager = context.getSystemService(AppOpsManager.class);
mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
mUserManager = context.getSystemService(UserManager.class);
LocalServices.addService(RoleManagerInternal.class, new Internal());
LocalManagerRegistry.addManager(RoleManagerLocal.class, new Local());
registerUserRemovedReceiver();
}
@@ -174,9 +173,9 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
getContext().registerReceiverForAllUsers(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
int userId = UserHandle.getUserId(intent.getIntExtra(Intent.EXTRA_UID, -1));
int userId = UserHandleCompat.getUserId(intent.getIntExtra(Intent.EXTRA_UID, -1));
if (DEBUG) {
Slog.i(LOG_TAG, "Packages changed - re-running initial grants for user "
Log.i(LOG_TAG, "Packages changed - re-running initial grants for user "
+ userId);
}
if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
@@ -200,7 +199,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
try {
future.get(30, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
Slog.e(LOG_TAG, "Failed to grant default roles for user " + userId, e);
Log.e(LOG_TAG, "Failed to grant default roles for user " + userId, e);
}
}
@@ -209,7 +208,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
synchronized (mLock) {
runnable = mGrantDefaultRolesThrottledRunnables.get(userId);
if (runnable == null) {
runnable = new ThrottledRunnable(FgThread.getHandler(),
runnable = new ThrottledRunnable(ForegroundThread.getHandler(),
GRANT_DEFAULT_ROLES_INTERVAL_MILLIS,
() -> maybeGrantDefaultRolesInternal(userId));
mGrantDefaultRolesThrottledRunnables.put(userId, runnable);
@@ -226,16 +225,16 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
String newPackagesHash = mPlatformHelper.computePackageStateHash(userId);
if (Objects.equals(oldPackagesHash, newPackagesHash)) {
if (DEBUG) {
Slog.i(LOG_TAG, "Already granted default roles for packages hash "
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.
Slog.i(LOG_TAG, "Granting default roles...");
Log.i(LOG_TAG, "Granting default roles...");
AndroidFuture<Void> future = new AndroidFuture<>();
getOrCreateController(userId).grantDefaultRoles(FgThread.getExecutor(),
getOrCreateController(userId).grantDefaultRoles(ForegroundThread.getExecutor(),
successful -> {
if (successful) {
userState.setPackagesHash(newPackagesHash);
@@ -273,7 +272,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
throw new RuntimeException(e);
}
controller = RoleControllerManager.createWithInitializedRemoteServiceComponentName(
FgThread.getHandler(), context);
ForegroundThread.getHandler(), context);
mControllers.put(userId, controller);
}
return controller;
@@ -321,8 +320,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
@Override
public void onRoleHoldersChanged(@NonNull String roleName, @UserIdInt int userId) {
mListenerHandler.sendMessage(PooledLambda.obtainMessage(
RoleManagerService::notifyRoleHoldersChanged, this, roleName, userId));
mListenerHandler.post(() -> notifyRoleHoldersChanged(roleName, userId));
}
@WorkerThread
@@ -333,7 +331,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
}
RemoteCallbackList<IOnRoleHoldersChangedListener> allUsersListeners = getListeners(
UserHandle.USER_ALL);
UserHandleCompat.USER_ALL);
if (allUsersListeners != null) {
notifyRoleHoldersChangedForListeners(allUsersListeners, roleName, userId);
}
@@ -350,7 +348,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
try {
listener.onRoleHoldersChanged(roleName, userId);
} catch (RemoteException e) {
Slog.e(LOG_TAG, "Error calling OnRoleHoldersChangedListener", e);
Log.e(LOG_TAG, "Error calling OnRoleHoldersChangedListener", e);
}
}
} finally {
@@ -364,7 +362,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
public boolean isRoleAvailable(@NonNull String roleName) {
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
int userId = UserHandle.getUserId(getCallingUid());
int userId = UserHandleCompat.getUserId(getCallingUid());
return getOrCreateUserState(userId).isRoleAvailable(roleName);
}
@@ -376,7 +374,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
int userId = UserHandle.getUserId(callingUid);
int userId = UserHandleCompat.getUserId(callingUid);
ArraySet<String> roleHolders = getOrCreateUserState(userId).getRoleHolders(roleName);
if (roleHolders == null) {
return false;
@@ -387,8 +385,8 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
@NonNull
@Override
public List<String> getRoleHoldersAsUser(@NonNull String roleName, @UserIdInt int userId) {
if (!mUserManagerInternal.exists(userId)) {
Slog.e(LOG_TAG, "user " + userId + " does not exist");
if (!isUserExistent(userId)) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
return Collections.emptyList();
}
enforceCrossUserPermission(userId, false, "getRoleHoldersAsUser");
@@ -408,8 +406,8 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
public void addRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
@RoleManager.ManageHoldersFlags int flags, @UserIdInt int userId,
@NonNull RemoteCallback callback) {
if (!mUserManagerInternal.exists(userId)) {
Slog.e(LOG_TAG, "user " + userId + " does not exist");
if (!isUserExistent(userId)) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
return;
}
enforceCrossUserPermission(userId, false, "addRoleHolderAsUser");
@@ -428,8 +426,8 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
public void removeRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
@RoleManager.ManageHoldersFlags int flags, @UserIdInt int userId,
@NonNull RemoteCallback callback) {
if (!mUserManagerInternal.exists(userId)) {
Slog.e(LOG_TAG, "user " + userId + " does not exist");
if (!isUserExistent(userId)) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
return;
}
enforceCrossUserPermission(userId, false, "removeRoleHolderAsUser");
@@ -448,8 +446,8 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
public void clearRoleHoldersAsUser(@NonNull String roleName,
@RoleManager.ManageHoldersFlags int flags, @UserIdInt int userId,
@NonNull RemoteCallback callback) {
if (!mUserManagerInternal.exists(userId)) {
Slog.e(LOG_TAG, "user " + userId + " does not exist");
if (!isUserExistent(userId)) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
return;
}
enforceCrossUserPermission(userId, false, "clearRoleHoldersAsUser");
@@ -465,8 +463,8 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
@Override
public void addOnRoleHoldersChangedListenerAsUser(
@NonNull IOnRoleHoldersChangedListener listener, @UserIdInt int userId) {
if (userId != UserHandle.USER_ALL && !mUserManagerInternal.exists(userId)) {
Slog.e(LOG_TAG, "user " + userId + " does not exist");
if (userId != UserHandleCompat.USER_ALL && !isUserExistent(userId)) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
return;
}
enforceCrossUserPermission(userId, true, "addOnRoleHoldersChangedListenerAsUser");
@@ -483,8 +481,8 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
@Override
public void removeOnRoleHoldersChangedListenerAsUser(
@NonNull IOnRoleHoldersChangedListener listener, @UserIdInt int userId) {
if (userId != UserHandle.USER_ALL && !mUserManagerInternal.exists(userId)) {
Slog.e(LOG_TAG, "user " + userId + " does not exist");
if (userId != UserHandleCompat.USER_ALL && !isUserExistent(userId)) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
return;
}
enforceCrossUserPermission(userId, true, "removeOnRoleHoldersChangedListenerAsUser");
@@ -508,7 +506,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
Objects.requireNonNull(roleNames, "roleNames cannot be null");
int userId = UserHandle.getUserId(Binder.getCallingUid());
int userId = UserHandleCompat.getUserId(Binder.getCallingUid());
getOrCreateUserState(userId).setRoleNames(roleNames);
}
@@ -522,7 +520,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
int userId = UserHandle.getUserId(Binder.getCallingUid());
int userId = UserHandleCompat.getUserId(Binder.getCallingUid());
return getOrCreateUserState(userId).addRoleHolder(roleName, packageName);
}
@@ -536,7 +534,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
int userId = UserHandle.getUserId(Binder.getCallingUid());
int userId = UserHandleCompat.getUserId(Binder.getCallingUid());
return getOrCreateUserState(userId).removeRoleHolder(roleName, packageName);
}
@@ -548,24 +546,30 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
int userId = UserHandle.getUserId(Binder.getCallingUid());
int userId = UserHandleCompat.getUserId(Binder.getCallingUid());
return getOrCreateUserState(userId).getHeldRoles(packageName);
}
private boolean isUserExistent(@UserIdInt int userId) {
// FIXME: This checks whether the user is alive, but we should check for whether the
// user is existent.
return mUserManager.getUserHandles(true).contains(UserHandle.of(userId));
}
private void enforceCrossUserPermission(@UserIdInt int userId, boolean allowAll,
@NonNull String message) {
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
final int callingUserId = UserHandleCompat.getUserId(callingUid);
if (userId == callingUserId) {
return;
}
Preconditions.checkArgument(userId >= UserHandle.USER_SYSTEM
|| (allowAll && userId == UserHandle.USER_ALL), "Invalid user " + userId);
Preconditions.checkArgument(userId >= UserHandleCompat.USER_SYSTEM
|| (allowAll && userId == UserHandleCompat.USER_ALL), "Invalid user " + userId);
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
if (callingUid == Process.SHELL_UID && userId >= UserHandle.USER_SYSTEM) {
if (mUserManagerInternal.hasUserRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES,
userId)) {
if (callingUid == Process.SHELL_UID && userId >= UserHandleCompat.USER_SYSTEM) {
if (mUserManager.hasUserRestrictionForUser(UserManager.DISALLOW_DEBUGGING_FEATURES,
UserHandle.of(userId))) {
throw new SecurityException("Shell does not have permission to access user "
+ userId);
}
@@ -576,7 +580,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
public int handleShellCommand(@NonNull ParcelFileDescriptor in,
@NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err,
@NonNull String[] args) {
return new RoleManagerShellCommand(this).exec(this, in.getFileDescriptor(),
return new RoleShellCommand(this).exec(this, in.getFileDescriptor(),
out.getFileDescriptor(), err.getFileDescriptor(), args);
}
@@ -584,7 +588,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
@Override
public String getBrowserRoleHolder(@UserIdInt int userId) {
final int callingUid = Binder.getCallingUid();
if (UserHandle.getUserId(callingUid) != userId) {
if (UserHandleCompat.getUserId(callingUid) != userId) {
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
}
@@ -625,12 +629,12 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
final Context context = getContext();
context.enforceCallingOrSelfPermission(
android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
if (UserHandle.getUserId(Binder.getCallingUid()) != userId) {
if (UserHandleCompat.getUserId(Binder.getCallingUid()) != userId) {
context.enforceCallingOrSelfPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
}
if (!mUserManagerInternal.exists(userId)) {
if (!isUserExistent(userId)) {
return false;
}
@@ -653,7 +657,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
try {
future.get(5, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
Slog.e(LOG_TAG, "Exception while setting default browser: " + packageName, e);
Log.e(LOG_TAG, "Exception while setting default browser: " + packageName, e);
return false;
}
} finally {
@@ -687,7 +691,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
dumpOutputStream = new DualDumpOutputStream(new ProtoOutputStream(
new FileOutputStream(fd)));
} else {
fout.println("ROLE MANAGER STATE (dumpsys role):");
fout.println("ROLE STATE (dumpsys role):");
dumpOutputStream = new DualDumpOutputStream(new IndentingPrintWriter(fout, " "));
}
@@ -718,11 +722,14 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
}
}
private class Internal extends RoleManagerInternal {
private class Local implements RoleManagerLocal {
@NonNull
@Override
public ArrayMap<String, ArraySet<String>> getRolesAndHolders(@UserIdInt int userId) {
return getOrCreateUserState(userId).getRolesAndHolders();
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();
}
}
}

View File

@@ -21,19 +21,19 @@ import android.annotation.Nullable;
import android.app.role.IRoleManager;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.UserHandle;
import com.android.modules.utils.BasicShellCommandHandler;
import com.android.server.role.compat.UserHandleCompat;
import java.io.PrintWriter;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
class RoleManagerShellCommand extends BasicShellCommandHandler {
class RoleShellCommand extends BasicShellCommandHandler {
@NonNull
private final IRoleManager mRoleManager;
RoleManagerShellCommand(@NonNull IRoleManager roleManager) {
RoleShellCommand(@NonNull IRoleManager roleManager) {
mRoleManager = roleManager;
}
@@ -86,7 +86,7 @@ class RoleManagerShellCommand extends BasicShellCommandHandler {
}
private int getUserIdMaybe() {
int userId = UserHandle.USER_SYSTEM;
int userId = UserHandleCompat.USER_SYSTEM;
String option = getNextOption();
if (option != null && option.equals("--user")) {
userId = Integer.parseInt(getNextArgRequired());
@@ -139,7 +139,7 @@ class RoleManagerShellCommand extends BasicShellCommandHandler {
@Override
public void onHelp() {
PrintWriter pw = getOutPrintWriter();
pw.println("Role manager (role) commands:");
pw.println("Role (role) commands:");
pw.println(" help or -h");
pw.println(" Print this help text.");
pw.println();

View File

@@ -25,15 +25,14 @@ import android.os.Handler;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.dump.DualDumpOutputStream;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.role.persistence.RolesPersistence;
import com.android.role.persistence.RolesState;
import com.android.server.role.util.BackgroundThread;
import com.android.server.role.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
@@ -197,7 +196,7 @@ class RoleUserState {
synchronized (mLock) {
if (!mRoles.containsKey(roleName)) {
mRoles.put(roleName, new ArraySet<>());
Slog.i(LOG_TAG, "Added new role: " + roleName);
Log.i(LOG_TAG, "Added new role: " + roleName);
scheduleWriteFileLocked();
return true;
} else {
@@ -221,7 +220,7 @@ class RoleUserState {
if (!roleNames.contains(roleName)) {
ArraySet<String> packageNames = mRoles.valueAt(i);
if (!packageNames.isEmpty()) {
Slog.e(LOG_TAG, "Holders of a removed role should have been cleaned up,"
Log.e(LOG_TAG, "Holders of a removed role should have been cleaned up,"
+ " role: " + roleName + ", holders: " + packageNames);
}
mRoles.removeAt(i);
@@ -255,7 +254,7 @@ class RoleUserState {
synchronized (mLock) {
ArraySet<String> roleHolders = mRoles.get(roleName);
if (roleHolders == null) {
Slog.e(LOG_TAG, "Cannot add role holder for unknown role, role: " + roleName
Log.e(LOG_TAG, "Cannot add role holder for unknown role, role: " + roleName
+ ", package: " + packageName);
return false;
}
@@ -286,7 +285,7 @@ class RoleUserState {
synchronized (mLock) {
ArraySet<String> roleHolders = mRoles.get(roleName);
if (roleHolders == null) {
Slog.e(LOG_TAG, "Cannot remove role holder for unknown role, role: " + roleName
Log.e(LOG_TAG, "Cannot remove role holder for unknown role, role: " + roleName
+ ", package: " + packageName);
return false;
}
@@ -330,8 +329,7 @@ class RoleUserState {
}
if (!mWriteScheduled) {
mWriteHandler.sendMessageDelayed(PooledLambda.obtainMessage(RoleUserState::writeFile,
this), WRITE_DELAY_MILLIS);
mWriteHandler.postDelayed(this::writeFile, WRITE_DELAY_MILLIS);
mWriteScheduled = true;
}
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright (C) 2021 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.server.role.compat;
import android.annotation.UserIdInt;
import android.os.UserHandle;
/**
* Helper for accessing features in {@link UserHandle}.
*/
public final class UserHandleCompat {
/**
* A user ID to indicate all users on the device.
*/
public static final int USER_ALL = UserHandle.ALL.getIdentifier();
/**
* A user ID to indicate the "system" user of the device.
*/
public static final int USER_SYSTEM = UserHandle.SYSTEM.getIdentifier();
private UserHandleCompat() {}
/**
* Get the user ID of a given UID.
*
* @param uid the UID
* @return the user ID
*/
@UserIdInt
public static int getUserId(int uid) {
return UserHandle.getUserHandleForUid(uid).getIdentifier();
}
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright (C) 2021 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.server.role.util;
import android.annotation.Nullable;
import java.util.Objects;
/**
* Array utilities.
*/
public final class ArrayUtils {
private ArrayUtils() {}
/**
* @see java.util.List#contains(Object)
*/
public static <T> boolean contains(@Nullable T[] array, T value) {
return indexOf(array, value) != -1;
}
/**
* Get the first element of an array, or {@code null} if none.
*
* @param array the array
* @param <T> the type of the elements of the array
* @return first element of an array, or {@code null} if none
*/
public static <T> T firstOrNull(@Nullable T[] array) {
return !isEmpty(array) ? array[0] : null;
}
/**
* @see java.util.List#indexOf(Object)
*/
public static <T> int indexOf(@Nullable T[] array, T value) {
if (array == null) {
return -1;
}
final int length = array.length;
for (int i = 0; i < length; i++) {
final T element = array[i];
if (Objects.equals(element, value)) {
return i;
}
}
return -1;
}
/**
* @see java.util.List#isEmpty()
*/
public static <T> boolean isEmpty(@Nullable T[] array) {
return array == null || array.length == 0;
}
}

View File

@@ -0,0 +1,93 @@
/*
* Copyright (C) 2021 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.server.role.util;
import android.annotation.NonNull;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.HandlerThread;
import com.android.internal.annotations.GuardedBy;
import java.util.concurrent.Executor;
/**
* Shared singleton background thread.
*/
public class BackgroundThread extends HandlerThread {
private static final Object sLock = new Object();
@GuardedBy("sLock")
private static BackgroundThread sInstance;
@GuardedBy("sLock")
private static Handler sHandler;
@GuardedBy("sLock")
private static Executor sExecutor;
private BackgroundThread() {
super(BackgroundThread.class.getName());
}
@GuardedBy("sLock")
private static void ensureInstanceLocked() {
if (sInstance == null) {
sInstance = new BackgroundThread();
sInstance.start();
sHandler = new Handler(sInstance.getLooper());
sExecutor = new HandlerExecutor(sHandler);
}
}
/**
* Get the singleton instance of thi class.
*
* @return the singleton instance of thi class
*/
@NonNull
public static BackgroundThread get() {
synchronized (sLock) {
ensureInstanceLocked();
return sInstance;
}
}
/**
* Get the {@link Handler} for this thread.
*
* @return the {@link Handler} for this thread.
*/
@NonNull
public static Handler getHandler() {
synchronized (sLock) {
ensureInstanceLocked();
return sHandler;
}
}
/**
* Get the {@link Executor} for this thread.
*
* @return the {@link Executor} for this thread.
*/
@NonNull
public static Executor getExecutor() {
synchronized (sLock) {
ensureInstanceLocked();
return sExecutor;
}
}
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright (C) 2021 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.server.role.util;
import android.annotation.Nullable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* {@link Collection} utilities.
*/
public class CollectionUtils {
private CollectionUtils() {}
/**
* Get the first element of a {@link List}, or {@code null} if none.
*
* @param list the {@link List}, or {@code null}
* @param <E> the element type of the {@link List}
* @return the first element of the {@link List}, or {@code 0} if none
*/
@Nullable
public static <E> E firstOrNull(@Nullable List<E> list) {
return !isEmpty(list) ? list.get(0) : null;
}
/**
* Check whether a {@link Collection} is empty or {@code null}.
*
* @param collection the {@link Collection}, or {@code null}
* @return whether the {@link Collection} is empty or {@code null}
*/
public static boolean isEmpty(@Nullable Collection<?> collection) {
return collection == null || collection.isEmpty();
}
/**
* Get the size of a {@link Collection}, or {@code 0} if {@code null}.
*
* @param collection the {@link Collection}, or {@code null}
* @return the size of the {@link Collection}, or {@code 0} if {@code null}
*/
public static int size(@Nullable Collection<?> collection) {
return collection != null ? collection.size() : 0;
}
/**
* Get the size of a {@link Map}, or {@code 0} if {@code null}.
*
* @param collection the {@link Map}, or {@code null}
* @return the size of the {@link Map}, or {@code 0} if {@code null}
*/
public static int size(@Nullable Map<?, ?> collection) {
return collection != null ? collection.size() : 0;
}
}

View File

@@ -0,0 +1,93 @@
/*
* Copyright (C) 2021 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.server.role.util;
import android.annotation.NonNull;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.HandlerThread;
import com.android.internal.annotations.GuardedBy;
import java.util.concurrent.Executor;
/**
* Shared singleton foreground thread.
*/
public class ForegroundThread extends HandlerThread {
private static final Object sLock = new Object();
@GuardedBy("sLock")
private static ForegroundThread sInstance;
@GuardedBy("sLock")
private static Handler sHandler;
@GuardedBy("sLock")
private static Executor sExecutor;
private ForegroundThread() {
super(ForegroundThread.class.getName());
}
@GuardedBy("sLock")
private static void ensureInstanceLocked() {
if (sInstance == null) {
sInstance = new ForegroundThread();
sInstance.start();
sHandler = new Handler(sInstance.getLooper());
sExecutor = new HandlerExecutor(sHandler);
}
}
/**
* Get the singleton instance of thi class.
*
* @return the singleton instance of thi class
*/
@NonNull
public static ForegroundThread get() {
synchronized (sLock) {
ensureInstanceLocked();
return sInstance;
}
}
/**
* Get the {@link Handler} for this thread.
*
* @return the {@link Handler} for this thread.
*/
@NonNull
public static Handler getHandler() {
synchronized (sLock) {
ensureInstanceLocked();
return sHandler;
}
}
/**
* Get the {@link Executor} for this thread.
*
* @return the {@link Executor} for this thread.
*/
@NonNull
public static Executor getExecutor() {
synchronized (sLock) {
ensureInstanceLocked();
return sExecutor;
}
}
}

View File

@@ -156,12 +156,13 @@ import com.android.internal.util.CollectionUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.BatteryService;
import com.android.server.BinderCallsStatsService;
import com.android.server.LocalManagerRegistry;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.SystemServiceManager;
import com.android.server.am.MemoryStatUtil.MemoryStat;
import com.android.server.notification.NotificationManagerService;
import com.android.server.role.RoleManagerInternal;
import com.android.server.role.RoleManagerLocal;
import com.android.server.stats.pull.IonMemoryUtil.IonAllocations;
import com.android.server.stats.pull.ProcfsMemoryUtil.MemorySnapshot;
import com.android.server.stats.pull.netstats.NetworkStatsExt;
@@ -2916,7 +2917,8 @@ public class StatsPullAtomService extends SystemService {
final long callingToken = Binder.clearCallingIdentity();
try {
PackageManager pm = mContext.getPackageManager();
RoleManagerInternal rmi = LocalServices.getService(RoleManagerInternal.class);
RoleManagerLocal roleManagerLocal = LocalManagerRegistry.getManager(
RoleManagerLocal.class);
List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
@@ -2924,27 +2926,23 @@ public class StatsPullAtomService extends SystemService {
for (int userNum = 0; userNum < numUsers; userNum++) {
int userId = users.get(userNum).getUserHandle().getIdentifier();
ArrayMap<String, ArraySet<String>> roles = rmi.getRolesAndHolders(userId);
Map<String, Set<String>> roles = roleManagerLocal.getRolesAndHolders(userId);
int numRoles = roles.size();
for (int roleNum = 0; roleNum < numRoles; roleNum++) {
String roleName = roles.keyAt(roleNum);
ArraySet<String> holders = roles.valueAt(roleNum);
int numHolders = holders.size();
for (int holderNum = 0; holderNum < numHolders; holderNum++) {
String holderName = holders.valueAt(holderNum);
for (Map.Entry<String, Set<String>> roleEntry : roles.entrySet()) {
String roleName = roleEntry.getKey();
Set<String> packageNames = roleEntry.getValue();
for (String packageName : packageNames) {
PackageInfo pkg;
try {
pkg = pm.getPackageInfoAsUser(holderName, 0, userId);
pkg = pm.getPackageInfoAsUser(packageName, 0, userId);
} catch (PackageManager.NameNotFoundException e) {
Slog.w(TAG, "Role holder " + holderName + " not found");
Slog.w(TAG, "Role holder " + packageName + " not found");
return StatsManager.PULL_SKIP;
}
pulledData.add(FrameworkStatsLog.buildStatsEvent(
atomTag, pkg.applicationInfo.uid, holderName, roleName));
atomTag, pkg.applicationInfo.uid, packageName, roleName));
}
}
}

View File

@@ -168,7 +168,7 @@ import com.android.server.powerstats.PowerStatsService;
import com.android.server.profcollect.ProfcollectForwardingService;
import com.android.server.recoverysystem.RecoverySystemService;
import com.android.server.restrictions.RestrictionsManagerService;
import com.android.server.role.RoleManagerService;
import com.android.server.role.RoleServicePlatformHelper;
import com.android.server.security.FileIntegrityService;
import com.android.server.security.KeyAttestationApplicationIdProviderService;
import com.android.server.security.KeyChainSystemService;
@@ -353,6 +353,7 @@ public final class SystemServer implements Dumpable {
"com.android.server.ConnectivityServiceInitializer";
private static final String IP_CONNECTIVITY_METRICS_CLASS =
"com.android.server.connectivity.IpConnectivityMetrics";
private static final String ROLE_SERVICE_CLASS = "com.android.server.role.RoleService";
private static final String TETHERING_CONNECTOR_CLASS = "android.net.ITetheringConnector";
@@ -2032,8 +2033,9 @@ public final class SystemServer implements Dumpable {
// Grants default permissions and defines roles
t.traceBegin("StartRoleManagerService");
mSystemServiceManager.startService(new RoleManagerService(
mSystemContext, new RoleServicePlatformHelperImpl(mSystemContext)));
LocalManagerRegistry.addManager(RoleServicePlatformHelper.class,
new RoleServicePlatformHelperImpl(mSystemContext));
mSystemServiceManager.startService(ROLE_SERVICE_CLASS);
t.traceEnd();
// We need to always start this service, regardless of whether the