Android SafetyNetClient.attest() Timeout

728 views Asked by At

As you may know SafetyNetClient.attest() runs async.
But in our app we want to receive the SafetyNetApi.AttestationResponse synchronously. Because the SafetyNet result is required as input for another use case.
To achieve that we implemented a "Wrapper" around SafetyNetClient.attest() which looks something like this.

public Result getAttestationResult(Input input) {
    
    // NOTE: ResultWaiter is our own component to get the result of a async operation in a synchronous manner.
    ResultWaiter<Result> waiter = ResultWaiter.<Result>builder(executor)
      .timeout(10) // timeout set to 10 seconds
      .build();

    Task<SafetyNetApi.AttestationResponse> task = SafetyNet.getClient(context).attest(input.nonce(), input.apiKey());

    // notify ResultWaiter if SafetyNetClient returns a result
    task.addOnSuccessListener(attestationResponse -> waiter.setResult(Result.builder()
      .jwsResult(attestationResponse.getJwsResult())
      .build()));

    // notify ResultWaiter if SafetyNetClient returns an exception
    task.addOnFailureListener(exception -> waiter.setResult(Result.builder()
      .error(exception)
      .build()));

    try {
      // NOTE: waiter.waitForResult() blocks the current thread where getAttestationResult() was called 
      // (of course this can not be the Main/UI Thread!)
      // the blocking is released if
      //    1. waiter.setResult() is called
      //    2. if configured timeout runs out, this method throws a TimeoutException
      return waiter.waitForResult();
    } catch (TimeoutException exception) {
      return Result.builder()
        .error(exception)
        .build();
    }
  }

The problem we currently face is that we have numerous end-users which are ending up in the catch (TimeoutException e) block of this code sample.
This means that SafetyNet did not provide a result or an error in the configured timeout of 10 seconds.

Under which circumstances might it be possible that SafetyNet doesn't return a result in 10 seconds?
Except maybe for the obvious reason of bad connectivity. There must be other reasons since we have a very high number of end-users with this issue.

We don't want to simply increase the timeout to something like 30 or 40 seconds because this would impact the user experience in this particular flow of the app where a SafetyNet attestation is required.

Is your app logic which implements SafetyNetClient.attest() simply waiting for the Task to either return a result or an exception indefinitely?
And you are relying on the fact that the Task has to end up in either OnSuccessListener or onFailureListener?

Do you have any experience on how long SafetyNetClient.attest() normally runs until it finishes in one of those listeners?

We can already exclude any bug in the ResusltWaiter component because it is used in several other parts of our app and there it works flawlessly.

Thanks for your help and feedback in advance!

1

There are 1 answers

0
Mark Nguyen On

I was struggling in 3 days with this issue and at first I thought that I had some problems with configuring the SafetyNet. However I finally found that it happens to physical Android device only, and restarting the router/modem (that the device is connecting to) helped.

This answer helped me: https://stackoverflow.com/a/51122769/10179386