Skip to content

Commit 260dc49

Browse files
authored
Merge 4cbaa1c into 0048b42
2 parents 0048b42 + 4cbaa1c commit 260dc49

File tree

14 files changed

+697
-85
lines changed

14 files changed

+697
-85
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
- Deduplicate battery breadcrumbs ([#4561](https://github.com/getsentry/sentry-java/pull/4561))
1414
- Remove unused method in ManifestMetadataReader ([#4585](https://github.com/getsentry/sentry-java/pull/4585))
1515
- Have single `NetworkCallback` registered at a time to reduce IPC calls ([#4562](https://github.com/getsentry/sentry-java/pull/4562))
16+
- Do not register for SystemEvents and NetworkCallbacks immediately when launched with non-foreground importance ([#4579](https://github.com/getsentry/sentry-java/pull/4579))
1617
- 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))
1718
- 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:
1819
```

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,16 +167,29 @@ public final class io/sentry/android/core/AppLifecycleIntegration : io/sentry/In
167167
}
168168

169169
public final class io/sentry/android/core/AppState : java/io/Closeable {
170+
public fun addAppStateListener (Lio/sentry/android/core/AppState$AppStateListener;)V
170171
public fun close ()V
171172
public static fun getInstance ()Lio/sentry/android/core/AppState;
173+
public fun getLifecycleObserver ()Lio/sentry/android/core/AppState$LifecycleObserver;
172174
public fun isInBackground ()Ljava/lang/Boolean;
175+
public fun registerLifecycleObserver (Lio/sentry/SentryOptions;)V
176+
public fun removeAppStateListener (Lio/sentry/android/core/AppState$AppStateListener;)V
177+
public fun resetInstance ()V
178+
public fun unregisterLifecycleObserver ()V
173179
}
174180

175181
public abstract interface class io/sentry/android/core/AppState$AppStateListener {
176182
public abstract fun onBackground ()V
177183
public abstract fun onForeground ()V
178184
}
179185

186+
public final class io/sentry/android/core/AppState$LifecycleObserver : androidx/lifecycle/DefaultLifecycleObserver {
187+
public fun <init> (Lio/sentry/android/core/AppState;)V
188+
public fun getListeners ()Ljava/util/List;
189+
public fun onStart (Landroidx/lifecycle/LifecycleOwner;)V
190+
public fun onStop (Landroidx/lifecycle/LifecycleOwner;)V
191+
}
192+
180193
public final class io/sentry/android/core/BuildConfig {
181194
public static final field BUILD_TYPE Ljava/lang/String;
182195
public static final field DEBUG Z

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

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

33
import androidx.annotation.NonNull;
44
import androidx.lifecycle.DefaultLifecycleObserver;
5-
import androidx.lifecycle.LifecycleObserver;
65
import androidx.lifecycle.LifecycleOwner;
76
import androidx.lifecycle.ProcessLifecycleOwner;
87
import io.sentry.ILogger;
98
import io.sentry.ISentryLifecycleToken;
109
import io.sentry.NoOpLogger;
1110
import io.sentry.SentryLevel;
11+
import io.sentry.SentryOptions;
1212
import io.sentry.android.core.internal.util.AndroidThreadChecker;
1313
import io.sentry.util.AutoClosableReentrantLock;
1414
import java.io.Closeable;
@@ -36,21 +36,23 @@ private AppState() {}
3636

3737
private volatile @Nullable Boolean inBackground = null;
3838

39-
@TestOnly
40-
LifecycleObserver getLifecycleObserver() {
41-
return lifecycleObserver;
42-
}
43-
4439
@TestOnly
4540
void setHandler(final @NotNull MainLooperHandler handler) {
4641
this.handler = handler;
4742
}
4843

44+
@ApiStatus.Internal
4945
@TestOnly
50-
void resetInstance() {
46+
public void resetInstance() {
5147
instance = new AppState();
5248
}
5349

50+
@ApiStatus.Internal
51+
@TestOnly
52+
public LifecycleObserver getLifecycleObserver() {
53+
return lifecycleObserver;
54+
}
55+
5456
public @Nullable Boolean isInBackground() {
5557
return inBackground;
5658
}
@@ -59,7 +61,7 @@ void setInBackground(final boolean inBackground) {
5961
this.inBackground = inBackground;
6062
}
6163

62-
void addAppStateListener(final @NotNull AppStateListener listener) {
64+
public void addAppStateListener(final @NotNull AppStateListener listener) {
6365
try (final @NotNull ISentryLifecycleToken ignored = lock.acquire()) {
6466
ensureLifecycleObserver(NoOpLogger.getInstance());
6567

@@ -69,15 +71,16 @@ void addAppStateListener(final @NotNull AppStateListener listener) {
6971
}
7072
}
7173

72-
void removeAppStateListener(final @NotNull AppStateListener listener) {
74+
public void removeAppStateListener(final @NotNull AppStateListener listener) {
7375
try (final @NotNull ISentryLifecycleToken ignored = lock.acquire()) {
7476
if (lifecycleObserver != null) {
7577
lifecycleObserver.listeners.remove(listener);
7678
}
7779
}
7880
}
7981

80-
void registerLifecycleObserver(final @Nullable SentryAndroidOptions options) {
82+
@ApiStatus.Internal
83+
public void registerLifecycleObserver(final @Nullable SentryOptions options) {
8184
if (lifecycleObserver != null) {
8285
return;
8386
}
@@ -133,7 +136,8 @@ private void addObserverInternal(final @NotNull ILogger logger) {
133136
}
134137
}
135138

136-
void unregisterLifecycleObserver() {
139+
@ApiStatus.Internal
140+
public void unregisterLifecycleObserver() {
137141
if (lifecycleObserver == null) {
138142
return;
139143
}
@@ -167,7 +171,8 @@ public void close() throws IOException {
167171
unregisterLifecycleObserver();
168172
}
169173

170-
final class LifecycleObserver implements DefaultLifecycleObserver {
174+
@ApiStatus.Internal
175+
public final class LifecycleObserver implements DefaultLifecycleObserver {
171176
final List<AppStateListener> listeners =
172177
new CopyOnWriteArrayList<AppStateListener>() {
173178
@Override
@@ -184,6 +189,12 @@ public boolean add(AppStateListener appStateListener) {
184189
}
185190
};
186191

192+
@ApiStatus.Internal
193+
@TestOnly
194+
public List<AppStateListener> getListeners() {
195+
return listeners;
196+
}
197+
187198
@Override
188199
public void onStart(@NonNull LifecycleOwner owner) {
189200
setInBackground(false);

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

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import io.sentry.SentryOptions;
2222
import io.sentry.android.core.util.AndroidLazyEvaluator;
2323
import io.sentry.protocol.App;
24-
import io.sentry.util.LazyEvaluator;
2524
import java.io.BufferedReader;
2625
import java.io.File;
2726
import java.io.FileReader;
@@ -91,20 +90,6 @@ private ContextUtils() {}
9190
// to avoid doing a bunch of Binder calls we use LazyEvaluator to cache the values that are static
9291
// during the app process running
9392

94-
private static final @NotNull LazyEvaluator<Boolean> isForegroundImportance =
95-
new LazyEvaluator<>(
96-
() -> {
97-
try {
98-
final ActivityManager.RunningAppProcessInfo appProcessInfo =
99-
new ActivityManager.RunningAppProcessInfo();
100-
ActivityManager.getMyMemoryState(appProcessInfo);
101-
return appProcessInfo.importance == IMPORTANCE_FOREGROUND;
102-
} catch (Throwable ignored) {
103-
// should never happen
104-
}
105-
return false;
106-
});
107-
10893
/**
10994
* Since this packageInfo uses flags 0 we can assume it's static and cache it as the package name
11095
* or version code cannot change during runtime, only after app update (which will spin up a new
@@ -284,7 +269,15 @@ static String getVersionName(final @NotNull PackageInfo packageInfo) {
284269
*/
285270
@ApiStatus.Internal
286271
public static boolean isForegroundImportance() {
287-
return isForegroundImportance.getValue();
272+
try {
273+
final ActivityManager.RunningAppProcessInfo appProcessInfo =
274+
new ActivityManager.RunningAppProcessInfo();
275+
ActivityManager.getMyMemoryState(appProcessInfo);
276+
return appProcessInfo.importance == IMPORTANCE_FOREGROUND;
277+
} catch (Throwable ignored) {
278+
// should never happen
279+
}
280+
return false;
288281
}
289282

290283
/**
@@ -544,7 +537,6 @@ public static Context getApplicationContext(final @NotNull Context context) {
544537

545538
@TestOnly
546539
static void resetInstance() {
547-
isForegroundImportance.resetValue();
548540
staticPackageInfo33.resetValue();
549541
staticPackageInfo.resetValue();
550542
applicationName.resetValue();

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

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import java.util.HashMap;
4444
import java.util.List;
4545
import java.util.Map;
46+
import java.util.concurrent.atomic.AtomicBoolean;
4647
import org.jetbrains.annotations.NotNull;
4748
import org.jetbrains.annotations.Nullable;
4849
import org.jetbrains.annotations.TestOnly;
@@ -62,6 +63,7 @@ public final class SystemEventsBreadcrumbsIntegration
6263
private volatile boolean isClosed = false;
6364
private volatile boolean isStopped = false;
6465
private volatile IntentFilter filter = null;
66+
private final @NotNull AtomicBoolean isReceiverRegistered = new AtomicBoolean(false);
6567
private final @NotNull AutoClosableReentrantLock receiverLock = new AutoClosableReentrantLock();
6668
// Track previous battery state to avoid duplicate breadcrumbs when values haven't changed
6769
private @Nullable BatteryState previousBatteryState;
@@ -101,14 +103,15 @@ public void register(final @NotNull IScopes scopes, final @NotNull SentryOptions
101103

102104
if (this.options.isEnableSystemEventBreadcrumbs()) {
103105
AppState.getInstance().addAppStateListener(this);
104-
registerReceiver(this.scopes, this.options, /* reportAsNewIntegration= */ true);
106+
107+
if (ContextUtils.isForegroundImportance()) {
108+
registerReceiver(this.scopes, this.options);
109+
}
105110
}
106111
}
107112

108113
private void registerReceiver(
109-
final @NotNull IScopes scopes,
110-
final @NotNull SentryAndroidOptions options,
111-
final boolean reportAsNewIntegration) {
114+
final @NotNull IScopes scopes, final @NotNull SentryAndroidOptions options) {
112115

113116
if (!options.isEnableSystemEventBreadcrumbs()) {
114117
return;
@@ -139,7 +142,7 @@ private void registerReceiver(
139142
// registerReceiver can throw SecurityException but it's not documented in the
140143
// official docs
141144
ContextUtils.registerReceiver(context, options, receiver, filter);
142-
if (reportAsNewIntegration) {
145+
if (!isReceiverRegistered.getAndSet(true)) {
143146
options
144147
.getLogger()
145148
.log(SentryLevel.DEBUG, "SystemEventsBreadcrumbsIntegration installed.");
@@ -239,7 +242,7 @@ public void onForeground() {
239242

240243
isStopped = false;
241244

242-
registerReceiver(scopes, options, /* reportAsNewIntegration= */ false);
245+
registerReceiver(scopes, options);
243246
}
244247

245248
@Override

0 commit comments

Comments
 (0)