diff --git a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/AndroidFriendlyRandomIdGenerator.java b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/AndroidFriendlyRandomIdGenerator.java new file mode 100644 index 00000000000..ae320ae9e52 --- /dev/null +++ b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/AndroidFriendlyRandomIdGenerator.java @@ -0,0 +1,42 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.trace; + +import io.opentelemetry.api.trace.SpanId; +import io.opentelemetry.api.trace.TraceId; +import java.util.Random; + +/** + * {@link IdGenerator} instance that doesn't use {@link java.util.concurrent.ThreadLocalRandom}, + * which is broken on most versions of Android (it uses the same seed everytime it starts up). + */ +enum AndroidFriendlyRandomIdGenerator implements IdGenerator { + INSTANCE; + + private static final Random random = new Random(); + + private static final long INVALID_ID = 0; + + @Override + public String generateSpanId() { + long id; + do { + id = random.nextLong(); + } while (id == INVALID_ID); + return SpanId.fromLong(id); + } + + @Override + public String generateTraceId() { + long idHi; + long idLo; + do { + idHi = random.nextLong(); + idLo = random.nextLong(); + } while (idHi == INVALID_ID && idLo == INVALID_ID); + return TraceId.fromLongs(idHi, idLo); + } +} diff --git a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/IdGenerator.java b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/IdGenerator.java index 80c8016639d..d28c969ccf6 100644 --- a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/IdGenerator.java +++ b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/IdGenerator.java @@ -21,6 +21,10 @@ public interface IdGenerator { * randomness but may change in the future. */ static IdGenerator random() { + // note: check borrowed from OkHttp's check for Android. + if ("Dalvik".equals(System.getProperty("java.vm.name"))) { + return AndroidFriendlyRandomIdGenerator.INSTANCE; + } return RandomIdGenerator.INSTANCE; } diff --git a/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/RandomIdGeneratorTest.java b/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/RandomIdGeneratorTest.java index 35a560fbd4d..fcbed588d26 100644 --- a/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/RandomIdGeneratorTest.java +++ b/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/RandomIdGeneratorTest.java @@ -19,11 +19,25 @@ void defaults() { // Can't assert values but can assert they're valid, try a lot as a sort of fuzz check. for (int i = 0; i < 1000; i++) { - CharSequence traceId = generator.generateTraceId(); - assertThat(traceId.toString()).isNotEqualTo(TraceId.getInvalid()); + String traceId = generator.generateTraceId(); + assertThat(traceId).isNotEqualTo(TraceId.getInvalid()); - CharSequence spanId = generator.generateSpanId(); - assertThat(spanId.toString()).isNotEqualTo(SpanId.getInvalid()); + String spanId = generator.generateSpanId(); + assertThat(spanId).isNotEqualTo(SpanId.getInvalid()); + } + } + + @Test + void androidVersion() { + IdGenerator generator = AndroidFriendlyRandomIdGenerator.INSTANCE; + + // Can't assert values but can assert they're valid, try a lot as a sort of fuzz check. + for (int i = 0; i < 1000; i++) { + String traceId = generator.generateTraceId(); + assertThat(traceId).isNotEqualTo(TraceId.getInvalid()); + + String spanId = generator.generateSpanId(); + assertThat(spanId).isNotEqualTo(SpanId.getInvalid()); } } }