grpc/grpc-java · critical · RuntimeException

We can not do TLS handshake on this Android version, please

Error message

We can not do TLS handshake on this Android version, please install the Google Play Services Dynamic Security Provider to use TLS

What it means

AndroidApiNegotiator (older Android path) throws this when the platform supports neither ALPN nor NPN TLS extensions (TlsExtensionType.NONE), so protocol negotiation cannot occur. The message instructs installing the Google Play Services Dynamic Security Provider.

Source

Thrown at okhttp/src/main/java/io/grpc/okhttp/OkHttpProtocolNegotiator.java:305

            return;
          }
        }
      } catch (IllegalAccessException e) {
        throw new RuntimeException(e);
      } catch (InvocationTargetException e) {
        throw new RuntimeException(e);
      } catch (InstantiationException e) {
        throw new RuntimeException(e);
      }

      Object[] parameters = {Platform.concatLengthPrefixed(protocols)};
      if (platform.getTlsExtensionType() == TlsExtensionType.ALPN_AND_NPN) {
        SET_ALPN_PROTOCOLS.invokeWithoutCheckedException(sslSocket, parameters);
      }
      if (platform.getTlsExtensionType() != TlsExtensionType.NONE) {
        SET_NPN_PROTOCOLS.invokeWithoutCheckedException(sslSocket, parameters);
      } else {
        throw new RuntimeException("We can not do TLS handshake on this Android version, please"
            + " install the Google Play Services Dynamic Security Provider to use TLS");
      }
    }

    @Override
    public String getSelectedProtocol(SSLSocket socket) {
      if (GET_APPLICATION_PROTOCOL != null) {
        try {
          return (String) GET_APPLICATION_PROTOCOL.invoke(socket);
        } catch (IllegalAccessException e) {
          throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
          Throwable targetException = e.getTargetException();
          if (targetException instanceof UnsupportedOperationException) {
            logger.log(
                Level.FINER,
                "Socket unsupported for getApplicationProtocol, will try old methods");
          } else {

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Add the Google Play Services Security Provider and call ProviderInstaller.installIfNeeded(context) before creating the channel
  2. Bundle Conscrypt for Android (org.conscrypt:conscrypt-android) and register it as the first security provider
  3. Raise minSdkVersion / require a device with TLS extension support
  4. Use plaintext only in controlled/test environments (not recommended for production)

Example fix

// before
OkHttpChannelBuilder.forAddress(host, port).build(); // old Android, no ALPN/NPN
// after
ProviderInstaller.installIfNeeded(context); // Google Play Services provider
OkHttpChannelBuilder.forAddress(host, port).build();
Defensive patterns

Strategy: fallback

Validate before calling

if (Platform.get().getTlsExtensionType() == TlsExtensionType.NONE) { ProviderInstaller.installIfNeeded(context); }

Type guard

boolean tlsExtensionsAvailable() { return Platform.get().getTlsExtensionType() != TlsExtensionType.NONE; }

Try / catch

try { stub.unaryCall(req); } catch (RuntimeException e) { if (e.getMessage().contains("Dynamic Security Provider")) { ProviderInstaller.installIfNeeded(context); retry(); } throw e; }

Prevention

When it happens

Trigger: Running gRPC-OkHttp with TLS on an old Android version whose default Conscrypt/SSLSocket lacks both ALPN and NPN, then performing a TLS handshake via configureTlsExtensions.

Common situations: Android < 4.4 or devices with outdated security patch level, apps not bundling Conscrypt, emulators with old system images.

Understand the failure class

Background: "unsupported platform" / "not supported on this platform" errors: what they mean and how to fix them — this error's family across 47 libraries.

Related errors


AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08). Data as JSON: /api/errors/9bacdaac7956c000. Report an issue: GitHub.