Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 97c84114 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add a lock to guard TCSession's destroy behavior."

parents 0a3b7c6a 010fa6ae
Loading
Loading
Loading
Loading
+57 −33
Original line number Diff line number Diff line
@@ -20,9 +20,11 @@ import android.annotation.NonNull;
import android.annotation.WorkerThread;
import android.view.textclassifier.SelectionEvent.InvocationMethod;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;

import java.util.Objects;
import java.util.function.Supplier;

import sun.misc.Cleaner;

@@ -40,6 +42,9 @@ final class TextClassificationSession implements TextClassifier {
    private final TextClassificationContext mClassificationContext;
    private final Cleaner mCleaner;

    private final Object mLock = new Object();

    @GuardedBy("mLock")
    private boolean mDestroyed;

    TextClassificationSession(TextClassificationContext context, TextClassifier delegate) {
@@ -54,8 +59,7 @@ final class TextClassificationSession implements TextClassifier {

    @Override
    public TextSelection suggestSelection(TextSelection.Request request) {
        checkDestroyed();
        return mDelegate.suggestSelection(request);
        return checkDestroyedAndRun(() -> mDelegate.suggestSelection(request));
    }

    private void initializeRemoteSession() {
@@ -67,36 +71,32 @@ final class TextClassificationSession implements TextClassifier {

    @Override
    public TextClassification classifyText(TextClassification.Request request) {
        checkDestroyed();
        return mDelegate.classifyText(request);
        return checkDestroyedAndRun(() -> mDelegate.classifyText(request));
    }

    @Override
    public TextLinks generateLinks(TextLinks.Request request) {
        checkDestroyed();
        return mDelegate.generateLinks(request);
        return checkDestroyedAndRun(() -> mDelegate.generateLinks(request));
    }

    @Override
    public ConversationActions suggestConversationActions(ConversationActions.Request request) {
        checkDestroyed();
        return mDelegate.suggestConversationActions(request);
        return checkDestroyedAndRun(() -> mDelegate.suggestConversationActions(request));
    }

    @Override
    public TextLanguage detectLanguage(TextLanguage.Request request) {
        checkDestroyed();
        return mDelegate.detectLanguage(request);
        return checkDestroyedAndRun(() -> mDelegate.detectLanguage(request));
    }

    @Override
    public int getMaxGenerateLinksTextLength() {
        checkDestroyed();
        return mDelegate.getMaxGenerateLinksTextLength();
        return checkDestroyedAndRun(mDelegate::getMaxGenerateLinksTextLength);
    }

    @Override
    public void onSelectionEvent(SelectionEvent event) {
        checkDestroyedAndRun(() -> {
            try {
                if (mEventHelper.sanitizeEvent(event)) {
                    mDelegate.onSelectionEvent(event);
@@ -105,10 +105,13 @@ final class TextClassificationSession implements TextClassifier {
                // Avoid crashing for event reporting.
                Log.e(LOG_TAG, "Error reporting text classifier selection event", e);
            }
            return null;
        });
    }

    @Override
    public void onTextClassifierEvent(TextClassifierEvent event) {
        checkDestroyedAndRun(() -> {
            try {
                event.mHiddenTempSessionId = mSessionId;
                mDelegate.onTextClassifierEvent(event);
@@ -116,28 +119,49 @@ final class TextClassificationSession implements TextClassifier {
                // Avoid crashing for event reporting.
                Log.e(LOG_TAG, "Error reporting text classifier event", e);
            }
            return null;
        });
    }

    @Override
    public void destroy() {
        synchronized (mLock) {
            if (!mDestroyed) {
                mCleaner.clean();
                mDestroyed = true;
            }
        }
    }

    @Override
    public boolean isDestroyed() {
        synchronized (mLock) {
            return mDestroyed;
        }
    }

    /**
     * @throws IllegalStateException if this TextClassification session has been destroyed.
     * Check whether the TextClassification Session was destroyed before and after the actual API
     * invocation, and return response if not.
     *
     * @param responseSupplier a Supplier that represents a TextClassifier call
     * @return the response of the TextClassifier call
     * @throws IllegalStateException if this TextClassification session was destroyed before the
     *                               call returned
     * @see #isDestroyed()
     * @see #destroy()
     */
    private void checkDestroyed() {
        if (mDestroyed) {
            throw new IllegalStateException("This TextClassification session has been destroyed");
    private <T> T checkDestroyedAndRun(Supplier<T> responseSupplier) {
        if (!isDestroyed()) {
            T response = responseSupplier.get();
            synchronized (mLock) {
                if (!mDestroyed) {
                    return response;
                }
            }
        }
        throw new IllegalStateException(
                "This TextClassification session has been destroyed");
    }

    /**