mirror of https://github.com/M66B/FairEmail.git
Updated Bugsnag
This commit is contained in:
parent
caab02b0d6
commit
3989504073
|
@ -575,7 +575,7 @@ dependencies {
|
|||
def minidns_version = "1.0.5"
|
||||
def openpgp_version = "12.0"
|
||||
def badge_version = "1.1.22"
|
||||
def bugsnag_version = "6.1.0"
|
||||
def bugsnag_version = "6.4.0"
|
||||
def biweekly_version = "0.6.8"
|
||||
def vcard_version = "0.12.1"
|
||||
def relinker_version = "1.4.5"
|
||||
|
|
|
@ -2,11 +2,26 @@ package com.bugsnag.android
|
|||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.ActivityManager
|
||||
import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_CACHED
|
||||
import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_CANT_SAVE_STATE
|
||||
import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY
|
||||
import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
|
||||
import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE
|
||||
import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE
|
||||
import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE
|
||||
import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE_PRE_26
|
||||
import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE
|
||||
import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_TOP_SLEEPING
|
||||
import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_TOP_SLEEPING_PRE_28
|
||||
import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE
|
||||
import android.app.ActivityManager.RunningAppProcessInfo.REASON_PROVIDER_IN_USE
|
||||
import android.app.ActivityManager.RunningAppProcessInfo.REASON_SERVICE_IN_USE
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build.VERSION
|
||||
import android.os.Build.VERSION_CODES
|
||||
import android.os.Process
|
||||
import android.os.SystemClock
|
||||
import com.bugsnag.android.internal.ImmutableConfig
|
||||
|
||||
|
@ -49,12 +64,57 @@ internal class AppDataCollector(
|
|||
)
|
||||
}
|
||||
|
||||
@SuppressLint("SwitchIntDef")
|
||||
@Suppress("DEPRECATION")
|
||||
private fun getProcessImportance(): String? {
|
||||
try {
|
||||
val appInfo = ActivityManager.RunningAppProcessInfo()
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
|
||||
ActivityManager.getMyMemoryState(appInfo)
|
||||
} else {
|
||||
val expectedPid = Process.myPid()
|
||||
activityManager?.runningAppProcesses
|
||||
?.find { it.pid == expectedPid }
|
||||
?.let {
|
||||
appInfo.importance = it.importance
|
||||
appInfo.pid = expectedPid
|
||||
}
|
||||
}
|
||||
|
||||
if (appInfo.pid == 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
return when (appInfo.importance) {
|
||||
IMPORTANCE_FOREGROUND -> "foreground"
|
||||
IMPORTANCE_FOREGROUND_SERVICE -> "foreground service"
|
||||
IMPORTANCE_TOP_SLEEPING -> "top sleeping"
|
||||
IMPORTANCE_TOP_SLEEPING_PRE_28 -> "top sleeping"
|
||||
IMPORTANCE_VISIBLE -> "visible"
|
||||
IMPORTANCE_PERCEPTIBLE -> "perceptible"
|
||||
IMPORTANCE_PERCEPTIBLE_PRE_26 -> "perceptible"
|
||||
IMPORTANCE_CANT_SAVE_STATE -> "can't save state"
|
||||
IMPORTANCE_CANT_SAVE_STATE_PRE_26 -> "can't save state"
|
||||
IMPORTANCE_SERVICE -> "service"
|
||||
IMPORTANCE_CACHED -> "cached/background"
|
||||
IMPORTANCE_GONE -> "gone"
|
||||
IMPORTANCE_EMPTY -> "empty"
|
||||
REASON_PROVIDER_IN_USE -> "provider in use"
|
||||
REASON_SERVICE_IN_USE -> "service in use"
|
||||
else -> "unknown importance (${appInfo.importance})"
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
fun getAppDataMetadata(): MutableMap<String, Any?> {
|
||||
val map = HashMap<String, Any?>()
|
||||
map["name"] = appName
|
||||
map["activeScreen"] = sessionTracker.contextActivity
|
||||
map["lowMemory"] = memoryTrimState.isLowMemory
|
||||
map["memoryTrimLevel"] = memoryTrimState.trimLevelDescription
|
||||
map["processImportance"] = getProcessImportance()
|
||||
|
||||
populateRuntimeMemoryMetadata(map)
|
||||
|
||||
|
@ -128,6 +188,7 @@ internal class AppDataCollector(
|
|||
packageManager != null && copy != null -> {
|
||||
packageManager.getApplicationLabel(copy).toString()
|
||||
}
|
||||
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
@ -156,6 +217,7 @@ internal class AppDataCollector(
|
|||
VERSION.SDK_INT >= VERSION_CODES.P -> {
|
||||
Application.getProcessName()
|
||||
}
|
||||
|
||||
else -> {
|
||||
// see https://stackoverflow.com/questions/19631894
|
||||
val clz = Class.forName("android.app.ActivityThread")
|
||||
|
@ -179,5 +241,7 @@ internal class AppDataCollector(
|
|||
* good approximation for how long the app has been running.
|
||||
*/
|
||||
fun getDurationMs(): Long = SystemClock.elapsedRealtime() - startTimeMs
|
||||
|
||||
private const val IMPORTANCE_CANT_SAVE_STATE_PRE_26 = 170
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,12 +29,14 @@ internal class BugsnagEventMapper(
|
|||
event.userImpl = convertUser(map.readEntry("user"))
|
||||
|
||||
// populate metadata
|
||||
val metadataMap: Map<String, Map<String, Any?>> = map.readEntry("metaData")
|
||||
val metadataMap: Map<String, Map<String, Any?>> =
|
||||
(map["metaData"] as? Map<String, Map<String, Any?>>).orEmpty()
|
||||
metadataMap.forEach { (key, value) ->
|
||||
event.addMetadata(key, value)
|
||||
}
|
||||
|
||||
val featureFlagsList: List<Map<String, Any?>> = map.readEntry("featureFlags")
|
||||
val featureFlagsList: List<Map<String, Any?>> =
|
||||
(map["featureFlags"] as? List<Map<String, Any?>>).orEmpty()
|
||||
featureFlagsList.forEach { featureFlagMap ->
|
||||
event.addFeatureFlag(
|
||||
featureFlagMap.readEntry("featureFlag"),
|
||||
|
@ -43,7 +45,8 @@ internal class BugsnagEventMapper(
|
|||
}
|
||||
|
||||
// populate breadcrumbs
|
||||
val breadcrumbList: List<MutableMap<String, Any?>> = map.readEntry("breadcrumbs")
|
||||
val breadcrumbList: List<MutableMap<String, Any?>> =
|
||||
(map["breadcrumbs"] as? List<MutableMap<String, Any?>>).orEmpty()
|
||||
breadcrumbList.mapTo(event.breadcrumbs) {
|
||||
Breadcrumb(
|
||||
convertBreadcrumbInternal(it),
|
||||
|
@ -226,8 +229,7 @@ internal class BugsnagEventMapper(
|
|||
is T -> return value
|
||||
null -> throw IllegalStateException("cannot find json property '$key'")
|
||||
else -> throw IllegalArgumentException(
|
||||
"json property '$key' not " +
|
||||
"of expected type, found ${value.javaClass.name}"
|
||||
"json property '$key' not of expected type, found ${value.javaClass.name}"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ internal class ConfigInternal(
|
|||
var releaseStage: String? = null
|
||||
var sendThreads: ThreadSendPolicy = ThreadSendPolicy.ALWAYS
|
||||
var persistUser: Boolean = true
|
||||
var generateAnonymousId: Boolean = true
|
||||
|
||||
var launchDurationMillis: Long = DEFAULT_LAUNCH_CRASH_THRESHOLD_MS
|
||||
|
||||
|
|
|
@ -178,6 +178,26 @@ public class Configuration implements CallbackAware, MetadataAware, UserAware, F
|
|||
impl.setPersistUser(persistUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not Bugsnag should generate an anonymous ID and persist it in local storage
|
||||
*
|
||||
* If disabled, any device ID that has been persisted will not be retrieved, and no new
|
||||
* device ID will be generated or stored
|
||||
*/
|
||||
public boolean getGenerateAnonymousId() {
|
||||
return impl.getGenerateAnonymousId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not Bugsnag should generate an anonymous ID and persist it in local storage
|
||||
*
|
||||
* If disabled, any device ID that has been persisted will not be retrieved, and no new
|
||||
* device ID will be generated or stored
|
||||
*/
|
||||
public void setGenerateAnonymousId(boolean generateAnonymousId) {
|
||||
impl.setGenerateAnonymousId(generateAnonymousId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the directory where event and session JSON payloads should be persisted if a network
|
||||
* request is not successful. If you use Bugsnag in multiple processes, then a unique
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.bugsnag.android
|
||||
|
||||
import android.content.Context
|
||||
import com.bugsnag.android.internal.ImmutableConfig
|
||||
import java.io.File
|
||||
import java.util.UUID
|
||||
|
||||
|
@ -8,18 +9,20 @@ import java.util.UUID
|
|||
* This class is responsible for persisting and retrieving the device ID and internal device ID,
|
||||
* which uniquely identify this device in various contexts.
|
||||
*/
|
||||
internal class DeviceIdStore @JvmOverloads constructor(
|
||||
internal class DeviceIdStore @JvmOverloads @Suppress("LongParameterList") constructor(
|
||||
context: Context,
|
||||
deviceIdfile: File = File(context.filesDir, "device-id"),
|
||||
deviceIdGenerator: () -> UUID = { UUID.randomUUID() },
|
||||
internalDeviceIdfile: File = File(context.filesDir, "internal-device-id"),
|
||||
internalDeviceIdGenerator: () -> UUID = { UUID.randomUUID() },
|
||||
private val sharedPrefMigrator: SharedPrefMigrator,
|
||||
config: ImmutableConfig,
|
||||
logger: Logger
|
||||
) {
|
||||
|
||||
private val persistence: DeviceIdPersistence
|
||||
private val internalPersistence: DeviceIdPersistence
|
||||
private val generateId = config.generateAnonymousId
|
||||
|
||||
init {
|
||||
persistence = DeviceIdFilePersistence(deviceIdfile, deviceIdGenerator, logger)
|
||||
|
@ -35,6 +38,12 @@ internal class DeviceIdStore @JvmOverloads constructor(
|
|||
* be used. If no value is present then a random UUID will be generated and persisted.
|
||||
*/
|
||||
fun loadDeviceId(): String? {
|
||||
// If generateAnonymousId = false, return null
|
||||
// so that a previously persisted device ID is not returned,
|
||||
// or a new one is not generated and persisted
|
||||
if (!generateId) {
|
||||
return null
|
||||
}
|
||||
var result = persistence.loadDeviceId(false)
|
||||
if (result != null) {
|
||||
return result
|
||||
|
@ -47,6 +56,12 @@ internal class DeviceIdStore @JvmOverloads constructor(
|
|||
}
|
||||
|
||||
fun loadInternalDeviceId(): String? {
|
||||
// If generateAnonymousId = false, return null
|
||||
// so that a previously persisted device ID is not returned,
|
||||
// or a new one is not generated and persisted
|
||||
if (!generateId) {
|
||||
return null
|
||||
}
|
||||
return internalPersistence.loadDeviceId(true)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,42 +1,113 @@
|
|||
package com.bugsnag.android
|
||||
|
||||
import java.io.IOException
|
||||
import kotlin.math.max
|
||||
|
||||
internal class FeatureFlags(
|
||||
internal val store: MutableMap<String, String?> = mutableMapOf()
|
||||
internal class FeatureFlags private constructor(
|
||||
@Volatile
|
||||
private var flags: Array<FeatureFlag>
|
||||
) : JsonStream.Streamable, FeatureFlagAware {
|
||||
private val emptyVariant = "__EMPTY_VARIANT_SENTINEL__"
|
||||
|
||||
@Synchronized override fun addFeatureFlag(name: String) {
|
||||
/*
|
||||
* Implemented as *effectively* a CopyOnWriteArrayList - but since FeatureFlags are
|
||||
* key/value pairs, CopyOnWriteArrayList would require external locking (in addition to it's
|
||||
* internal locking) for us to be sure we are not adding duplicates.
|
||||
*
|
||||
* This class aims to have similar performance while also ensuring that the FeatureFlag object
|
||||
* themselves don't leak, as they are mutable and we want 'copy' to be an O(1) snapshot
|
||||
* operation for when an Event is created.
|
||||
*
|
||||
* It's assumed that *most* FeatureFlags will be added up-front, or during the normal app
|
||||
* lifecycle (not during an Event).
|
||||
*
|
||||
* As such a copy-on-write structure allows an Event to simply capture a reference to the
|
||||
* "snapshot" of FeatureFlags that were active when the Event was created.
|
||||
*/
|
||||
|
||||
constructor() : this(emptyArray<FeatureFlag>())
|
||||
|
||||
override fun addFeatureFlag(name: String) {
|
||||
addFeatureFlag(name, null)
|
||||
}
|
||||
|
||||
@Synchronized override fun addFeatureFlag(name: String, variant: String?) {
|
||||
store[name] = variant ?: emptyVariant
|
||||
}
|
||||
override fun addFeatureFlag(name: String, variant: String?) {
|
||||
synchronized(this) {
|
||||
val flagArray = flags
|
||||
val index = flagArray.indexOfFirst { it.name == name }
|
||||
|
||||
@Synchronized override fun addFeatureFlags(featureFlags: Iterable<FeatureFlag>) {
|
||||
featureFlags.forEach { (name, variant) ->
|
||||
addFeatureFlag(name, variant)
|
||||
flags = when {
|
||||
// this is a new FeatureFlag
|
||||
index == -1 -> flagArray + FeatureFlag(name, variant)
|
||||
|
||||
// this is a change to an existing FeatureFlag
|
||||
flagArray[index].variant != variant -> flagArray.copyOf().also {
|
||||
// replace the existing FeatureFlag in-place
|
||||
it[index] = FeatureFlag(name, variant)
|
||||
}
|
||||
|
||||
// no actual change, so we return
|
||||
else -> return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized override fun clearFeatureFlag(name: String) {
|
||||
store.remove(name)
|
||||
override fun addFeatureFlags(featureFlags: Iterable<FeatureFlag>) {
|
||||
synchronized(this) {
|
||||
val flagArray = flags
|
||||
|
||||
val newFlags = ArrayList<FeatureFlag>(
|
||||
// try to guess a reasonable upper-bound for the output array
|
||||
if (featureFlags is Collection<*>) flagArray.size + featureFlags.size
|
||||
else max(flagArray.size * 2, flagArray.size)
|
||||
)
|
||||
|
||||
newFlags.addAll(flagArray)
|
||||
|
||||
featureFlags.forEach { (name, variant) ->
|
||||
val existingIndex = newFlags.indexOfFirst { it.name == name }
|
||||
when (existingIndex) {
|
||||
// add a new flag to the end of the list
|
||||
-1 -> newFlags.add(FeatureFlag(name, variant))
|
||||
// replace the existing flag
|
||||
else -> newFlags[existingIndex] = FeatureFlag(name, variant)
|
||||
}
|
||||
}
|
||||
|
||||
flags = newFlags.toTypedArray()
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized override fun clearFeatureFlags() {
|
||||
store.clear()
|
||||
override fun clearFeatureFlag(name: String) {
|
||||
synchronized(this) {
|
||||
val flagArray = flags
|
||||
val index = flagArray.indexOfFirst { it.name == name }
|
||||
if (index == -1) {
|
||||
return
|
||||
}
|
||||
|
||||
val out = arrayOfNulls<FeatureFlag>(flagArray.size - 1)
|
||||
flagArray.copyInto(out, 0, 0, index)
|
||||
flagArray.copyInto(out, index, index + 1)
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
flags = out as Array<FeatureFlag>
|
||||
}
|
||||
}
|
||||
|
||||
override fun clearFeatureFlags() {
|
||||
synchronized(this) {
|
||||
flags = emptyArray()
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun toStream(stream: JsonStream) {
|
||||
val storeCopy = synchronized(this) { store.toMap() }
|
||||
val storeCopy = flags
|
||||
stream.beginArray()
|
||||
storeCopy.forEach { (name, variant) ->
|
||||
stream.beginObject()
|
||||
stream.name("featureFlag").value(name)
|
||||
if (variant != emptyVariant) {
|
||||
if (variant != null) {
|
||||
stream.name("variant").value(variant)
|
||||
}
|
||||
stream.endObject()
|
||||
|
@ -44,9 +115,7 @@ internal class FeatureFlags(
|
|||
stream.endArray()
|
||||
}
|
||||
|
||||
@Synchronized fun toList(): List<FeatureFlag> = store.entries.map { (name, variant) ->
|
||||
FeatureFlag(name, variant.takeUnless { it == emptyVariant })
|
||||
}
|
||||
fun toList(): List<FeatureFlag> = flags.map { (name, variant) -> FeatureFlag(name, variant) }
|
||||
|
||||
@Synchronized fun copy() = FeatureFlags(store.toMutableMap())
|
||||
fun copy() = FeatureFlags(flags)
|
||||
}
|
||||
|
|
|
@ -145,6 +145,7 @@ class JsonWriter implements Closeable, Flushable {
|
|||
*/
|
||||
private static final String[] REPLACEMENT_CHARS;
|
||||
private static final String[] HTML_SAFE_REPLACEMENT_CHARS;
|
||||
|
||||
static {
|
||||
REPLACEMENT_CHARS = new String[128];
|
||||
for (int i = 0; i <= 0x1f; i++) {
|
||||
|
@ -165,11 +166,14 @@ class JsonWriter implements Closeable, Flushable {
|
|||
HTML_SAFE_REPLACEMENT_CHARS['\''] = "\\u0027";
|
||||
}
|
||||
|
||||
/** The output data, containing at most one top-level array or object. */
|
||||
/**
|
||||
* The output data, containing at most one top-level array or object.
|
||||
*/
|
||||
private final Writer out;
|
||||
|
||||
private int[] stack = new int[32];
|
||||
private int stackSize = 0;
|
||||
|
||||
{
|
||||
push(EMPTY_DOCUMENT);
|
||||
}
|
||||
|
@ -337,7 +341,7 @@ class JsonWriter implements Closeable, Flushable {
|
|||
* given bracket.
|
||||
*/
|
||||
private JsonWriter close(int empty, int nonempty, String closeBracket)
|
||||
throws IOException {
|
||||
throws IOException {
|
||||
int context = peek();
|
||||
if (context != nonempty && context != empty) {
|
||||
throw new IllegalStateException("Nesting problem.");
|
||||
|
@ -437,7 +441,7 @@ class JsonWriter implements Closeable, Flushable {
|
|||
}
|
||||
writeDeferredName();
|
||||
beforeValue();
|
||||
out.append(value);
|
||||
out.write(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -490,17 +494,18 @@ class JsonWriter implements Closeable, Flushable {
|
|||
/**
|
||||
* Encodes {@code value}.
|
||||
*
|
||||
* @param value a finite value. May not be {@link Double#isNaN() NaNs} or
|
||||
* {@link Double#isInfinite() infinities}.
|
||||
* @param value a finite value.
|
||||
* @return this writer.
|
||||
*/
|
||||
public JsonWriter value(double value) throws IOException {
|
||||
writeDeferredName();
|
||||
if (!lenient && (Double.isNaN(value) || Double.isInfinite(value))) {
|
||||
throw new IllegalArgumentException("Numeric values must be finite, but was " + value);
|
||||
// omit these values instead of attempting to write them
|
||||
deferredName = null;
|
||||
} else {
|
||||
writeDeferredName();
|
||||
beforeValue();
|
||||
out.write(Double.toString(value));
|
||||
}
|
||||
beforeValue();
|
||||
out.append(Double.toString(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -520,7 +525,7 @@ class JsonWriter implements Closeable, Flushable {
|
|||
* Encodes {@code value}.
|
||||
*
|
||||
* @param value a finite value. May not be {@link Double#isNaN() NaNs} or
|
||||
* {@link Double#isInfinite() infinities}.
|
||||
* {@link Double#isInfinite() infinities}.
|
||||
* @return this writer.
|
||||
*/
|
||||
public JsonWriter value(Number value) throws IOException {
|
||||
|
@ -528,14 +533,16 @@ class JsonWriter implements Closeable, Flushable {
|
|||
return nullValue();
|
||||
}
|
||||
|
||||
writeDeferredName();
|
||||
String string = value.toString();
|
||||
if (!lenient
|
||||
&& (string.equals("-Infinity") || string.equals("Infinity") || string.equals("NaN"))) {
|
||||
throw new IllegalArgumentException("Numeric values must be finite, but was " + value);
|
||||
&& (string.equals("-Infinity") || string.equals("Infinity") || string.equals("NaN"))) {
|
||||
// omit this value
|
||||
deferredName = null;
|
||||
} else {
|
||||
writeDeferredName();
|
||||
beforeValue();
|
||||
out.write(string);
|
||||
}
|
||||
beforeValue();
|
||||
out.append(string);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -634,7 +641,7 @@ class JsonWriter implements Closeable, Flushable {
|
|||
case NONEMPTY_DOCUMENT:
|
||||
if (!lenient) {
|
||||
throw new IllegalStateException(
|
||||
"JSON must have only one top-level value.");
|
||||
"JSON must have only one top-level value.");
|
||||
}
|
||||
// fall-through
|
||||
case EMPTY_DOCUMENT: // first in document
|
||||
|
@ -647,12 +654,12 @@ class JsonWriter implements Closeable, Flushable {
|
|||
break;
|
||||
|
||||
case NONEMPTY_ARRAY: // another in array
|
||||
out.append(',');
|
||||
out.write(',');
|
||||
newline();
|
||||
break;
|
||||
|
||||
case DANGLING_NAME: // value for name
|
||||
out.append(separator);
|
||||
out.write(separator);
|
||||
replaceTop(NONEMPTY_OBJECT);
|
||||
break;
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ internal class ManifestConfigLoader {
|
|||
private const val AUTO_DETECT_ERRORS = "$BUGSNAG_NS.AUTO_DETECT_ERRORS"
|
||||
private const val PERSIST_USER = "$BUGSNAG_NS.PERSIST_USER"
|
||||
private const val SEND_THREADS = "$BUGSNAG_NS.SEND_THREADS"
|
||||
private const val GENERATE_ANONYMOUS_ID = "$BUGSNAG_NS.GENERATE_ANONYMOUS_ID"
|
||||
|
||||
// endpoints
|
||||
private const val ENDPOINT_NOTIFY = "$BUGSNAG_NS.ENDPOINT_NOTIFY"
|
||||
|
@ -108,6 +109,7 @@ internal class ManifestConfigLoader {
|
|||
autoTrackSessions = data.getBoolean(AUTO_TRACK_SESSIONS, autoTrackSessions)
|
||||
autoDetectErrors = data.getBoolean(AUTO_DETECT_ERRORS, autoDetectErrors)
|
||||
persistUser = data.getBoolean(PERSIST_USER, persistUser)
|
||||
generateAnonymousId = data.getBoolean(GENERATE_ANONYMOUS_ID, generateAnonymousId)
|
||||
|
||||
val str = data.getString(SEND_THREADS)
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import java.io.IOException
|
|||
*/
|
||||
class Notifier @JvmOverloads constructor(
|
||||
var name: String = "Android Bugsnag Notifier",
|
||||
var version: String = "6.1.0",
|
||||
var version: String = "6.4.0",
|
||||
var url: String = "https://bugsnag.com"
|
||||
) : JsonStream.Streamable {
|
||||
|
||||
|
|
|
@ -11,9 +11,11 @@ internal class ObjectJsonStreamer {
|
|||
companion object {
|
||||
internal const val REDACTED_PLACEHOLDER = "[REDACTED]"
|
||||
internal const val OBJECT_PLACEHOLDER = "[OBJECT]"
|
||||
|
||||
internal val DEFAULT_REDACTED_KEYS = setOf(Pattern.compile(".*password.*", Pattern.CASE_INSENSITIVE))
|
||||
}
|
||||
|
||||
var redactedKeys = setOf(Pattern.compile(".*password.*", Pattern.CASE_INSENSITIVE))
|
||||
var redactedKeys = DEFAULT_REDACTED_KEYS
|
||||
|
||||
// Write complex/nested values to a JsonStreamer
|
||||
@Throws(IOException::class)
|
||||
|
|
|
@ -36,6 +36,7 @@ class SessionTracker extends BaseObservable implements ForegroundDetector.OnActi
|
|||
private volatile Session currentSession = null;
|
||||
final BackgroundTaskService backgroundTaskService;
|
||||
final Logger logger;
|
||||
private boolean shouldSuppressFirstAutoSession = false;
|
||||
|
||||
SessionTracker(ImmutableConfig configuration,
|
||||
CallbackState callbackState,
|
||||
|
@ -76,7 +77,7 @@ class SessionTracker extends BaseObservable implements ForegroundDetector.OnActi
|
|||
@VisibleForTesting
|
||||
Session startNewSession(@NonNull Date date, @Nullable User user,
|
||||
boolean autoCaptured) {
|
||||
if (client.getConfig().shouldDiscardSession(autoCaptured)) {
|
||||
if (shouldDiscardSession(autoCaptured)) {
|
||||
return null;
|
||||
}
|
||||
String id = UUID.randomUUID().toString();
|
||||
|
@ -92,12 +93,29 @@ class SessionTracker extends BaseObservable implements ForegroundDetector.OnActi
|
|||
}
|
||||
|
||||
Session startSession(boolean autoCaptured) {
|
||||
if (client.getConfig().shouldDiscardSession(autoCaptured)) {
|
||||
if (shouldDiscardSession(autoCaptured)) {
|
||||
return null;
|
||||
}
|
||||
return startNewSession(new Date(), client.getUser(), autoCaptured);
|
||||
}
|
||||
|
||||
private boolean shouldDiscardSession(boolean autoCaptured) {
|
||||
if (client.getConfig().shouldDiscardSession(autoCaptured)) {
|
||||
return true;
|
||||
} else {
|
||||
Session existingSession = currentSession;
|
||||
if (autoCaptured
|
||||
&& existingSession != null
|
||||
&& !existingSession.isAutoCaptured()
|
||||
&& shouldSuppressFirstAutoSession) {
|
||||
shouldSuppressFirstAutoSession = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void pauseSession() {
|
||||
Session session = currentSession;
|
||||
|
||||
|
|
|
@ -19,7 +19,8 @@ internal class StorageModule(
|
|||
DeviceIdStore(
|
||||
appContext,
|
||||
sharedPrefMigrator = sharedPrefMigrator,
|
||||
logger = logger
|
||||
logger = logger,
|
||||
config = immutableConfig
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,9 @@ internal class UserStore @JvmOverloads constructor(
|
|||
* [Configuration.getPersistUser] is true.
|
||||
*
|
||||
* If no user is stored on disk, then a default [User] is used which uses the device ID
|
||||
* as its ID.
|
||||
* as its ID (unless the generateAnonymousId config option is set to false, in which case the
|
||||
* device ID and therefore the user ID is set to
|
||||
* null).
|
||||
*
|
||||
* The [UserState] provides a mechanism for observing value changes to its user property,
|
||||
* so to avoid interfering with this the method should only be called once for each [Client].
|
||||
|
@ -46,6 +48,8 @@ internal class UserStore @JvmOverloads constructor(
|
|||
|
||||
val userState = when {
|
||||
loadedUser != null && validUser(loadedUser) -> UserState(loadedUser)
|
||||
// if generateAnonymousId config option is false, the deviceId should already be null
|
||||
// here
|
||||
else -> UserState(User(deviceId, null, null))
|
||||
}
|
||||
|
||||
|
|
|
@ -57,6 +57,7 @@ data class ImmutableConfig(
|
|||
val persistenceDirectory: Lazy<File>,
|
||||
val sendLaunchCrashesSynchronously: Boolean,
|
||||
val attemptDeliveryOnCrash: Boolean,
|
||||
val generateAnonymousId: Boolean,
|
||||
|
||||
// results cached here to avoid unnecessary lookups in Client.
|
||||
val packageInfo: PackageInfo?,
|
||||
|
@ -166,6 +167,7 @@ internal fun convertToImmutableConfig(
|
|||
delivery = config.delivery,
|
||||
endpoints = config.endpoints,
|
||||
persistUser = config.persistUser,
|
||||
generateAnonymousId = config.generateAnonymousId,
|
||||
launchDurationMillis = config.launchDurationMillis,
|
||||
logger = config.logger!!,
|
||||
maxBreadcrumbs = config.maxBreadcrumbs,
|
||||
|
|
Loading…
Reference in New Issue