Loading services/core/java/com/android/server/role/RoleManagerService.java +116 −81 Original line number Diff line number Diff line Loading @@ -18,13 +18,11 @@ package com.android.server.role; import android.Manifest; import android.annotation.AnyThread; import android.annotation.CheckResult; import android.annotation.MainThread; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.annotation.WorkerThread; import android.app.ActivityManager; import android.app.AppOpsManager; import android.app.role.IOnRoleHoldersChangedListener; import android.app.role.IRoleManager; Loading @@ -34,20 +32,22 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.Signature; import android.os.Binder; import android.os.Handler; import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.RemoteCallback; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ShellCallback; 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.PackageUtils; import android.util.Slog; import android.util.SparseArray; Loading @@ -57,11 +57,7 @@ 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.BitUtils; import com.android.internal.util.CollectionUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.FunctionalUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; import com.android.internal.util.dump.DualDumpOutputStream; import com.android.internal.util.function.pooled.PooledLambda; Loading @@ -71,7 +67,10 @@ import com.android.server.SystemService; import com.android.server.pm.UserManagerInternal; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.FileDescriptor; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; Loading @@ -87,17 +86,18 @@ import java.util.concurrent.TimeoutException; * @see RoleManager */ public class RoleManagerService extends SystemService implements RoleUserState.Callback { private static final String LOG_TAG = RoleManagerService.class.getSimpleName(); private static final boolean DEBUG = false; private static final long GRANT_DEFAULT_ROLES_INTERVAL_MILLIS = 1000; @NonNull private final UserManagerInternal mUserManagerInternal; @NonNull private final AppOpsManager mAppOpsManager; @NonNull private final PackageManagerInternal mPackageManagerInternal; @NonNull private final UserManagerInternal mUserManagerInternal; @NonNull private final Object mLock = new Object(); Loading Loading @@ -146,8 +146,9 @@ public class RoleManagerService extends SystemService implements RoleUserState.C RoleControllerManager.initializeRemoteServiceComponentName(context); mUserManagerInternal = LocalServices.getService(UserManagerInternal.class); mAppOpsManager = context.getSystemService(AppOpsManager.class); mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); mUserManagerInternal = LocalServices.getService(UserManagerInternal.class); LocalServices.addService(RoleManagerInternal.class, new Internal()); Loading @@ -157,15 +158,16 @@ public class RoleManagerService extends SystemService implements RoleUserState.C private void registerUserRemovedReceiver() { IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_USER_REMOVED); getContext().registerReceiverAsUser(new BroadcastReceiver() { 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.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); int userId = intent.<UserHandle>getParcelableExtra(Intent.EXTRA_USER) .getIdentifier(); onRemoveUser(userId); } } }, UserHandle.ALL, intentFilter, null, null); }, intentFilter, null, null); } @Override Loading @@ -178,7 +180,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); intentFilter.addDataScheme("package"); intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); getContext().registerReceiverAsUser(new BroadcastReceiver() { getContext().registerReceiverForAllUsers(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { int userId = UserHandle.getUserId(intent.getIntExtra(Intent.EXTRA_UID, -1)); Loading @@ -193,12 +195,12 @@ public class RoleManagerService extends SystemService implements RoleUserState.C } maybeGrantDefaultRolesAsync(userId); } }, UserHandle.ALL, intentFilter, null, null); }, intentFilter, null, null); } @Override public void onUserStarting(@NonNull TargetUser user) { maybeGrantDefaultRolesSync(user.getUserIdentifier()); maybeGrantDefaultRolesSync(user.getUserHandle().getIdentifier()); } @MainThread Loading Loading @@ -230,7 +232,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C private AndroidFuture<Void> maybeGrantDefaultRolesInternal(@UserIdInt int userId) { RoleUserState userState = getOrCreateUserState(userId); String oldPackagesHash = userState.getPackagesHash(); String newPackagesHash = computeComponentStateHash(userId); String newPackagesHash = computePackageStateHash(userId); if (Objects.equals(oldPackagesHash, newPackagesHash)) { if (DEBUG) { Slog.i(LOG_TAG, "Already granted default roles for packages hash " Loading Loading @@ -282,35 +284,42 @@ public class RoleManagerService extends SystemService implements RoleUserState.C } @Nullable private static String computeComponentStateHash(@UserIdInt int userId) { PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class); ByteArrayOutputStream out = new ByteArrayOutputStream(); private String computePackageStateHash(@UserIdInt int userId) { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream); pm.forEachInstalledPackage(FunctionalUtils.uncheckExceptions(pkg -> { out.write(pkg.getPackageName().getBytes()); out.write(BitUtils.toBytes(pkg.getLongVersionCode())); out.write(pm.getApplicationEnabledState(pkg.getPackageName(), userId)); mPackageManagerInternal.forEachInstalledPackage(pkg -> { try { dataOutputStream.writeUTF(pkg.getPackageName()); dataOutputStream.writeLong(pkg.getLongVersionCode()); dataOutputStream.writeInt(mPackageManagerInternal.getApplicationEnabledState( pkg.getPackageName(), userId)); ArraySet<String> enabledComponents = pm.getEnabledComponents(pkg.getPackageName(), userId); mPackageManagerInternal.getEnabledComponents(pkg.getPackageName(), userId); int numComponents = CollectionUtils.size(enabledComponents); out.write(numComponents); dataOutputStream.writeInt(numComponents); for (int i = 0; i < numComponents; i++) { out.write(enabledComponents.valueAt(i).getBytes()); dataOutputStream.writeUTF(enabledComponents.valueAt(i)); } ArraySet<String> disabledComponents = pm.getDisabledComponents(pkg.getPackageName(), userId); mPackageManagerInternal.getDisabledComponents(pkg.getPackageName(), userId); numComponents = CollectionUtils.size(disabledComponents); for (int i = 0; i < numComponents; i++) { out.write(disabledComponents.valueAt(i).getBytes()); dataOutputStream.writeUTF(disabledComponents.valueAt(i)); } for (Signature signature : pkg.getSigningDetails().signatures) { out.write(signature.toByteArray()); dataOutputStream.write(signature.toByteArray()); } } catch (IOException e) { // Never happens for ByteArrayOutputStream and DataOutputStream. throw new AssertionError(e); } }), userId); }, userId); return PackageUtils.computeSha256Digest(out.toByteArray()); return PackageUtils.computeSha256Digest(byteArrayOutputStream.toByteArray()); } @NonNull Loading @@ -335,7 +344,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C try { context = systemContext.createPackageContextAsUser( systemContext.getPackageName(), 0, UserHandle.of(userId)); } catch (NameNotFoundException e) { } catch (PackageManager.NameNotFoundException e) { throw new RuntimeException(e); } controller = RoleControllerManager.createWithInitializedRemoteServiceComponentName( Loading Loading @@ -371,9 +380,11 @@ public class RoleManagerService extends SystemService implements RoleUserState.C RoleUserState userState; synchronized (mLock) { mGrantDefaultRolesThrottledRunnables.remove(userId); listeners = mListeners.removeReturnOld(userId); listeners = mListeners.get(userId); mListeners.remove(userId); mControllers.remove(userId); userState = mUserStates.removeReturnOld(userId); userState = mUserStates.get(userId); mUserStates.remove(userId); } if (listeners != null) { listeners.kill(); Loading Loading @@ -455,7 +466,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C Slog.e(LOG_TAG, "user " + userId + " does not exist"); return Collections.emptyList(); } userId = handleIncomingUser(userId, false, "getRoleHoldersAsUser"); enforceCrossUserPermission(userId, false, "getRoleHoldersAsUser"); getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS, "getRoleHoldersAsUser"); Loading @@ -476,7 +487,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C Slog.e(LOG_TAG, "user " + userId + " does not exist"); return; } userId = handleIncomingUser(userId, false, "addRoleHolderAsUser"); enforceCrossUserPermission(userId, false, "addRoleHolderAsUser"); getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS, "addRoleHolderAsUser"); Loading @@ -496,7 +507,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C Slog.e(LOG_TAG, "user " + userId + " does not exist"); return; } userId = handleIncomingUser(userId, false, "removeRoleHolderAsUser"); enforceCrossUserPermission(userId, false, "removeRoleHolderAsUser"); getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS, "removeRoleHolderAsUser"); Loading @@ -516,7 +527,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C Slog.e(LOG_TAG, "user " + userId + " does not exist"); return; } userId = handleIncomingUser(userId, false, "clearRoleHoldersAsUser"); enforceCrossUserPermission(userId, false, "clearRoleHoldersAsUser"); getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS, "clearRoleHoldersAsUser"); Loading @@ -533,7 +544,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C Slog.e(LOG_TAG, "user " + userId + " does not exist"); return; } userId = handleIncomingUser(userId, true, "addOnRoleHoldersChangedListenerAsUser"); enforceCrossUserPermission(userId, true, "addOnRoleHoldersChangedListenerAsUser"); getContext().enforceCallingOrSelfPermission(Manifest.permission.OBSERVE_ROLE_HOLDERS, "addOnRoleHoldersChangedListenerAsUser"); Loading @@ -551,7 +562,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C Slog.e(LOG_TAG, "user " + userId + " does not exist"); return; } userId = handleIncomingUser(userId, true, "removeOnRoleHoldersChangedListenerAsUser"); enforceCrossUserPermission(userId, true, "removeOnRoleHoldersChangedListenerAsUser"); getContext().enforceCallingOrSelfPermission(Manifest.permission.OBSERVE_ROLE_HOLDERS, "removeOnRoleHoldersChangedListenerAsUser"); Loading @@ -572,7 +583,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C Objects.requireNonNull(roleNames, "roleNames cannot be null"); int userId = UserHandle.getCallingUserId(); int userId = UserHandle.getUserId(Binder.getCallingUid()); getOrCreateUserState(userId).setRoleNames(roleNames); } Loading @@ -586,7 +597,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.getCallingUserId(); int userId = UserHandle.getUserId(Binder.getCallingUid()); return getOrCreateUserState(userId).addRoleHolder(roleName, packageName); } Loading @@ -600,7 +611,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.getCallingUserId(); int userId = UserHandle.getUserId(Binder.getCallingUid()); return getOrCreateUserState(userId).removeRoleHolder(roleName, packageName); } Loading @@ -612,23 +623,36 @@ public class RoleManagerService extends SystemService implements RoleUserState.C Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty"); int userId = UserHandle.getCallingUserId(); int userId = UserHandle.getUserId(Binder.getCallingUid()); return getOrCreateUserState(userId).getHeldRoles(packageName); } @CheckResult private int handleIncomingUser(@UserIdInt int userId, boolean allowAll, @NonNull String name) { return ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId, allowAll, true, name, null); private void enforceCrossUserPermission(@UserIdInt int userId, boolean allowAll, @NonNull String message) { final int callingUid = Binder.getCallingUid(); final int callingUserId = UserHandle.getUserId(callingUid); if (userId == callingUserId) { return; } Preconditions.checkArgument(userId >= UserHandle.USER_SYSTEM || (allowAll && userId == UserHandle.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)) { throw new SecurityException("Shell does not have permission to access user " + userId); } } } @Override public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out, @Nullable FileDescriptor err, @NonNull String[] args, @Nullable ShellCallback callback, @NonNull ResultReceiver resultReceiver) { new RoleManagerShellCommand(this).exec(this, in, out, err, args, callback, resultReceiver); public int handleShellCommand(@NonNull ParcelFileDescriptor in, @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err, @NonNull String[] args) { return new RoleManagerShellCommand(this).exec(this, in.getFileDescriptor(), out.getFileDescriptor(), err.getFileDescriptor(), args); } @Nullable Loading @@ -639,9 +663,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C getContext().enforceCallingOrSelfPermission( android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null); } final PackageManagerInternal packageManager = LocalServices.getService( PackageManagerInternal.class); if (packageManager.getInstantAppPackageName(callingUid) != null) { if (mPackageManagerInternal.getInstantAppPackageName(callingUid) != null) { return null; } Loading @@ -659,7 +681,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C final Context context = getContext(); context.enforceCallingOrSelfPermission( android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null); if (UserHandle.getCallingUserId() != userId) { if (UserHandle.getUserId(Binder.getCallingUid()) != userId) { context.enforceCallingOrSelfPermission( android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null); } Loading Loading @@ -711,35 +733,48 @@ public class RoleManagerService extends SystemService implements RoleUserState.C @Override protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout, @Nullable String[] args) { if (!DumpUtils.checkDumpPermission(getContext(), LOG_TAG, fout)) { if (!checkDumpPermission("role", fout)) { return; } boolean dumpAsProto = args != null && ArrayUtils.contains(args, "--proto"); DualDumpOutputStream dumpOutputStream; if (dumpAsProto) { dumpOutputStream = new DualDumpOutputStream(new ProtoOutputStream(fd)); dumpOutputStream = new DualDumpOutputStream(new ProtoOutputStream( new FileOutputStream(fd))); } else { fout.println("ROLE MANAGER STATE (dumpsys role):"); dumpOutputStream = new DualDumpOutputStream(new IndentingPrintWriter(fout, " ")); } int[] userIds = mUserManagerInternal.getUserIds(); int userIdsLength = userIds.length; for (int i = 0; i < userIdsLength; i++) { int userId = userIds[i]; synchronized (mLock) { final int userStatesSize = mUserStates.size(); for (int i = 0; i < userStatesSize; i++) { final RoleUserState userState = mUserStates.valueAt(i); RoleUserState userState = getOrCreateUserState(userId); userState.dump(dumpOutputStream, "user_states", RoleManagerServiceDumpProto.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 Internal extends RoleManagerInternal { @NonNull @Override public ArrayMap<String, ArraySet<String>> getRolesAndHolders(@UserIdInt int userId) { Loading services/core/java/com/android/server/role/RoleManagerShellCommand.java +6 −9 Original line number Diff line number Diff line Loading @@ -21,16 +21,15 @@ import android.annotation.Nullable; import android.app.role.IRoleManager; import android.os.RemoteCallback; import android.os.RemoteException; import android.os.ShellCommand; import android.os.UserHandle; import android.util.Log; import com.android.modules.utils.BasicShellCommandHandler; import java.io.PrintWriter; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; class RoleManagerShellCommand extends ShellCommand { class RoleManagerShellCommand extends BasicShellCommandHandler { @NonNull private final IRoleManager mRoleManager; Loading @@ -39,7 +38,6 @@ class RoleManagerShellCommand extends ShellCommand { } private class CallbackFuture extends CompletableFuture<Void> { @NonNull public RemoteCallback createCallback() { return new RemoteCallback(result -> { Loading @@ -57,8 +55,7 @@ class RoleManagerShellCommand extends ShellCommand { get(5, TimeUnit.SECONDS); return 0; } catch (Exception e) { getErrPrintWriter().println("Error: see logcat for details.\n" + Log.getStackTraceString(e)); getErrPrintWriter().println("Error: see logcat for details.\n" + e); return -1; } } Loading Loading @@ -92,7 +89,7 @@ class RoleManagerShellCommand extends ShellCommand { int userId = UserHandle.USER_SYSTEM; String option = getNextOption(); if (option != null && option.equals("--user")) { userId = UserHandle.parseUserArg(getNextArgRequired()); userId = Integer.parseInt(getNextArgRequired()); } return userId; } Loading Loading @@ -143,7 +140,7 @@ class RoleManagerShellCommand extends ShellCommand { public void onHelp() { PrintWriter pw = getOutPrintWriter(); pw.println("Role manager (role) commands:"); pw.println(" help"); pw.println(" help or -h"); pw.println(" Print this help text."); pw.println(); pw.println(" add-role-holder [--user USER_ID] ROLE PACKAGE [FLAGS]"); Loading services/core/java/com/android/server/role/RoleUserState.java +8 −9 Original line number Diff line number Diff line Loading @@ -28,7 +28,6 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.AtomicFile; import android.util.Slog; import android.util.TypedXmlPullParser; import android.util.Xml; import com.android.internal.annotations.GuardedBy; Loading @@ -55,8 +54,7 @@ import java.util.Set; /** * Stores the state of roles for a user. */ public class RoleUserState { class RoleUserState { private static final String LOG_TAG = RoleUserState.class.getSimpleName(); public static final int VERSION_UNDEFINED = -1; Loading Loading @@ -104,7 +102,7 @@ public class RoleUserState { private boolean mDestroyed; @NonNull private final Handler mWriteHandler = new Handler(BackgroundThread.getHandler().getLooper()); private final Handler mWriteHandler = new Handler(BackgroundThread.get().getLooper()); /** * Create a new user state, and read its state from disk if previously persisted. Loading Loading @@ -392,7 +390,8 @@ public class RoleUserState { private void readLegacyFileLocked() { File file = getFile(mUserId); try (FileInputStream in = new AtomicFile(file).openRead()) { TypedXmlPullParser parser = Xml.resolvePullParser(in); XmlPullParser parser = Xml.newPullParser(); parser.setInput(in, null); parseXmlLocked(parser); Slog.i(LOG_TAG, "Read roles.xml successfully"); } catch (FileNotFoundException e) { Loading @@ -402,7 +401,7 @@ public class RoleUserState { } } private void parseXmlLocked(@NonNull TypedXmlPullParser parser) throws IOException, private void parseXmlLocked(@NonNull XmlPullParser parser) throws IOException, XmlPullParserException { int type; int depth; Loading @@ -421,9 +420,9 @@ public class RoleUserState { Slog.w(LOG_TAG, "Missing <" + TAG_ROLES + "> in roles.xml"); } private void parseRolesLocked(@NonNull TypedXmlPullParser parser) throws IOException, private void parseRolesLocked(@NonNull XmlPullParser parser) throws IOException, XmlPullParserException { mVersion = parser.getAttributeInt(null, ATTRIBUTE_VERSION); mVersion = Integer.parseInt(parser.getAttributeValue(null, ATTRIBUTE_VERSION)); mPackagesHash = parser.getAttributeValue(null, ATTRIBUTE_PACKAGES_HASH); mRoles.clear(); Loading @@ -445,7 +444,7 @@ public class RoleUserState { } @NonNull private ArraySet<String> parseRoleHoldersLocked(@NonNull TypedXmlPullParser parser) private ArraySet<String> parseRoleHoldersLocked(@NonNull XmlPullParser parser) throws IOException, XmlPullParserException { ArraySet<String> roleHolders = new ArraySet<>(); Loading Loading
services/core/java/com/android/server/role/RoleManagerService.java +116 −81 Original line number Diff line number Diff line Loading @@ -18,13 +18,11 @@ package com.android.server.role; import android.Manifest; import android.annotation.AnyThread; import android.annotation.CheckResult; import android.annotation.MainThread; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.annotation.WorkerThread; import android.app.ActivityManager; import android.app.AppOpsManager; import android.app.role.IOnRoleHoldersChangedListener; import android.app.role.IRoleManager; Loading @@ -34,20 +32,22 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.Signature; import android.os.Binder; import android.os.Handler; import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.RemoteCallback; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ShellCallback; 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.PackageUtils; import android.util.Slog; import android.util.SparseArray; Loading @@ -57,11 +57,7 @@ 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.BitUtils; import com.android.internal.util.CollectionUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.FunctionalUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; import com.android.internal.util.dump.DualDumpOutputStream; import com.android.internal.util.function.pooled.PooledLambda; Loading @@ -71,7 +67,10 @@ import com.android.server.SystemService; import com.android.server.pm.UserManagerInternal; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.FileDescriptor; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; Loading @@ -87,17 +86,18 @@ import java.util.concurrent.TimeoutException; * @see RoleManager */ public class RoleManagerService extends SystemService implements RoleUserState.Callback { private static final String LOG_TAG = RoleManagerService.class.getSimpleName(); private static final boolean DEBUG = false; private static final long GRANT_DEFAULT_ROLES_INTERVAL_MILLIS = 1000; @NonNull private final UserManagerInternal mUserManagerInternal; @NonNull private final AppOpsManager mAppOpsManager; @NonNull private final PackageManagerInternal mPackageManagerInternal; @NonNull private final UserManagerInternal mUserManagerInternal; @NonNull private final Object mLock = new Object(); Loading Loading @@ -146,8 +146,9 @@ public class RoleManagerService extends SystemService implements RoleUserState.C RoleControllerManager.initializeRemoteServiceComponentName(context); mUserManagerInternal = LocalServices.getService(UserManagerInternal.class); mAppOpsManager = context.getSystemService(AppOpsManager.class); mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); mUserManagerInternal = LocalServices.getService(UserManagerInternal.class); LocalServices.addService(RoleManagerInternal.class, new Internal()); Loading @@ -157,15 +158,16 @@ public class RoleManagerService extends SystemService implements RoleUserState.C private void registerUserRemovedReceiver() { IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_USER_REMOVED); getContext().registerReceiverAsUser(new BroadcastReceiver() { 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.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); int userId = intent.<UserHandle>getParcelableExtra(Intent.EXTRA_USER) .getIdentifier(); onRemoveUser(userId); } } }, UserHandle.ALL, intentFilter, null, null); }, intentFilter, null, null); } @Override Loading @@ -178,7 +180,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); intentFilter.addDataScheme("package"); intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); getContext().registerReceiverAsUser(new BroadcastReceiver() { getContext().registerReceiverForAllUsers(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { int userId = UserHandle.getUserId(intent.getIntExtra(Intent.EXTRA_UID, -1)); Loading @@ -193,12 +195,12 @@ public class RoleManagerService extends SystemService implements RoleUserState.C } maybeGrantDefaultRolesAsync(userId); } }, UserHandle.ALL, intentFilter, null, null); }, intentFilter, null, null); } @Override public void onUserStarting(@NonNull TargetUser user) { maybeGrantDefaultRolesSync(user.getUserIdentifier()); maybeGrantDefaultRolesSync(user.getUserHandle().getIdentifier()); } @MainThread Loading Loading @@ -230,7 +232,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C private AndroidFuture<Void> maybeGrantDefaultRolesInternal(@UserIdInt int userId) { RoleUserState userState = getOrCreateUserState(userId); String oldPackagesHash = userState.getPackagesHash(); String newPackagesHash = computeComponentStateHash(userId); String newPackagesHash = computePackageStateHash(userId); if (Objects.equals(oldPackagesHash, newPackagesHash)) { if (DEBUG) { Slog.i(LOG_TAG, "Already granted default roles for packages hash " Loading Loading @@ -282,35 +284,42 @@ public class RoleManagerService extends SystemService implements RoleUserState.C } @Nullable private static String computeComponentStateHash(@UserIdInt int userId) { PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class); ByteArrayOutputStream out = new ByteArrayOutputStream(); private String computePackageStateHash(@UserIdInt int userId) { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream); pm.forEachInstalledPackage(FunctionalUtils.uncheckExceptions(pkg -> { out.write(pkg.getPackageName().getBytes()); out.write(BitUtils.toBytes(pkg.getLongVersionCode())); out.write(pm.getApplicationEnabledState(pkg.getPackageName(), userId)); mPackageManagerInternal.forEachInstalledPackage(pkg -> { try { dataOutputStream.writeUTF(pkg.getPackageName()); dataOutputStream.writeLong(pkg.getLongVersionCode()); dataOutputStream.writeInt(mPackageManagerInternal.getApplicationEnabledState( pkg.getPackageName(), userId)); ArraySet<String> enabledComponents = pm.getEnabledComponents(pkg.getPackageName(), userId); mPackageManagerInternal.getEnabledComponents(pkg.getPackageName(), userId); int numComponents = CollectionUtils.size(enabledComponents); out.write(numComponents); dataOutputStream.writeInt(numComponents); for (int i = 0; i < numComponents; i++) { out.write(enabledComponents.valueAt(i).getBytes()); dataOutputStream.writeUTF(enabledComponents.valueAt(i)); } ArraySet<String> disabledComponents = pm.getDisabledComponents(pkg.getPackageName(), userId); mPackageManagerInternal.getDisabledComponents(pkg.getPackageName(), userId); numComponents = CollectionUtils.size(disabledComponents); for (int i = 0; i < numComponents; i++) { out.write(disabledComponents.valueAt(i).getBytes()); dataOutputStream.writeUTF(disabledComponents.valueAt(i)); } for (Signature signature : pkg.getSigningDetails().signatures) { out.write(signature.toByteArray()); dataOutputStream.write(signature.toByteArray()); } } catch (IOException e) { // Never happens for ByteArrayOutputStream and DataOutputStream. throw new AssertionError(e); } }), userId); }, userId); return PackageUtils.computeSha256Digest(out.toByteArray()); return PackageUtils.computeSha256Digest(byteArrayOutputStream.toByteArray()); } @NonNull Loading @@ -335,7 +344,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C try { context = systemContext.createPackageContextAsUser( systemContext.getPackageName(), 0, UserHandle.of(userId)); } catch (NameNotFoundException e) { } catch (PackageManager.NameNotFoundException e) { throw new RuntimeException(e); } controller = RoleControllerManager.createWithInitializedRemoteServiceComponentName( Loading Loading @@ -371,9 +380,11 @@ public class RoleManagerService extends SystemService implements RoleUserState.C RoleUserState userState; synchronized (mLock) { mGrantDefaultRolesThrottledRunnables.remove(userId); listeners = mListeners.removeReturnOld(userId); listeners = mListeners.get(userId); mListeners.remove(userId); mControllers.remove(userId); userState = mUserStates.removeReturnOld(userId); userState = mUserStates.get(userId); mUserStates.remove(userId); } if (listeners != null) { listeners.kill(); Loading Loading @@ -455,7 +466,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C Slog.e(LOG_TAG, "user " + userId + " does not exist"); return Collections.emptyList(); } userId = handleIncomingUser(userId, false, "getRoleHoldersAsUser"); enforceCrossUserPermission(userId, false, "getRoleHoldersAsUser"); getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS, "getRoleHoldersAsUser"); Loading @@ -476,7 +487,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C Slog.e(LOG_TAG, "user " + userId + " does not exist"); return; } userId = handleIncomingUser(userId, false, "addRoleHolderAsUser"); enforceCrossUserPermission(userId, false, "addRoleHolderAsUser"); getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS, "addRoleHolderAsUser"); Loading @@ -496,7 +507,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C Slog.e(LOG_TAG, "user " + userId + " does not exist"); return; } userId = handleIncomingUser(userId, false, "removeRoleHolderAsUser"); enforceCrossUserPermission(userId, false, "removeRoleHolderAsUser"); getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS, "removeRoleHolderAsUser"); Loading @@ -516,7 +527,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C Slog.e(LOG_TAG, "user " + userId + " does not exist"); return; } userId = handleIncomingUser(userId, false, "clearRoleHoldersAsUser"); enforceCrossUserPermission(userId, false, "clearRoleHoldersAsUser"); getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS, "clearRoleHoldersAsUser"); Loading @@ -533,7 +544,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C Slog.e(LOG_TAG, "user " + userId + " does not exist"); return; } userId = handleIncomingUser(userId, true, "addOnRoleHoldersChangedListenerAsUser"); enforceCrossUserPermission(userId, true, "addOnRoleHoldersChangedListenerAsUser"); getContext().enforceCallingOrSelfPermission(Manifest.permission.OBSERVE_ROLE_HOLDERS, "addOnRoleHoldersChangedListenerAsUser"); Loading @@ -551,7 +562,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C Slog.e(LOG_TAG, "user " + userId + " does not exist"); return; } userId = handleIncomingUser(userId, true, "removeOnRoleHoldersChangedListenerAsUser"); enforceCrossUserPermission(userId, true, "removeOnRoleHoldersChangedListenerAsUser"); getContext().enforceCallingOrSelfPermission(Manifest.permission.OBSERVE_ROLE_HOLDERS, "removeOnRoleHoldersChangedListenerAsUser"); Loading @@ -572,7 +583,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C Objects.requireNonNull(roleNames, "roleNames cannot be null"); int userId = UserHandle.getCallingUserId(); int userId = UserHandle.getUserId(Binder.getCallingUid()); getOrCreateUserState(userId).setRoleNames(roleNames); } Loading @@ -586,7 +597,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.getCallingUserId(); int userId = UserHandle.getUserId(Binder.getCallingUid()); return getOrCreateUserState(userId).addRoleHolder(roleName, packageName); } Loading @@ -600,7 +611,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.getCallingUserId(); int userId = UserHandle.getUserId(Binder.getCallingUid()); return getOrCreateUserState(userId).removeRoleHolder(roleName, packageName); } Loading @@ -612,23 +623,36 @@ public class RoleManagerService extends SystemService implements RoleUserState.C Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty"); int userId = UserHandle.getCallingUserId(); int userId = UserHandle.getUserId(Binder.getCallingUid()); return getOrCreateUserState(userId).getHeldRoles(packageName); } @CheckResult private int handleIncomingUser(@UserIdInt int userId, boolean allowAll, @NonNull String name) { return ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId, allowAll, true, name, null); private void enforceCrossUserPermission(@UserIdInt int userId, boolean allowAll, @NonNull String message) { final int callingUid = Binder.getCallingUid(); final int callingUserId = UserHandle.getUserId(callingUid); if (userId == callingUserId) { return; } Preconditions.checkArgument(userId >= UserHandle.USER_SYSTEM || (allowAll && userId == UserHandle.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)) { throw new SecurityException("Shell does not have permission to access user " + userId); } } } @Override public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out, @Nullable FileDescriptor err, @NonNull String[] args, @Nullable ShellCallback callback, @NonNull ResultReceiver resultReceiver) { new RoleManagerShellCommand(this).exec(this, in, out, err, args, callback, resultReceiver); public int handleShellCommand(@NonNull ParcelFileDescriptor in, @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err, @NonNull String[] args) { return new RoleManagerShellCommand(this).exec(this, in.getFileDescriptor(), out.getFileDescriptor(), err.getFileDescriptor(), args); } @Nullable Loading @@ -639,9 +663,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C getContext().enforceCallingOrSelfPermission( android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null); } final PackageManagerInternal packageManager = LocalServices.getService( PackageManagerInternal.class); if (packageManager.getInstantAppPackageName(callingUid) != null) { if (mPackageManagerInternal.getInstantAppPackageName(callingUid) != null) { return null; } Loading @@ -659,7 +681,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C final Context context = getContext(); context.enforceCallingOrSelfPermission( android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null); if (UserHandle.getCallingUserId() != userId) { if (UserHandle.getUserId(Binder.getCallingUid()) != userId) { context.enforceCallingOrSelfPermission( android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null); } Loading Loading @@ -711,35 +733,48 @@ public class RoleManagerService extends SystemService implements RoleUserState.C @Override protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout, @Nullable String[] args) { if (!DumpUtils.checkDumpPermission(getContext(), LOG_TAG, fout)) { if (!checkDumpPermission("role", fout)) { return; } boolean dumpAsProto = args != null && ArrayUtils.contains(args, "--proto"); DualDumpOutputStream dumpOutputStream; if (dumpAsProto) { dumpOutputStream = new DualDumpOutputStream(new ProtoOutputStream(fd)); dumpOutputStream = new DualDumpOutputStream(new ProtoOutputStream( new FileOutputStream(fd))); } else { fout.println("ROLE MANAGER STATE (dumpsys role):"); dumpOutputStream = new DualDumpOutputStream(new IndentingPrintWriter(fout, " ")); } int[] userIds = mUserManagerInternal.getUserIds(); int userIdsLength = userIds.length; for (int i = 0; i < userIdsLength; i++) { int userId = userIds[i]; synchronized (mLock) { final int userStatesSize = mUserStates.size(); for (int i = 0; i < userStatesSize; i++) { final RoleUserState userState = mUserStates.valueAt(i); RoleUserState userState = getOrCreateUserState(userId); userState.dump(dumpOutputStream, "user_states", RoleManagerServiceDumpProto.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 Internal extends RoleManagerInternal { @NonNull @Override public ArrayMap<String, ArraySet<String>> getRolesAndHolders(@UserIdInt int userId) { Loading
services/core/java/com/android/server/role/RoleManagerShellCommand.java +6 −9 Original line number Diff line number Diff line Loading @@ -21,16 +21,15 @@ import android.annotation.Nullable; import android.app.role.IRoleManager; import android.os.RemoteCallback; import android.os.RemoteException; import android.os.ShellCommand; import android.os.UserHandle; import android.util.Log; import com.android.modules.utils.BasicShellCommandHandler; import java.io.PrintWriter; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; class RoleManagerShellCommand extends ShellCommand { class RoleManagerShellCommand extends BasicShellCommandHandler { @NonNull private final IRoleManager mRoleManager; Loading @@ -39,7 +38,6 @@ class RoleManagerShellCommand extends ShellCommand { } private class CallbackFuture extends CompletableFuture<Void> { @NonNull public RemoteCallback createCallback() { return new RemoteCallback(result -> { Loading @@ -57,8 +55,7 @@ class RoleManagerShellCommand extends ShellCommand { get(5, TimeUnit.SECONDS); return 0; } catch (Exception e) { getErrPrintWriter().println("Error: see logcat for details.\n" + Log.getStackTraceString(e)); getErrPrintWriter().println("Error: see logcat for details.\n" + e); return -1; } } Loading Loading @@ -92,7 +89,7 @@ class RoleManagerShellCommand extends ShellCommand { int userId = UserHandle.USER_SYSTEM; String option = getNextOption(); if (option != null && option.equals("--user")) { userId = UserHandle.parseUserArg(getNextArgRequired()); userId = Integer.parseInt(getNextArgRequired()); } return userId; } Loading Loading @@ -143,7 +140,7 @@ class RoleManagerShellCommand extends ShellCommand { public void onHelp() { PrintWriter pw = getOutPrintWriter(); pw.println("Role manager (role) commands:"); pw.println(" help"); pw.println(" help or -h"); pw.println(" Print this help text."); pw.println(); pw.println(" add-role-holder [--user USER_ID] ROLE PACKAGE [FLAGS]"); Loading
services/core/java/com/android/server/role/RoleUserState.java +8 −9 Original line number Diff line number Diff line Loading @@ -28,7 +28,6 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.AtomicFile; import android.util.Slog; import android.util.TypedXmlPullParser; import android.util.Xml; import com.android.internal.annotations.GuardedBy; Loading @@ -55,8 +54,7 @@ import java.util.Set; /** * Stores the state of roles for a user. */ public class RoleUserState { class RoleUserState { private static final String LOG_TAG = RoleUserState.class.getSimpleName(); public static final int VERSION_UNDEFINED = -1; Loading Loading @@ -104,7 +102,7 @@ public class RoleUserState { private boolean mDestroyed; @NonNull private final Handler mWriteHandler = new Handler(BackgroundThread.getHandler().getLooper()); private final Handler mWriteHandler = new Handler(BackgroundThread.get().getLooper()); /** * Create a new user state, and read its state from disk if previously persisted. Loading Loading @@ -392,7 +390,8 @@ public class RoleUserState { private void readLegacyFileLocked() { File file = getFile(mUserId); try (FileInputStream in = new AtomicFile(file).openRead()) { TypedXmlPullParser parser = Xml.resolvePullParser(in); XmlPullParser parser = Xml.newPullParser(); parser.setInput(in, null); parseXmlLocked(parser); Slog.i(LOG_TAG, "Read roles.xml successfully"); } catch (FileNotFoundException e) { Loading @@ -402,7 +401,7 @@ public class RoleUserState { } } private void parseXmlLocked(@NonNull TypedXmlPullParser parser) throws IOException, private void parseXmlLocked(@NonNull XmlPullParser parser) throws IOException, XmlPullParserException { int type; int depth; Loading @@ -421,9 +420,9 @@ public class RoleUserState { Slog.w(LOG_TAG, "Missing <" + TAG_ROLES + "> in roles.xml"); } private void parseRolesLocked(@NonNull TypedXmlPullParser parser) throws IOException, private void parseRolesLocked(@NonNull XmlPullParser parser) throws IOException, XmlPullParserException { mVersion = parser.getAttributeInt(null, ATTRIBUTE_VERSION); mVersion = Integer.parseInt(parser.getAttributeValue(null, ATTRIBUTE_VERSION)); mPackagesHash = parser.getAttributeValue(null, ATTRIBUTE_PACKAGES_HASH); mRoles.clear(); Loading @@ -445,7 +444,7 @@ public class RoleUserState { } @NonNull private ArraySet<String> parseRoleHoldersLocked(@NonNull TypedXmlPullParser parser) private ArraySet<String> parseRoleHoldersLocked(@NonNull XmlPullParser parser) throws IOException, XmlPullParserException { ArraySet<String> roleHolders = new ArraySet<>(); Loading