diff options
author | 2019-01-22 21:42:56 +0000 | |
---|---|---|
committer | 2019-02-08 13:05:38 +0000 | |
commit | ec1b164923f62b681eb4683f4c5c3d37a457f354 (patch) | |
tree | c8a6e3a77fddfb8723feec22fe7795180dfca392 | |
parent | 64ca10b75bb7e8b8b9633b57f2a5fcaeb3c395b3 (diff) |
RESTRICT AUTOMERGE Close TextClassifier native resources.
Bug: 122904322
Test: atest android.view.textclassifier.TextClassificationManagerTest
Test: (MANUAL)
1. Start an app with a TextView
2. Select the text to trigger the text selection toolbar and TextClassifier
3. Close the app's activity by repeatedly clicking back on the nav bar
4. Start a Profiler for the app and observe for memory growth
5. Repeat 1 - 3 several times and observe.
If the bug still exists, memory should grow at about 4 - 5MB.
If the bug is fixed, Memory should remain about the same across activity restarts.
Change-Id: Id9a60dea85cf3949de030042537287ddb29842a2
-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. */ |