Bugsnag 5.9.3

pull/199/head
M66B 3 years ago
parent e363d5bb34
commit 7ce6d3b50e

@ -25,7 +25,7 @@ internal class BreadcrumbInternal internal constructor(
@Throws(IOException::class) @Throws(IOException::class)
override fun toStream(writer: JsonStream) { override fun toStream(writer: JsonStream) {
writer.beginObject() writer.beginObject()
writer.name("timestamp").value(DateUtils.toIso8601(timestamp)) writer.name("timestamp").value(timestamp)
writer.name("name").value(message) writer.name("name").value(message)
writer.name("type").value(type.toString()) writer.name("type").value(type.toString())
writer.name("metaData") writer.name("metaData")

@ -1,5 +1,7 @@
package com.bugsnag.android; package com.bugsnag.android;
import static com.bugsnag.android.ContextExtensionsKt.getActivityManagerFrom;
import static com.bugsnag.android.ContextExtensionsKt.getStorageManagerFrom;
import static com.bugsnag.android.ImmutableConfigKt.sanitiseConfiguration; import static com.bugsnag.android.ImmutableConfigKt.sanitiseConfiguration;
import static com.bugsnag.android.SeverityReason.REASON_HANDLED_EXCEPTION; import static com.bugsnag.android.SeverityReason.REASON_HANDLED_EXCEPTION;
@ -74,7 +76,10 @@ public class Client implements MetadataAware, CallbackAware, UserAware {
private final SessionLifecycleCallback sessionLifecycleCallback; private final SessionLifecycleCallback sessionLifecycleCallback;
private final Connectivity connectivity; private final Connectivity connectivity;
@Nullable
private final StorageManager storageManager; private final StorageManager storageManager;
final Logger logger; final Logger logger;
final DeliveryDelegate deliveryDelegate; final DeliveryDelegate deliveryDelegate;
@ -143,7 +148,7 @@ public class Client implements MetadataAware, CallbackAware, UserAware {
int maxBreadcrumbs = immutableConfig.getMaxBreadcrumbs(); int maxBreadcrumbs = immutableConfig.getMaxBreadcrumbs();
breadcrumbState = new BreadcrumbState(maxBreadcrumbs, callbackState, logger); breadcrumbState = new BreadcrumbState(maxBreadcrumbs, callbackState, logger);
storageManager = (StorageManager) appContext.getSystemService(Context.STORAGE_SERVICE); storageManager = getStorageManagerFrom(appContext);
contextState = new ContextState(); contextState = new ContextState();
contextState.setContext(configuration.getContext()); contextState.setContext(configuration.getContext());
@ -153,8 +158,7 @@ public class Client implements MetadataAware, CallbackAware, UserAware {
sessionStore, logger, bgTaskService); sessionStore, logger, bgTaskService);
metadataState = copyMetadataState(configuration); metadataState = copyMetadataState(configuration);
ActivityManager am = ActivityManager am = getActivityManagerFrom(appContext);
(ActivityManager) appContext.getSystemService(Context.ACTIVITY_SERVICE);
launchCrashTracker = new LaunchCrashTracker(immutableConfig); launchCrashTracker = new LaunchCrashTracker(immutableConfig);
appDataCollector = new AppDataCollector(appContext, appContext.getPackageManager(), appDataCollector = new AppDataCollector(appContext, appContext.getPackageManager(),
@ -256,7 +260,7 @@ public class Client implements MetadataAware, CallbackAware, UserAware {
ActivityBreadcrumbCollector activityBreadcrumbCollector, ActivityBreadcrumbCollector activityBreadcrumbCollector,
SessionLifecycleCallback sessionLifecycleCallback, SessionLifecycleCallback sessionLifecycleCallback,
Connectivity connectivity, Connectivity connectivity,
StorageManager storageManager, @Nullable StorageManager storageManager,
Logger logger, Logger logger,
DeliveryDelegate deliveryDelegate, DeliveryDelegate deliveryDelegate,
LastRunInfoStore lastRunInfoStore, LastRunInfoStore lastRunInfoStore,

@ -24,9 +24,11 @@ internal class ConnectivityCompat(
callback: NetworkChangeCallback? callback: NetworkChangeCallback?
) : Connectivity { ) : Connectivity {
private val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager private val cm = context.getConnectivityManager()
private val connectivity: Connectivity = private val connectivity: Connectivity =
when { when {
cm == null -> UnknownConnectivity
Build.VERSION.SDK_INT >= Build.VERSION_CODES.N -> ConnectivityApi24(cm, callback) Build.VERSION.SDK_INT >= Build.VERSION_CODES.N -> ConnectivityApi24(cm, callback)
else -> ConnectivityLegacy(context, cm, callback) else -> ConnectivityLegacy(context, cm, callback)
} }
@ -125,3 +127,21 @@ internal class ConnectivityApi24(
} }
} }
} }
/**
* Connectivity used in cases where we cannot access the system ConnectivityManager.
* We assume that there is some sort of network and do not attempt to report any network changes.
*/
internal object UnknownConnectivity : Connectivity {
override fun registerForNetworkChanges() {}
override fun unregisterForNetworkChanges() {}
override fun hasNetworkConnection(): Boolean {
return true
}
override fun retrieveNetworkAccessState(): String {
return "unknown"
}
}

@ -1,10 +1,14 @@
package com.bugsnag.android package com.bugsnag.android
import android.app.ActivityManager
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.IntentFilter import android.content.IntentFilter
import android.net.ConnectivityManager
import android.os.RemoteException import android.os.RemoteException
import android.os.storage.StorageManager
import java.lang.RuntimeException
/** /**
* Calls [Context.registerReceiver] but swallows [SecurityException] and [RemoteException] * Calls [Context.registerReceiver] but swallows [SecurityException] and [RemoteException]
@ -45,3 +49,23 @@ internal fun Context.unregisterReceiverSafe(
logger?.w("Failed to register receiver", exc) logger?.w("Failed to register receiver", exc)
} }
} }
private inline fun <reified T> Context.safeGetSystemService(name: String): T? {
return try {
getSystemService(name) as? T
} catch (exc: RuntimeException) {
null
}
}
@JvmName("getActivityManagerFrom")
internal fun Context.getActivityManager(): ActivityManager? =
safeGetSystemService(Context.ACTIVITY_SERVICE)
@JvmName("getConnectivityManagerFrom")
internal fun Context.getConnectivityManager(): ConnectivityManager? =
safeGetSystemService(Context.CONNECTIVITY_SERVICE)
@JvmName("getStorageManagerFrom")
internal fun Context.getStorageManager(): StorageManager? =
safeGetSystemService(Context.STORAGE_SERVICE)

@ -42,7 +42,7 @@ class DeviceWithState internal constructor(
writer.name("orientation").value(orientation) writer.name("orientation").value(orientation)
if (time != null) { if (time != null) {
writer.name("time").value(DateUtils.toIso8601(time!!)) writer.name("time").value(time)
} }
} }
} }

@ -11,17 +11,17 @@ internal class ErrorInternal @JvmOverloads internal constructor(
internal companion object { internal companion object {
fun createError(exc: Throwable, projectPackages: Collection<String>, logger: Logger): MutableList<Error> { fun createError(exc: Throwable, projectPackages: Collection<String>, logger: Logger): MutableList<Error> {
val errors = mutableListOf<ErrorInternal>() return exc.safeUnrollCauses()
.mapTo(mutableListOf()) { currentEx ->
// Somehow it's possible for stackTrace to be null in rare cases
val stacktrace = currentEx.stackTrace ?: arrayOf<StackTraceElement>()
val trace =
Stacktrace.stacktraceFromJavaTrace(stacktrace, projectPackages, logger)
val errorInternal =
ErrorInternal(currentEx.javaClass.name, currentEx.localizedMessage, trace)
var currentEx: Throwable? = exc return@mapTo Error(errorInternal, logger)
while (currentEx != null) { }
// Somehow it's possible for stackTrace to be null in rare cases
val stacktrace = currentEx.stackTrace ?: arrayOf<StackTraceElement>()
val trace = Stacktrace.stacktraceFromJavaTrace(stacktrace, projectPackages, logger)
errors.add(ErrorInternal(currentEx.javaClass.name, currentEx.localizedMessage, trace))
currentEx = currentEx.cause
}
return errors.map { Error(it, logger) }.toMutableList()
} }
} }

@ -109,7 +109,7 @@ internal class EventInternal @JvmOverloads internal constructor(
val copy = Session.copySession(session) val copy = Session.copySession(session)
writer.name("session").beginObject() writer.name("session").beginObject()
writer.name("id").value(copy.id) writer.name("id").value(copy.id)
writer.name("startedAt").value(DateUtils.toIso8601(copy.startedAt)) writer.name("startedAt").value(copy.startedAt)
writer.name("events").beginObject() writer.name("events").beginObject()
writer.name("handled").value(copy.handledCount.toLong()) writer.name("handled").value(copy.handledCount.toLong())
writer.name("unhandled").value(copy.unhandledCount.toLong()) writer.name("unhandled").value(copy.unhandledCount.toLong())

@ -1,20 +1,23 @@
package com.bugsnag.android; package com.bugsnag.android;
import static com.bugsnag.android.ContextExtensionsKt.getActivityManagerFrom;
import android.app.ActivityManager; import android.app.ActivityManager;
import android.content.Context; import android.content.Context;
import android.os.Build; import android.os.Build;
import android.os.Process; import android.os.Process;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import java.util.List; import java.util.List;
class ForegroundDetector { class ForegroundDetector {
@Nullable
private final ActivityManager activityManager; private final ActivityManager activityManager;
ForegroundDetector(Context context) { ForegroundDetector(Context context) {
this.activityManager = this.activityManager = getActivityManagerFrom(context);
(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
} }
/** /**
@ -56,6 +59,10 @@ class ForegroundDetector {
@Nullable @Nullable
private ActivityManager.RunningAppProcessInfo getProcessInfoPreApi16() { private ActivityManager.RunningAppProcessInfo getProcessInfoPreApi16() {
if (activityManager == null) {
return null;
}
List<ActivityManager.RunningAppProcessInfo> appProcesses List<ActivityManager.RunningAppProcessInfo> appProcesses
= activityManager.getRunningAppProcesses(); = activityManager.getRunningAppProcesses();

@ -9,6 +9,7 @@ import android.os.Build;
import android.os.storage.StorageManager; import android.os.storage.StorageManager;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -22,6 +23,8 @@ class InternalReportDelegate implements EventStore.Delegate {
final Logger logger; final Logger logger;
final ImmutableConfig config; final ImmutableConfig config;
@Nullable
final StorageManager storageManager; final StorageManager storageManager;
final AppDataCollector appDataCollector; final AppDataCollector appDataCollector;
@ -34,7 +37,7 @@ class InternalReportDelegate implements EventStore.Delegate {
InternalReportDelegate(Context context, InternalReportDelegate(Context context,
Logger logger, Logger logger,
ImmutableConfig immutableConfig, ImmutableConfig immutableConfig,
StorageManager storageManager, @Nullable StorageManager storageManager,
AppDataCollector appDataCollector, AppDataCollector appDataCollector,
DeviceDataCollector deviceDataCollector, DeviceDataCollector deviceDataCollector,
SessionTracker sessionTracker, SessionTracker sessionTracker,
@ -72,7 +75,7 @@ class InternalReportDelegate implements EventStore.Delegate {
} }
void recordStorageCacheBehavior(Event event) { void recordStorageCacheBehavior(Event event) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (storageManager != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
File cacheDir = appContext.getCacheDir(); File cacheDir = appContext.getCacheDir();
File errDir = new File(cacheDir, "bugsnag-errors"); File errDir = new File(cacheDir, "bugsnag-errors");
@ -113,7 +116,7 @@ class InternalReportDelegate implements EventStore.Delegate {
// can only modify headers if DefaultDelivery is in use // can only modify headers if DefaultDelivery is in use
if (delivery instanceof DefaultDelivery) { if (delivery instanceof DefaultDelivery) {
Map<String, String> headers = params.getHeaders(); Map<String, String> headers = params.getHeaders();
headers.put(HEADER_INTERNAL_ERROR, "true"); headers.put(HEADER_INTERNAL_ERROR, "bugsnag-android");
headers.remove(DeliveryHeadersKt.HEADER_API_KEY); headers.remove(DeliveryHeadersKt.HEADER_API_KEY);
DefaultDelivery defaultDelivery = (DefaultDelivery) delivery; DefaultDelivery defaultDelivery = (DefaultDelivery) delivery;
defaultDelivery.deliver(params.getEndpoint(), payload, headers); defaultDelivery.deliver(params.getEndpoint(), payload, headers);

@ -7,7 +7,7 @@ import java.io.IOException
*/ */
class Notifier @JvmOverloads constructor( class Notifier @JvmOverloads constructor(
var name: String = "Android Bugsnag Notifier", var name: String = "Android Bugsnag Notifier",
var version: String = "5.9.2", var version: String = "5.9.3",
var url: String = "https://bugsnag.com" var url: String = "https://bugsnag.com"
) : JsonStream.Streamable { ) : JsonStream.Streamable {

@ -2,6 +2,7 @@ package com.bugsnag.android
import java.io.IOException import java.io.IOException
import java.lang.reflect.Array import java.lang.reflect.Array
import java.util.Date
internal class ObjectJsonStreamer { internal class ObjectJsonStreamer {
@ -21,6 +22,7 @@ internal class ObjectJsonStreamer {
obj is Number -> writer.value(obj) obj is Number -> writer.value(obj)
obj is Boolean -> writer.value(obj) obj is Boolean -> writer.value(obj)
obj is JsonStream.Streamable -> obj.toStream(writer) obj is JsonStream.Streamable -> obj.toStream(writer)
obj is Date -> writer.value(DateUtils.toIso8601(obj))
obj is Map<*, *> -> mapToStream(writer, obj, shouldRedactKeys) obj is Map<*, *> -> mapToStream(writer, obj, shouldRedactKeys)
obj is Collection<*> -> collectionToStream(writer, obj) obj is Collection<*> -> collectionToStream(writer, obj)
obj.javaClass.isArray -> arrayToStream(writer, obj) obj.javaClass.isArray -> arrayToStream(writer, obj)

@ -232,7 +232,7 @@ public final class Session implements JsonStream.Streamable, UserAware {
void serializeSessionInfo(@NonNull JsonStream writer) throws IOException { void serializeSessionInfo(@NonNull JsonStream writer) throws IOException {
writer.beginObject(); writer.beginObject();
writer.name("id").value(id); writer.name("id").value(id);
writer.name("startedAt").value(DateUtils.toIso8601(startedAt)); writer.name("startedAt").value(startedAt);
writer.name("user").value(user); writer.name("user").value(user);
writer.endObject(); writer.endObject();
} }

@ -2,9 +2,11 @@ package com.bugsnag.android;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.text.TextUtils; import android.text.TextUtils;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
@ -87,12 +89,7 @@ class StrictModeHandler {
* @return the root cause of the throwable * @return the root cause of the throwable
*/ */
private Throwable getRootCause(Throwable throwable) { private Throwable getRootCause(Throwable throwable) {
Throwable cause = throwable.getCause(); List<Throwable> causes = ThrowableUtils.safeUnrollCauses(throwable);
return causes.get(causes.size() - 1);
if (cause == null) {
return throwable;
} else {
return getRootCause(cause);
}
} }
} }

@ -5,14 +5,14 @@ import java.io.IOException
/** /**
* Capture and serialize the state of all threads at the time of an exception. * Capture and serialize the state of all threads at the time of an exception.
*/ */
internal class ThreadState @JvmOverloads constructor( internal class ThreadState @Suppress("LongParameterList") @JvmOverloads constructor(
exc: Throwable?, exc: Throwable?,
isUnhandled: Boolean, isUnhandled: Boolean,
sendThreads: ThreadSendPolicy, sendThreads: ThreadSendPolicy,
projectPackages: Collection<String>, projectPackages: Collection<String>,
logger: Logger, logger: Logger,
currentThread: java.lang.Thread = java.lang.Thread.currentThread(), currentThread: java.lang.Thread = java.lang.Thread.currentThread(),
stackTraces: MutableMap<java.lang.Thread, Array<StackTraceElement>> = java.lang.Thread.getAllStackTraces() stackTraces: MutableMap<java.lang.Thread, Array<StackTraceElement>>? = null
) : JsonStream.Streamable { ) : JsonStream.Streamable {
internal constructor( internal constructor(
@ -29,7 +29,7 @@ internal class ThreadState @JvmOverloads constructor(
threads = when { threads = when {
recordThreads -> captureThreadTrace( recordThreads -> captureThreadTrace(
stackTraces, stackTraces ?: java.lang.Thread.getAllStackTraces(),
currentThread, currentThread,
exc, exc,
isUnhandled, isUnhandled,

@ -0,0 +1,19 @@
@file:JvmName("ThrowableUtils")
package com.bugsnag.android
/**
* Unroll the list of causes for this Throwable, handling any recursion that may appear within
* the chain. The first element returned will be this Throwable, and the last will be the root
* cause or last non-recursive Throwable.
*/
internal fun Throwable.safeUnrollCauses(): List<Throwable> {
val causes = LinkedHashSet<Throwable>()
var currentEx: Throwable? = this
// Set.add will return false if we have already "seen" currentEx
while (currentEx != null && causes.add(currentEx)) {
currentEx = currentEx.cause
}
return causes.toList()
}
Loading…
Cancel
Save