Loading services/core/java/com/android/server/inputmethod/ImeTrackerService.java +64 −44 Original line number Original line Diff line number Diff line Loading @@ -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. Loading @@ -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. Loading Loading
services/core/java/com/android/server/inputmethod/ImeTrackerService.java +64 −44 Original line number Original line Diff line number Diff line Loading @@ -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. Loading @@ -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. Loading