airbnb / epoxy

Epoxy is an Android library for building complex screens in a RecyclerView
https://goo.gl/eIK82p
Apache License 2.0
8.51k stars 728 forks source link

Change the way the Compose interop works to avoid Android 12 bug #1370

Closed rossbacher closed 8 months ago

rossbacher commented 8 months ago

The way the composeEpoxyModel function was written it would create a function that looked like this (in decompiled dex bytecode (for readability compiled to Java))

public static final ComposeEpoxyModel composeEpoxyModel(String id, Object[] keys, Function2<? super Composer, ? super Integer, Unit> composeFunction) {
    ...
    ComposeEpoxyModel $this$composeEpoxyModel_u24lambda_u240 = new ComposeEpoxyModel(Arrays.copyOf(keys, keys.length), composeFunction);
    $this$composeEpoxyModel_u24lambda_u240.id(id);
    return $this$composeEpoxyModel_u24lambda_u240;
}

this would trigger a ART bug in the (non mainline patched version of Android 12) to optimize the this line away

$this$composeEpoxyModel_u24lambda_u240.id(id);

and lead to crashes on Android 12.

More background at: https://github.com/airbnb/epoxy/issues/1199 and https://issuetracker.google.com/issues/197818595

This works around this issue by making sure that the creation, setting the id and adding to the controller of a ComposeEpoxyModel is happening in the same location in compiled bytecode.

Note: If you run R8 with optimization enabled, the method outlining optimization might still outline some of that inlined code again and thus still cause this problem but that is a different issue that can be dealt with by disabling outlining or all optimization.