|
49 | 49 | import timber.log.Timber; |
50 | 50 |
|
51 | 51 | import java.io.File; |
| 52 | +import java.util.concurrent.ExecutorService; |
| 53 | +import java.util.concurrent.Executors; |
| 54 | +import java.util.concurrent.Future; |
| 55 | +import java.util.concurrent.TimeUnit; |
| 56 | +import java.util.concurrent.TimeoutException; |
52 | 57 |
|
53 | 58 | import static eu.opencloud.android.data.authentication.AuthenticationConstantsKt.KEY_CLIENT_REGISTRATION_CLIENT_EXPIRATION_DATE; |
54 | 59 | import static eu.opencloud.android.data.authentication.AuthenticationConstantsKt.KEY_CLIENT_REGISTRATION_CLIENT_ID; |
@@ -318,6 +323,30 @@ private String refreshToken( |
318 | 323 | String authTokenType, |
319 | 324 | AccountManager accountManager |
320 | 325 | ) { |
| 326 | + // Run refresh on a worker with a short timeout to avoid ANR in AccountAuthenticatorService. |
| 327 | + ExecutorService executor = Executors.newSingleThreadExecutor(); |
| 328 | + Future<String> future = executor.submit(() -> |
| 329 | + refreshTokenInternal(account, authTokenType, accountManager) |
| 330 | + ); |
| 331 | + try { |
| 332 | + return future.get(10, TimeUnit.SECONDS); // stay below 20s ANR window |
| 333 | + } catch (TimeoutException e) { |
| 334 | + Timber.w(e, "OAuth token refresh timed out, fallback to interactive login"); |
| 335 | + future.cancel(true); |
| 336 | + return null; |
| 337 | + } catch (Exception e) { |
| 338 | + Timber.e(e, "OAuth token refresh failed"); |
| 339 | + return null; |
| 340 | + } finally { |
| 341 | + executor.shutdownNow(); |
| 342 | + } |
| 343 | + } |
| 344 | + |
| 345 | + private String refreshTokenInternal( |
| 346 | + Account account, |
| 347 | + String authTokenType, |
| 348 | + AccountManager accountManager |
| 349 | + ) { |
321 | 350 |
|
322 | 351 | // Prepare everything to perform the token request |
323 | 352 | String refreshToken = accountManager.getUserData(account, KEY_OAUTH2_REFRESH_TOKEN); |
|
0 commit comments