{"record":{"id":"9a3d7bae912ffb87","repo":"MuntashirAkon/AppManager","slug":"unmodifiable-permission-permissionname","errorCode":null,"errorMessage":"Unmodifiable permission ${permissionName}","messagePattern":"Unmodifiable permission (.+?)","errorType":"exception","errorClass":"PermissionException","httpStatus":null,"severity":"error","filePath":"app/src/main/java/io/github/muntashirakon/AppManager/permission/AppOpPermissionController.java","lineNumber":184,"sourceCode":"            }\n            boolean killApp = permission.isAppOpAllowed() != granted\n                    && (permission.readOnly || legacyRuntime);\n            if (!permission.isReadOnly() && !legacyRuntime) {\n                permission.setGranted(granted);\n            }\n            permission.setAppOpAllowed(granted);\n            persist(packageInfo.applicationInfo, permission, appOpsManager, null, false);\n            killIfNeeded(packageInfo.applicationInfo.uid, killApp);\n            return PermissionChangeResult.success();\n        } catch (Exception e) {\n            return PermissionChangeResult.failure(\n                    \"Could not change permission \" + permissionName, e);\n        }\n    }\n\n    private void requireModifiable(@NonNull Permission permission) throws PermissionException {\n        if (!isModifiable(permission)) {\n            throw new PermissionException(\"Unmodifiable permission \" + permission.getName());\n        }\n    }\n\n    private void killIfNeeded(int uid, boolean killApp) throws PermissionException {\n        if (!killApp || !mAppOpPlatform.canKillUid()) {\n            return;\n        }\n        try {\n            mAppOpPlatform.killUid(uid, KILL_REASON_APP_OP_CHANGE);\n        } catch (Exception e) {\n            throw new PermissionException(e);\n        }\n    }\n\n    private void persist(@NonNull ApplicationInfo applicationInfo,\n                         @NonNull Permission permission,\n                         @NonNull AppOpsManagerCompat appOpsManager,\n                         @Nullable String revokeReason) throws PermissionException {","sourceCodeStart":166,"sourceCodeEnd":202,"githubUrl":"https://github.com/MuntashirAkon/AppManager/blob/0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5/app/src/main/java/io/github/muntashirakon/AppManager/permission/AppOpPermissionController.java#L166-L202","documentation":"AppOpPermissionController.requireModifiable() checks isModifiable(permission) before grant/revoke; permissions that the controller is not allowed to change (e.g. platform-managed or protected permissions) throw PermissionException('Unmodifiable permission ...').","triggerScenarios":"Calling grant() or revoke() on a Permission for which isModifiable() returns false — typically permissions owned/enforced by the system rather than this controller.","commonSituations":"Trying to revoke permissions that Android marks as fixed or development-only; batch-applying overrides to every declared permission without filtering; targeting privileged/system apps.","solutions":["Check isModifiable(permission) (or the permission's flags) before calling grant/revoke and skip non-modifiable ones","Restrict the operation to permissions the controller supports","If the permission truly should be changeable, run with sufficient privileges (root/adb) or use the appropriate platform mechanism"],"exampleFix":"// before\ncontroller.revoke(permission, reason); // may throw for fixed permissions\n// after\nif (controller.isModifiable(permission)) {\n    controller.revoke(permission, reason);\n}","handlingStrategy":"try-catch","validationCode":"if (!controller.isModifiable(permission)) {\n    skip.add(permission); // don't call grant/revoke\n}","typeGuard":null,"tryCatchPattern":"try {\n    controller.grant(permission);\n} catch (PermissionException e) {\n    Log.w(TAG, \"Skipping unmodifiable permission \" + permission.getName(), e);\n}","preventionTips":["Pre-filter permissions with isModifiable() in bulk operations","Treat system-fixed permissions as read-only","Request root/adb privileges when modification of protected permissions is required"],"tags":["java","android","permissions"],"backgroundTag":"insufficient-permissions","analyzedSha":"0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5","analyzedAt":"2026-09-12T14:03:37.243Z","contentChangedAt":"2026-09-12T14:03:37.243Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}