Skip to content

Commit

Permalink
Select cleaner implementations for Android, java.lang.ref and fallbac…
Browse files Browse the repository at this point in the history
…k to JNA
  • Loading branch information
jhugman committed Jan 8, 2024
1 parent 196275b commit 19120c8
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 64 deletions.
49 changes: 0 additions & 49 deletions uniffi_bindgen/src/bindings/kotlin/templates/AndroidCleaner.kt

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,9 @@ internal interface UniffiLib : Library {
}
}
{% if ci.contains_object_types() %}
// The cleaner for the whole library.
internal val CLEANER: {% if config.android_cleaner() -%} AndroidCleaner {%- else -%} Cleaner {%- endif %} by lazy {
{%- if config.android_cleaner() %}
AndroidCleaner.instance()
{%- else %}
Cleaner.create()
{%- endif %}
// The Cleaner for the whole library
internal val CLEANER: UniffiCleaner by lazy {
UniffiCleaner.create()
}
{%- endif %}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@

// The cleaner interface for Object finalization code to run.
// This is the entry point to any implementation that we're using.
//
// The cleaner registers objects and returns cleanables, so now we are
// defining a `UniffiCleaner` with a `UniffiClenaer.Cleanable` to abstract the
// different implmentations available at compile time.
interface UniffiCleaner {
interface Cleanable {
fun clean()
}

fun register(value: Any, cleanUpTask: Runnable): UniffiCleaner.Cleanable

companion object
}

// The fallback Jna cleaner, which is available for both Android, and the JVM.
private class UniffiJnaCleaner : UniffiCleaner {
private val cleaner = com.sun.jna.internal.Cleaner.getCleaner()

override fun register(value: Any, cleanUpTask: Runnable): UniffiCleaner.Cleanable =
UniffiJnaCleanable(cleaner.register(value, cleanUpTask))
}

private class UniffiJnaCleanable(
private val cleanable: com.sun.jna.internal.Cleaner.Cleanable,
) : UniffiCleaner.Cleanable {
override fun clean() = cleanable.clean()
}

// We decide at uniffi binding generation time whether we were
// using Android or not.
// There are further runtime checks to chose the correct implementation
// of the cleaner.
{% if config.android_cleaner() %}
{%- include "ObjectCleanerHelperAndroid.kt" %}
{%- else %}
{%- include "ObjectCleanerHelperJvm.kt" %}
{%- endif %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{{- self.add_import("android.os.Build") }}

private fun UniffiCleaner.Companion.create(): UniffiCleaner =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
AndroidSystemCleaner()
} else {
UniffiJnaCleaner()
}

// The SystemCleaner, available from API Level 33.
private class AndroidSystemCleaner : UniffiCleaner {
val cleaner = android.system.SystemCleaner.cleaner()

override fun register(value: Any, cleanUpTask: Runnable): UniffiCleaner.Cleanable =
AndroidSystemCleanable(cleaner.register(value, cleanUpTask))
}

private class AndroidSystemCleanable(
private val cleanable: java.lang.ref.Cleaner.Cleanable,
) : UniffiCleaner.Cleanable {
override fun clean() = cleanable.clean()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
private fun UniffiCleaner.Companion.create(): UniffiCleaner =
try {
// For safety's sake: if the library hasn't been run in android_cleaner = true
// mode, but is being run on Android, then we still need to think about
// Android API versions.
// So we check if java.lang.ref.Cleaner is there, and use that…
Class.`forName`("java.lang.ref.Cleaner")
JavaLangRefCleaner()
} catch (e: ClassNotFoundException) {
// … otherwise, fallback to the JNA cleaner.
UniffiJnaCleaner()
}

private class JavaLangRefCleaner : UniffiCleaner {
val cleaner = java.lang.ref.Cleaner.create()

override fun register(value: Any, cleanUpTask: Runnable): UniffiCleaner.Cleanable =
JavaLangRefCleanable(cleaner.register(value, cleanUpTask))
}

private class JavaLangRefCleanable(
val cleanable: java.lang.ref.Cleaner.Cleanable
) : UniffiCleaner.Cleanable {
override fun clean() = cleanable.clean()
}
4 changes: 2 additions & 2 deletions uniffi_bindgen/src/bindings/kotlin/templates/ObjectRuntime.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{{- self.add_import("java.lang.ref.Cleaner") }}
{{- self.add_import("java.util.concurrent.atomic.AtomicLong") }}
{{- self.add_import("java.util.concurrent.atomic.AtomicBoolean") }}
{%- include "ObjectCleanerHelper.kt" %}

// The base class for all UniFFI Object types.
//
Expand Down Expand Up @@ -115,7 +115,7 @@ abstract class FFIObject: Disposable, AutoCloseable {
}

protected val pointer: Pointer?
protected abstract val cleanable: {% if config.android_cleaner() -%} AndroidCleanable {%- else -%} Cleaner.Cleanable {%- endif %}
protected abstract val cleanable: UniffiCleaner.Cleanable

private val wasDestroyed = AtomicBoolean(false)
private val callCounter = AtomicLong(1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ open class {{ impl_class_name }} : FFIObject, {{ interface_name }} {
{%- when None %}
{%- endmatch %}

override val cleanable: Cleaner.Cleanable = UniffiLib.CLEANER.register(this, UniffiCleanAction(pointer))
override val cleanable: UniffiCleaner.Cleanable = UniffiLib.CLEANER.register(this, UniffiCleanAction(pointer))

// Use a static inner class instead of a closure so as not to accidentally
// capture `this` as part of the cleanable's action.
Expand Down
5 changes: 0 additions & 5 deletions uniffi_bindgen/src/bindings/kotlin/templates/wrapper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,6 @@ import java.nio.ByteOrder
import java.nio.CharBuffer
import java.nio.charset.CodingErrorAction
import java.util.concurrent.ConcurrentHashMap
{%- if config.android_cleaner() %}
import android.os.Build
import android.system.SystemCleaner
import com.sun.jna.internal.Cleaner as JnaCleaner
{%- endif %}

{%- for req in self.imports() %}
{{ req.render() }}
Expand Down

0 comments on commit 19120c8

Please sign in to comment.