Mobile Development 16 min read

Why R8’s ApiModel Adds an Extra new‑instance Instruction and Crashes Android Apps

This article explains how R8’s ApiModel optimization can generate a redundant new‑instance bytecode that triggers class initialization failures, why synchronized or try‑catch blocks also cause the issue, and presents four practical solutions including disabling ApiModel, official patches, custom fixes, and business‑level refactoring.

DeWu Technology
DeWu Technology
DeWu Technology
Why R8’s ApiModel Adds an Extra new‑instance Instruction and Crashes Android Apps

Background

R8 is Google’s compiler optimizer that rewrites bytecode to reduce APK size and improve performance. When upgrading AGP, a native crash was observed in SurfaceTexture caused by an extra new‑instance instruction in the smali code.

Reproducing the Issue

The crash occurs when a new SurfaceTexture(...) call is compiled into a redundant new‑instance followed by a call to a static method generated by ApiModel outlining.

Problem Analysis

ApiModel performs code outlining: identical code fragments are extracted into a separate static method, and the original call site is replaced with a call to that method. Even a single use of a high‑API method triggers outlining, creating an extra new‑instance that does not invoke the constructor’s <init> method. Because SurfaceTexture overrides finalize, the stray instance leads to a native SIGNAL 11 memory error during garbage collection.

The outlining logic resides in InstanceInitializerOutliner->rewriteCode. During the first pass it replaces <init> calls with calls to the generated outline method. In the second pass it decides whether the original new‑instance can be removed. If the method canSkipClInit finds any non‑local‑variable instructions between new‑instance and the invoke‑direct, it assumes class‑initialization logic and keeps the instruction.

Typical patterns that prevent removal include parameter calculations, synchronized blocks, and try‑catch blocks, because the compiler inserts extra instructions (e.g., FALLTHROUGH) that the analysis treats as class‑initialization code.

How R8 Determines API Versions

Since R8 3.3, a .ser database maps each Android API element to the Android version that introduced it. At compile time R8 looks up the API level of each method call to decide whether outlining is needed.

Why try‑catch Also Triggers the Issue

When Java code contains a synchronized block, the compiler generates a try‑catch wrapper to ensure the lock is released on exceptions. The added FALLTHROUGH instructions are treated like normal code, causing canSkipClInit to retain the new‑instance.

Solutions

Disable ApiModel : Set the system property com.android.tools.r8.disableApiModeling=1 to turn off the outlining feature.

Official Fix : R8 team provides a temporary workaround by isolating high‑API calls in separate methods; a later MR disables ApiModel for SurfaceTexture.

Self‑Fix : Replace the stray new‑instance with a safe class‑loading trigger such as a static field access, though this requires maintaining a custom R8 build.

Business Refactor (Recommended) : Log outline generation, identify affected classes, and rewrite code to avoid passing parameters or using synchronized/try‑catch around high‑API calls, optionally adding a blacklist for third‑party libraries.

Summary

Upgrading AGP enables ApiModel, which can introduce an extra new‑instance instruction that triggers class‑initialization failures for classes like SurfaceTexture. The root cause lies in the canSkipClInit analysis of surrounding instructions. Disabling ApiModel, applying the official patch, or refactoring the code are viable mitigation strategies.

OptimizationAndroidR8CompilationApiModelnew-instance
DeWu Technology
Written by

DeWu Technology

A platform for sharing and discussing tech knowledge, guiding you toward the cloud of technology.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.