## Affected Version
`com.adjust.sdk:adjust-android:5.4.6`
I also checked the latest Maven Central release, `5.7.0`, and the related source code appears unchanged.
## Crash
We observed the following fatal crash in production:
```text
Fatal Exception: java.lang.IllegalArgumentException: millis < 0: -9000
at java.lang.Thread.sleep(Thread.java:399)
at java.lang.Thread.sleep(Thread.java:355)
at java.lang.Thread.run(Thread.java:1012)
Problem
If the backend response contains a negative retry_in value, the SDK passes it directly to Thread.sleep(long) through SingleThreadCachedScheduler.schedule().
On Android, Thread.sleep(long) throws IllegalArgumentException when millis is negative. Since the SDK only catches InterruptedException, this can crash the app.
Source Code
Repository:
https://github.com/adjust/android_sdk
ActivityPackageSender
responseData.retryIn = UtilNetworking.extractJsonLong(jsonResponse, "retry_in");
responseData.continueIn = UtilNetworking.extractJsonLong(jsonResponse, "continue_in");
PackageHandler
if (responseData.retryIn != null) {
long retryIn = responseData.retryIn;
scheduler.schedule(runnable, retryIn);
return;
}
SingleThreadCachedScheduler
try {
Thread.sleep(millisecondsDelay);
} catch (InterruptedException e) {
AdjustFactory.getLogger().warn("Sleep delay exception: %s", e.getMessage());
}
IllegalArgumentException is not caught here.
Expected Behavior
The SDK should not crash when retry_in is negative.
It should either:
- clamp negative values to
0
- ignore invalid negative
retry_in
- treat negative
retry_in as immediate retry
- or catch
IllegalArgumentException in the scheduler
Suggested Fix
One possible fix is to validate retry_in before scheduling:
if (responseData.retryIn != null && responseData.retryIn > 0) {
long retryIn = responseData.retryIn;
scheduler.schedule(runnable, retryIn);
return;
}
Alternatively, the scheduler could guard the delay value:
Thread.sleep(Math.max(0, millisecondsDelay));
Additional Context
continue_in already has a positive-value guard:
if (previousResponseContinueIn != null && previousResponseContinueIn > 0) {
scheduler.schedule(runnable, previousResponseContinueIn);
}
But retry_in does not have the same guard.
Problem
If the backend response contains a negative
retry_invalue, the SDK passes it directly toThread.sleep(long)throughSingleThreadCachedScheduler.schedule().On Android,
Thread.sleep(long)throwsIllegalArgumentExceptionwhenmillisis negative. Since the SDK only catchesInterruptedException, this can crash the app.Source Code
Repository:
https://github.com/adjust/android_sdk
ActivityPackageSenderPackageHandlerSingleThreadCachedSchedulerIllegalArgumentExceptionis not caught here.Expected Behavior
The SDK should not crash when
retry_inis negative.It should either:
0retry_inretry_inas immediate retryIllegalArgumentExceptionin the schedulerSuggested Fix
One possible fix is to validate
retry_inbefore scheduling:Alternatively, the scheduler could guard the delay value:
Additional Context
continue_inalready has a positive-value guard:But
retry_indoes not have the same guard.