diff options
-rw-r--r-- | core/java/android/view/textclassifier/TextClassifierImpl.java | 34 | ||||
-rw-r--r-- | core/java/android/view/textclassifier/TextClassifierImplNative.java | 17 |
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. */ |