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

Commit 5cacb673 authored by Antonio Kantek's avatar Antonio Kantek
Browse files

Avoid synchronization at method level in ImeTrackerService

Bug: 304341834
Test: atest FrameworksServicesTests
Change-Id: Ic9833947f746b0bd7767431a801cac760f03ce86
parent eb7e841e
Loading
Loading
Loading
Loading
+64 −44
Original line number Original line Diff line number Diff line
@@ -60,85 +60,100 @@ public final class ImeTrackerService extends IImeTracker.Stub {
    private static final long TIMEOUT_MS = 10_000;
    private static final long TIMEOUT_MS = 10_000;


    /** Handler for registering timeouts for live entries. */
    /** Handler for registering timeouts for live entries. */
    @GuardedBy("mLock")
    private final Handler mHandler;
    private final Handler mHandler;


    /** Singleton instance of the History. */
    /** Singleton instance of the History. */
    @GuardedBy("ImeTrackerService.this")
    @GuardedBy("mLock")
    private final History mHistory = new History();
    private final History mHistory = new History();


    private final Object mLock = new Object();

    ImeTrackerService(@NonNull Looper looper) {
    ImeTrackerService(@NonNull Looper looper) {
        mHandler = new Handler(looper, null /* callback */, true /* async */);
        mHandler = new Handler(looper, null /* callback */, true /* async */);
    }
    }


    @NonNull
    @NonNull
    @Override
    @Override
    public synchronized ImeTracker.Token onRequestShow(@NonNull String tag, int uid,
    public ImeTracker.Token onRequestShow(@NonNull String tag, int uid,
            @ImeTracker.Origin int origin, @SoftInputShowHideReason int reason) {
            @ImeTracker.Origin int origin, @SoftInputShowHideReason int reason) {
        final var binder = new Binder();
        final var binder = new Binder();
        final var token = new ImeTracker.Token(binder, tag);
        final var token = new ImeTracker.Token(binder, tag);
        final var entry = new History.Entry(tag, uid, ImeTracker.TYPE_SHOW, ImeTracker.STATUS_RUN,
        final var entry = new History.Entry(tag, uid, ImeTracker.TYPE_SHOW, ImeTracker.STATUS_RUN,
                origin, reason);
                origin, reason);
        synchronized (mLock) {
            mHistory.addEntry(binder, entry);
            mHistory.addEntry(binder, entry);


            // Register a delayed task to handle the case where the new entry times out.
            // Register a delayed task to handle the case where the new entry times out.
            mHandler.postDelayed(() -> {
            mHandler.postDelayed(() -> {
            synchronized (ImeTrackerService.this) {
                synchronized (mLock) {
                mHistory.setFinished(token, ImeTracker.STATUS_TIMEOUT, ImeTracker.PHASE_NOT_SET);
                    mHistory.setFinished(token, ImeTracker.STATUS_TIMEOUT,
                            ImeTracker.PHASE_NOT_SET);
                }
                }
            }, TIMEOUT_MS);
            }, TIMEOUT_MS);

        }
        return token;
        return token;
    }
    }


    @NonNull
    @NonNull
    @Override
    @Override
    public synchronized ImeTracker.Token onRequestHide(@NonNull String tag, int uid,
    public ImeTracker.Token onRequestHide(@NonNull String tag, int uid,
            @ImeTracker.Origin int origin, @SoftInputShowHideReason int reason) {
            @ImeTracker.Origin int origin, @SoftInputShowHideReason int reason) {
        final var binder = new Binder();
        final var binder = new Binder();
        final var token = new ImeTracker.Token(binder, tag);
        final var token = new ImeTracker.Token(binder, tag);
        final var entry = new History.Entry(tag, uid, ImeTracker.TYPE_HIDE, ImeTracker.STATUS_RUN,
        final var entry = new History.Entry(tag, uid, ImeTracker.TYPE_HIDE, ImeTracker.STATUS_RUN,
                origin, reason);
                origin, reason);
        synchronized (mLock) {
            mHistory.addEntry(binder, entry);
            mHistory.addEntry(binder, entry);


            // Register a delayed task to handle the case where the new entry times out.
            // Register a delayed task to handle the case where the new entry times out.
            mHandler.postDelayed(() -> {
            mHandler.postDelayed(() -> {
            synchronized (ImeTrackerService.this) {
                synchronized (mLock) {
                mHistory.setFinished(token, ImeTracker.STATUS_TIMEOUT, ImeTracker.PHASE_NOT_SET);
                    mHistory.setFinished(token, ImeTracker.STATUS_TIMEOUT,
                            ImeTracker.PHASE_NOT_SET);
                }
                }
            }, TIMEOUT_MS);
            }, TIMEOUT_MS);

        }
        return token;
        return token;
    }
    }


    @Override
    @Override
    public synchronized void onProgress(@NonNull IBinder binder, @ImeTracker.Phase int phase) {
    public void onProgress(@NonNull IBinder binder, @ImeTracker.Phase int phase) {
        synchronized (mLock) {
            final var entry = mHistory.getEntry(binder);
            final var entry = mHistory.getEntry(binder);
            if (entry == null) return;
            if (entry == null) return;


            entry.mPhase = phase;
            entry.mPhase = phase;
        }
        }
    }


    @Override
    @Override
    public synchronized void onFailed(@NonNull ImeTracker.Token statsToken,
    public void onFailed(@NonNull ImeTracker.Token statsToken, @ImeTracker.Phase int phase) {
            @ImeTracker.Phase int phase) {
        synchronized (mLock) {
            mHistory.setFinished(statsToken, ImeTracker.STATUS_FAIL, phase);
            mHistory.setFinished(statsToken, ImeTracker.STATUS_FAIL, phase);
        }
        }
    }


    @Override
    @Override
    public synchronized void onCancelled(@NonNull ImeTracker.Token statsToken,
    public void onCancelled(@NonNull ImeTracker.Token statsToken, @ImeTracker.Phase int phase) {
            @ImeTracker.Phase int phase) {
        synchronized (mLock) {
            mHistory.setFinished(statsToken, ImeTracker.STATUS_CANCEL, phase);
            mHistory.setFinished(statsToken, ImeTracker.STATUS_CANCEL, phase);
        }
        }
    }


    @Override
    @Override
    public synchronized void onShown(@NonNull ImeTracker.Token statsToken) {
    public void onShown(@NonNull ImeTracker.Token statsToken) {
        synchronized (mLock) {
            mHistory.setFinished(statsToken, ImeTracker.STATUS_SUCCESS, ImeTracker.PHASE_NOT_SET);
            mHistory.setFinished(statsToken, ImeTracker.STATUS_SUCCESS, ImeTracker.PHASE_NOT_SET);
        }
        }
    }


    @Override
    @Override
    public synchronized void onHidden(@NonNull ImeTracker.Token statsToken) {
    public void onHidden(@NonNull ImeTracker.Token statsToken) {
        synchronized (mLock) {
            mHistory.setFinished(statsToken, ImeTracker.STATUS_SUCCESS, ImeTracker.PHASE_NOT_SET);
            mHistory.setFinished(statsToken, ImeTracker.STATUS_SUCCESS, ImeTracker.PHASE_NOT_SET);
        }
        }
    }


    /**
    /**
     * Updates the IME request tracking token with new information available in IMMS.
     * Updates the IME request tracking token with new information available in IMMS.
@@ -146,26 +161,31 @@ public final class ImeTrackerService extends IImeTracker.Stub {
     * @param statsToken the token corresponding to the current IME request.
     * @param statsToken the token corresponding to the current IME request.
     * @param requestWindowName the name of the window that created the IME request.
     * @param requestWindowName the name of the window that created the IME request.
     */
     */
    public synchronized void onImmsUpdate(@NonNull ImeTracker.Token statsToken,
    public void onImmsUpdate(@NonNull ImeTracker.Token statsToken,
            @NonNull String requestWindowName) {
            @NonNull String requestWindowName) {
        synchronized (mLock) {
            final var entry = mHistory.getEntry(statsToken.getBinder());
            final var entry = mHistory.getEntry(statsToken.getBinder());
            if (entry == null) return;
            if (entry == null) return;


            entry.mRequestWindowName = requestWindowName;
            entry.mRequestWindowName = requestWindowName;
        }
        }
    }


    /** Dumps the contents of the history. */
    /** Dumps the contents of the history. */
    public synchronized void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
    public void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
        synchronized (mLock) {
            mHistory.dump(pw, prefix);
            mHistory.dump(pw, prefix);
        }
        }
    }


    @EnforcePermission(Manifest.permission.TEST_INPUT_METHOD)
    @EnforcePermission(Manifest.permission.TEST_INPUT_METHOD)
    @Override
    @Override
    public synchronized boolean hasPendingImeVisibilityRequests() {
    public boolean hasPendingImeVisibilityRequests() {
        super.hasPendingImeVisibilityRequests_enforcePermission();
        super.hasPendingImeVisibilityRequests_enforcePermission();

        synchronized (mLock) {
            return !mHistory.mLiveEntries.isEmpty();
            return !mHistory.mLiveEntries.isEmpty();
        }
        }
    }


    /**
    /**
     * A circular buffer storing the most recent few {@link ImeTracker.Token} entries information.
     * A circular buffer storing the most recent few {@link ImeTracker.Token} entries information.