MuntashirAkon/AppManager · error · IllegalStateException
Unknown AppOpsManager mode
Error message
Unknown AppOpsManager mode
What it means
checkStoragePermission checks the result of an AppOpsManager operation and only knows MODE_ALLOWED, MODE_ERRORED and MODE_IGNORED. If the system returns any other AppOpsManager mode (e.g. MODE_DEFAULT), it throws IllegalStateException("Unknown AppOpsManager mode " + opMode).
Solutions
- Handle MODE_DEFAULT explicitly by falling back to checkSelfOrRemotePermission instead of throwing.
- Log the unknown opMode and treat it conservatively (deny) rather than crashing.
- Update the switch to cover all AppOpsManager.MODE_* constants for the target SDK.
- Reproduce and test on the specific ROM/Android version that returns the unknown mode.
Example fix
// before
default:
throw new IllegalStateException("Unknown AppOpsManager mode " + opMode);
// after
case AppOpsManager.MODE_DEFAULT:
return checkSelfOrRemotePermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, callingUid);
default:
return false; Defensive patterns
Strategy: try-catch
Validate before calling
int opMode = appOps.checkOpNoThrow(op, uid, packageName);
if (opMode != AppOpsManager.MODE_ALLOWED
&& opMode != AppOpsManager.MODE_ERRORED
&& opMode != AppOpsManager.MODE_IGNORED
&& opMode != AppOpsManager.MODE_DEFAULT) {
// unknown mode: skip the AppOps path and use a plain permission check
} Try / catch
try {
hasStorage = SelfPermissions.checkStoragePermission(callingUid);
} catch (IllegalStateException e) {
hasStorage = ContextCompat.checkSelfPermission(ctx, Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED;
} Prevention
- Test storage-permission checks on all supported Android versions and OEM ROMs.
- Treat MODE_DEFAULT as 'fall back to regular permission check', never an exception.
- Keep AppOps mode handling in sync with the target SDK's AppOpsManager constants.
- Prefer the regular permission check as primary and AppOps only as refinement.
When it happens
Trigger: Calling checkStoragePermission on an Android version/ROM where AppOpsManager returns MODE_DEFAULT or a vendor-specific mode for the storage op, e.g. when the op was never explicitly set for the calling uid.
Common situations: Running on modified/OEM ROMs with non-standard AppOps behavior, Android version changes that reinterpret AppOps modes, uids whose storage op has only the default mode.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- An uninstallation was necessary but couldn't perform it.
- App Manager does not have the required permission
- Could not backup data
- Could not create cache. Is this OS broken?
- Could not create directory
AI-assisted analysis of MuntashirAkon/AppManager@0152f468fc (2026-09-12).
Data as JSON: /api/errors/f972e6b1dc096fda.
Report an issue: GitHub.
Appendix: source
Thrown at app/src/main/java/io/github/muntashirakon/AppManager/self/SelfPermissions.java:216
public static boolean checkStoragePermission() {
int callingUid = Users.getSelfOrRemoteUid();
if (callingUid == Ops.ROOT_UID) {
return true;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
String packageName = getCallingPackage(callingUid);
AppOpsManagerCompat appOps = new AppOpsManagerCompat();
int opMode = appOps.checkOpNoThrow(AppOpsManagerHidden.OP_MANAGE_EXTERNAL_STORAGE, callingUid, packageName);
switch (opMode) {
case AppOpsManager.MODE_DEFAULT:
return checkSelfOrRemotePermission(Manifest.permission.MANAGE_EXTERNAL_STORAGE, callingUid);
case AppOpsManager.MODE_ALLOWED:
return true;
case AppOpsManager.MODE_ERRORED:
case AppOpsManager.MODE_IGNORED:
return false;
default:
throw new IllegalStateException("Unknown AppOpsManager mode " + opMode);
}
}
return checkSelfOrRemotePermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, callingUid);
}
public static boolean checkCrossUserPermission(@UserIdInt int userId, boolean requireFullPermission) {
int callingUid = Users.getSelfOrRemoteUid();
return checkCrossUserPermission(userId, requireFullPermission, callingUid);
}
public static boolean checkCrossUserPermission(@UserIdInt int userId, boolean requireFullPermission, int callingUid) {
if (userId == UserHandleHidden.USER_NULL) {
userId = UserHandleHidden.myUserId();
}
if (userId < 0 && userId != UserHandleHidden.USER_ALL) {
throw new IllegalArgumentException("Invalid userId " + userId);
}
if (isSystemOrRootOrShell(callingUid) || userId == UserHandleHidden.getUserId(callingUid)) {View on GitHub (pinned to 0152f468fc)