You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Track the currently known feature-parity gaps and high-risk untested behavior in the trimmable typemap implementation.
The goal is not to restore every legacy implementation detail. It is to identify behavior that applications and bindings reasonably depend on, decide the intended contract, and add explicit support or an actionable diagnostic.
This list is an investigation backlog. Items without an existing focused issue are not necessarily confirmed product defects.
Known regression that prompted this audit
Forward managed attributes to Java annotations. (#12549, #12608)
[tests] Cover WebView JavaScript annotations #12608 adds a focused local-HTML WebView regression proving the annotation survives generated Java and DEX and JavaScript invokes the managed bridge under llvm-ir/CoreCLR, trimmable/CoreCLR, and trimmable/NativeAOT.
Reconstructed pre-fix NativeAOT output retained the bridge method but omitted the annotation and timed out exactly like the original Uno failure.
The annotation regression showed that scanner and runtime coverage can remain green while the semantic contents of generated Java have changed.
Constructor and activation parity
Constructor discovery and ordinary Java-created activation now have substantial coverage, including primitives, strings, arrays, Context, IAttributeSet, exceptions, managed-first construction, and Java-first construction. The remaining risk is concentrated in less common activation paths:
Peer identity and replaceability during activation. (#12566)
Reentrant and synchronized concurrent constructor-time lookups preserve one final managed peer and exactly-once construction.
The unchanged fixture passes with llvm-ir, trimmable CoreCLR, and NativeAOT; no production fix was required.
Virtual callbacks from Java constructors. (#12566)
Added a replacement fixture using normal [Register] plus generated static/UCO registration, without unsupported dynamic native registration.
Peer identity, exactly-once construction, callback dispatch, concurrency, and exception propagation pass unchanged in all three configurations; no production fix was required.
Non-static Java inner classes — investigated; not an llvm-ir parity feature.
The llvm-ir path omits the nested derived JCW and Java activation fails with ClassNotFoundException, even with an explicit nested [Register].
A trimmable-only implementation was prototyped, but it will not be landed under the requirement that parity fixtures pass with llvm-ir first.
Confirmed trimmable typemap defect: [Export(Throws = ...)] metadata was parsed but dropped from generated Java constructors.
The unchanged constructor fixture passed with llvm-ir and failed with trimmable CoreCLR and NativeAOT before the fix; all three configurations pass after the fix.
Interface and abstract-type invoker activation. (#12565)
Confirmed trimmable typemap defect: JniTypeSignatureAttribute.InvokerType was ignored, allowing hierarchy fallback to select the wrong proxy.
Constructor-based XA, Java.Interop, inherited-interface, abstract-type, and repeated-lookup identity tests now pass with llvm-ir, trimmable CoreCLR, and NativeAOT.
Cross-assembly invokers are excluded: llvm-ir resolves invokers from the target assembly and does not support that shape.
Wrapping an existing Java object as a caller-supplied closed managed generic type was already supported; coverage now proves exactly-once activation and stable identity across all configurations.
Java-created open generic peers remain unsupported because Java cannot provide managed type arguments.
Ambiguous or unrepresentable constructor signatures. (#12567)
Added localized XA4259-XA4262 diagnostics for collapsed JNI signatures, unsupported parameter shapes, missing compatible Java base constructors, and invalid SuperArgumentsString expressions.
Validation stops before writing partial Java output and covers inferred, [Export], [Register], and [JniConstructorSignature] constructor forms.
Confirmed trimmable typemap defect: cross-assembly peers with the same generated JCW name silently overwrote one .java file while retaining duplicate/inconsistent ACW and typemap mappings.
The unchanged fixture fails with XA4215 under llvm-ir; trimmable now rejects the collision deterministically before writing typemap, Java, or ACW-map outputs.
The shared llvm-ir/trimmable fixture compiles both generated source sets with javac and compares parsed classfile semantics for hierarchy, ordered interfaces, constructors, methods, fields, visibility/modifiers, and throws.
Runtime-retained annotation presence is independently verified in generated Java, DEX, and an end-to-end WebView JavaScript bridge.
The comparator has already exposed and regression-tested checked-exception and interface-declaration defects; future focused parity items should extend this semantic corpus rather than use raw source-string equality.
Redundant and colliding interface declarations. (#12585)
Confirmed trimmable typemap defect: redundant parent interfaces and two managed aliases for one Java interface produced implements Root, Derived, Derived, which fails javac with repeated interface.
Scanner-side most-derived filtering plus ordered Java-name deduplication now matches llvm-ir while preserving complete direct-interface metadata and alias associations.
Generic parent ancestry is handled by the type-definition algorithm; deeper covariant/bridge runtime cases remain future corpus expansion rather than blockers for this fix.
Ordinary JCWs support the frozen OpenJDK 21/Unicode 15 portable identifier set, including BMP letters, currency symbols, and connector punctuation, with consistent source/classfile/ACW/typemap/DEX/JNI identity and three-runtime constructor activation.
Names must already be NFC; combining/format parts and canonically non-NFC names are rejected early to avoid normalization-sensitive path corruption. Nothing is normalized silently.
Supplementary identifiers are preserved in javac/classfile/DEX but cannot be loaded by Android FindClass in any tested runtime, so managed supplementary JCWs are rejected early. Currency/connector starts remain non-component-only because AAPT rejects them in manifest class names.
Validation is frozen to JDK 21 Unicode data rather than host .NET tables; newer Unicode assignments require an explicit table/toolchain update.
[ExportField] validation and runtime coverage. (#12596)
Confirmed NativeAOT gap: parameterized and void initializers could emit typemap/invalid Java output instead of legacy XA4205/XA4208; generic declaring types could bypass XA4207 or report later diagnostics first.
Trimmable validation now matches measured llvm-ir precedence and stops before writing root/per-assembly typemaps or Java output.
Classfile/javac coverage verifies ordered field declarations, type/modifiers, public/protected static and instance fields; device coverage verifies primitive/object and instance JNI reads across all three configurations.
Duplicate and invalid Java field names remain javac failures in llvm-ir and both trimmable runtimes; no trimmable-only diagnostic was introduced.
Confirmed NativeAOT defect: arbitrary managed types and other unsupported [Export]/[ExportField] signatures silently degraded to java.lang.Object, emitted typemap/Java/ACW-map outputs, or failed later with non-actionable errors.
Trimmable scanning now emits localized XA4263 before outputs for unresolved managed objects, generic method/non-Java instantiations, invalid special mappings, and function pointers, while preserving supported Java peers, interfaces, enums, strings, arrays, collections, and exact Stream/XmlReader mappings.
Exported constructors preserve metadata constructor identity, static constructors remain ignored, full attribute/type/assembly identity is validated, and assembly/type-forwarder resolution cannot borrow same-named peers, enums, or framework special types from another assembly.
Byref, pointer, rectangular-array, and nested structural constructor shapes remain owned by XA4260 in [typemap] Diagnose unsupported constructor shapes #12567; measured llvm-ir-supported array special mappings are classified without generating invalid trimmable dispatcher IL.
Runtime behavior
Java aliases and casts in realistic AppCompat/view inflation paths. (#12609)
A focused AppCompat XML-inflation app covers Toolbar/AppCompatImageButton most-derived lookup, repeated identity, a concrete same-JNI alias, ITintableBackgroundView JavaCast/JavaAs, managed-created peers, and caller-directed JavaList<string> wrapping.
The unchanged fixture passes under llvm-ir/CoreCLR, trimmable/CoreCLR, and trimmable/NativeAOT, so no production change was required and the focused historical mismatch is stale/not reproducible.
The three broad Xamarin.Forms 5.0 skips remain separately unclassified because that legacy package was unavailable in the offline test cache and those fixtures also combine bundle/debug behavior.
Static/default interface methods and desugaring. (#12610)
The supported direct contract now covers JavaObjectArray<object>, duplicate/null entries, repeated lookup identity, JavaList<object>, JavaDictionary<object,object>, nested collection round trips, disposal, and GC/Java-root lifetime across MonoVM, llvm-ir/CoreCLR, trimmable/CoreCLR, and NativeAOT.
The Investigate JavaProxyObject support in trimmable typemap #11703 semantic difference is intentional: llvm-ir JavaProxyObject forwards managed Equals/GetHashCode/ToString, while trimmable proxies use Java reference identity, System.identityHashCode, and exact default Object.toString.
Reflection-oriented general value-marshaler/ActivatePeer APIs remain unsupported; this closes only the narrower direct array/collection proxy contract.
A minimal app with package-private unbound Java peers covers JavaList<IValueProvider>, JavaCollection<IValueProvider>, and dictionaries with interface keys/values/both, plus inherited-interface invokers, identity, null/duplicates, mutation, removal, and raw-JNI enumeration.
The unchanged fixture passes under llvm-ir/CoreCLR, trimmable/CoreCLR, and trimmable/NativeAOT. Exclusive NativeAOT DGML paths prove SafeJavaCollectionFactory roots the canonical list/collection/dictionary activation constructors without incidental closed-wrapper roots.
JavaCollection<T>.Remove remains independently broken under llvm-ir due to its existing method descriptor, so that non-parity issue is excluded.
Multi-RID and reference/implementation assembly selection.
Verify RID-specific assets and trim closures instead of relying on the first RID.
Ensure implementation assemblies are selected deterministically when reference and implementation assemblies share a simple name.
R8 incremental invalidation.
A managed reachability/DGML-only change must update keep rules and force DEX regeneration.
Fast deployment and packaging variants.
Exercise add/remove/rename of Java peers under the trimmable typemap.
Cover APK/AAB, assembly stores, ReadyToRun, single/multiple RIDs, and R8 on/off.
Explicit non-goals and intentional incompatibilities
The following should not be treated as missing parity unless the product contract changes:
Dynamic native registration and [JniAddNativeMethodRegistration] are unsupported by design. The build should reject them consistently with a coded diagnostic.
Java.Interop callable attributes such as [JavaCallable] and [JavaCallableConstructor] are currently unsupported by design. Supporting them would mean translating them into the existing generated export/constructor/UCO model, not restoring ManagedPeer; investigate only if Java.Interop-authored assemblies are supported Android inputs.
Legacy package naming policies and exact crc64... names are intentionally incompatible. Explicit [Register] names are the compatibility mechanism for externally referenced Java names.
Reflection-oriented type/value-manager APIs, including runtime ActivatePeer() and general value-marshaler lookup, are intentionally unavailable. Required product behavior should use generated proxies and marshalers.
Java-created open generic peers are unsupported because Java cannot identify the managed generic arguments.
Proposed validation strategy
Add a shared fixture corpus that can be processed by both the legacy XAJavaInterop1/llvm-ir and trimmable pipelines.
Compare parsed Java semantics, not raw source text.
Compile all generated JCWs with javac.
Run Java-created, managed-created, reentrant, and concurrent activation cases on device.
Compare Release artifacts and runtime behavior with R8 enabled and disabled.
Exercise CoreCLR Debug/Release and NativeAOT Release across multiple ABIs/RIDs.
Require explicit diagnostics for every intentional non-goal instead of allowing late runtime failures.
Summary
Track the currently known feature-parity gaps and high-risk untested behavior in the trimmable typemap implementation.
The goal is not to restore every legacy implementation detail. It is to identify behavior that applications and bindings reasonably depend on, decide the intended contract, and add explicit support or an actionable diagnostic.
This list is an investigation backlog. Items without an existing focused issue are not necessarily confirmed product defects.
Known regression that prompted this audit
@android.webkit.JavascriptInterface.The annotation regression showed that scanner and runtime coverage can remain green while the semantic contents of generated Java have changed.
Constructor and activation parity
Constructor discovery and ordinary Java-created activation now have substantial coverage, including primitives, strings, arrays,
Context,IAttributeSet, exceptions, managed-first construction, and Java-first construction. The remaining risk is concentrated in less common activation paths:Peer identity and replaceability during activation. (#12566)
Virtual callbacks from Java constructors. (#12566)
[Register]plus generated static/UCO registration, without unsupported dynamic native registration.Non-static Java inner classes — investigated; not an llvm-ir parity feature.
ClassNotFoundException, even with an explicit nested[Register].Constructor
throwsdeclarations. (#12564)[Export(Throws = ...)]metadata was parsed but dropped from generated Java constructors.Interface and abstract-type invoker activation. (#12565)
JniTypeSignatureAttribute.InvokerTypewas ignored, allowing hierarchy fallback to select the wrong proxy.Closed generic wrapper activation. (#12564)
Ambiguous or unrepresentable constructor signatures. (#12567)
SuperArgumentsStringexpressions.[Export],[Register], and[JniConstructorSignature]constructor forms.JCW and Java-source parity
Duplicate Java wrapper names. (#12569)
.javafile while retaining duplicate/inconsistent ACW and typemap mappings.Generated Java semantic parity. (#12573, #12608)
javacand compares parsed classfile semantics for hierarchy, ordered interfaces, constructors, methods, fields, visibility/modifiers, andthrows.Redundant and colliding interface declarations. (#12585)
implements Root, Derived, Derived, which failsjavacwithrepeated interface.Unicode Java identifiers. (#12607)
FindClassin any tested runtime, so managed supplementary JCWs are rejected early. Currency/connector starts remain non-component-only because AAPT rejects them in manifest class names.[ExportField]validation and runtime coverage. (#12596)javacfailures in llvm-ir and both trimmable runtimes; no trimmable-only diagnostic was introduced.Unsupported export signatures. (#12597)
[Export]/[ExportField]signatures silently degraded tojava.lang.Object, emitted typemap/Java/ACW-map outputs, or failed later with non-actionable errors.Runtime behavior
Java aliases and casts in realistic AppCompat/view inflation paths. (#12609)
ITintableBackgroundViewJavaCast/JavaAs, managed-created peers, and caller-directedJavaList<string>wrapping.Static/default interface methods and desugaring. (#12610)
NoSuchMethodErrorskip predates the static fallback fix in [TrimmableTypeMap] Add GetStaticMethodFallbackTypesCore override for desugared default interface methods #11050 and is stale.Plain managed-object proxy behavior. (#12612)
JavaObjectArray<object>, duplicate/null entries, repeated lookup identity,JavaList<object>,JavaDictionary<object,object>, nested collection round trips, disposal, and GC/Java-root lifetime across MonoVM, llvm-ir/CoreCLR, trimmable/CoreCLR, and NativeAOT.JavaProxyObjectforwards managedEquals/GetHashCode/ToString, while trimmable proxies use Java reference identity,System.identityHashCode, and exact defaultObject.toString.ActivatePeerAPIs remain unsupported; this closes only the narrower direct array/collection proxy contract.Interface-valued Java collections. (#12614)
JavaList<IValueProvider>,JavaCollection<IValueProvider>, and dictionaries with interface keys/values/both, plus inherited-interface invokers, identity, null/duplicates, mutation, removal, and raw-JNI enumeration.SafeJavaCollectionFactoryroots the canonical list/collection/dictionary activation constructors without incidental closed-wrapper roots.JavaCollection<T>.Removeremains independently broken under llvm-ir due to its existing method descriptor, so that non-parity issue is excluded.Application-defined value types in containers.
Throwable round trips.
Build, trimming, and packaging
R8 retention for Java outside the managed reachability graph.
AndroidJavaSource, binding Java, JNI/reflection-only entry points, and multidex behavior.XML-created custom views and resource-designer dependencies.
AppWithStyleableUsageRunsfailure reaches the managed constructor but cannot load_Microsoft.Android.Resource.Designer.Incremental typemap correctness.
Pre-generated framework typemaps.
Multi-RID and reference/implementation assembly selection.
R8 incremental invalidation.
Fast deployment and packaging variants.
Explicit non-goals and intentional incompatibilities
The following should not be treated as missing parity unless the product contract changes:
[JniAddNativeMethodRegistration]are unsupported by design. The build should reject them consistently with a coded diagnostic.[JavaCallable]and[JavaCallableConstructor]are currently unsupported by design. Supporting them would mean translating them into the existing generated export/constructor/UCO model, not restoringManagedPeer; investigate only if Java.Interop-authored assemblies are supported Android inputs.crc64...names are intentionally incompatible. Explicit[Register]names are the compatibility mechanism for externally referenced Java names.ActivatePeer()and general value-marshaler lookup, are intentionally unavailable. Required product behavior should use generated proxies and marshalers.Proposed validation strategy
javac.