bind: replace Java finalizers with PhantomReferences

Android runs a finalizer watchdog that tracks the running time of
finalizers and throws an exception if any runs too long. Our
finalizers do very little work and as such are not affected by the
timeout. However, there has been reports, for example:

https://stackoverflow.com/questions/24021609/how-to-handle-java-util-concurrent-timeoutexception-android-os-binderproxy-fin

that the watchdog does not take into account periods where the device
goes to sleep in the middle of a finalizer run. So if a given app runs
in the background, the Java GC starts a finalizer and the device goes
to sleep before it returns, an exception will crash the app if the sleep
period extends the watchdog timeout.

The problem might be fixed on some newer version of Android, but the
problem is reported for as late as Android 6.

The suggested workaround is to use PhantomReferences and run a
background thread that take dead references off a ReferenceQueue and
perform cleanup.

This CL builds on the previous CL and splits up the Ref class so Refs
only reference counts Java objects, while a new class GoRef tracks Go
references. The Go references are wrapped in PhantomReferences that in
turn appear on a GoRefQueue to be cleaned up by a background (daemon)
Thread.

Change-Id: I04e3296b851999c612d3baf6a593cc044c2c5bdd
Reviewed-on: https://go-review.googlesource.com/106876
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
This commit is contained in:
Elias Naur
2018-04-17 15:00:01 +00:00
parent 5b452fe89a
commit e7d878f9d0
15 changed files with 163 additions and 158 deletions
+10 -15
View File
@@ -84,66 +84,61 @@ public abstract class Java {
private static native void _init();
private static final class proxyF implements Seq.Proxy, F {
private final Seq.Ref ref;
private final int refnum;
@Override public final int incRefnum() {
int refnum = ref.refnum;
Seq.incGoRef(refnum);
return refnum;
}
proxyF(int refnum) { this.ref = Seq.trackGoRef(refnum); }
proxyF(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); }
public native String toString();
}
private static final class proxyL implements Seq.Proxy, L {
private final Seq.Ref ref;
private final int refnum;
@Override public final int incRefnum() {
int refnum = ref.refnum;
Seq.incGoRef(refnum);
return refnum;
}
proxyL(int refnum) { this.ref = Seq.trackGoRef(refnum); }
proxyL(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); }
public native String toString();
}
private static final class proxyO implements Seq.Proxy, O {
private final Seq.Ref ref;
private final int refnum;
@Override public final int incRefnum() {
int refnum = ref.refnum;
Seq.incGoRef(refnum);
return refnum;
}
proxyO(int refnum) { this.ref = Seq.trackGoRef(refnum); }
proxyO(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); }
public native String toString();
}
private static final class proxyR implements Seq.Proxy, R {
private final Seq.Ref ref;
private final int refnum;
@Override public final int incRefnum() {
int refnum = ref.refnum;
Seq.incGoRef(refnum);
return refnum;
}
proxyR(int refnum) { this.ref = Seq.trackGoRef(refnum); }
proxyR(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); }
}
private static final class proxyS implements Seq.Proxy, S {
private final Seq.Ref ref;
private final int refnum;
@Override public final int incRefnum() {
int refnum = ref.refnum;
Seq.incGoRef(refnum);
return refnum;
}
proxyS(int refnum) { this.ref = Seq.trackGoRef(refnum); }
proxyS(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); }
public native String toString();
}