summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/textclassifier/TextClassifierImpl.java34
-rw-r--r--core/java/android/view/textclassifier/TextClassifierImplNative.java17
2 files changed, 39 insertions, 12 deletions
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 6e5751abbc40..9aa59c1ffc1e 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -64,6 +64,9 @@ import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+//TODO: use java.lang.ref.Cleaner once Android supports Java 9
+import sun.misc.Cleaner;
+
/**
* Default implementation of the {@link TextClassifier} interface.
*
@@ -92,6 +95,8 @@ public final class TextClassifierImpl implements TextClassifier {
private ModelFile mModel;
@GuardedBy("mLock") // Do not access outside this lock.
private TextClassifierImplNative mNative;
+ @GuardedBy("mLock")
+ private Cleaner mNativeCleaner;
private final Object mLoggerLock = new Object();
@GuardedBy("mLoggerLock") // Do not access outside this lock.
@@ -304,12 +309,12 @@ public final class TextClassifierImpl implements TextClassifier {
if (bestModel == null) {
throw new FileNotFoundException("No model for " + localeList.toLanguageTags());
}
- if (mNative == null || !Objects.equals(mModel, bestModel)) {
+ if (mNative == null || mNative.isClosed() || !Objects.equals(mModel, bestModel)) {
Log.d(DEFAULT_LOG_TAG, "Loading " + bestModel);
- destroyNativeIfExistsLocked();
final ParcelFileDescriptor fd = ParcelFileDescriptor.open(
new File(bestModel.getPath()), ParcelFileDescriptor.MODE_READ_ONLY);
mNative = new TextClassifierImplNative(fd.getFd());
+ mNativeCleaner = Cleaner.create(this, new NativeCloser(mNative));
closeAndLogError(fd);
mModel = bestModel;
}
@@ -324,14 +329,6 @@ public final class TextClassifierImpl implements TextClassifier {
}
}
- @GuardedBy("mLock") // Do not call outside this lock.
- private void destroyNativeIfExistsLocked() {
- if (mNative != null) {
- mNative.close();
- mNative = null;
- }
- }
-
private static String concatenateLocales(@Nullable LocaleList locales) {
return (locales == null) ? "" : locales.toLanguageTags();
}
@@ -822,4 +819,21 @@ public final class TextClassifierImpl implements TextClassifier {
parsedTime.hashCode());
}
}
+
+ /**
+ * Code to close a TextClassifierImplNative. Must not reference the TextClassifierImpl.
+ */
+ private static final class NativeCloser implements Runnable {
+
+ private final TextClassifierImplNative mNative;
+
+ NativeCloser(TextClassifierImplNative nativeImpl) {
+ mNative = Preconditions.checkNotNull(nativeImpl);
+ }
+
+ @Override
+ public void run() {
+ mNative.close();
+ }
+ }
}
diff --git a/core/java/android/view/textclassifier/TextClassifierImplNative.java b/core/java/android/view/textclassifier/TextClassifierImplNative.java
index 3d4c8f2863ea..e8f60223d1ed 100644
--- a/core/java/android/view/textclassifier/TextClassifierImplNative.java
+++ b/core/java/android/view/textclassifier/TextClassifierImplNative.java
@@ -28,7 +28,8 @@ final class TextClassifierImplNative {
System.loadLibrary("textclassifier");
}
- private final long mModelPtr;
+ private final Object mCloseLock = new Object();
+ private long mModelPtr;
/**
* Creates a new instance of TextClassifierImplNative, using the provided model image, given as
@@ -102,7 +103,19 @@ final class TextClassifierImplNative {
/** Frees up the allocated memory. */
public void close() {
- nativeClose(mModelPtr);
+ synchronized (mCloseLock) {
+ if (!isClosed()) {
+ nativeClose(mModelPtr);
+ mModelPtr = 0;
+ }
+ }
+ }
+
+ /**
+ * Returns true if this object is closed, returns false otherwise.
+ */
+ public boolean isClosed() {
+ return mModelPtr == 0L;
}
/** Returns a comma separated list of locales supported by the model as BCP 47 tags. */