Add logs for ImeTrackerService#History#setFinished
This enables tracking which token timed out. Bug: 269089722 Test: Open Keyboard in any app, observe logcat for new log entries, manually decrease timeout threshold Change-Id: I3e3bc09765871b7d71975df4692351be8ace462e
This commit is contained in:
@@ -25,6 +25,7 @@ import android.annotation.RequiresNoPermission;
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.content.Context;
|
||||
import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ResultReceiver;
|
||||
@@ -547,51 +548,57 @@ final class IInputMethodManagerGlobalInvoker {
|
||||
}
|
||||
}
|
||||
|
||||
/** @see com.android.server.inputmethod.ImeTrackerService#onRequestShow */
|
||||
@AnyThread
|
||||
@Nullable
|
||||
static IBinder onRequestShow(int uid, @ImeTracker.Origin int origin,
|
||||
@SoftInputShowHideReason int reason) {
|
||||
@NonNull
|
||||
static ImeTracker.Token onRequestShow(@NonNull String tag, int uid,
|
||||
@ImeTracker.Origin int origin, @SoftInputShowHideReason int reason) {
|
||||
final IImeTracker service = getImeTrackerService();
|
||||
if (service == null) {
|
||||
return null;
|
||||
// Create token with "fake" binder if the service was not found.
|
||||
return new ImeTracker.Token(new Binder(), tag);
|
||||
}
|
||||
try {
|
||||
return service.onRequestShow(uid, origin, reason);
|
||||
return service.onRequestShow(tag, uid, origin, reason);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/** @see com.android.server.inputmethod.ImeTrackerService#onRequestHide */
|
||||
@AnyThread
|
||||
@Nullable
|
||||
static IBinder onRequestHide(int uid, @ImeTracker.Origin int origin,
|
||||
@SoftInputShowHideReason int reason) {
|
||||
@NonNull
|
||||
static ImeTracker.Token onRequestHide(@NonNull String tag, int uid,
|
||||
@ImeTracker.Origin int origin, @SoftInputShowHideReason int reason) {
|
||||
final IImeTracker service = getImeTrackerService();
|
||||
if (service == null) {
|
||||
return null;
|
||||
// Create token with "fake" binder if the service was not found.
|
||||
return new ImeTracker.Token(new Binder(), tag);
|
||||
}
|
||||
try {
|
||||
return service.onRequestHide(uid, origin, reason);
|
||||
return service.onRequestHide(tag, uid, origin, reason);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/** @see com.android.server.inputmethod.ImeTrackerService#onProgress */
|
||||
@AnyThread
|
||||
static void onProgress(@NonNull IBinder statsToken, @ImeTracker.Phase int phase) {
|
||||
static void onProgress(@NonNull IBinder binder, @ImeTracker.Phase int phase) {
|
||||
final IImeTracker service = getImeTrackerService();
|
||||
if (service == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
service.onProgress(statsToken, phase);
|
||||
service.onProgress(binder, phase);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/** @see com.android.server.inputmethod.ImeTrackerService#onFailed */
|
||||
@AnyThread
|
||||
static void onFailed(@NonNull IBinder statsToken, @ImeTracker.Phase int phase) {
|
||||
static void onFailed(@NonNull ImeTracker.Token statsToken, @ImeTracker.Phase int phase) {
|
||||
final IImeTracker service = getImeTrackerService();
|
||||
if (service == null) {
|
||||
return;
|
||||
@@ -603,8 +610,9 @@ final class IInputMethodManagerGlobalInvoker {
|
||||
}
|
||||
}
|
||||
|
||||
/** @see com.android.server.inputmethod.ImeTrackerService#onCancelled */
|
||||
@AnyThread
|
||||
static void onCancelled(@NonNull IBinder statsToken, @ImeTracker.Phase int phase) {
|
||||
static void onCancelled(@NonNull ImeTracker.Token statsToken, @ImeTracker.Phase int phase) {
|
||||
final IImeTracker service = getImeTrackerService();
|
||||
if (service == null) {
|
||||
return;
|
||||
@@ -616,8 +624,9 @@ final class IInputMethodManagerGlobalInvoker {
|
||||
}
|
||||
}
|
||||
|
||||
/** @see com.android.server.inputmethod.ImeTrackerService#onShown */
|
||||
@AnyThread
|
||||
static void onShown(@NonNull IBinder statsToken) {
|
||||
static void onShown(@NonNull ImeTracker.Token statsToken) {
|
||||
final IImeTracker service = getImeTrackerService();
|
||||
if (service == null) {
|
||||
return;
|
||||
@@ -629,8 +638,9 @@ final class IInputMethodManagerGlobalInvoker {
|
||||
}
|
||||
}
|
||||
|
||||
/** @see com.android.server.inputmethod.ImeTrackerService#onHidden */
|
||||
@AnyThread
|
||||
static void onHidden(@NonNull IBinder statsToken) {
|
||||
static void onHidden(@NonNull ImeTracker.Token statsToken) {
|
||||
final IImeTracker service = getImeTrackerService();
|
||||
if (service == null) {
|
||||
return;
|
||||
@@ -642,6 +652,7 @@ final class IInputMethodManagerGlobalInvoker {
|
||||
}
|
||||
}
|
||||
|
||||
/** @see com.android.server.inputmethod.ImeTrackerService#hasPendingImeVisibilityRequests */
|
||||
@AnyThread
|
||||
@RequiresPermission(Manifest.permission.TEST_INPUT_METHOD)
|
||||
static boolean hasPendingImeVisibilityRequests() {
|
||||
|
||||
@@ -26,7 +26,6 @@ import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.ActivityThread;
|
||||
import android.content.Context;
|
||||
import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
@@ -47,7 +46,7 @@ import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/** @hide */
|
||||
@@ -321,9 +320,8 @@ public interface ImeTracker {
|
||||
/**
|
||||
* Creates an IME show request tracking token.
|
||||
*
|
||||
* @param component the component name where the IME show request was created,
|
||||
* or {@code null} otherwise
|
||||
* (defaulting to {@link ActivityThread#currentProcessName()}).
|
||||
* @param component the component name where the IME request was created, or {@code null}
|
||||
* otherwise (defaulting to {@link ActivityThread#currentProcessName()}).
|
||||
* @param uid the uid of the client that requested the IME.
|
||||
* @param origin the origin of the IME show request.
|
||||
* @param reason the reason why the IME show request was created.
|
||||
@@ -337,9 +335,8 @@ public interface ImeTracker {
|
||||
/**
|
||||
* Creates an IME hide request tracking token.
|
||||
*
|
||||
* @param component the component name where the IME hide request was created,
|
||||
* or {@code null} otherwise
|
||||
* (defaulting to {@link ActivityThread#currentProcessName()}).
|
||||
* @param component the component name where the IME request was created, or {@code null}
|
||||
* otherwise (defaulting to {@link ActivityThread#currentProcessName()}).
|
||||
* @param uid the uid of the client that requested the IME.
|
||||
* @param origin the origin of the IME hide request.
|
||||
* @param reason the reason why the IME hide request was created.
|
||||
@@ -435,8 +432,7 @@ public interface ImeTracker {
|
||||
mLogProgress = SystemProperties.getBoolean("persist.debug.imetracker", false);
|
||||
// Update logging flag dynamically.
|
||||
SystemProperties.addChangeCallback(() ->
|
||||
mLogProgress =
|
||||
SystemProperties.getBoolean("persist.debug.imetracker", false));
|
||||
mLogProgress = SystemProperties.getBoolean("persist.debug.imetracker", false));
|
||||
}
|
||||
|
||||
/** Whether progress should be logged. */
|
||||
@@ -446,10 +442,9 @@ public interface ImeTracker {
|
||||
@Override
|
||||
public Token onRequestShow(@Nullable String component, int uid, @Origin int origin,
|
||||
@SoftInputShowHideReason int reason) {
|
||||
IBinder binder = IInputMethodManagerGlobalInvoker.onRequestShow(uid, origin, reason);
|
||||
if (binder == null) binder = new Binder();
|
||||
|
||||
final Token token = Token.build(binder, component);
|
||||
final var tag = getTag(component);
|
||||
final var token = IInputMethodManagerGlobalInvoker.onRequestShow(tag, uid, origin,
|
||||
reason);
|
||||
|
||||
Log.i(TAG, token.mTag + ": onRequestShow at " + Debug.originToString(origin)
|
||||
+ " reason " + InputMethodDebug.softInputDisplayReasonToString(reason));
|
||||
@@ -461,10 +456,9 @@ public interface ImeTracker {
|
||||
@Override
|
||||
public Token onRequestHide(@Nullable String component, int uid, @Origin int origin,
|
||||
@SoftInputShowHideReason int reason) {
|
||||
IBinder binder = IInputMethodManagerGlobalInvoker.onRequestHide(uid, origin, reason);
|
||||
if (binder == null) binder = new Binder();
|
||||
|
||||
final Token token = Token.build(binder, component);
|
||||
final var tag = getTag(component);
|
||||
final var token = IInputMethodManagerGlobalInvoker.onRequestHide(tag, uid, origin,
|
||||
reason);
|
||||
|
||||
Log.i(TAG, token.mTag + ": onRequestHide at " + Debug.originToString(origin)
|
||||
+ " reason " + InputMethodDebug.softInputDisplayReasonToString(reason));
|
||||
@@ -485,7 +479,7 @@ public interface ImeTracker {
|
||||
@Override
|
||||
public void onFailed(@Nullable Token token, @Phase int phase) {
|
||||
if (token == null) return;
|
||||
IInputMethodManagerGlobalInvoker.onFailed(token.mBinder, phase);
|
||||
IInputMethodManagerGlobalInvoker.onFailed(token, phase);
|
||||
|
||||
Log.i(TAG, token.mTag + ": onFailed at " + Debug.phaseToString(phase));
|
||||
}
|
||||
@@ -499,7 +493,7 @@ public interface ImeTracker {
|
||||
@Override
|
||||
public void onCancelled(@Nullable Token token, @Phase int phase) {
|
||||
if (token == null) return;
|
||||
IInputMethodManagerGlobalInvoker.onCancelled(token.mBinder, phase);
|
||||
IInputMethodManagerGlobalInvoker.onCancelled(token, phase);
|
||||
|
||||
Log.i(TAG, token.mTag + ": onCancelled at " + Debug.phaseToString(phase));
|
||||
}
|
||||
@@ -507,7 +501,7 @@ public interface ImeTracker {
|
||||
@Override
|
||||
public void onShown(@Nullable Token token) {
|
||||
if (token == null) return;
|
||||
IInputMethodManagerGlobalInvoker.onShown(token.mBinder);
|
||||
IInputMethodManagerGlobalInvoker.onShown(token);
|
||||
|
||||
Log.i(TAG, token.mTag + ": onShown");
|
||||
}
|
||||
@@ -515,10 +509,24 @@ public interface ImeTracker {
|
||||
@Override
|
||||
public void onHidden(@Nullable Token token) {
|
||||
if (token == null) return;
|
||||
IInputMethodManagerGlobalInvoker.onHidden(token.mBinder);
|
||||
IInputMethodManagerGlobalInvoker.onHidden(token);
|
||||
|
||||
Log.i(TAG, token.mTag + ": onHidden");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a logging tag using the given component name.
|
||||
*
|
||||
* @param component the component name where the IME request was created, or {@code null}
|
||||
* otherwise (defaulting to {@link ActivityThread#currentProcessName()}).
|
||||
*/
|
||||
@NonNull
|
||||
private String getTag(@Nullable String component) {
|
||||
if (component == null) {
|
||||
component = ActivityThread.currentProcessName();
|
||||
}
|
||||
return component + ":" + Integer.toHexString(ThreadLocalRandom.current().nextInt());
|
||||
}
|
||||
};
|
||||
|
||||
/** The singleton IME tracker instance for instrumenting jank metrics. */
|
||||
@@ -528,28 +536,31 @@ public interface ImeTracker {
|
||||
ImeLatencyTracker LATENCY_TRACKER = new ImeLatencyTracker();
|
||||
|
||||
/** A token that tracks the progress of an IME request. */
|
||||
class Token implements Parcelable {
|
||||
final class Token implements Parcelable {
|
||||
|
||||
/** The binder used to identify this token. */
|
||||
@NonNull
|
||||
public final IBinder mBinder;
|
||||
private final IBinder mBinder;
|
||||
|
||||
/** The logging tag. */
|
||||
@NonNull
|
||||
private final String mTag;
|
||||
|
||||
@NonNull
|
||||
private static Token build(@NonNull IBinder binder, @Nullable String component) {
|
||||
if (component == null) component = ActivityThread.currentProcessName();
|
||||
final String tag = component + ":" + Integer.toHexString((new Random().nextInt()));
|
||||
|
||||
return new Token(binder, tag);
|
||||
}
|
||||
|
||||
private Token(@NonNull IBinder binder, @NonNull String tag) {
|
||||
public Token(@NonNull IBinder binder, @NonNull String tag) {
|
||||
mBinder = binder;
|
||||
mTag = tag;
|
||||
}
|
||||
|
||||
/** Returns the {@link Token#mTag} */
|
||||
private Token(@NonNull Parcel in) {
|
||||
mBinder = in.readStrongBinder();
|
||||
mTag = in.readString8();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public IBinder getBinder() {
|
||||
return mBinder;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String getTag() {
|
||||
return mTag;
|
||||
@@ -562,7 +573,7 @@ public interface ImeTracker {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeStrongBinder(mBinder);
|
||||
dest.writeString8(mTag);
|
||||
}
|
||||
@@ -571,12 +582,11 @@ public interface ImeTracker {
|
||||
public static final Creator<Token> CREATOR = new Creator<>() {
|
||||
@NonNull
|
||||
@Override
|
||||
public Token createFromParcel(Parcel source) {
|
||||
final IBinder binder = source.readStrongBinder();
|
||||
final String tag = source.readString8();
|
||||
return new Token(binder, tag);
|
||||
public Token createFromParcel(@NonNull Parcel in) {
|
||||
return new Token(in);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Token[] newArray(int size) {
|
||||
return new Token[size];
|
||||
@@ -589,40 +599,50 @@ public interface ImeTracker {
|
||||
*
|
||||
* Note: This is held in a separate class so that it only gets initialized when actually needed.
|
||||
*/
|
||||
class Debug {
|
||||
final class Debug {
|
||||
|
||||
@NonNull
|
||||
private static final Map<Integer, String> sTypes =
|
||||
getFieldMapping(ImeTracker.class, "TYPE_");
|
||||
@NonNull
|
||||
private static final Map<Integer, String> sStatus =
|
||||
getFieldMapping(ImeTracker.class, "STATUS_");
|
||||
@NonNull
|
||||
private static final Map<Integer, String> sOrigins =
|
||||
getFieldMapping(ImeTracker.class, "ORIGIN_");
|
||||
@NonNull
|
||||
private static final Map<Integer, String> sPhases =
|
||||
getFieldMapping(ImeTracker.class, "PHASE_");
|
||||
|
||||
@NonNull
|
||||
public static String typeToString(@Type int type) {
|
||||
return sTypes.getOrDefault(type, "TYPE_" + type);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static String statusToString(@Status int status) {
|
||||
return sStatus.getOrDefault(status, "STATUS_" + status);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static String originToString(@Origin int origin) {
|
||||
return sOrigins.getOrDefault(origin, "ORIGIN_" + origin);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static String phaseToString(@Phase int phase) {
|
||||
return sPhases.getOrDefault(phase, "PHASE_" + phase);
|
||||
}
|
||||
|
||||
private static Map<Integer, String> getFieldMapping(Class<?> cls, String fieldPrefix) {
|
||||
@NonNull
|
||||
private static Map<Integer, String> getFieldMapping(Class<?> cls,
|
||||
@NonNull String fieldPrefix) {
|
||||
return Arrays.stream(cls.getDeclaredFields())
|
||||
.filter(field -> field.getName().startsWith(fieldPrefix))
|
||||
.collect(Collectors.toMap(Debug::getFieldValue, Field::getName));
|
||||
}
|
||||
|
||||
private static int getFieldValue(Field field) {
|
||||
private static int getFieldValue(@NonNull Field field) {
|
||||
try {
|
||||
return field.getInt(null);
|
||||
} catch (IllegalAccessException e) {
|
||||
|
||||
@@ -19,38 +19,40 @@ package com.android.internal.view;
|
||||
import android.view.inputmethod.ImeTracker;
|
||||
|
||||
/**
|
||||
* Interface to the global Ime tracker, used by all client applications.
|
||||
* Interface to the global IME tracker service, used by all client applications.
|
||||
* {@hide}
|
||||
*/
|
||||
interface IImeTracker {
|
||||
|
||||
/**
|
||||
* Called when an IME show request is created,
|
||||
* returns a new Binder to be associated with the IME tracking token.
|
||||
* Called when an IME show request is created.
|
||||
*
|
||||
* @param tag the logging tag.
|
||||
* @param uid the uid of the client that requested the IME.
|
||||
* @param origin the origin of the IME show request.
|
||||
* @param reason the reason why the IME show request was created.
|
||||
* @return A new IME tracking token.
|
||||
*/
|
||||
IBinder onRequestShow(int uid, int origin, int reason);
|
||||
ImeTracker.Token onRequestShow(String tag, int uid, int origin, int reason);
|
||||
|
||||
/**
|
||||
* Called when an IME hide request is created,
|
||||
* returns a new Binder to be associated with the IME tracking token.
|
||||
* Called when an IME hide request is created.
|
||||
*
|
||||
* @param tag the logging tag.
|
||||
* @param uid the uid of the client that requested the IME.
|
||||
* @param origin the origin of the IME hide request.
|
||||
* @param reason the reason why the IME hide request was created.
|
||||
* @return A new IME tracking token.
|
||||
*/
|
||||
IBinder onRequestHide(int uid, int origin, int reason);
|
||||
ImeTracker.Token onRequestHide(String tag, int uid, int origin, int reason);
|
||||
|
||||
/**
|
||||
* Called when the IME request progresses to a further phase.
|
||||
*
|
||||
* @param statsToken the token tracking the current IME request.
|
||||
* @param binder the binder of token tracking the current IME request.
|
||||
* @param phase the new phase the IME request reached.
|
||||
*/
|
||||
oneway void onProgress(in IBinder statsToken, int phase);
|
||||
oneway void onProgress(in IBinder binder, int phase);
|
||||
|
||||
/**
|
||||
* Called when the IME request fails.
|
||||
@@ -58,7 +60,7 @@ interface IImeTracker {
|
||||
* @param statsToken the token tracking the current IME request.
|
||||
* @param phase the phase the IME request failed at.
|
||||
*/
|
||||
oneway void onFailed(in IBinder statsToken, int phase);
|
||||
oneway void onFailed(in ImeTracker.Token statsToken, int phase);
|
||||
|
||||
/**
|
||||
* Called when the IME request is cancelled.
|
||||
@@ -66,21 +68,21 @@ interface IImeTracker {
|
||||
* @param statsToken the token tracking the current IME request.
|
||||
* @param phase the phase the IME request was cancelled at.
|
||||
*/
|
||||
oneway void onCancelled(in IBinder statsToken, int phase);
|
||||
oneway void onCancelled(in ImeTracker.Token statsToken, int phase);
|
||||
|
||||
/**
|
||||
* Called when the IME show request is successful.
|
||||
*
|
||||
* @param statsToken the token tracking the current IME request.
|
||||
*/
|
||||
oneway void onShown(in IBinder statsToken);
|
||||
oneway void onShown(in ImeTracker.Token statsToken);
|
||||
|
||||
/**
|
||||
* Called when the IME hide request is successful.
|
||||
*
|
||||
* @param statsToken the token tracking the current IME request.
|
||||
*/
|
||||
oneway void onHidden(in IBinder statsToken);
|
||||
oneway void onHidden(in ImeTracker.Token statsToken);
|
||||
|
||||
/**
|
||||
* Checks whether there are any pending IME visibility requests.
|
||||
|
||||
@@ -24,6 +24,7 @@ import android.os.Binder;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
import android.view.inputmethod.ImeTracker;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
@@ -53,7 +54,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
@SuppressWarnings("GuardedBy")
|
||||
public final class ImeTrackerService extends IImeTracker.Stub {
|
||||
|
||||
static final String TAG = "ImeTrackerService";
|
||||
private static final String TAG = ImeTracker.TAG;
|
||||
|
||||
/** The threshold in milliseconds after which a history entry is considered timed out. */
|
||||
private static final long TIMEOUT_MS = 10_000;
|
||||
@@ -71,67 +72,71 @@ public final class ImeTrackerService extends IImeTracker.Stub {
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public synchronized IBinder onRequestShow(int uid, @ImeTracker.Origin int origin,
|
||||
@SoftInputShowHideReason int reason) {
|
||||
final IBinder binder = new Binder();
|
||||
final History.Entry entry = new History.Entry(uid, ImeTracker.TYPE_SHOW,
|
||||
ImeTracker.STATUS_RUN, origin, reason);
|
||||
public synchronized ImeTracker.Token onRequestShow(@NonNull String tag, int uid,
|
||||
@ImeTracker.Origin int origin, @SoftInputShowHideReason int reason) {
|
||||
final var binder = new Binder();
|
||||
final var token = new ImeTracker.Token(binder, tag);
|
||||
final var entry = new History.Entry(uid, ImeTracker.TYPE_SHOW, ImeTracker.STATUS_RUN,
|
||||
origin, reason);
|
||||
mHistory.addEntry(binder, entry);
|
||||
|
||||
// Register a delayed task to handle the case where the new entry times out.
|
||||
mHandler.postDelayed(() -> {
|
||||
synchronized (ImeTrackerService.this) {
|
||||
mHistory.setFinished(binder, ImeTracker.STATUS_TIMEOUT, ImeTracker.PHASE_NOT_SET);
|
||||
mHistory.setFinished(token, ImeTracker.STATUS_TIMEOUT, ImeTracker.PHASE_NOT_SET);
|
||||
}
|
||||
}, TIMEOUT_MS);
|
||||
|
||||
return binder;
|
||||
return token;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public synchronized IBinder onRequestHide(int uid, @ImeTracker.Origin int origin,
|
||||
@SoftInputShowHideReason int reason) {
|
||||
final IBinder binder = new Binder();
|
||||
final History.Entry entry = new History.Entry(uid, ImeTracker.TYPE_HIDE,
|
||||
ImeTracker.STATUS_RUN, origin, reason);
|
||||
public synchronized ImeTracker.Token onRequestHide(@NonNull String tag, int uid,
|
||||
@ImeTracker.Origin int origin, @SoftInputShowHideReason int reason) {
|
||||
final var binder = new Binder();
|
||||
final var token = new ImeTracker.Token(binder, tag);
|
||||
final var entry = new History.Entry(uid, ImeTracker.TYPE_HIDE, ImeTracker.STATUS_RUN,
|
||||
origin, reason);
|
||||
mHistory.addEntry(binder, entry);
|
||||
|
||||
// Register a delayed task to handle the case where the new entry times out.
|
||||
mHandler.postDelayed(() -> {
|
||||
synchronized (ImeTrackerService.this) {
|
||||
mHistory.setFinished(binder, ImeTracker.STATUS_TIMEOUT, ImeTracker.PHASE_NOT_SET);
|
||||
mHistory.setFinished(token, ImeTracker.STATUS_TIMEOUT, ImeTracker.PHASE_NOT_SET);
|
||||
}
|
||||
}, TIMEOUT_MS);
|
||||
|
||||
return binder;
|
||||
return token;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onProgress(@NonNull IBinder statsToken, @ImeTracker.Phase int phase) {
|
||||
final History.Entry entry = mHistory.getEntry(statsToken);
|
||||
public synchronized void onProgress(@NonNull IBinder binder, @ImeTracker.Phase int phase) {
|
||||
final var entry = mHistory.getEntry(binder);
|
||||
if (entry == null) return;
|
||||
|
||||
entry.mPhase = phase;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onFailed(@NonNull IBinder statsToken, @ImeTracker.Phase int phase) {
|
||||
public synchronized void onFailed(@NonNull ImeTracker.Token statsToken,
|
||||
@ImeTracker.Phase int phase) {
|
||||
mHistory.setFinished(statsToken, ImeTracker.STATUS_FAIL, phase);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onCancelled(@NonNull IBinder statsToken, @ImeTracker.Phase int phase) {
|
||||
public synchronized void onCancelled(@NonNull ImeTracker.Token statsToken,
|
||||
@ImeTracker.Phase int phase) {
|
||||
mHistory.setFinished(statsToken, ImeTracker.STATUS_CANCEL, phase);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onShown(@NonNull IBinder statsToken) {
|
||||
public synchronized void onShown(@NonNull ImeTracker.Token statsToken) {
|
||||
mHistory.setFinished(statsToken, ImeTracker.STATUS_SUCCESS, ImeTracker.PHASE_NOT_SET);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onHidden(@NonNull IBinder statsToken) {
|
||||
public synchronized void onHidden(@NonNull ImeTracker.Token statsToken) {
|
||||
mHistory.setFinished(statsToken, ImeTracker.STATUS_SUCCESS, ImeTracker.PHASE_NOT_SET);
|
||||
}
|
||||
|
||||
@@ -141,9 +146,9 @@ public final class ImeTrackerService extends IImeTracker.Stub {
|
||||
* @param statsToken the token corresponding to the current IME request.
|
||||
* @param requestWindowName the name of the window that created the IME request.
|
||||
*/
|
||||
public synchronized void onImmsUpdate(@NonNull IBinder statsToken,
|
||||
public synchronized void onImmsUpdate(@NonNull ImeTracker.Token statsToken,
|
||||
@NonNull String requestWindowName) {
|
||||
final History.Entry entry = mHistory.getEntry(statsToken);
|
||||
final var entry = mHistory.getEntry(statsToken.getBinder());
|
||||
if (entry == null) return;
|
||||
|
||||
entry.mRequestWindowName = requestWindowName;
|
||||
@@ -181,17 +186,17 @@ public final class ImeTrackerService extends IImeTracker.Stub {
|
||||
/** Latest entry sequence number. */
|
||||
private static final AtomicInteger sSequenceNumber = new AtomicInteger(0);
|
||||
|
||||
/** Adds a live entry. */
|
||||
/** Adds a live entry corresponding to the given IME tracking token's binder. */
|
||||
@GuardedBy("ImeTrackerService.this")
|
||||
private void addEntry(@NonNull IBinder statsToken, @NonNull Entry entry) {
|
||||
mLiveEntries.put(statsToken, entry);
|
||||
private void addEntry(@NonNull IBinder binder, @NonNull Entry entry) {
|
||||
mLiveEntries.put(binder, entry);
|
||||
}
|
||||
|
||||
/** Gets the entry corresponding to the given IME tracking token, if it exists. */
|
||||
/** Gets the entry corresponding to the given IME tracking token's binder, if it exists. */
|
||||
@Nullable
|
||||
@GuardedBy("ImeTrackerService.this")
|
||||
private Entry getEntry(@NonNull IBinder statsToken) {
|
||||
return mLiveEntries.get(statsToken);
|
||||
private Entry getEntry(@NonNull IBinder binder) {
|
||||
return mLiveEntries.get(binder);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -204,10 +209,21 @@ public final class ImeTrackerService extends IImeTracker.Stub {
|
||||
* (or {@link ImeTracker#PHASE_NOT_SET} otherwise).
|
||||
*/
|
||||
@GuardedBy("ImeTrackerService.this")
|
||||
private void setFinished(@NonNull IBinder statsToken, @ImeTracker.Status int status,
|
||||
@ImeTracker.Phase int phase) {
|
||||
final Entry entry = mLiveEntries.remove(statsToken);
|
||||
if (entry == null) return;
|
||||
private void setFinished(@NonNull ImeTracker.Token statsToken,
|
||||
@ImeTracker.Status int status, @ImeTracker.Phase int phase) {
|
||||
final var entry = mLiveEntries.remove(statsToken.getBinder());
|
||||
if (entry == null) {
|
||||
// This will be unconditionally called through the postDelayed above to handle
|
||||
// potential timeouts, and is thus intentionally dropped to avoid having to manually
|
||||
// save and remove the registered callback. Only timeout calls are expected.
|
||||
if (status != ImeTracker.STATUS_TIMEOUT) {
|
||||
Log.i(TAG, statsToken.getTag()
|
||||
+ ": setFinished on previously finished token at "
|
||||
+ ImeTracker.Debug.phaseToString(phase) + " with "
|
||||
+ ImeTracker.Debug.statusToString(status));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
entry.mDuration = System.currentTimeMillis() - entry.mStartTime;
|
||||
entry.mStatus = status;
|
||||
@@ -216,6 +232,13 @@ public final class ImeTrackerService extends IImeTracker.Stub {
|
||||
entry.mPhase = phase;
|
||||
}
|
||||
|
||||
if (status == ImeTracker.STATUS_TIMEOUT) {
|
||||
// All events other than timeouts are already logged in the client-side ImeTracker.
|
||||
Log.i(TAG, statsToken.getTag() + ": setFinished at "
|
||||
+ ImeTracker.Debug.phaseToString(entry.mPhase) + " with "
|
||||
+ ImeTracker.Debug.statusToString(status));
|
||||
}
|
||||
|
||||
// Remove excess entries overflowing capacity (plus one for the new entry).
|
||||
while (mEntries.size() >= CAPACITY) {
|
||||
mEntries.remove();
|
||||
@@ -232,21 +255,20 @@ public final class ImeTrackerService extends IImeTracker.Stub {
|
||||
/** Dumps the contents of the circular buffer. */
|
||||
@GuardedBy("ImeTrackerService.this")
|
||||
private void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
|
||||
final DateTimeFormatter formatter =
|
||||
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS", Locale.US)
|
||||
.withZone(ZoneId.systemDefault());
|
||||
final var formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS", Locale.US)
|
||||
.withZone(ZoneId.systemDefault());
|
||||
|
||||
pw.print(prefix);
|
||||
pw.println("ImeTrackerService#History.mLiveEntries:");
|
||||
|
||||
for (final Entry entry: mLiveEntries.values()) {
|
||||
for (final var entry: mLiveEntries.values()) {
|
||||
dumpEntry(entry, pw, prefix, formatter);
|
||||
}
|
||||
|
||||
pw.print(prefix);
|
||||
pw.println("ImeTrackerService#History.mEntries:");
|
||||
|
||||
for (final Entry entry: mEntries) {
|
||||
for (final var entry: mEntries) {
|
||||
dumpEntry(entry, pw, prefix, formatter);
|
||||
}
|
||||
}
|
||||
@@ -323,7 +345,7 @@ public final class ImeTrackerService extends IImeTracker.Stub {
|
||||
/**
|
||||
* Name of the window that created the IME request.
|
||||
*
|
||||
* Note: This is later set through {@link #onImmsUpdate(IBinder, String)}.
|
||||
* Note: This is later set through {@link #onImmsUpdate}.
|
||||
*/
|
||||
@NonNull
|
||||
private String mRequestWindowName = "not set";
|
||||
|
||||
@@ -4629,7 +4629,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
info.imeSurfaceParentName));
|
||||
|
||||
if (statsToken != null) {
|
||||
mImeTrackerService.onImmsUpdate(statsToken.mBinder, info.requestWindowName);
|
||||
mImeTrackerService.onImmsUpdate(statsToken, info.requestWindowName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user