Skip to content

Commit e6ffd7b

Browse files
authored
Reduce main thread work on init (#3036)
* delete old profiles in the background on SDK init * moved some Integration.register() to the background using executorService * Move integrations registration to background during init (#3043) * removed integrations registration falling back to calling thread
1 parent b172d4e commit e6ffd7b

25 files changed

+588
-209
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
### Fixes
6+
7+
- Reduce main thread work on init ([#3036](https://github.com/getsentry/sentry-java/pull/3036))
8+
- Move Integrations registration to background on init ([#3043](https://github.com/getsentry/sentry-java/pull/3043))
9+
310
## 6.34.0
411

512
### Features

sentry-android-core/src/main/java/io/sentry/android/core/AnrIntegration.java

Lines changed: 46 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
public final class AnrIntegration implements Integration, Closeable {
2828

2929
private final @NotNull Context context;
30+
private boolean isClosed = false;
31+
private final @NotNull Object startLock = new Object();
3032

3133
public AnrIntegration(final @NotNull Context context) {
3234
this.context = context;
@@ -55,27 +57,47 @@ private void register(final @NotNull IHub hub, final @NotNull SentryAndroidOptio
5557
.log(SentryLevel.DEBUG, "AnrIntegration enabled: %s", options.isAnrEnabled());
5658

5759
if (options.isAnrEnabled()) {
58-
synchronized (watchDogLock) {
59-
if (anrWatchDog == null) {
60-
options
61-
.getLogger()
62-
.log(
63-
SentryLevel.DEBUG,
64-
"ANR timeout in milliseconds: %d",
65-
options.getAnrTimeoutIntervalMillis());
66-
67-
anrWatchDog =
68-
new ANRWatchDog(
69-
options.getAnrTimeoutIntervalMillis(),
70-
options.isAnrReportInDebug(),
71-
error -> reportANR(hub, options, error),
72-
options.getLogger(),
73-
context);
74-
anrWatchDog.start();
75-
76-
options.getLogger().log(SentryLevel.DEBUG, "AnrIntegration installed.");
77-
addIntegrationToSdkVersion();
78-
}
60+
addIntegrationToSdkVersion();
61+
try {
62+
options
63+
.getExecutorService()
64+
.submit(
65+
() -> {
66+
synchronized (startLock) {
67+
if (!isClosed) {
68+
startAnrWatchdog(hub, options);
69+
}
70+
}
71+
});
72+
} catch (Throwable e) {
73+
options
74+
.getLogger()
75+
.log(SentryLevel.DEBUG, "Failed to start AnrIntegration on executor thread.", e);
76+
}
77+
}
78+
}
79+
80+
private void startAnrWatchdog(
81+
final @NotNull IHub hub, final @NotNull SentryAndroidOptions options) {
82+
synchronized (watchDogLock) {
83+
if (anrWatchDog == null) {
84+
options
85+
.getLogger()
86+
.log(
87+
SentryLevel.DEBUG,
88+
"ANR timeout in milliseconds: %d",
89+
options.getAnrTimeoutIntervalMillis());
90+
91+
anrWatchDog =
92+
new ANRWatchDog(
93+
options.getAnrTimeoutIntervalMillis(),
94+
options.isAnrReportInDebug(),
95+
error -> reportANR(hub, options, error),
96+
options.getLogger(),
97+
context);
98+
anrWatchDog.start();
99+
100+
options.getLogger().log(SentryLevel.DEBUG, "AnrIntegration installed.");
79101
}
80102
}
81103
}
@@ -126,6 +148,9 @@ ANRWatchDog getANRWatchDog() {
126148

127149
@Override
128150
public void close() throws IOException {
151+
synchronized (startLock) {
152+
isClosed = true;
153+
}
129154
synchronized (watchDogLock) {
130155
if (anrWatchDog != null) {
131156
anrWatchDog.interrupt();

sentry-android-core/src/main/java/io/sentry/android/core/EnvelopeFileObserverIntegration.java

Lines changed: 43 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
public abstract class EnvelopeFileObserverIntegration implements Integration, Closeable {
1717
private @Nullable EnvelopeFileObserver observer;
1818
private @Nullable ILogger logger;
19+
private boolean isClosed = false;
20+
private final @NotNull Object startLock = new Object();
1921

2022
public static @NotNull EnvelopeFileObserverIntegration getOutboxFileObserver() {
2123
return new OutboxEnvelopeFileObserverIntegration();
@@ -37,30 +39,55 @@ public final void register(final @NotNull IHub hub, final @NotNull SentryOptions
3739
logger.log(
3840
SentryLevel.DEBUG, "Registering EnvelopeFileObserverIntegration for path: %s", path);
3941

40-
final OutboxSender outboxSender =
41-
new OutboxSender(
42-
hub,
43-
options.getEnvelopeReader(),
44-
options.getSerializer(),
45-
logger,
46-
options.getFlushTimeoutMillis());
47-
48-
observer =
49-
new EnvelopeFileObserver(path, outboxSender, logger, options.getFlushTimeoutMillis());
5042
try {
51-
observer.startWatching();
52-
logger.log(SentryLevel.DEBUG, "EnvelopeFileObserverIntegration installed.");
53-
} catch (Throwable e) {
54-
// it could throw eg NoSuchFileException or NullPointerException
5543
options
56-
.getLogger()
57-
.log(SentryLevel.ERROR, "Failed to initialize EnvelopeFileObserverIntegration.", e);
44+
.getExecutorService()
45+
.submit(
46+
() -> {
47+
synchronized (startLock) {
48+
if (!isClosed) {
49+
startOutboxSender(hub, options, path);
50+
}
51+
}
52+
});
53+
} catch (Throwable e) {
54+
logger.log(
55+
SentryLevel.DEBUG,
56+
"Failed to start EnvelopeFileObserverIntegration on executor thread.",
57+
e);
5858
}
5959
}
6060
}
6161

62+
private void startOutboxSender(
63+
final @NotNull IHub hub, final @NotNull SentryOptions options, final @NotNull String path) {
64+
final OutboxSender outboxSender =
65+
new OutboxSender(
66+
hub,
67+
options.getEnvelopeReader(),
68+
options.getSerializer(),
69+
options.getLogger(),
70+
options.getFlushTimeoutMillis());
71+
72+
observer =
73+
new EnvelopeFileObserver(
74+
path, outboxSender, options.getLogger(), options.getFlushTimeoutMillis());
75+
try {
76+
observer.startWatching();
77+
options.getLogger().log(SentryLevel.DEBUG, "EnvelopeFileObserverIntegration installed.");
78+
} catch (Throwable e) {
79+
// it could throw eg NoSuchFileException or NullPointerException
80+
options
81+
.getLogger()
82+
.log(SentryLevel.ERROR, "Failed to initialize EnvelopeFileObserverIntegration.", e);
83+
}
84+
}
85+
6286
@Override
6387
public void close() {
88+
synchronized (startLock) {
89+
isClosed = true;
90+
}
6491
if (observer != null) {
6592
observer.stopWatching();
6693

sentry-android-core/src/main/java/io/sentry/android/core/PhoneStateBreadcrumbsIntegration.java

Lines changed: 44 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,13 @@ public final class PhoneStateBreadcrumbsIntegration implements Integration, Clos
2323
private @Nullable SentryAndroidOptions options;
2424
@TestOnly @Nullable PhoneStateChangeListener listener;
2525
private @Nullable TelephonyManager telephonyManager;
26+
private boolean isClosed = false;
27+
private final @NotNull Object startLock = new Object();
2628

2729
public PhoneStateBreadcrumbsIntegration(final @NotNull Context context) {
2830
this.context = Objects.requireNonNull(context, "Context is required");
2931
}
3032

31-
@SuppressWarnings("deprecation")
3233
@Override
3334
public void register(final @NotNull IHub hub, final @NotNull SentryOptions options) {
3435
Objects.requireNonNull(hub, "Hub is required");
@@ -46,28 +47,55 @@ public void register(final @NotNull IHub hub, final @NotNull SentryOptions optio
4647

4748
if (this.options.isEnableSystemEventBreadcrumbs()
4849
&& Permissions.hasPermission(context, READ_PHONE_STATE)) {
49-
telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
50-
if (telephonyManager != null) {
51-
try {
52-
listener = new PhoneStateChangeListener(hub);
53-
telephonyManager.listen(listener, android.telephony.PhoneStateListener.LISTEN_CALL_STATE);
54-
55-
options.getLogger().log(SentryLevel.DEBUG, "PhoneStateBreadcrumbsIntegration installed.");
56-
addIntegrationToSdkVersion();
57-
} catch (Throwable e) {
58-
this.options
59-
.getLogger()
60-
.log(SentryLevel.INFO, e, "TelephonyManager is not available or ready to use.");
61-
}
62-
} else {
63-
this.options.getLogger().log(SentryLevel.INFO, "TelephonyManager is not available");
50+
try {
51+
options
52+
.getExecutorService()
53+
.submit(
54+
() -> {
55+
synchronized (startLock) {
56+
if (!isClosed) {
57+
startTelephonyListener(hub, options);
58+
}
59+
}
60+
});
61+
} catch (Throwable e) {
62+
options
63+
.getLogger()
64+
.log(
65+
SentryLevel.DEBUG,
66+
"Failed to start PhoneStateBreadcrumbsIntegration on executor thread.",
67+
e);
68+
}
69+
}
70+
}
71+
72+
@SuppressWarnings("deprecation")
73+
private void startTelephonyListener(
74+
final @NotNull IHub hub, final @NotNull SentryOptions options) {
75+
telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
76+
if (telephonyManager != null) {
77+
try {
78+
listener = new PhoneStateChangeListener(hub);
79+
telephonyManager.listen(listener, android.telephony.PhoneStateListener.LISTEN_CALL_STATE);
80+
81+
options.getLogger().log(SentryLevel.DEBUG, "PhoneStateBreadcrumbsIntegration installed.");
82+
addIntegrationToSdkVersion();
83+
} catch (Throwable e) {
84+
options
85+
.getLogger()
86+
.log(SentryLevel.INFO, e, "TelephonyManager is not available or ready to use.");
6487
}
88+
} else {
89+
options.getLogger().log(SentryLevel.INFO, "TelephonyManager is not available");
6590
}
6691
}
6792

6893
@SuppressWarnings("deprecation")
6994
@Override
7095
public void close() throws IOException {
96+
synchronized (startLock) {
97+
isClosed = true;
98+
}
7199
if (telephonyManager != null && listener != null) {
72100
telephonyManager.listen(listener, android.telephony.PhoneStateListener.LISTEN_NONE);
73101
listener = null;

sentry-android-core/src/main/java/io/sentry/android/core/SendCachedEnvelopeIntegration.java

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,20 +40,21 @@ public void register(@NotNull IHub hub, @NotNull SentryOptions options) {
4040
return;
4141
}
4242

43-
final SendCachedEnvelopeFireAndForgetIntegration.SendFireAndForget sender =
44-
factory.create(hub, androidOptions);
45-
46-
if (sender == null) {
47-
androidOptions.getLogger().log(SentryLevel.ERROR, "SendFireAndForget factory is null.");
48-
return;
49-
}
50-
5143
try {
5244
Future<?> future =
5345
androidOptions
5446
.getExecutorService()
5547
.submit(
5648
() -> {
49+
final SendCachedEnvelopeFireAndForgetIntegration.SendFireAndForget sender =
50+
factory.create(hub, androidOptions);
51+
52+
if (sender == null) {
53+
androidOptions
54+
.getLogger()
55+
.log(SentryLevel.ERROR, "SendFireAndForget factory is null.");
56+
return;
57+
}
5758
try {
5859
sender.send();
5960
} catch (Throwable e) {

sentry-android-core/src/main/java/io/sentry/android/core/SystemEventsBreadcrumbsIntegration.java

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ public final class SystemEventsBreadcrumbsIntegration implements Integration, Cl
6565
private @Nullable SentryAndroidOptions options;
6666

6767
private final @NotNull List<String> actions;
68+
private boolean isClosed = false;
69+
private final @NotNull Object startLock = new Object();
6870

6971
public SystemEventsBreadcrumbsIntegration(final @NotNull Context context) {
7072
this(context, getDefaultActions());
@@ -92,27 +94,49 @@ public void register(final @NotNull IHub hub, final @NotNull SentryOptions optio
9294
this.options.isEnableSystemEventBreadcrumbs());
9395

9496
if (this.options.isEnableSystemEventBreadcrumbs()) {
95-
receiver = new SystemEventsBroadcastReceiver(hub, this.options.getLogger());
96-
final IntentFilter filter = new IntentFilter();
97-
for (String item : actions) {
98-
filter.addAction(item);
99-
}
97+
10098
try {
101-
// registerReceiver can throw SecurityException but it's not documented in the official docs
102-
ContextUtils.registerReceiver(context, options, receiver, filter);
103-
this.options
104-
.getLogger()
105-
.log(SentryLevel.DEBUG, "SystemEventsBreadcrumbsIntegration installed.");
106-
addIntegrationToSdkVersion();
99+
options
100+
.getExecutorService()
101+
.submit(
102+
() -> {
103+
synchronized (startLock) {
104+
if (!isClosed) {
105+
startSystemEventsReceiver(hub, (SentryAndroidOptions) options);
106+
}
107+
}
108+
});
107109
} catch (Throwable e) {
108-
this.options.setEnableSystemEventBreadcrumbs(false);
109-
this.options
110+
options
110111
.getLogger()
111-
.log(SentryLevel.ERROR, "Failed to initialize SystemEventsBreadcrumbsIntegration.", e);
112+
.log(
113+
SentryLevel.DEBUG,
114+
"Failed to start SystemEventsBreadcrumbsIntegration on executor thread.",
115+
e);
112116
}
113117
}
114118
}
115119

120+
private void startSystemEventsReceiver(
121+
final @NotNull IHub hub, final @NotNull SentryAndroidOptions options) {
122+
receiver = new SystemEventsBroadcastReceiver(hub, options.getLogger());
123+
final IntentFilter filter = new IntentFilter();
124+
for (String item : actions) {
125+
filter.addAction(item);
126+
}
127+
try {
128+
// registerReceiver can throw SecurityException but it's not documented in the official docs
129+
ContextUtils.registerReceiver(context, options, receiver, filter);
130+
options.getLogger().log(SentryLevel.DEBUG, "SystemEventsBreadcrumbsIntegration installed.");
131+
addIntegrationToSdkVersion();
132+
} catch (Throwable e) {
133+
options.setEnableSystemEventBreadcrumbs(false);
134+
options
135+
.getLogger()
136+
.log(SentryLevel.ERROR, "Failed to initialize SystemEventsBreadcrumbsIntegration.", e);
137+
}
138+
}
139+
116140
@SuppressWarnings("deprecation")
117141
private static @NotNull List<String> getDefaultActions() {
118142
final List<String> actions = new ArrayList<>();
@@ -164,6 +188,9 @@ public void register(final @NotNull IHub hub, final @NotNull SentryOptions optio
164188

165189
@Override
166190
public void close() throws IOException {
191+
synchronized (startLock) {
192+
isClosed = true;
193+
}
167194
if (receiver != null) {
168195
context.unregisterReceiver(receiver);
169196
receiver = null;

0 commit comments

Comments
 (0)