open-telemetry / open-telemetry/opentelemetry-java-instrumentation
Avoid main-thread disk I/O during InstrumenterCustomizerProvider SPI initialization on Android
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 2.6k
- Forks
- 1.2k
- Avg merge
- 2d 18h
- Merged PRs (30d)
- 228
Description
Description
On Android, the first OpenTelemetry instrumenter construction performs a classpath ServiceLoader lookup for InstrumenterCustomizerProvider.
When this occurs on the main thread with Android StrictMode enabled, it causes a DiskReadViolation.
The lookup path is:
InstrumenterBuilder.build()
→ InternalInstrumenterCustomizerUtil
→ InstrumenterCustomizerUtil.
→ ServiceLoaderUtil.load(...)
→ ServiceLoader
→ ClassLoader.getResources()
→ JarFile / ZipFile
→ disk read
The operation is one-time, but it took approximately 80 ms in our test and violates Android main-thread I/O rules.
Versions
opentelemetry-instrumentation-api: 2.30.0opentelemetry-instrumentation-api-incubator: 2.30.0-alpha- Android application using StrictMode
- Instrumenter:
DefaultHttpClientInstrumenterBuilder
Reproduction
Enable StrictMode before constructing an instrumenter:
Construct the first OpenTelemetry instrumenter.
import android.os.StrictMode;
import com.splunk.rum.instrumentation.okhttp3.OkHttpTelemetry;
import io.opentelemetry.api.OpenTelemetry;
StrictMode.setThreadPolicy(
new StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.penaltyLog()
.build());
OkHttpTelemetry telemetry =
OkHttpTelemetry.builder(OpenTelemetry.noop()).build();
The first instrumenter construction produces a DiskReadViolation similar to:
StrictMode policy violation; ~duration=80 ms: android.os.strictmode.DiskReadViolation
at android.os.StrictMode$AndroidBlockGuardPolicy.onReadFromDisk(StrictMode.java:1658)
at java.io.UnixFileSystem.getLastModifiedTime(UnixFileSystem.java:289)
at java.io.File.lastModified(File.java:937)
at java.util.zip.ZipFile.<init>(ZipFile.java:265)
at java.util.zip.ZipFile.<init>(ZipFile.java:187)
at java.util.jar.JarFile.<init>(JarFile.java:169)
at java.util.jar.JarFile.<init>(JarFile.java:106)
at libcore.io.ClassPathURLStreamHandler.<init>(ClassPathURLStreamHandler.java:46)
at dalvik.system.DexPathList$Element.maybeInit(DexPathList.java:750)
at dalvik.system.DexPathList$Element.findResource(DexPathList.java:777)
at dalvik.system.DexPathList.findResources(DexPathList.java:572)
at dalvik.system.BaseDexClassLoader.findResources(BaseDexClassLoader.java:330)
at java.lang.ClassLoader.getResources(ClassLoader.java:839)
at java.util.ServiceLoader$LazyIterator.hasNextService(ServiceLoader.java:349)
at java.util.ServiceLoader$LazyIterator.hasNext(ServiceLoader.java:402)
at java.util.ServiceLoader$1.hasNext(ServiceLoader.java:488)
at io.opentelemetry.instrumentation.api.incubator.instrumenter.internal.InstrumenterCustomizerUtil.<clinit>(InstrumenterCustomizerUtil.java:24)
at java.lang.Class.classForName(Native Method)
at java.lang.Class.forName(Class.java:454)
at java.lang.Class.forName(Class.java:379)
at io.opentelemetry.instrumentation.api.internal.InternalInstrumenterCustomizerUtil.<clinit>(InternalInstrumenterCustomizerUtil.java:22)
at io.opentelemetry.instrumentation.api.internal.InternalInstrumenterCustomizerUtil.getInstrumenterCustomizerProviders(InternalInstrumenterCustomizerUtil.java:38)
at io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder.applyCustomizers(InstrumenterBuilder.java:438)
at io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder.buildInstrumenter(InstrumenterBuilder.java:303)
at io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder.buildInstrumenter(InstrumenterBuilder.java:295)
at io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpClientInstrumenterBuilder.build(DefaultHttpClientInstrumenterBuilder.java:242)
Possible Solutions
Make SPI discovery Android-safe.
Avoid the lookup when no customizer providers are present.
Provide a supported opt-out for Android/library instrumentation.
Note: The customizer SPI was introduced through the instrumenter extension work in
#13917,
which shipped with the 2.19.0 release.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with InstrumenterBuilder.applyCustomizers and trace InternalInstrumenterCustomizerUtil, InstrumenterCustomizerUtil, and ServiceLoaderUtil to understand when SPI discovery runs. Reproduce the first DefaultHttpClientInstrumenterBuilder construction with Android StrictMode enabled, then verify the chosen approach avoids the main-thread disk read while preserving customizer-provider discovery.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- android, java
- Domain
- api, mobile-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100