Skip to content

Commit be0f7c6

Browse files
authored
Merge branch 'main' into markushi/chore/speedup-agp-test-matrix
2 parents d822e58 + 0048b42 commit be0f7c6

File tree

15 files changed

+708
-360
lines changed

15 files changed

+708
-360
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,22 @@
55
### Improvements
66

77
- Session Replay: Use main thread looper to schedule replay capture ([#4542](https://github.com/getsentry/sentry-java/pull/4542))
8+
- Use single `LifecycleObserver` and multi-cast it to the integrations interested in lifecycle states ([#4567](https://github.com/getsentry/sentry-java/pull/4567))
89

910
### Fixes
1011

1112
- Cache network capabilities and status to reduce IPC calls ([#4560](https://github.com/getsentry/sentry-java/pull/4560))
1213
- Deduplicate battery breadcrumbs ([#4561](https://github.com/getsentry/sentry-java/pull/4561))
1314
- Remove unused method in ManifestMetadataReader ([#4585](https://github.com/getsentry/sentry-java/pull/4585))
1415
- Have single `NetworkCallback` registered at a time to reduce IPC calls ([#4562](https://github.com/getsentry/sentry-java/pull/4562))
16+
- Limit ProGuard keep rules for native methods within `sentry-android-ndk` to the `io.sentry.**` namespace. ([#4427](https://github.com/getsentry/sentry-java/pull/4427))
17+
- If you relied on the Sentry SDK to keep native method names for JNI compatibility within your namespace, please review your ProGuard rules and ensure the configuration still works. Especially when you're not consuming any of the default Android proguard rules (`proguard-android.txt` or `proguard-android-optimize.txt`) the following config should be present:
18+
```
19+
-keepclasseswithmembernames class * {
20+
native <methods>;
21+
}
22+
```
23+
- Fix abstract method error in `SentrySupportSQLiteDatabase` ([#4597](https://github.com/getsentry/sentry-java/pull/4597))
1524

1625
## 8.18.0
1726

gradle/libs.versions.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ androidx-lifecycle-common-java8 = { module = "androidx.lifecycle:lifecycle-commo
7979
androidx-lifecycle-process = { module = "androidx.lifecycle:lifecycle-process", version.ref = "androidxLifecycle" }
8080
androidx-navigation-runtime = { module = "androidx.navigation:navigation-runtime", version.ref = "androidxNavigation" }
8181
androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "androidxNavigation" }
82-
androidx-sqlite = { module = "androidx.sqlite:sqlite", version = "2.3.1" }
82+
androidx-sqlite = { module = "androidx.sqlite:sqlite", version = "2.5.2" }
8383
androidx-recyclerview = { module = "androidx.recyclerview:recyclerview", version = "1.2.1" }
8484
coil-compose = { module = "io.coil-kt:coil-compose", version = "2.6.0" }
8585
commons-compress = {module = "org.apache.commons:commons-compress", version = "1.25.0"}

sentry-android-core/api/sentry-android-core.api

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,11 +166,17 @@ public final class io/sentry/android/core/AppLifecycleIntegration : io/sentry/In
166166
public fun register (Lio/sentry/IScopes;Lio/sentry/SentryOptions;)V
167167
}
168168

169-
public final class io/sentry/android/core/AppState {
169+
public final class io/sentry/android/core/AppState : java/io/Closeable {
170+
public fun close ()V
170171
public static fun getInstance ()Lio/sentry/android/core/AppState;
171172
public fun isInBackground ()Ljava/lang/Boolean;
172173
}
173174

175+
public abstract interface class io/sentry/android/core/AppState$AppStateListener {
176+
public abstract fun onBackground ()V
177+
public abstract fun onForeground ()V
178+
}
179+
174180
public final class io/sentry/android/core/BuildConfig {
175181
public static final field BUILD_TYPE Ljava/lang/String;
176182
public static final field DEBUG Z
@@ -422,11 +428,13 @@ public class io/sentry/android/core/SpanFrameMetricsCollector : io/sentry/IPerfo
422428
public fun onSpanStarted (Lio/sentry/ISpan;)V
423429
}
424430

425-
public final class io/sentry/android/core/SystemEventsBreadcrumbsIntegration : io/sentry/Integration, java/io/Closeable {
431+
public final class io/sentry/android/core/SystemEventsBreadcrumbsIntegration : io/sentry/Integration, io/sentry/android/core/AppState$AppStateListener, java/io/Closeable {
426432
public fun <init> (Landroid/content/Context;)V
427433
public fun <init> (Landroid/content/Context;Ljava/util/List;)V
428434
public fun close ()V
429435
public static fun getDefaultActions ()Ljava/util/List;
436+
public fun onBackground ()V
437+
public fun onForeground ()V
430438
public fun register (Lio/sentry/IScopes;Lio/sentry/SentryOptions;)V
431439
}
432440

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ static void loadDefaultAndMetadataOptions(
128128
options.setCacheDirPath(getCacheDir(context).getAbsolutePath());
129129

130130
readDefaultOptionValues(options, context, buildInfoProvider);
131+
AppState.getInstance().registerLifecycleObserver(options);
131132
}
132133

133134
@TestOnly

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

Lines changed: 26 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22

33
import static io.sentry.util.IntegrationUtils.addIntegrationToSdkVersion;
44

5-
import androidx.lifecycle.ProcessLifecycleOwner;
65
import io.sentry.IScopes;
6+
import io.sentry.ISentryLifecycleToken;
77
import io.sentry.Integration;
88
import io.sentry.SentryLevel;
99
import io.sentry.SentryOptions;
10-
import io.sentry.android.core.internal.util.AndroidThreadChecker;
10+
import io.sentry.util.AutoClosableReentrantLock;
1111
import io.sentry.util.Objects;
1212
import java.io.Closeable;
1313
import java.io.IOException;
@@ -17,20 +17,11 @@
1717

1818
public final class AppLifecycleIntegration implements Integration, Closeable {
1919

20+
private final @NotNull AutoClosableReentrantLock lock = new AutoClosableReentrantLock();
2021
@TestOnly @Nullable volatile LifecycleWatcher watcher;
2122

2223
private @Nullable SentryAndroidOptions options;
2324

24-
private final @NotNull MainLooperHandler handler;
25-
26-
public AppLifecycleIntegration() {
27-
this(new MainLooperHandler());
28-
}
29-
30-
AppLifecycleIntegration(final @NotNull MainLooperHandler handler) {
31-
this.handler = handler;
32-
}
33-
3425
@Override
3526
public void register(final @NotNull IScopes scopes, final @NotNull SentryOptions options) {
3627
Objects.requireNonNull(scopes, "Scopes are required");
@@ -55,85 +46,47 @@ public void register(final @NotNull IScopes scopes, final @NotNull SentryOptions
5546

5647
if (this.options.isEnableAutoSessionTracking()
5748
|| this.options.isEnableAppLifecycleBreadcrumbs()) {
58-
try {
59-
Class.forName("androidx.lifecycle.DefaultLifecycleObserver");
60-
Class.forName("androidx.lifecycle.ProcessLifecycleOwner");
61-
if (AndroidThreadChecker.getInstance().isMainThread()) {
62-
addObserver(scopes);
63-
} else {
64-
// some versions of the androidx lifecycle-process require this to be executed on the main
65-
// thread.
66-
handler.post(() -> addObserver(scopes));
49+
try (final ISentryLifecycleToken ignored = lock.acquire()) {
50+
if (watcher != null) {
51+
return;
6752
}
68-
} catch (ClassNotFoundException e) {
69-
options
70-
.getLogger()
71-
.log(
72-
SentryLevel.WARNING,
73-
"androidx.lifecycle is not available, AppLifecycleIntegration won't be installed");
74-
} catch (IllegalStateException e) {
75-
options
76-
.getLogger()
77-
.log(SentryLevel.ERROR, "AppLifecycleIntegration could not be installed", e);
78-
}
79-
}
80-
}
8153

82-
private void addObserver(final @NotNull IScopes scopes) {
83-
// this should never happen, check added to avoid warnings from NullAway
84-
if (this.options == null) {
85-
return;
86-
}
54+
watcher =
55+
new LifecycleWatcher(
56+
scopes,
57+
this.options.getSessionTrackingIntervalMillis(),
58+
this.options.isEnableAutoSessionTracking(),
59+
this.options.isEnableAppLifecycleBreadcrumbs());
8760

88-
watcher =
89-
new LifecycleWatcher(
90-
scopes,
91-
this.options.getSessionTrackingIntervalMillis(),
92-
this.options.isEnableAutoSessionTracking(),
93-
this.options.isEnableAppLifecycleBreadcrumbs());
61+
AppState.getInstance().addAppStateListener(watcher);
62+
}
9463

95-
try {
96-
ProcessLifecycleOwner.get().getLifecycle().addObserver(watcher);
9764
options.getLogger().log(SentryLevel.DEBUG, "AppLifecycleIntegration installed.");
9865
addIntegrationToSdkVersion("AppLifecycle");
99-
} catch (Throwable e) {
100-
// This is to handle a potential 'AbstractMethodError' gracefully. The error is triggered in
101-
// connection with conflicting dependencies of the androidx.lifecycle.
102-
// //See the issue here: https://github.com/getsentry/sentry-java/pull/2228
103-
watcher = null;
104-
options
105-
.getLogger()
106-
.log(
107-
SentryLevel.ERROR,
108-
"AppLifecycleIntegration failed to get Lifecycle and could not be installed.",
109-
e);
11066
}
11167
}
11268

11369
private void removeObserver() {
114-
final @Nullable LifecycleWatcher watcherRef = watcher;
70+
final @Nullable LifecycleWatcher watcherRef;
71+
try (final ISentryLifecycleToken ignored = lock.acquire()) {
72+
watcherRef = watcher;
73+
watcher = null;
74+
}
75+
11576
if (watcherRef != null) {
116-
ProcessLifecycleOwner.get().getLifecycle().removeObserver(watcherRef);
77+
AppState.getInstance().removeAppStateListener(watcherRef);
11778
if (options != null) {
11879
options.getLogger().log(SentryLevel.DEBUG, "AppLifecycleIntegration removed.");
11980
}
12081
}
121-
watcher = null;
12282
}
12383

12484
@Override
12585
public void close() throws IOException {
126-
if (watcher == null) {
127-
return;
128-
}
129-
if (AndroidThreadChecker.getInstance().isMainThread()) {
130-
removeObserver();
131-
} else {
132-
// some versions of the androidx lifecycle-process require this to be executed on the main
133-
// thread.
134-
// avoid method refs on Android due to some issues with older AGP setups
135-
// noinspection Convert2MethodRef
136-
handler.post(() -> removeObserver());
137-
}
86+
removeObserver();
87+
// TODO: probably should move it to Scopes.close(), but that'd require a new interface and
88+
// different implementations for Java and Android. This is probably fine like this too, because
89+
// integrations are closed in the same place
90+
AppState.getInstance().unregisterLifecycleObserver();
13891
}
13992
}

0 commit comments

Comments
 (0)