Skip to content

Commit

Permalink
Merge eb98375 into cd268a3
Browse files Browse the repository at this point in the history
  • Loading branch information
markushi authored Sep 1, 2023
2 parents cd268a3 + eb98375 commit a5f58d4
Show file tree
Hide file tree
Showing 15 changed files with 450 additions and 92 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@
import io.sentry.DeduplicateMultithreadedEventProcessor;
import io.sentry.DefaultTransactionPerformanceCollector;
import io.sentry.ILogger;
import io.sentry.NoOpConnectionStatusProvider;
import io.sentry.SendFireAndForgetEnvelopeSender;
import io.sentry.SendFireAndForgetOutboxSender;
import io.sentry.SentryLevel;
import io.sentry.android.core.cache.AndroidEnvelopeCache;
import io.sentry.android.core.internal.debugmeta.AssetsDebugMetaLoader;
import io.sentry.android.core.internal.gestures.AndroidViewGestureTargetLocator;
import io.sentry.android.core.internal.modules.AssetsModulesLoader;
import io.sentry.android.core.internal.util.AndroidConnectionStatusProvider;
import io.sentry.android.core.internal.util.AndroidMainThreadChecker;
import io.sentry.android.core.internal.util.SentryFrameMetricsCollector;
import io.sentry.android.fragment.FragmentLifecycleIntegration;
Expand Down Expand Up @@ -130,14 +132,19 @@ static void initializeIntegrationsAndProcessors(
options.setEnvelopeDiskCache(new AndroidEnvelopeCache(options));
}

if (options.getConnectionStatusProvider() instanceof NoOpConnectionStatusProvider) {
options.setConnectionStatusProvider(
new AndroidConnectionStatusProvider(context, options.getLogger(), buildInfoProvider));
}

options.addEventProcessor(new DeduplicateMultithreadedEventProcessor(options));
options.addEventProcessor(
new DefaultAndroidEventProcessor(context, buildInfoProvider, options));
options.addEventProcessor(new PerformanceAndroidEventProcessor(options, activityFramesTracker));
options.addEventProcessor(new ScreenshotEventProcessor(options, buildInfoProvider));
options.addEventProcessor(new ViewHierarchyEventProcessor(options));
options.addEventProcessor(new AnrV2EventProcessor(context, options, buildInfoProvider));
options.setTransportGate(new AndroidTransportGate(context, options.getLogger()));
options.setTransportGate(new AndroidTransportGate(options));
final SentryFrameMetricsCollector frameMetricsCollector =
new SentryFrameMetricsCollector(context, options, buildInfoProvider);
options.setTransactionProfiler(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,26 @@
package io.sentry.android.core;

import android.content.Context;
import io.sentry.ILogger;
import io.sentry.android.core.internal.util.ConnectivityChecker;
import io.sentry.IConnectionStatusProvider;
import io.sentry.SentryOptions;
import io.sentry.transport.ITransportGate;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.TestOnly;

final class AndroidTransportGate implements ITransportGate {

private final Context context;
private final @NotNull ILogger logger;
private final @NotNull SentryOptions options;

AndroidTransportGate(final @NotNull Context context, final @NotNull ILogger logger) {
this.context = context;
this.logger = logger;
AndroidTransportGate(final @NotNull SentryOptions options) {
this.options = options;
}

@Override
public boolean isConnected() {
return isConnected(ConnectivityChecker.getConnectionStatus(context, logger));
return isConnected(options.getConnectionStatusProvider().getConnectionStatus());
}

@TestOnly
boolean isConnected(final @NotNull ConnectivityChecker.Status status) {
boolean isConnected(final @NotNull IConnectionStatusProvider.ConnectionStatus status) {
// let's assume its connected if there's no permission or something as we can't really know
// whether is online or not.
switch (status) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
import android.util.DisplayMetrics;
import io.sentry.DateUtils;
import io.sentry.SentryLevel;
import io.sentry.android.core.internal.util.ConnectivityChecker;
import io.sentry.android.core.internal.util.CpuInfoUtils;
import io.sentry.android.core.internal.util.DeviceOrientations;
import io.sentry.android.core.internal.util.RootChecker;
Expand Down Expand Up @@ -180,8 +179,8 @@ private void setDeviceIO(final @NotNull Device device, final boolean includeDyna
}

Boolean connected;
switch (ConnectivityChecker.getConnectionStatus(context, options.getLogger())) {
case NOT_CONNECTED:
switch (options.getConnectionStatusProvider().getConnectionStatus()) {
case DISCONNECTED:
connected = false;
break;
case CONNECTED:
Expand Down Expand Up @@ -223,8 +222,7 @@ private void setDeviceIO(final @NotNull Device device, final boolean includeDyna

if (device.getConnectionType() == null) {
// wifi, ethernet or cellular, null if none
device.setConnectionType(
ConnectivityChecker.getConnectionType(context, options.getLogger(), buildInfoProvider));
device.setConnectionType(options.getConnectionStatusProvider().getConnectionType());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import io.sentry.SentryLevel;
import io.sentry.SentryOptions;
import io.sentry.TypeCheckHint;
import io.sentry.android.core.internal.util.ConnectivityChecker;
import io.sentry.android.core.internal.util.AndroidConnectionStatusProvider;
import io.sentry.util.Objects;
import java.io.Closeable;
import java.io.IOException;
Expand Down Expand Up @@ -69,7 +69,7 @@ public void register(final @NotNull IHub hub, final @NotNull SentryOptions optio

networkCallback = new NetworkBreadcrumbsNetworkCallback(hub, buildInfoProvider);
final boolean registered =
ConnectivityChecker.registerNetworkCallback(
AndroidConnectionStatusProvider.registerNetworkCallback(
context, logger, buildInfoProvider, networkCallback);

// The specific error is logged in the ConnectivityChecker method
Expand All @@ -86,7 +86,7 @@ public void register(final @NotNull IHub hub, final @NotNull SentryOptions optio
@Override
public void close() throws IOException {
if (networkCallback != null) {
ConnectivityChecker.unregisterNetworkCallback(
AndroidConnectionStatusProvider.unregisterNetworkCallback(
context, logger, buildInfoProvider, networkCallback);
logger.log(SentryLevel.DEBUG, "NetworkBreadcrumbsIntegration remove.");
}
Expand Down Expand Up @@ -208,7 +208,7 @@ static class NetworkBreadcrumbConnectionDetail {
this.signalStrength = strength > -100 ? strength : 0;
this.isVpn = networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN);
String connectionType =
ConnectivityChecker.getConnectionType(networkCapabilities, buildInfoProvider);
AndroidConnectionStatusProvider.getConnectionType(networkCapabilities, buildInfoProvider);
this.type = connectionType != null ? connectionType : "";
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,40 +7,48 @@
import android.net.Network;
import android.net.NetworkCapabilities;
import android.os.Build;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import io.sentry.IConnectionStatusProvider;
import io.sentry.ILogger;
import io.sentry.SentryLevel;
import io.sentry.android.core.BuildInfoProvider;
import java.util.HashMap;
import java.util.Map;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;

/**
* Note: ConnectivityManager sometimes throws SecurityExceptions on Android 11. Hence all relevant
* calls are guarded with try/catch. see https://issuetracker.google.com/issues/175055271 for more
* details
*/
@ApiStatus.Internal
public final class ConnectivityChecker {
public final class AndroidConnectionStatusProvider implements IConnectionStatusProvider {

public enum Status {
CONNECTED,
NOT_CONNECTED,
NO_PERMISSION,
UNKNOWN
}
private final @NotNull Context context;
private final @NotNull ILogger logger;
private final @NotNull BuildInfoProvider buildInfoProvider;
private final @NotNull Map<IConnectionStatusObserver, ConnectivityManager.NetworkCallback>
registeredCallbacks;

private ConnectivityChecker() {}
public AndroidConnectionStatusProvider(
@NotNull Context context,
@NotNull ILogger logger,
@NotNull BuildInfoProvider buildInfoProvider) {
this.context = context;
this.logger = logger;
this.buildInfoProvider = buildInfoProvider;
this.registeredCallbacks = new HashMap<>();
}

/**
* Return the Connection status
*
* @return the ConnectionStatus
*/
public static @NotNull ConnectivityChecker.Status getConnectionStatus(
final @NotNull Context context, final @NotNull ILogger logger) {
@Override
public @NotNull ConnectionStatus getConnectionStatus() {
final ConnectivityManager connectivityManager = getConnectivityManager(context, logger);
if (connectivityManager == null) {
return Status.UNKNOWN;
return ConnectionStatus.UNKNOWN;
}
return getConnectionStatus(context, connectivityManager, logger);
// getActiveNetworkInfo might return null if VPN doesn't specify its
Expand All @@ -50,6 +58,50 @@ private ConnectivityChecker() {}
// connectivityManager.registerDefaultNetworkCallback(...)
}

@Override
public @Nullable String getConnectionType() {
return getConnectionType(context, logger, buildInfoProvider);
}

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public boolean addConnectionStatusObserver(@NotNull IConnectionStatusObserver observer) {
final ConnectivityManager.NetworkCallback callback =
new ConnectivityManager.NetworkCallback() {
@Override
public void onAvailable(@NonNull Network network) {
observer.onConnectionStatusChanged(getConnectionStatus());
}

@Override
public void onLosing(@NonNull Network network, int maxMsToLive) {
observer.onConnectionStatusChanged(getConnectionStatus());
}

@Override
public void onLost(@NonNull Network network) {
observer.onConnectionStatusChanged(getConnectionStatus());
}

@Override
public void onUnavailable() {
observer.onConnectionStatusChanged(getConnectionStatus());
}
};

registeredCallbacks.put(observer, callback);
return registerNetworkCallback(context, logger, buildInfoProvider, callback);
}

@Override
public void removeConnectionStatusObserver(@NotNull IConnectionStatusObserver observer) {
final @Nullable ConnectivityManager.NetworkCallback callback =
registeredCallbacks.remove(observer);
if (callback != null) {
unregisterNetworkCallback(context, logger, buildInfoProvider, callback);
}
}

/**
* Return the Connection status
*
Expand All @@ -59,25 +111,27 @@ private ConnectivityChecker() {}
* @return true if connected or no permission to check, false otherwise
*/
@SuppressWarnings({"deprecation", "MissingPermission"})
private static @NotNull ConnectivityChecker.Status getConnectionStatus(
private static @NotNull IConnectionStatusProvider.ConnectionStatus getConnectionStatus(
final @NotNull Context context,
final @NotNull ConnectivityManager connectivityManager,
final @NotNull ILogger logger) {
if (!Permissions.hasPermission(context, Manifest.permission.ACCESS_NETWORK_STATE)) {
logger.log(SentryLevel.INFO, "No permission (ACCESS_NETWORK_STATE) to check network status.");
return Status.NO_PERMISSION;
return ConnectionStatus.NO_PERMISSION;
}

try {
final android.net.NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
if (activeNetworkInfo == null) {
logger.log(SentryLevel.INFO, "NetworkInfo is null, there's no active network.");
return Status.NOT_CONNECTED;
return ConnectionStatus.DISCONNECTED;
}
return activeNetworkInfo.isConnected() ? Status.CONNECTED : Status.NOT_CONNECTED;
return activeNetworkInfo.isConnected()
? ConnectionStatus.CONNECTED
: ConnectionStatus.DISCONNECTED;
} catch (Throwable t) {
logger.log(SentryLevel.ERROR, "Could not retrieve Connection Status", t);
return Status.UNKNOWN;
return ConnectionStatus.UNKNOWN;
}
}

Expand Down Expand Up @@ -273,4 +327,11 @@ public static void unregisterNetworkCallback(
logger.log(SentryLevel.ERROR, "unregisterNetworkCallback failed", t);
}
}

@TestOnly
@NotNull
public Map<IConnectionStatusObserver, ConnectivityManager.NetworkCallback>
getRegisteredCallbacks() {
return registeredCallbacks;
}
}
Loading

0 comments on commit a5f58d4

Please sign in to comment.