Skip to content

Commit

Permalink
Reduce main thread work on init (#3036)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
stefanosiano authored Nov 27, 2023
1 parent b172d4e commit e6ffd7b
Show file tree
Hide file tree
Showing 25 changed files with 588 additions and 209 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## Unreleased

### Fixes

- Reduce main thread work on init ([#3036](https://github.com/getsentry/sentry-java/pull/3036))
- Move Integrations registration to background on init ([#3043](https://github.com/getsentry/sentry-java/pull/3043))

## 6.34.0

### Features
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
public final class AnrIntegration implements Integration, Closeable {

private final @NotNull Context context;
private boolean isClosed = false;
private final @NotNull Object startLock = new Object();

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

if (options.isAnrEnabled()) {
synchronized (watchDogLock) {
if (anrWatchDog == null) {
options
.getLogger()
.log(
SentryLevel.DEBUG,
"ANR timeout in milliseconds: %d",
options.getAnrTimeoutIntervalMillis());

anrWatchDog =
new ANRWatchDog(
options.getAnrTimeoutIntervalMillis(),
options.isAnrReportInDebug(),
error -> reportANR(hub, options, error),
options.getLogger(),
context);
anrWatchDog.start();

options.getLogger().log(SentryLevel.DEBUG, "AnrIntegration installed.");
addIntegrationToSdkVersion();
}
addIntegrationToSdkVersion();
try {
options
.getExecutorService()
.submit(
() -> {
synchronized (startLock) {
if (!isClosed) {
startAnrWatchdog(hub, options);
}
}
});
} catch (Throwable e) {
options
.getLogger()
.log(SentryLevel.DEBUG, "Failed to start AnrIntegration on executor thread.", e);
}
}
}

private void startAnrWatchdog(
final @NotNull IHub hub, final @NotNull SentryAndroidOptions options) {
synchronized (watchDogLock) {
if (anrWatchDog == null) {
options
.getLogger()
.log(
SentryLevel.DEBUG,
"ANR timeout in milliseconds: %d",
options.getAnrTimeoutIntervalMillis());

anrWatchDog =
new ANRWatchDog(
options.getAnrTimeoutIntervalMillis(),
options.isAnrReportInDebug(),
error -> reportANR(hub, options, error),
options.getLogger(),
context);
anrWatchDog.start();

options.getLogger().log(SentryLevel.DEBUG, "AnrIntegration installed.");
}
}
}
Expand Down Expand Up @@ -126,6 +148,9 @@ ANRWatchDog getANRWatchDog() {

@Override
public void close() throws IOException {
synchronized (startLock) {
isClosed = true;
}
synchronized (watchDogLock) {
if (anrWatchDog != null) {
anrWatchDog.interrupt();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
public abstract class EnvelopeFileObserverIntegration implements Integration, Closeable {
private @Nullable EnvelopeFileObserver observer;
private @Nullable ILogger logger;
private boolean isClosed = false;
private final @NotNull Object startLock = new Object();

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

final OutboxSender outboxSender =
new OutboxSender(
hub,
options.getEnvelopeReader(),
options.getSerializer(),
logger,
options.getFlushTimeoutMillis());

observer =
new EnvelopeFileObserver(path, outboxSender, logger, options.getFlushTimeoutMillis());
try {
observer.startWatching();
logger.log(SentryLevel.DEBUG, "EnvelopeFileObserverIntegration installed.");
} catch (Throwable e) {
// it could throw eg NoSuchFileException or NullPointerException
options
.getLogger()
.log(SentryLevel.ERROR, "Failed to initialize EnvelopeFileObserverIntegration.", e);
.getExecutorService()
.submit(
() -> {
synchronized (startLock) {
if (!isClosed) {
startOutboxSender(hub, options, path);
}
}
});
} catch (Throwable e) {
logger.log(
SentryLevel.DEBUG,
"Failed to start EnvelopeFileObserverIntegration on executor thread.",
e);
}
}
}

private void startOutboxSender(
final @NotNull IHub hub, final @NotNull SentryOptions options, final @NotNull String path) {
final OutboxSender outboxSender =
new OutboxSender(
hub,
options.getEnvelopeReader(),
options.getSerializer(),
options.getLogger(),
options.getFlushTimeoutMillis());

observer =
new EnvelopeFileObserver(
path, outboxSender, options.getLogger(), options.getFlushTimeoutMillis());
try {
observer.startWatching();
options.getLogger().log(SentryLevel.DEBUG, "EnvelopeFileObserverIntegration installed.");
} catch (Throwable e) {
// it could throw eg NoSuchFileException or NullPointerException
options
.getLogger()
.log(SentryLevel.ERROR, "Failed to initialize EnvelopeFileObserverIntegration.", e);
}
}

@Override
public void close() {
synchronized (startLock) {
isClosed = true;
}
if (observer != null) {
observer.stopWatching();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,13 @@ public final class PhoneStateBreadcrumbsIntegration implements Integration, Clos
private @Nullable SentryAndroidOptions options;
@TestOnly @Nullable PhoneStateChangeListener listener;
private @Nullable TelephonyManager telephonyManager;
private boolean isClosed = false;
private final @NotNull Object startLock = new Object();

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

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

if (this.options.isEnableSystemEventBreadcrumbs()
&& Permissions.hasPermission(context, READ_PHONE_STATE)) {
telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
if (telephonyManager != null) {
try {
listener = new PhoneStateChangeListener(hub);
telephonyManager.listen(listener, android.telephony.PhoneStateListener.LISTEN_CALL_STATE);

options.getLogger().log(SentryLevel.DEBUG, "PhoneStateBreadcrumbsIntegration installed.");
addIntegrationToSdkVersion();
} catch (Throwable e) {
this.options
.getLogger()
.log(SentryLevel.INFO, e, "TelephonyManager is not available or ready to use.");
}
} else {
this.options.getLogger().log(SentryLevel.INFO, "TelephonyManager is not available");
try {
options
.getExecutorService()
.submit(
() -> {
synchronized (startLock) {
if (!isClosed) {
startTelephonyListener(hub, options);
}
}
});
} catch (Throwable e) {
options
.getLogger()
.log(
SentryLevel.DEBUG,
"Failed to start PhoneStateBreadcrumbsIntegration on executor thread.",
e);
}
}
}

@SuppressWarnings("deprecation")
private void startTelephonyListener(
final @NotNull IHub hub, final @NotNull SentryOptions options) {
telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
if (telephonyManager != null) {
try {
listener = new PhoneStateChangeListener(hub);
telephonyManager.listen(listener, android.telephony.PhoneStateListener.LISTEN_CALL_STATE);

options.getLogger().log(SentryLevel.DEBUG, "PhoneStateBreadcrumbsIntegration installed.");
addIntegrationToSdkVersion();
} catch (Throwable e) {
options
.getLogger()
.log(SentryLevel.INFO, e, "TelephonyManager is not available or ready to use.");
}
} else {
options.getLogger().log(SentryLevel.INFO, "TelephonyManager is not available");
}
}

@SuppressWarnings("deprecation")
@Override
public void close() throws IOException {
synchronized (startLock) {
isClosed = true;
}
if (telephonyManager != null && listener != null) {
telephonyManager.listen(listener, android.telephony.PhoneStateListener.LISTEN_NONE);
listener = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,20 +40,21 @@ public void register(@NotNull IHub hub, @NotNull SentryOptions options) {
return;
}

final SendCachedEnvelopeFireAndForgetIntegration.SendFireAndForget sender =
factory.create(hub, androidOptions);

if (sender == null) {
androidOptions.getLogger().log(SentryLevel.ERROR, "SendFireAndForget factory is null.");
return;
}

try {
Future<?> future =
androidOptions
.getExecutorService()
.submit(
() -> {
final SendCachedEnvelopeFireAndForgetIntegration.SendFireAndForget sender =
factory.create(hub, androidOptions);

if (sender == null) {
androidOptions
.getLogger()
.log(SentryLevel.ERROR, "SendFireAndForget factory is null.");
return;
}
try {
sender.send();
} catch (Throwable e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ public final class SystemEventsBreadcrumbsIntegration implements Integration, Cl
private @Nullable SentryAndroidOptions options;

private final @NotNull List<String> actions;
private boolean isClosed = false;
private final @NotNull Object startLock = new Object();

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

if (this.options.isEnableSystemEventBreadcrumbs()) {
receiver = new SystemEventsBroadcastReceiver(hub, this.options.getLogger());
final IntentFilter filter = new IntentFilter();
for (String item : actions) {
filter.addAction(item);
}

try {
// registerReceiver can throw SecurityException but it's not documented in the official docs
ContextUtils.registerReceiver(context, options, receiver, filter);
this.options
.getLogger()
.log(SentryLevel.DEBUG, "SystemEventsBreadcrumbsIntegration installed.");
addIntegrationToSdkVersion();
options
.getExecutorService()
.submit(
() -> {
synchronized (startLock) {
if (!isClosed) {
startSystemEventsReceiver(hub, (SentryAndroidOptions) options);
}
}
});
} catch (Throwable e) {
this.options.setEnableSystemEventBreadcrumbs(false);
this.options
options
.getLogger()
.log(SentryLevel.ERROR, "Failed to initialize SystemEventsBreadcrumbsIntegration.", e);
.log(
SentryLevel.DEBUG,
"Failed to start SystemEventsBreadcrumbsIntegration on executor thread.",
e);
}
}
}

private void startSystemEventsReceiver(
final @NotNull IHub hub, final @NotNull SentryAndroidOptions options) {
receiver = new SystemEventsBroadcastReceiver(hub, options.getLogger());
final IntentFilter filter = new IntentFilter();
for (String item : actions) {
filter.addAction(item);
}
try {
// registerReceiver can throw SecurityException but it's not documented in the official docs
ContextUtils.registerReceiver(context, options, receiver, filter);
options.getLogger().log(SentryLevel.DEBUG, "SystemEventsBreadcrumbsIntegration installed.");
addIntegrationToSdkVersion();
} catch (Throwable e) {
options.setEnableSystemEventBreadcrumbs(false);
options
.getLogger()
.log(SentryLevel.ERROR, "Failed to initialize SystemEventsBreadcrumbsIntegration.", e);
}
}

@SuppressWarnings("deprecation")
private static @NotNull List<String> getDefaultActions() {
final List<String> actions = new ArrayList<>();
Expand Down Expand Up @@ -164,6 +188,9 @@ public void register(final @NotNull IHub hub, final @NotNull SentryOptions optio

@Override
public void close() throws IOException {
synchronized (startLock) {
isClosed = true;
}
if (receiver != null) {
context.unregisterReceiver(receiver);
receiver = null;
Expand Down
Loading

0 comments on commit e6ffd7b

Please sign in to comment.