Loading src/com/android/packageinstaller/role/service/RoleControllerServiceImpl.java +119 −231 Original line number Diff line number Diff line Loading @@ -16,27 +16,22 @@ package com.android.packageinstaller.role.service; import android.Manifest; import android.app.AppOpsManager; import android.app.role.RoleControllerService; import android.app.role.RoleManager; import android.app.role.RoleManagerCallback; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PermissionInfo; import android.os.Binder; import android.os.Build; import android.os.Handler; import android.os.HandlerThread; import android.os.Process; import android.os.UserHandle; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.WorkerThread; import com.android.packageinstaller.permission.utils.ArrayUtils; Loading Loading @@ -64,204 +59,17 @@ public class RoleControllerServiceImpl extends RoleControllerService { private RoleManager mRoleManager; private AppOpsManager mAppOpsManager; private HandlerThread mWorkerThread; private Handler mWorkerHandler; @Override public void onCreate() { super.onCreate(); mRoleManager = getSystemService(RoleManager.class); mAppOpsManager = getSystemService(AppOpsManager.class); mWorkerThread = new HandlerThread(RoleControllerServiceImpl.class.getSimpleName()); mWorkerThread.start(); mWorkerHandler = new Handler(mWorkerThread.getLooper()); } @Override public void onDestroy() { super.onDestroy(); mWorkerThread.quitSafely(); } @Override public void onGrantDefaultRoles(@NonNull RoleManagerCallback callback) { enforceCallerSystemUid("onGrantDefaultRoles"); if (callback == null) { Log.e(LOG_TAG, "callback cannot be null"); return; } mWorkerHandler.post(() -> grantDefaultRoles(callback)); } @Override public void onAddRoleHolder(@NonNull String roleName, @NonNull String packageName, int flags, @NonNull RoleManagerCallback callback) { enforceCallerSystemUid("onAddRoleHolder"); if (callback == null) { Log.e(LOG_TAG, "callback cannot be null"); return; } if (TextUtils.isEmpty(roleName)) { Log.e(LOG_TAG, "roleName cannot be null or empty: " + roleName); callback.onFailure(); return; } if (TextUtils.isEmpty(packageName)) { Log.e(LOG_TAG, "packageName cannot be null or empty: " + roleName); callback.onFailure(); return; } if (!checkFlags(flags, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP)) { callback.onFailure(); return; } mWorkerHandler.post(() -> addRoleHolder(roleName, packageName, flags, callback)); } @Override public void onRemoveRoleHolder(@NonNull String roleName, @NonNull String packageName, int flags, @NonNull RoleManagerCallback callback) { enforceCallerSystemUid("onRemoveRoleHolder"); if (callback == null) { Log.e(LOG_TAG, "callback cannot be null"); return; } if (TextUtils.isEmpty(roleName)) { Log.e(LOG_TAG, "roleName cannot be null or empty: " + roleName); callback.onFailure(); return; } if (TextUtils.isEmpty(packageName)) { Log.e(LOG_TAG, "packageName cannot be null or empty: " + roleName); callback.onFailure(); return; } if (!checkFlags(flags, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP)) { callback.onFailure(); return; } mWorkerHandler.post(() -> removeRoleHolder(roleName, packageName, flags, callback)); } @Override public void onClearRoleHolders(@NonNull String roleName, int flags, @NonNull RoleManagerCallback callback) { enforceCallerSystemUid("onClearRoleHolders"); if (callback == null) { Log.e(LOG_TAG, "callback cannot be null"); return; } if (TextUtils.isEmpty(roleName)) { Log.e(LOG_TAG, "roleName cannot be null or empty: " + roleName); callback.onFailure(); return; } if (!checkFlags(flags, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP)) { callback.onFailure(); return; } mWorkerHandler.post(() -> clearRoleHolders(roleName, flags, callback)); } @Override public void onSmsKillSwitchToggled(boolean enabled) { enforceCallerSystemUid("onSmsKillSwitchToggled"); mWorkerHandler.post(() -> { PackageManager packageManager = getPackageManager(); List<PackageInfo> installedPackages = getPackageManager().getInstalledPackages(0); for (int i = 0, size = installedPackages.size(); i < size; i++) { PackageInfo pkg = installedPackages.get(i); onSmsKillSwitchToggled(enabled, pkg, Utils.getPlatformPermissionsOfGroup( packageManager, android.Manifest.permission_group.SMS)); onSmsKillSwitchToggled(enabled, pkg, Utils.getPlatformPermissionsOfGroup( packageManager, android.Manifest.permission_group.CALL_LOG)); } grantDefaultRoles(null); }); } @Override public boolean onIsApplicationQualifiedForRole(@NonNull String roleName, @NonNull String packageName) { Role role = Roles.get(this).get(roleName); if (role == null) { return false; } if (!role.isAvailable(this)) { return false; } return role.isPackageQualified(packageName, this); } @Override public boolean onIsRoleVisible(@NonNull String roleName) { Role role = Roles.get(this).get(roleName); if (role == null) { return false; } if (!role.isAvailable(this)) { return false; } return role.isVisibleAsUser(Process.myUserHandle(), this); } private void enforceCallerSystemUid(@NonNull String methodName) { if (Binder.getCallingUid() != Process.SYSTEM_UID) { throw new SecurityException("Only the system process call " + methodName + "()"); } } void onSmsKillSwitchToggled(boolean smsRestrictionEnabled, PackageInfo pkg, List<PermissionInfo> permissions) { PackageManager pm = getPackageManager(); int uid = pkg.applicationInfo.uid; for (int i = 0, permissionsSize = permissions.size(); i < permissionsSize; i++) { PermissionInfo permission = permissions.get(i); try { int permFlags = pm.getPermissionFlags(permission.name, pkg.packageName, Process.myUserHandle()); if ((permFlags & (PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT | PackageManager.FLAG_PERMISSION_SYSTEM_FIXED)) != 0) { continue; } if ((permFlags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) { pm.updatePermissionFlags(permission.name, pkg.packageName, PackageManager.FLAG_PERMISSION_POLICY_FIXED, 0, Process.myUserHandle()); } String appOp = AppOpsManager.permissionToOp(permission.name); if (appOp != null) { mAppOpsManager.setUidMode(appOp, uid, smsRestrictionEnabled ? AppOpsManager.MODE_DEFAULT : AppOpsManager.MODE_ALLOWED); } if (!smsRestrictionEnabled && pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) { pm.revokeRuntimePermission( pkg.packageName, permission.name, Process.myUserHandle()); } } catch (Exception e) { Log.e(LOG_TAG, "Unexpected exception while cleaning up state for package " + pkg.packageName + " & " + permission.name, e); continue; } } } @WorkerThread private void grantDefaultRoles(@Nullable RoleManagerCallback callback) { public boolean onGrantDefaultRoles() { if (DEBUG) { Log.i(LOG_TAG, "Granting default roles, user: " + UserHandle.myUserId()); } Loading Loading @@ -371,9 +179,7 @@ public class RoleControllerServiceImpl extends RoleControllerService { updateUserSensitive(); if (callback != null) { callback.onSuccess(); } return true; } /** Loading Loading @@ -422,26 +228,28 @@ public class RoleControllerServiceImpl extends RoleControllerService { } } @Override @WorkerThread private void addRoleHolder(@NonNull String roleName, @NonNull String packageName, int flags, @NonNull RoleManagerCallback callback) { public boolean onAddRoleHolder(@NonNull String roleName, @NonNull String packageName, int flags) { if (!checkFlags(flags, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP)) { return false; } Role role = Roles.get(this).get(roleName); if (role == null) { Log.e(LOG_TAG, "Unknown role: " + roleName); callback.onFailure(); return; return false; } if (!role.isAvailable(this)) { Log.e(LOG_TAG, "Role is unavailable: " + roleName); callback.onFailure(); return; return false; } if (!role.isPackageQualified(packageName, this)) { Log.e(LOG_TAG, "Package does not qualify for the role, package: " + packageName + ", role: " + roleName); callback.onFailure(); return; return false; } boolean added = false; Loading @@ -461,8 +269,7 @@ public class RoleControllerServiceImpl extends RoleControllerService { boolean removed = removeRoleHolderInternal(role, currentPackageName, false); if (!removed) { // TODO: Clean up? callback.onFailure(); return; return false; } } } Loading @@ -470,76 +277,77 @@ public class RoleControllerServiceImpl extends RoleControllerService { boolean dontKillApp = hasFlag(flags, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP); added = addRoleHolderInternal(role, packageName, dontKillApp, true, added); if (!added) { callback.onFailure(); return; return false; } role.onHolderSelectedAsUser(this, Process.myUserHandle()); callback.onSuccess(); return true; } @Override @WorkerThread private void removeRoleHolder(@NonNull String roleName, @NonNull String packageName, int flags, @NonNull RoleManagerCallback callback) { public boolean onRemoveRoleHolder(@NonNull String roleName, @NonNull String packageName, int flags) { if (!checkFlags(flags, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP)) { return false; } Role role = Roles.get(this).get(roleName); if (role == null) { Log.e(LOG_TAG, "Unknown role: " + roleName); callback.onFailure(); return; return false; } if (!role.isAvailable(this)) { Log.e(LOG_TAG, "Role is unavailable: " + roleName); callback.onFailure(); return; return false; } boolean dontKillApp = hasFlag(flags, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP); boolean removed = removeRoleHolderInternal(role, packageName, dontKillApp); if (!removed) { callback.onFailure(); return; return false; } // TODO: Should we consider this successful regardless? boolean fallbackSuccessful = addFallbackRoleHolderMaybe(role); if (!fallbackSuccessful) { callback.onFailure(); return; return false; } callback.onSuccess(); return true; } @Override @WorkerThread private void clearRoleHolders(@NonNull String roleName, int flags, @NonNull RoleManagerCallback callback) { public boolean onClearRoleHolders(@NonNull String roleName, int flags) { if (!checkFlags(flags, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP)) { return false; } Role role = Roles.get(this).get(roleName); if (role == null) { Log.e(LOG_TAG, "Unknown role: " + roleName); callback.onFailure(); return; return false; } if (!role.isAvailable(this)) { Log.e(LOG_TAG, "Role is unavailable: " + roleName); callback.onFailure(); return; return false; } boolean dontKillApp = hasFlag(flags, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP); boolean cleared = clearRoleHoldersInternal(role, dontKillApp); if (!cleared) { callback.onFailure(); return false; } // TODO: Should we consider this successful regardless? boolean fallbackSuccessful = addFallbackRoleHolderMaybe(role); if (!fallbackSuccessful) { callback.onFailure(); return; return false; } callback.onSuccess(); return true; } @WorkerThread Loading Loading @@ -639,6 +447,86 @@ public class RoleControllerServiceImpl extends RoleControllerService { return addRoleHolderInternal(role, fallbackPackageName, true); } @WorkerThread @Override public void onSmsKillSwitchToggled(boolean enabled) { PackageManager packageManager = getPackageManager(); List<PackageInfo> installedPackages = getPackageManager().getInstalledPackages(0); for (int i = 0, size = installedPackages.size(); i < size; i++) { PackageInfo packageInfo = installedPackages.get(i); onSmsKillSwitchToggled(enabled, packageInfo, Utils.getPlatformPermissionsOfGroup( packageManager, Manifest.permission_group.SMS)); onSmsKillSwitchToggled(enabled, packageInfo, Utils.getPlatformPermissionsOfGroup( packageManager, Manifest.permission_group.CALL_LOG)); } onGrantDefaultRoles(); } @WorkerThread private void onSmsKillSwitchToggled(boolean enabled, @NonNull PackageInfo packageInfo, @NonNull List<PermissionInfo> permissions) { PackageManager packageManager = getPackageManager(); int uid = packageInfo.applicationInfo.uid; for (int i = 0, permissionsSize = permissions.size(); i < permissionsSize; i++) { PermissionInfo permission = permissions.get(i); try { int permissionFlags = packageManager.getPermissionFlags(permission.name, packageInfo.packageName, Process.myUserHandle()); if ((permissionFlags & (PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT | PackageManager.FLAG_PERMISSION_SYSTEM_FIXED)) != 0) { continue; } if ((permissionFlags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) { packageManager.updatePermissionFlags(permission.name, packageInfo.packageName, PackageManager.FLAG_PERMISSION_POLICY_FIXED, 0, Process.myUserHandle()); } String appOp = AppOpsManager.permissionToOp(permission.name); if (appOp != null) { mAppOpsManager.setUidMode(appOp, uid, enabled ? AppOpsManager.MODE_DEFAULT : AppOpsManager.MODE_ALLOWED); } if (!enabled && packageInfo.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M) { packageManager.revokeRuntimePermission(packageInfo.packageName, permission.name, Process.myUserHandle()); } } catch (Exception e) { Log.e(LOG_TAG, "Unexpected exception while cleaning up state for package " + packageInfo.packageName + " & " + permission.name, e); } } } @Override public boolean onIsApplicationQualifiedForRole(@NonNull String roleName, @NonNull String packageName) { Role role = Roles.get(this).get(roleName); if (role == null) { return false; } if (!role.isAvailable(this)) { return false; } return role.isPackageQualified(packageName, this); } @Override public boolean onIsRoleVisible(@NonNull String roleName) { Role role = Roles.get(this).get(roleName); if (role == null) { return false; } if (!role.isAvailable(this)) { return false; } return role.isVisibleAsUser(Process.myUserHandle(), this); } private static boolean checkFlags(int flags, int allowedFlags) { if ((flags & allowedFlags) != flags) { Log.e(LOG_TAG, "flags is invalid, flags: 0x" + Integer.toHexString(flags) Loading src/com/android/packageinstaller/role/ui/ManageRoleHolderStateLiveData.java +7 −13 Original line number Diff line number Diff line Loading @@ -17,7 +17,6 @@ package com.android.packageinstaller.role.ui; import android.app.role.RoleManager; import android.app.role.RoleManagerCallback; import android.content.Context; import android.os.UserHandle; import android.util.Log; Loading @@ -26,6 +25,7 @@ import androidx.annotation.NonNull; import androidx.lifecycle.LiveData; import java.util.concurrent.Executor; import java.util.function.Consumer; /** * {@link LiveData} for the state of managing a role holder. Loading Loading @@ -71,17 +71,14 @@ public class ManageRoleHolderStateLiveData extends LiveData<Integer> { RoleManager roleManager = context.getSystemService(RoleManager.class); Executor executor = context.getMainExecutor(); RoleManagerCallback callback = new RoleManagerCallback() { @Override public void onSuccess() { Consumer<Boolean> callback = successful -> { if (successful) { if (DEBUG) { Log.i(LOG_TAG, "Package " + (add ? "added" : "removed") + " as role holder, role: " + roleName + ", package: " + packageName); } setValue(STATE_SUCCESS); } @Override public void onFailure() { } else { if (DEBUG) { Log.i(LOG_TAG, "Failed to " + (add ? "add" : "remove") + " package as role holder, role: " + roleName + ", package: " Loading Loading @@ -120,16 +117,13 @@ public class ManageRoleHolderStateLiveData extends LiveData<Integer> { RoleManager roleManager = context.getSystemService(RoleManager.class); Executor executor = context.getMainExecutor(); RoleManagerCallback callback = new RoleManagerCallback() { @Override public void onSuccess() { Consumer<Boolean> callback = successful -> { if (successful) { if (DEBUG) { Log.i(LOG_TAG, "Cleared role holders, role: " + roleName); } setValue(STATE_SUCCESS); } @Override public void onFailure() { } else { if (DEBUG) { Log.i(LOG_TAG, "Failed to clear role holders, role: " + roleName); } Loading Loading
src/com/android/packageinstaller/role/service/RoleControllerServiceImpl.java +119 −231 Original line number Diff line number Diff line Loading @@ -16,27 +16,22 @@ package com.android.packageinstaller.role.service; import android.Manifest; import android.app.AppOpsManager; import android.app.role.RoleControllerService; import android.app.role.RoleManager; import android.app.role.RoleManagerCallback; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PermissionInfo; import android.os.Binder; import android.os.Build; import android.os.Handler; import android.os.HandlerThread; import android.os.Process; import android.os.UserHandle; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.WorkerThread; import com.android.packageinstaller.permission.utils.ArrayUtils; Loading Loading @@ -64,204 +59,17 @@ public class RoleControllerServiceImpl extends RoleControllerService { private RoleManager mRoleManager; private AppOpsManager mAppOpsManager; private HandlerThread mWorkerThread; private Handler mWorkerHandler; @Override public void onCreate() { super.onCreate(); mRoleManager = getSystemService(RoleManager.class); mAppOpsManager = getSystemService(AppOpsManager.class); mWorkerThread = new HandlerThread(RoleControllerServiceImpl.class.getSimpleName()); mWorkerThread.start(); mWorkerHandler = new Handler(mWorkerThread.getLooper()); } @Override public void onDestroy() { super.onDestroy(); mWorkerThread.quitSafely(); } @Override public void onGrantDefaultRoles(@NonNull RoleManagerCallback callback) { enforceCallerSystemUid("onGrantDefaultRoles"); if (callback == null) { Log.e(LOG_TAG, "callback cannot be null"); return; } mWorkerHandler.post(() -> grantDefaultRoles(callback)); } @Override public void onAddRoleHolder(@NonNull String roleName, @NonNull String packageName, int flags, @NonNull RoleManagerCallback callback) { enforceCallerSystemUid("onAddRoleHolder"); if (callback == null) { Log.e(LOG_TAG, "callback cannot be null"); return; } if (TextUtils.isEmpty(roleName)) { Log.e(LOG_TAG, "roleName cannot be null or empty: " + roleName); callback.onFailure(); return; } if (TextUtils.isEmpty(packageName)) { Log.e(LOG_TAG, "packageName cannot be null or empty: " + roleName); callback.onFailure(); return; } if (!checkFlags(flags, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP)) { callback.onFailure(); return; } mWorkerHandler.post(() -> addRoleHolder(roleName, packageName, flags, callback)); } @Override public void onRemoveRoleHolder(@NonNull String roleName, @NonNull String packageName, int flags, @NonNull RoleManagerCallback callback) { enforceCallerSystemUid("onRemoveRoleHolder"); if (callback == null) { Log.e(LOG_TAG, "callback cannot be null"); return; } if (TextUtils.isEmpty(roleName)) { Log.e(LOG_TAG, "roleName cannot be null or empty: " + roleName); callback.onFailure(); return; } if (TextUtils.isEmpty(packageName)) { Log.e(LOG_TAG, "packageName cannot be null or empty: " + roleName); callback.onFailure(); return; } if (!checkFlags(flags, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP)) { callback.onFailure(); return; } mWorkerHandler.post(() -> removeRoleHolder(roleName, packageName, flags, callback)); } @Override public void onClearRoleHolders(@NonNull String roleName, int flags, @NonNull RoleManagerCallback callback) { enforceCallerSystemUid("onClearRoleHolders"); if (callback == null) { Log.e(LOG_TAG, "callback cannot be null"); return; } if (TextUtils.isEmpty(roleName)) { Log.e(LOG_TAG, "roleName cannot be null or empty: " + roleName); callback.onFailure(); return; } if (!checkFlags(flags, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP)) { callback.onFailure(); return; } mWorkerHandler.post(() -> clearRoleHolders(roleName, flags, callback)); } @Override public void onSmsKillSwitchToggled(boolean enabled) { enforceCallerSystemUid("onSmsKillSwitchToggled"); mWorkerHandler.post(() -> { PackageManager packageManager = getPackageManager(); List<PackageInfo> installedPackages = getPackageManager().getInstalledPackages(0); for (int i = 0, size = installedPackages.size(); i < size; i++) { PackageInfo pkg = installedPackages.get(i); onSmsKillSwitchToggled(enabled, pkg, Utils.getPlatformPermissionsOfGroup( packageManager, android.Manifest.permission_group.SMS)); onSmsKillSwitchToggled(enabled, pkg, Utils.getPlatformPermissionsOfGroup( packageManager, android.Manifest.permission_group.CALL_LOG)); } grantDefaultRoles(null); }); } @Override public boolean onIsApplicationQualifiedForRole(@NonNull String roleName, @NonNull String packageName) { Role role = Roles.get(this).get(roleName); if (role == null) { return false; } if (!role.isAvailable(this)) { return false; } return role.isPackageQualified(packageName, this); } @Override public boolean onIsRoleVisible(@NonNull String roleName) { Role role = Roles.get(this).get(roleName); if (role == null) { return false; } if (!role.isAvailable(this)) { return false; } return role.isVisibleAsUser(Process.myUserHandle(), this); } private void enforceCallerSystemUid(@NonNull String methodName) { if (Binder.getCallingUid() != Process.SYSTEM_UID) { throw new SecurityException("Only the system process call " + methodName + "()"); } } void onSmsKillSwitchToggled(boolean smsRestrictionEnabled, PackageInfo pkg, List<PermissionInfo> permissions) { PackageManager pm = getPackageManager(); int uid = pkg.applicationInfo.uid; for (int i = 0, permissionsSize = permissions.size(); i < permissionsSize; i++) { PermissionInfo permission = permissions.get(i); try { int permFlags = pm.getPermissionFlags(permission.name, pkg.packageName, Process.myUserHandle()); if ((permFlags & (PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT | PackageManager.FLAG_PERMISSION_SYSTEM_FIXED)) != 0) { continue; } if ((permFlags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) { pm.updatePermissionFlags(permission.name, pkg.packageName, PackageManager.FLAG_PERMISSION_POLICY_FIXED, 0, Process.myUserHandle()); } String appOp = AppOpsManager.permissionToOp(permission.name); if (appOp != null) { mAppOpsManager.setUidMode(appOp, uid, smsRestrictionEnabled ? AppOpsManager.MODE_DEFAULT : AppOpsManager.MODE_ALLOWED); } if (!smsRestrictionEnabled && pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) { pm.revokeRuntimePermission( pkg.packageName, permission.name, Process.myUserHandle()); } } catch (Exception e) { Log.e(LOG_TAG, "Unexpected exception while cleaning up state for package " + pkg.packageName + " & " + permission.name, e); continue; } } } @WorkerThread private void grantDefaultRoles(@Nullable RoleManagerCallback callback) { public boolean onGrantDefaultRoles() { if (DEBUG) { Log.i(LOG_TAG, "Granting default roles, user: " + UserHandle.myUserId()); } Loading Loading @@ -371,9 +179,7 @@ public class RoleControllerServiceImpl extends RoleControllerService { updateUserSensitive(); if (callback != null) { callback.onSuccess(); } return true; } /** Loading Loading @@ -422,26 +228,28 @@ public class RoleControllerServiceImpl extends RoleControllerService { } } @Override @WorkerThread private void addRoleHolder(@NonNull String roleName, @NonNull String packageName, int flags, @NonNull RoleManagerCallback callback) { public boolean onAddRoleHolder(@NonNull String roleName, @NonNull String packageName, int flags) { if (!checkFlags(flags, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP)) { return false; } Role role = Roles.get(this).get(roleName); if (role == null) { Log.e(LOG_TAG, "Unknown role: " + roleName); callback.onFailure(); return; return false; } if (!role.isAvailable(this)) { Log.e(LOG_TAG, "Role is unavailable: " + roleName); callback.onFailure(); return; return false; } if (!role.isPackageQualified(packageName, this)) { Log.e(LOG_TAG, "Package does not qualify for the role, package: " + packageName + ", role: " + roleName); callback.onFailure(); return; return false; } boolean added = false; Loading @@ -461,8 +269,7 @@ public class RoleControllerServiceImpl extends RoleControllerService { boolean removed = removeRoleHolderInternal(role, currentPackageName, false); if (!removed) { // TODO: Clean up? callback.onFailure(); return; return false; } } } Loading @@ -470,76 +277,77 @@ public class RoleControllerServiceImpl extends RoleControllerService { boolean dontKillApp = hasFlag(flags, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP); added = addRoleHolderInternal(role, packageName, dontKillApp, true, added); if (!added) { callback.onFailure(); return; return false; } role.onHolderSelectedAsUser(this, Process.myUserHandle()); callback.onSuccess(); return true; } @Override @WorkerThread private void removeRoleHolder(@NonNull String roleName, @NonNull String packageName, int flags, @NonNull RoleManagerCallback callback) { public boolean onRemoveRoleHolder(@NonNull String roleName, @NonNull String packageName, int flags) { if (!checkFlags(flags, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP)) { return false; } Role role = Roles.get(this).get(roleName); if (role == null) { Log.e(LOG_TAG, "Unknown role: " + roleName); callback.onFailure(); return; return false; } if (!role.isAvailable(this)) { Log.e(LOG_TAG, "Role is unavailable: " + roleName); callback.onFailure(); return; return false; } boolean dontKillApp = hasFlag(flags, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP); boolean removed = removeRoleHolderInternal(role, packageName, dontKillApp); if (!removed) { callback.onFailure(); return; return false; } // TODO: Should we consider this successful regardless? boolean fallbackSuccessful = addFallbackRoleHolderMaybe(role); if (!fallbackSuccessful) { callback.onFailure(); return; return false; } callback.onSuccess(); return true; } @Override @WorkerThread private void clearRoleHolders(@NonNull String roleName, int flags, @NonNull RoleManagerCallback callback) { public boolean onClearRoleHolders(@NonNull String roleName, int flags) { if (!checkFlags(flags, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP)) { return false; } Role role = Roles.get(this).get(roleName); if (role == null) { Log.e(LOG_TAG, "Unknown role: " + roleName); callback.onFailure(); return; return false; } if (!role.isAvailable(this)) { Log.e(LOG_TAG, "Role is unavailable: " + roleName); callback.onFailure(); return; return false; } boolean dontKillApp = hasFlag(flags, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP); boolean cleared = clearRoleHoldersInternal(role, dontKillApp); if (!cleared) { callback.onFailure(); return false; } // TODO: Should we consider this successful regardless? boolean fallbackSuccessful = addFallbackRoleHolderMaybe(role); if (!fallbackSuccessful) { callback.onFailure(); return; return false; } callback.onSuccess(); return true; } @WorkerThread Loading Loading @@ -639,6 +447,86 @@ public class RoleControllerServiceImpl extends RoleControllerService { return addRoleHolderInternal(role, fallbackPackageName, true); } @WorkerThread @Override public void onSmsKillSwitchToggled(boolean enabled) { PackageManager packageManager = getPackageManager(); List<PackageInfo> installedPackages = getPackageManager().getInstalledPackages(0); for (int i = 0, size = installedPackages.size(); i < size; i++) { PackageInfo packageInfo = installedPackages.get(i); onSmsKillSwitchToggled(enabled, packageInfo, Utils.getPlatformPermissionsOfGroup( packageManager, Manifest.permission_group.SMS)); onSmsKillSwitchToggled(enabled, packageInfo, Utils.getPlatformPermissionsOfGroup( packageManager, Manifest.permission_group.CALL_LOG)); } onGrantDefaultRoles(); } @WorkerThread private void onSmsKillSwitchToggled(boolean enabled, @NonNull PackageInfo packageInfo, @NonNull List<PermissionInfo> permissions) { PackageManager packageManager = getPackageManager(); int uid = packageInfo.applicationInfo.uid; for (int i = 0, permissionsSize = permissions.size(); i < permissionsSize; i++) { PermissionInfo permission = permissions.get(i); try { int permissionFlags = packageManager.getPermissionFlags(permission.name, packageInfo.packageName, Process.myUserHandle()); if ((permissionFlags & (PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT | PackageManager.FLAG_PERMISSION_SYSTEM_FIXED)) != 0) { continue; } if ((permissionFlags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) { packageManager.updatePermissionFlags(permission.name, packageInfo.packageName, PackageManager.FLAG_PERMISSION_POLICY_FIXED, 0, Process.myUserHandle()); } String appOp = AppOpsManager.permissionToOp(permission.name); if (appOp != null) { mAppOpsManager.setUidMode(appOp, uid, enabled ? AppOpsManager.MODE_DEFAULT : AppOpsManager.MODE_ALLOWED); } if (!enabled && packageInfo.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M) { packageManager.revokeRuntimePermission(packageInfo.packageName, permission.name, Process.myUserHandle()); } } catch (Exception e) { Log.e(LOG_TAG, "Unexpected exception while cleaning up state for package " + packageInfo.packageName + " & " + permission.name, e); } } } @Override public boolean onIsApplicationQualifiedForRole(@NonNull String roleName, @NonNull String packageName) { Role role = Roles.get(this).get(roleName); if (role == null) { return false; } if (!role.isAvailable(this)) { return false; } return role.isPackageQualified(packageName, this); } @Override public boolean onIsRoleVisible(@NonNull String roleName) { Role role = Roles.get(this).get(roleName); if (role == null) { return false; } if (!role.isAvailable(this)) { return false; } return role.isVisibleAsUser(Process.myUserHandle(), this); } private static boolean checkFlags(int flags, int allowedFlags) { if ((flags & allowedFlags) != flags) { Log.e(LOG_TAG, "flags is invalid, flags: 0x" + Integer.toHexString(flags) Loading
src/com/android/packageinstaller/role/ui/ManageRoleHolderStateLiveData.java +7 −13 Original line number Diff line number Diff line Loading @@ -17,7 +17,6 @@ package com.android.packageinstaller.role.ui; import android.app.role.RoleManager; import android.app.role.RoleManagerCallback; import android.content.Context; import android.os.UserHandle; import android.util.Log; Loading @@ -26,6 +25,7 @@ import androidx.annotation.NonNull; import androidx.lifecycle.LiveData; import java.util.concurrent.Executor; import java.util.function.Consumer; /** * {@link LiveData} for the state of managing a role holder. Loading Loading @@ -71,17 +71,14 @@ public class ManageRoleHolderStateLiveData extends LiveData<Integer> { RoleManager roleManager = context.getSystemService(RoleManager.class); Executor executor = context.getMainExecutor(); RoleManagerCallback callback = new RoleManagerCallback() { @Override public void onSuccess() { Consumer<Boolean> callback = successful -> { if (successful) { if (DEBUG) { Log.i(LOG_TAG, "Package " + (add ? "added" : "removed") + " as role holder, role: " + roleName + ", package: " + packageName); } setValue(STATE_SUCCESS); } @Override public void onFailure() { } else { if (DEBUG) { Log.i(LOG_TAG, "Failed to " + (add ? "add" : "remove") + " package as role holder, role: " + roleName + ", package: " Loading Loading @@ -120,16 +117,13 @@ public class ManageRoleHolderStateLiveData extends LiveData<Integer> { RoleManager roleManager = context.getSystemService(RoleManager.class); Executor executor = context.getMainExecutor(); RoleManagerCallback callback = new RoleManagerCallback() { @Override public void onSuccess() { Consumer<Boolean> callback = successful -> { if (successful) { if (DEBUG) { Log.i(LOG_TAG, "Cleared role holders, role: " + roleName); } setValue(STATE_SUCCESS); } @Override public void onFailure() { } else { if (DEBUG) { Log.i(LOG_TAG, "Failed to clear role holders, role: " + roleName); } Loading