termux/termux-app · error · IllegalStateException
%1$s requires "Display over other apps" permission to start
Error message
%1$s requires "Display over other apps" permission to start activities and services from background on Android >= 10. Grants it from Android Settings -> Apps -> %1$s -> Advanced -> Draw over other apps. The permission name may be different on different devices, like on Xiaomi, its called "Display pop-up windows while running in the background", check https://dontkillmyapp.com for device specific issues.
What it means
Thrown by AmSocketServer.runAmCommand when, on Android 10+, a 'start' or 'startservice' am subcommand is requested but the app lacks the SYSTEM_ALERT_WINDOW ('Display over other apps') permission. Starting activities/services from the background requires this permission on API 29+. The message is a localized resource string formatted with the app name.
Source
Thrown at termux-shared/src/main/java/com/termux/shared/shell/am/AmSocketServer.java:222
* @param stderr The {@link StringBuilder} to set stderr in that is returned by the am command.
* @param checkDisplayOverAppsPermission Check if {@link Manifest.permission#SYSTEM_ALERT_WINDOW}
* has been granted if running on Android `>= 10` and
* starting activity or service.
* @return Returns the {@code error} if am command failed, otherwise {@code null}.
*/
public static Error runAmCommand(@NonNull Context context,
String[] amCommandArray,
@NonNull StringBuilder stdout, @NonNull StringBuilder stderr,
boolean checkDisplayOverAppsPermission) {
try (ByteArrayOutputStream stdoutByteStream = new ByteArrayOutputStream();
PrintStream stdoutPrintStream = new PrintStream(stdoutByteStream);
ByteArrayOutputStream stderrByteStream = new ByteArrayOutputStream();
PrintStream stderrPrintStream = new PrintStream(stderrByteStream)) {
if (checkDisplayOverAppsPermission && amCommandArray.length >= 1 &&
(amCommandArray[0].equals("start") || amCommandArray[0].equals("startservice")) &&
!PermissionUtils.validateDisplayOverOtherAppsPermissionForPostAndroid10(context, true)) {
throw new IllegalStateException(context.getString(R.string.error_display_over_other_apps_permission_not_granted,
PackageUtils.getAppNameForPackage(context)));
}
new Am(stdoutPrintStream, stderrPrintStream, (Application) context.getApplicationContext()).run(amCommandArray);
// Set stdout to value set by am command in stdoutPrintStream
stdoutPrintStream.flush();
stdout.append(stdoutByteStream.toString(StandardCharsets.UTF_8.name()));
// Set stderr to value set by am command in stderrPrintStream
stderrPrintStream.flush();
stderr.append(stderrByteStream.toString(StandardCharsets.UTF_8.name()));
} catch (Exception e) {
return AmSocketServerErrno.ERRNO_RUN_AM_COMMAND_FAILED_WITH_EXCEPTION.getError(e, Arrays.toString(amCommandArray), e.getMessage());
}
return null;
}View on GitHub (pinned to 3df69d1da1)
Solutions
- Request the user to grant 'Display over other apps' via Settings (the message links to it).
- Programmatically send the user to ACTION_MANAGE_OVERLAY_PERMISSION settings before issuing background start commands.
- Pass checkDisplayOverAppsPermission=false only if you have verified another valid way to start from background (rare).
- Check PermissionUtils.validateDisplayOverOtherAppsPermissionForPostAndroid10(context, false) before calling runAmCommand and degrade gracefully.
Example fix
// before
if (checkDisplayOverAppsPermission && ... &&
!PermissionUtils.validateDisplayOverOtherAppsPermissionForPostAndroid10(context, true)) {
throw new IllegalStateException(context.getString(R.string.error_display_over_other_apps_permission_not_granted, ...));
}
// after (pre-check + send user to settings instead of throwing blindly)
if (checkDisplayOverAppsPermission && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
&& !Settings.canDrawOverOtherApps(context)) {
Intent i = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + context.getPackageName()));
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
return Error.withErrno(...); // signal caller to retry after grant
} Defensive patterns
Strategy: validation
Validate before calling
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
&& ("start".equals(amCommandArray[0]) || "startservice".equals(amCommandArray[0]))
&& !Settings.canDrawOverOtherApps(context)) {
// send user to settings instead of letting runAmCommand throw
Intent i = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + context.getPackageName()));
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
return;
} Try / catch
try {
AmSocketServer.runAmCommand(context, cmd, stdout, stderr, true);
} catch (IllegalStateException e) {
if (e.getMessage() != null && e.getMessage().contains("Display over other apps")) {
promptUserForOverlayPermission();
} else throw e;
} Prevention
- Check Settings.canDrawOverOtherApps() before issuing background start commands on API 29+.
- Guide the user to the overlay-permission settings screen proactively.
- Be aware OEM battery/background killers may reset this permission.
When it happens
Trigger: Calling runAmCommand with an amCommandArray whose first element is 'start' or 'startservice', checkDisplayOverAppsPermission=true, on Android >= 10, while Settings.canDrawOverOtherApps() returns false.
Common situations: Fresh install without granting the overlay permission; background service tries to launch an activity; OEM battery-optimizer/background-killer reset the permission; plugin app invoking am from background.
Related errors
- Malformed symlink line:
- No SYMLINKS.txt encountered
- Moving termux prefix staging to prefix directory failed
- Invalid path:
- Failed to create document with id
AI-assisted analysis of termux/termux-app@3df69d1da1 (2026-08-13).
Data as JSON: /api/errors/2965378871135c6e.
Report an issue: GitHub.