Skip to content

Use different soname for Dart SDK Android build - #204

Merged
simolus3 merged 3 commits into
mainfrom
android-soname
Jul 27, 2026
Merged

Use different soname for Dart SDK Android build#204
simolus3 merged 3 commits into
mainfrom
android-soname

Conversation

@simolus3

@simolus3 simolus3 commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

On Android, the core extension is distributed in two ways:

  1. As an Android library bundle published to Maven Central (used by the Kotlin and React Native SDKs).
  2. As standalone .so files attached to GitHub releases (used by the Dart and Dotnet SDKs).

Through peculiar but not entirely unreasonable setups, it's possible to end up with both in the same app. powersync-ja/powersync.dart#442 is an example of this: One database is managed by the PowerSync Dart SDK, another one by the Kotlin SDK. In this setup, two copies of SQLite and the core extension are included in the app. As long as they never touch the same database file, this should be fine. However, because the two builds have the same soname entry, the Android loader considers them equal and won't load them both. This causes sqlite3_powersync_init to be called twice with different sqlite3_api_routines pointers, which quickly leads to crashes as we try to use database pointers from one SQLite copy with function pointers from the other.

To fix this, this gives the distributions unique names: Files in the Android library keep their libpowersync.so name, while standalone files are named libpowersync_core.so, the name used by the Dart build hook.

I have verified the following with assets attached to CI runs:

  • Running patchelf --print-soname on libpowersync.$arch.android.so files prints libpowersync_core.so.
  • Running patchelf --print-soname on JNI files in the aar prints libpowersync.so, same as before.
  • Changing the Dart SDK to use the updated files allows running it along with the Kotlin library in the same process (tested with this repro, which would crash before).

@simolus3
simolus3 marked this pull request as ready for review July 27, 2026 11:25
@simolus3
simolus3 requested a review from rkistner July 27, 2026 11:26

@rkistner rkistner left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm happy with the change.

To help with my understanding, can the same thing happen by including multiple copies of the same .so file produced here? For example by using the both the Dart and the Dotnet SDKs in the same app?

@simolus3

Copy link
Copy Markdown
Contributor Author

happen by including multiple copies of the same .so file produced here

I believe the same thing would happen if both the Dart and Dotnet SDKs were used in the same app, yes. I am not familiar with C# SQLite bindings though. If they work by bundling a libsqlite3.so with the app then the Android Gradle plugin would merge that with the libsqlite3.so contributed by package:sqlite3 and things might be fine since it's a single copy of SQLite and the core extension. Kotlin doesn't use a plain libsqlite3.so since it needs JNI bindings to be part of that build.

@simolus3 simolus3 mentioned this pull request Jul 27, 2026
@simolus3
simolus3 merged commit d94c195 into main Jul 27, 2026
32 checks passed
@simolus3
simolus3 deleted the android-soname branch July 27, 2026 13:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants