-
-
Notifications
You must be signed in to change notification settings - Fork 472
perf(android): Defer SentryFrameMetricsCollector thread startup #5641
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,12 +14,14 @@ | |
| import android.view.Window; | ||
| import androidx.annotation.RequiresApi; | ||
| import io.sentry.ILogger; | ||
| import io.sentry.ISentryLifecycleToken; | ||
| import io.sentry.SentryLevel; | ||
| import io.sentry.SentryOptions; | ||
| import io.sentry.SentryUUID; | ||
| import io.sentry.android.core.BuildInfoProvider; | ||
| import io.sentry.android.core.ContextUtils; | ||
| import io.sentry.android.core.SentryFramesDelayResult; | ||
| import io.sentry.util.AutoClosableReentrantLock; | ||
| import io.sentry.util.Objects; | ||
| import java.lang.ref.WeakReference; | ||
| import java.lang.reflect.Field; | ||
|
|
@@ -45,7 +47,8 @@ public final class SentryFrameMetricsCollector implements Application.ActivityLi | |
| private final @NotNull Set<Window> trackedWindows = new CopyOnWriteArraySet<>(); | ||
|
|
||
| private final @NotNull ILogger logger; | ||
| private @Nullable Handler handler; | ||
| private volatile @Nullable Handler handler; | ||
| private final @NotNull AutoClosableReentrantLock handlerLock = new AutoClosableReentrantLock(); | ||
| private @Nullable WeakReference<Window> currentWindow; | ||
| private final @NotNull Map<String, FrameMetricsCollectorListener> listenerMap = | ||
| new ConcurrentHashMap<>(); | ||
|
|
@@ -113,12 +116,8 @@ public SentryFrameMetricsCollector( | |
| } | ||
| isAvailable = true; | ||
|
|
||
| HandlerThread handlerThread = | ||
| new HandlerThread("io.sentry.android.core.internal.util.SentryFrameMetricsCollector"); | ||
| handlerThread.setUncaughtExceptionHandler( | ||
| (thread, e) -> logger.log(SentryLevel.ERROR, "Error during frames measurements.", e)); | ||
| handlerThread.start(); | ||
| handler = new Handler(handlerThread.getLooper()); | ||
| // The frame metrics HandlerThread is started lazily on the first startCollection() call. | ||
| // Starting it here would block the main thread on HandlerThread.getLooper() during SDK init. | ||
|
|
||
| // We have to register the lifecycle callback, even if no profile is started, otherwise when we | ||
| // start a profile, we wouldn't have the current activity and couldn't get the frameMetrics. | ||
|
|
@@ -281,12 +280,34 @@ public void onActivityDestroyed(@NotNull Activity activity) {} | |
| if (!isAvailable) { | ||
| return null; | ||
| } | ||
| ensureHandlerThreadStarted(); | ||
| final String uid = SentryUUID.generateSentryId(); | ||
| listenerMap.put(uid, listener); | ||
| trackCurrentWindow(); | ||
| return uid; | ||
| } | ||
|
|
||
| /** | ||
| * Lazily starts the background HandlerThread used to receive frame metrics. Deferred out of the | ||
| * constructor because {@link HandlerThread#getLooper()} blocks the caller (the main thread during | ||
| * SDK init) until the thread is ready, and the handler is only needed once collection starts. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π₯ |
||
| */ | ||
| private void ensureHandlerThreadStarted() { | ||
| if (handler != null) { | ||
| return; | ||
| } | ||
| try (final @NotNull ISentryLifecycleToken ignored = handlerLock.acquire()) { | ||
| if (handler == null) { | ||
| final HandlerThread handlerThread = | ||
| new HandlerThread("io.sentry.android.core.internal.util.SentryFrameMetricsCollector"); | ||
| handlerThread.setUncaughtExceptionHandler( | ||
| (thread, e) -> logger.log(SentryLevel.ERROR, "Error during frames measurements.", e)); | ||
| handlerThread.start(); | ||
| handler = new Handler(handlerThread.getLooper()); | ||
| } | ||
| } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. m: Thoughts about catching (I realize we didn't do so before, but now we'll be starting the handler thread outside of |
||
| } | ||
|
|
||
| public void stopCollection(final @Nullable String listenerId) { | ||
| if (!isAvailable) { | ||
| return; | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like this comment isn't useful here since this isn't where one would look for it. I'll remove it after a review unless anyone thinks otherwise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed β‘