mirror of https://github.com/M66B/FairEmail.git
Updated Bugsnag to v5.30.0
This commit is contained in:
parent
03de3b55c9
commit
21c71ffcc8
|
@ -3,47 +3,56 @@ package com.bugsnag.android
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import java.util.WeakHashMap
|
||||||
|
|
||||||
internal class ActivityBreadcrumbCollector(
|
internal class ActivityBreadcrumbCollector(
|
||||||
private val cb: (message: String, method: Map<String, Any>) -> Unit
|
private val cb: (message: String, method: Map<String, Any>) -> Unit
|
||||||
) : Application.ActivityLifecycleCallbacks {
|
) : Application.ActivityLifecycleCallbacks {
|
||||||
|
|
||||||
var prevState: String? = null
|
private val prevState = WeakHashMap<Activity, String>()
|
||||||
|
|
||||||
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) =
|
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) =
|
||||||
leaveBreadcrumb(getActivityName(activity), "onCreate()", savedInstanceState != null)
|
leaveBreadcrumb(activity, "onCreate()", savedInstanceState != null)
|
||||||
|
|
||||||
override fun onActivityStarted(activity: Activity) =
|
override fun onActivityStarted(activity: Activity) =
|
||||||
leaveBreadcrumb(getActivityName(activity), "onStart()")
|
leaveBreadcrumb(activity, "onStart()")
|
||||||
|
|
||||||
override fun onActivityResumed(activity: Activity) =
|
override fun onActivityResumed(activity: Activity) =
|
||||||
leaveBreadcrumb(getActivityName(activity), "onResume()")
|
leaveBreadcrumb(activity, "onResume()")
|
||||||
|
|
||||||
override fun onActivityPaused(activity: Activity) =
|
override fun onActivityPaused(activity: Activity) =
|
||||||
leaveBreadcrumb(getActivityName(activity), "onPause()")
|
leaveBreadcrumb(activity, "onPause()")
|
||||||
|
|
||||||
override fun onActivityStopped(activity: Activity) =
|
override fun onActivityStopped(activity: Activity) =
|
||||||
leaveBreadcrumb(getActivityName(activity), "onStop()")
|
leaveBreadcrumb(activity, "onStop()")
|
||||||
|
|
||||||
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) =
|
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) =
|
||||||
leaveBreadcrumb(getActivityName(activity), "onSaveInstanceState()")
|
leaveBreadcrumb(activity, "onSaveInstanceState()")
|
||||||
|
|
||||||
override fun onActivityDestroyed(activity: Activity) =
|
override fun onActivityDestroyed(activity: Activity) {
|
||||||
leaveBreadcrumb(getActivityName(activity), "onDestroy()")
|
leaveBreadcrumb(activity, "onDestroy()")
|
||||||
|
prevState.remove(activity)
|
||||||
|
}
|
||||||
|
|
||||||
private fun getActivityName(activity: Activity) = activity.javaClass.simpleName
|
private fun getActivityName(activity: Activity) = activity.javaClass.simpleName
|
||||||
|
|
||||||
private fun leaveBreadcrumb(activityName: String, lifecycleCallback: String, hasBundle: Boolean? = null) {
|
private fun leaveBreadcrumb(
|
||||||
|
activity: Activity,
|
||||||
|
lifecycleCallback: String,
|
||||||
|
hasBundle: Boolean? = null
|
||||||
|
) {
|
||||||
val metadata = mutableMapOf<String, Any>()
|
val metadata = mutableMapOf<String, Any>()
|
||||||
if (hasBundle != null) {
|
if (hasBundle != null) {
|
||||||
metadata["hasBundle"] = hasBundle
|
metadata["hasBundle"] = hasBundle
|
||||||
}
|
}
|
||||||
val previousVal = prevState
|
val previousVal = prevState[activity]
|
||||||
|
|
||||||
if (previousVal != null) {
|
if (previousVal != null) {
|
||||||
metadata["previous"] = previousVal
|
metadata["previous"] = previousVal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val activityName = getActivityName(activity)
|
||||||
cb("$activityName#$lifecycleCallback", metadata)
|
cb("$activityName#$lifecycleCallback", metadata)
|
||||||
prevState = lifecycleCallback
|
prevState[activity] = lifecycleCallback
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,11 +2,13 @@ package com.bugsnag.android;
|
||||||
|
|
||||||
import static com.bugsnag.android.SeverityReason.REASON_HANDLED_EXCEPTION;
|
import static com.bugsnag.android.SeverityReason.REASON_HANDLED_EXCEPTION;
|
||||||
|
|
||||||
|
import com.bugsnag.android.internal.BackgroundTaskService;
|
||||||
import com.bugsnag.android.internal.ImmutableConfig;
|
import com.bugsnag.android.internal.ImmutableConfig;
|
||||||
import com.bugsnag.android.internal.InternalMetrics;
|
import com.bugsnag.android.internal.InternalMetrics;
|
||||||
import com.bugsnag.android.internal.InternalMetricsImpl;
|
import com.bugsnag.android.internal.InternalMetricsImpl;
|
||||||
import com.bugsnag.android.internal.InternalMetricsNoop;
|
import com.bugsnag.android.internal.InternalMetricsNoop;
|
||||||
import com.bugsnag.android.internal.StateObserver;
|
import com.bugsnag.android.internal.StateObserver;
|
||||||
|
import com.bugsnag.android.internal.TaskType;
|
||||||
import com.bugsnag.android.internal.dag.ConfigModule;
|
import com.bugsnag.android.internal.dag.ConfigModule;
|
||||||
import com.bugsnag.android.internal.dag.ContextModule;
|
import com.bugsnag.android.internal.dag.ContextModule;
|
||||||
import com.bugsnag.android.internal.dag.SystemServiceModule;
|
import com.bugsnag.android.internal.dag.SystemServiceModule;
|
||||||
|
@ -303,7 +305,7 @@ public class Client implements MetadataAware, CallbackAware, UserAware, FeatureF
|
||||||
registerListenersInBackground();
|
registerListenersInBackground();
|
||||||
|
|
||||||
// Leave auto breadcrumb
|
// Leave auto breadcrumb
|
||||||
Map<String, Object> data = Collections.emptyMap();
|
Map<String, Object> data = new HashMap<>();
|
||||||
leaveAutoBreadcrumb("Bugsnag loaded", BreadcrumbType.STATE, data);
|
leaveAutoBreadcrumb("Bugsnag loaded", BreadcrumbType.STATE, data);
|
||||||
|
|
||||||
logger.d("Bugsnag loaded");
|
logger.d("Bugsnag loaded");
|
||||||
|
|
|
@ -2,6 +2,7 @@ package com.bugsnag.android;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
|
import androidx.annotation.IntRange;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
@ -305,7 +306,7 @@ public class Configuration implements CallbackAware, MetadataAware, UserAware, F
|
||||||
* By default, this value is set at 5,000ms. Setting the value to 0 will count all crashes
|
* By default, this value is set at 5,000ms. Setting the value to 0 will count all crashes
|
||||||
* as launch crashes until markLaunchCompleted() is called.
|
* as launch crashes until markLaunchCompleted() is called.
|
||||||
*/
|
*/
|
||||||
public void setLaunchDurationMillis(long launchDurationMillis) {
|
public void setLaunchDurationMillis(@IntRange(from = 0) long launchDurationMillis) {
|
||||||
if (launchDurationMillis >= MIN_LAUNCH_CRASH_THRESHOLD_MS) {
|
if (launchDurationMillis >= MIN_LAUNCH_CRASH_THRESHOLD_MS) {
|
||||||
impl.setLaunchDurationMillis(launchDurationMillis);
|
impl.setLaunchDurationMillis(launchDurationMillis);
|
||||||
} else {
|
} else {
|
||||||
|
@ -524,12 +525,12 @@ public class Configuration implements CallbackAware, MetadataAware, UserAware, F
|
||||||
*
|
*
|
||||||
* By default, 100 breadcrumbs are stored: this can be amended up to a maximum of 500.
|
* By default, 100 breadcrumbs are stored: this can be amended up to a maximum of 500.
|
||||||
*/
|
*/
|
||||||
public void setMaxBreadcrumbs(int maxBreadcrumbs) {
|
public void setMaxBreadcrumbs(@IntRange(from = 0, to = 500) int maxBreadcrumbs) {
|
||||||
if (maxBreadcrumbs >= MIN_BREADCRUMBS && maxBreadcrumbs <= MAX_BREADCRUMBS) {
|
if (maxBreadcrumbs >= MIN_BREADCRUMBS && maxBreadcrumbs <= MAX_BREADCRUMBS) {
|
||||||
impl.setMaxBreadcrumbs(maxBreadcrumbs);
|
impl.setMaxBreadcrumbs(maxBreadcrumbs);
|
||||||
} else {
|
} else {
|
||||||
getLogger().e("Invalid configuration value detected. "
|
getLogger().e("Invalid configuration value detected. "
|
||||||
+ "Option maxBreadcrumbs should be an integer between 0-100. "
|
+ "Option maxBreadcrumbs should be an integer between 0-500. "
|
||||||
+ "Supplied value is " + maxBreadcrumbs);
|
+ "Supplied value is " + maxBreadcrumbs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -540,8 +541,8 @@ public class Configuration implements CallbackAware, MetadataAware, UserAware, F
|
||||||
*
|
*
|
||||||
* By default, 32 events are persisted.
|
* By default, 32 events are persisted.
|
||||||
*/
|
*/
|
||||||
public int getMaxPersistedEvents() {
|
public int getMaxPersistedEvents() {
|
||||||
return impl.getMaxPersistedEvents();
|
return impl.getMaxPersistedEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -550,7 +551,7 @@ public class Configuration implements CallbackAware, MetadataAware, UserAware, F
|
||||||
*
|
*
|
||||||
* By default, 32 events are persisted.
|
* By default, 32 events are persisted.
|
||||||
*/
|
*/
|
||||||
public void setMaxPersistedEvents(int maxPersistedEvents) {
|
public void setMaxPersistedEvents(@IntRange(from = 0) int maxPersistedEvents) {
|
||||||
if (maxPersistedEvents >= 0) {
|
if (maxPersistedEvents >= 0) {
|
||||||
impl.setMaxPersistedEvents(maxPersistedEvents);
|
impl.setMaxPersistedEvents(maxPersistedEvents);
|
||||||
} else {
|
} else {
|
||||||
|
@ -576,7 +577,7 @@ public class Configuration implements CallbackAware, MetadataAware, UserAware, F
|
||||||
*
|
*
|
||||||
* By default, up to 200 threads are reported.
|
* By default, up to 200 threads are reported.
|
||||||
*/
|
*/
|
||||||
public void setMaxReportedThreads(int maxReportedThreads) {
|
public void setMaxReportedThreads(@IntRange(from = 0) int maxReportedThreads) {
|
||||||
if (maxReportedThreads >= 0) {
|
if (maxReportedThreads >= 0) {
|
||||||
impl.setMaxReportedThreads(maxReportedThreads);
|
impl.setMaxReportedThreads(maxReportedThreads);
|
||||||
} else {
|
} else {
|
||||||
|
@ -602,7 +603,7 @@ public class Configuration implements CallbackAware, MetadataAware, UserAware, F
|
||||||
*
|
*
|
||||||
* By default, 128 sessions are persisted.
|
* By default, 128 sessions are persisted.
|
||||||
*/
|
*/
|
||||||
public void setMaxPersistedSessions(int maxPersistedSessions) {
|
public void setMaxPersistedSessions(@IntRange(from = 0) int maxPersistedSessions) {
|
||||||
if (maxPersistedSessions >= 0) {
|
if (maxPersistedSessions >= 0) {
|
||||||
impl.setMaxPersistedSessions(maxPersistedSessions);
|
impl.setMaxPersistedSessions(maxPersistedSessions);
|
||||||
} else {
|
} else {
|
||||||
|
@ -628,7 +629,7 @@ public class Configuration implements CallbackAware, MetadataAware, UserAware, F
|
||||||
*
|
*
|
||||||
* By default, the limit is 10,000.
|
* By default, the limit is 10,000.
|
||||||
*/
|
*/
|
||||||
public void setMaxStringValueLength(int maxStringValueLength) {
|
public void setMaxStringValueLength(@IntRange(from = 0) int maxStringValueLength) {
|
||||||
if (maxStringValueLength >= 0) {
|
if (maxStringValueLength >= 0) {
|
||||||
impl.setMaxStringValueLength(maxStringValueLength);
|
impl.setMaxStringValueLength(maxStringValueLength);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package com.bugsnag.android
|
package com.bugsnag.android
|
||||||
|
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
|
import com.bugsnag.android.internal.BackgroundTaskService
|
||||||
import com.bugsnag.android.internal.dag.ConfigModule
|
import com.bugsnag.android.internal.dag.ConfigModule
|
||||||
import com.bugsnag.android.internal.dag.ContextModule
|
import com.bugsnag.android.internal.dag.ContextModule
|
||||||
import com.bugsnag.android.internal.dag.DependencyModule
|
import com.bugsnag.android.internal.dag.DependencyModule
|
||||||
|
|
|
@ -2,7 +2,9 @@ package com.bugsnag.android;
|
||||||
|
|
||||||
import static com.bugsnag.android.SeverityReason.REASON_PROMISE_REJECTION;
|
import static com.bugsnag.android.SeverityReason.REASON_PROMISE_REJECTION;
|
||||||
|
|
||||||
|
import com.bugsnag.android.internal.BackgroundTaskService;
|
||||||
import com.bugsnag.android.internal.ImmutableConfig;
|
import com.bugsnag.android.internal.ImmutableConfig;
|
||||||
|
import com.bugsnag.android.internal.TaskType;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
|
@ -11,6 +11,8 @@ import android.content.res.Resources
|
||||||
import android.os.BatteryManager
|
import android.os.BatteryManager
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
|
import com.bugsnag.android.internal.BackgroundTaskService
|
||||||
|
import com.bugsnag.android.internal.TaskType
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package com.bugsnag.android
|
package com.bugsnag.android
|
||||||
|
|
||||||
|
import com.bugsnag.android.internal.BackgroundTaskService
|
||||||
import com.bugsnag.android.internal.dag.ConfigModule
|
import com.bugsnag.android.internal.dag.ConfigModule
|
||||||
import com.bugsnag.android.internal.dag.ContextModule
|
import com.bugsnag.android.internal.dag.ContextModule
|
||||||
import com.bugsnag.android.internal.dag.DependencyModule
|
import com.bugsnag.android.internal.dag.DependencyModule
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package com.bugsnag.android;
|
package com.bugsnag.android;
|
||||||
|
|
||||||
|
import com.bugsnag.android.internal.BackgroundTaskService;
|
||||||
import com.bugsnag.android.internal.ImmutableConfig;
|
import com.bugsnag.android.internal.ImmutableConfig;
|
||||||
|
import com.bugsnag.android.internal.TaskType;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
|
@ -3,8 +3,10 @@ package com.bugsnag.android;
|
||||||
import static com.bugsnag.android.DeliveryHeadersKt.HEADER_INTERNAL_ERROR;
|
import static com.bugsnag.android.DeliveryHeadersKt.HEADER_INTERNAL_ERROR;
|
||||||
import static com.bugsnag.android.SeverityReason.REASON_UNHANDLED_EXCEPTION;
|
import static com.bugsnag.android.SeverityReason.REASON_UNHANDLED_EXCEPTION;
|
||||||
|
|
||||||
|
import com.bugsnag.android.internal.BackgroundTaskService;
|
||||||
import com.bugsnag.android.internal.ImmutableConfig;
|
import com.bugsnag.android.internal.ImmutableConfig;
|
||||||
import com.bugsnag.android.internal.JsonHelper;
|
import com.bugsnag.android.internal.JsonHelper;
|
||||||
|
import com.bugsnag.android.internal.TaskType;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package com.bugsnag.android;
|
package com.bugsnag.android;
|
||||||
|
|
||||||
|
import com.bugsnag.android.internal.TaskType;
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
class LibraryLoader {
|
class LibraryLoader {
|
||||||
|
|
|
@ -265,6 +265,14 @@ public class NativeInterface {
|
||||||
getClient().addMetadata(tab, key, value);
|
getClient().addMetadata(tab, key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add metadata to subsequent exception reports with a Hashmap
|
||||||
|
*/
|
||||||
|
public static void addMetadata(@NonNull final String tab,
|
||||||
|
@NonNull final Map<String, ?> metadata) {
|
||||||
|
getClient().addMetadata(tab, metadata);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the client report release stage
|
* Return the client report release stage
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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.28.2",
|
var version: String = "5.30.0",
|
||||||
var url: String = "https://bugsnag.com"
|
var url: String = "https://bugsnag.com"
|
||||||
) : JsonStream.Streamable {
|
) : JsonStream.Streamable {
|
||||||
|
|
||||||
|
|
|
@ -15,10 +15,9 @@ internal class PluginClient(
|
||||||
}
|
}
|
||||||
|
|
||||||
private val plugins: Set<Plugin>
|
private val plugins: Set<Plugin>
|
||||||
|
private val ndkPlugin = instantiatePlugin(NDK_PLUGIN, immutableConfig.enabledErrorTypes.ndkCrashes)
|
||||||
private val ndkPlugin = instantiatePlugin(NDK_PLUGIN)
|
private val anrPlugin = instantiatePlugin(ANR_PLUGIN, immutableConfig.enabledErrorTypes.anrs)
|
||||||
private val anrPlugin = instantiatePlugin(ANR_PLUGIN)
|
private val rnPlugin = instantiatePlugin(RN_PLUGIN, immutableConfig.enabledErrorTypes.unhandledRejections)
|
||||||
private val rnPlugin = instantiatePlugin(RN_PLUGIN)
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val set = mutableSetOf<Plugin>()
|
val set = mutableSetOf<Plugin>()
|
||||||
|
@ -32,12 +31,14 @@ internal class PluginClient(
|
||||||
plugins = set.toSet()
|
plugins = set.toSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun instantiatePlugin(clz: String): Plugin? {
|
private fun instantiatePlugin(clz: String, isWarningEnabled: Boolean): Plugin? {
|
||||||
return try {
|
return try {
|
||||||
val pluginClz = Class.forName(clz)
|
val pluginClz = Class.forName(clz)
|
||||||
pluginClz.newInstance() as Plugin
|
pluginClz.newInstance() as Plugin
|
||||||
} catch (exc: ClassNotFoundException) {
|
} catch (exc: ClassNotFoundException) {
|
||||||
logger.d("Plugin '$clz' is not on the classpath - functionality will not be enabled.")
|
if (isWarningEnabled) {
|
||||||
|
logger.d("Plugin '$clz' is not on the classpath - functionality will not be enabled.")
|
||||||
|
}
|
||||||
null
|
null
|
||||||
} catch (exc: Throwable) {
|
} catch (exc: Throwable) {
|
||||||
logger.e("Failed to load plugin '$clz'", exc)
|
logger.e("Failed to load plugin '$clz'", exc)
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
package com.bugsnag.android
|
package com.bugsnag.android
|
||||||
|
|
||||||
import androidx.annotation.VisibleForTesting
|
import androidx.annotation.VisibleForTesting
|
||||||
import java.io.BufferedReader
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.util.concurrent.atomic.AtomicBoolean
|
import java.io.Reader
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to detect whether the device is rooted. Root detection errs on the side of false
|
* Attempts to detect whether the device is rooted. Root detection errs on the side of false
|
||||||
|
@ -41,12 +40,13 @@ internal class RootDetector @JvmOverloads constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val libraryLoaded = AtomicBoolean(false)
|
@Volatile
|
||||||
|
private var libraryLoaded = false
|
||||||
|
|
||||||
init {
|
init {
|
||||||
try {
|
try {
|
||||||
System.loadLibrary("bugsnag-root-detection")
|
System.loadLibrary("bugsnag-root-detection")
|
||||||
libraryLoaded.set(true)
|
libraryLoaded = true
|
||||||
} catch (ignored: UnsatisfiedLinkError) {
|
} catch (ignored: UnsatisfiedLinkError) {
|
||||||
// library couldn't load. This could be due to root detection countermeasures,
|
// library couldn't load. This could be due to root detection countermeasures,
|
||||||
// or down to genuine OS level bugs with library loading - in either case
|
// or down to genuine OS level bugs with library loading - in either case
|
||||||
|
@ -107,7 +107,7 @@ internal class RootDetector @JvmOverloads constructor(
|
||||||
line.replace("\\s".toRegex(), "")
|
line.replace("\\s".toRegex(), "")
|
||||||
}.filter { line ->
|
}.filter { line ->
|
||||||
line.startsWith("ro.debuggable=[1]") || line.startsWith("ro.secure=[0]")
|
line.startsWith("ro.debuggable=[1]") || line.startsWith("ro.secure=[0]")
|
||||||
}.count() > 0
|
}.any()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
@ -120,8 +120,7 @@ internal class RootDetector @JvmOverloads constructor(
|
||||||
var process: Process? = null
|
var process: Process? = null
|
||||||
return try {
|
return try {
|
||||||
process = processBuilder.start()
|
process = processBuilder.start()
|
||||||
val output = process.inputStream.bufferedReader().use(BufferedReader::readText)
|
process.inputStream.bufferedReader().use { it.isNotBlank() }
|
||||||
output.isNotBlank()
|
|
||||||
} catch (ignored: IOException) {
|
} catch (ignored: IOException) {
|
||||||
false
|
false
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -131,11 +130,21 @@ internal class RootDetector @JvmOverloads constructor(
|
||||||
|
|
||||||
private external fun performNativeRootChecks(): Boolean
|
private external fun performNativeRootChecks(): Boolean
|
||||||
|
|
||||||
|
private fun Reader.isNotBlank(): Boolean {
|
||||||
|
while (true) {
|
||||||
|
val ch = read()
|
||||||
|
when {
|
||||||
|
ch == -1 -> return false
|
||||||
|
!ch.toChar().isWhitespace() -> return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs root checks which require native code.
|
* Performs root checks which require native code.
|
||||||
*/
|
*/
|
||||||
private fun nativeCheckRoot(): Boolean = when {
|
private fun nativeCheckRoot(): Boolean = when {
|
||||||
libraryLoaded.get() -> performNativeRootChecks()
|
libraryLoaded -> performNativeRootChecks()
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
package com.bugsnag.android;
|
package com.bugsnag.android;
|
||||||
|
|
||||||
|
import com.bugsnag.android.internal.BackgroundTaskService;
|
||||||
import com.bugsnag.android.internal.DateUtils;
|
import com.bugsnag.android.internal.DateUtils;
|
||||||
import com.bugsnag.android.internal.ImmutableConfig;
|
import com.bugsnag.android.internal.ImmutableConfig;
|
||||||
|
import com.bugsnag.android.internal.TaskType;
|
||||||
|
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
|
|
||||||
|
@ -10,22 +12,21 @@ import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.Collection;
|
import java.util.ArrayDeque;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.Deque;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
|
||||||
import java.util.concurrent.RejectedExecutionException;
|
import java.util.concurrent.RejectedExecutionException;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
|
||||||
|
|
||||||
class SessionTracker extends BaseObservable {
|
class SessionTracker extends BaseObservable {
|
||||||
|
|
||||||
private static final int DEFAULT_TIMEOUT_MS = 30000;
|
private static final int DEFAULT_TIMEOUT_MS = 30000;
|
||||||
|
|
||||||
private final Collection<String>
|
private final Deque<String>
|
||||||
foregroundActivities = new ConcurrentLinkedQueue<>();
|
foregroundActivities = new ArrayDeque<>();
|
||||||
private final long timeoutMs;
|
private final long timeoutMs;
|
||||||
|
|
||||||
private final ImmutableConfig configuration;
|
private final ImmutableConfig configuration;
|
||||||
|
@ -132,7 +133,7 @@ class SessionTracker extends BaseObservable {
|
||||||
private void notifySessionStartObserver(final Session session) {
|
private void notifySessionStartObserver(final Session session) {
|
||||||
final String startedAt = DateUtils.toIso8601(session.getStartedAt());
|
final String startedAt = DateUtils.toIso8601(session.getStartedAt());
|
||||||
updateState(new StateEvent.StartSession(session.getId(), startedAt,
|
updateState(new StateEvent.StartSession(session.getId(), startedAt,
|
||||||
session.getHandledCount(), session.getUnhandledCount()));
|
session.getHandledCount(), session.getUnhandledCount()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -358,22 +359,23 @@ class SessionTracker extends BaseObservable {
|
||||||
void updateForegroundTracker(String activityName, boolean activityStarting, long nowMs) {
|
void updateForegroundTracker(String activityName, boolean activityStarting, long nowMs) {
|
||||||
if (activityStarting) {
|
if (activityStarting) {
|
||||||
long noActivityRunningForMs = nowMs - lastExitedForegroundMs.get();
|
long noActivityRunningForMs = nowMs - lastExitedForegroundMs.get();
|
||||||
|
synchronized (foregroundActivities) {
|
||||||
|
if (foregroundActivities.isEmpty()) {
|
||||||
|
lastEnteredForegroundMs.set(nowMs);
|
||||||
|
|
||||||
//FUTURE:SM Race condition between isEmpty and put
|
if (noActivityRunningForMs >= timeoutMs
|
||||||
if (foregroundActivities.isEmpty()) {
|
&& configuration.getAutoTrackSessions()) {
|
||||||
lastEnteredForegroundMs.set(nowMs);
|
startNewSession(new Date(), client.getUser(), true);
|
||||||
|
}
|
||||||
if (noActivityRunningForMs >= timeoutMs
|
|
||||||
&& configuration.getAutoTrackSessions()) {
|
|
||||||
startNewSession(new Date(), client.getUser(), true);
|
|
||||||
}
|
}
|
||||||
|
foregroundActivities.add(activityName);
|
||||||
}
|
}
|
||||||
foregroundActivities.add(activityName);
|
|
||||||
} else {
|
} else {
|
||||||
foregroundActivities.remove(activityName);
|
synchronized (foregroundActivities) {
|
||||||
|
foregroundActivities.removeLastOccurrence(activityName);
|
||||||
if (foregroundActivities.isEmpty()) {
|
if (foregroundActivities.isEmpty()) {
|
||||||
lastExitedForegroundMs.set(nowMs);
|
lastExitedForegroundMs.set(nowMs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
client.getContextState().setAutomaticContext(getContextActivity());
|
client.getContextState().setAutomaticContext(getContextActivity());
|
||||||
|
@ -397,14 +399,8 @@ class SessionTracker extends BaseObservable {
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
String getContextActivity() {
|
String getContextActivity() {
|
||||||
if (foregroundActivities.isEmpty()) {
|
synchronized (foregroundActivities) {
|
||||||
return null;
|
return foregroundActivities.peekLast();
|
||||||
} else {
|
|
||||||
// linked hash set retains order of added activity and ensures uniqueness
|
|
||||||
// therefore obtain the most recently added
|
|
||||||
int size = foregroundActivities.size();
|
|
||||||
String[] activities = foregroundActivities.toArray(new String[size]);
|
|
||||||
return activities[size - 1];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package com.bugsnag.android
|
package com.bugsnag.android
|
||||||
|
|
||||||
|
import com.bugsnag.android.internal.BackgroundTaskService
|
||||||
import com.bugsnag.android.internal.dag.ConfigModule
|
import com.bugsnag.android.internal.dag.ConfigModule
|
||||||
import com.bugsnag.android.internal.dag.DependencyModule
|
import com.bugsnag.android.internal.dag.DependencyModule
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package com.bugsnag.android
|
package com.bugsnag.android.internal
|
||||||
|
|
||||||
import androidx.annotation.VisibleForTesting
|
import androidx.annotation.VisibleForTesting
|
||||||
import java.util.concurrent.BlockingQueue
|
import java.util.concurrent.BlockingQueue
|
||||||
|
@ -18,7 +18,7 @@ import java.lang.Thread as JThread
|
||||||
* The type of task which is being submitted. This determines which execution queue
|
* The type of task which is being submitted. This determines which execution queue
|
||||||
* the task will be added to.
|
* the task will be added to.
|
||||||
*/
|
*/
|
||||||
internal enum class TaskType {
|
enum class TaskType {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A task that sends an error request. Any filesystem operations
|
* A task that sends an error request. Any filesystem operations
|
||||||
|
@ -91,7 +91,7 @@ internal fun createExecutor(name: String, type: TaskType, keepAlive: Boolean): E
|
||||||
* It also avoids short-running operations being held up by long-running operations submitted
|
* It also avoids short-running operations being held up by long-running operations submitted
|
||||||
* to the same executor.
|
* to the same executor.
|
||||||
*/
|
*/
|
||||||
internal class BackgroundTaskService(
|
class BackgroundTaskService(
|
||||||
// these executors must remain single-threaded - the SDK makes assumptions
|
// these executors must remain single-threaded - the SDK makes assumptions
|
||||||
// about synchronization based on this.
|
// about synchronization based on this.
|
||||||
@get:VisibleForTesting
|
@get:VisibleForTesting
|
|
@ -1,7 +1,7 @@
|
||||||
package com.bugsnag.android.internal.dag
|
package com.bugsnag.android.internal.dag
|
||||||
|
|
||||||
import com.bugsnag.android.BackgroundTaskService
|
import com.bugsnag.android.internal.BackgroundTaskService
|
||||||
import com.bugsnag.android.TaskType
|
import com.bugsnag.android.internal.TaskType
|
||||||
|
|
||||||
internal abstract class DependencyModule {
|
internal abstract class DependencyModule {
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ buildscript {
|
||||||
classpath 'com.android.tools.build:gradle:8.0.1'
|
classpath 'com.android.tools.build:gradle:8.0.1'
|
||||||
// https://github.com/bugsnag/bugsnag-android-gradle-plugin
|
// https://github.com/bugsnag/bugsnag-android-gradle-plugin
|
||||||
// https://mvnrepository.com/artifact/com.bugsnag/bugsnag-android-gradle-plugin
|
// https://mvnrepository.com/artifact/com.bugsnag/bugsnag-android-gradle-plugin
|
||||||
classpath "com.bugsnag:bugsnag-android-gradle-plugin:7.3.1"
|
classpath "com.bugsnag:bugsnag-android-gradle-plugin:8.0.1"
|
||||||
// https://mvnrepository.com/artifact/org.jetbrains.kotlin/kotlin-gradle-plugin
|
// https://mvnrepository.com/artifact/org.jetbrains.kotlin/kotlin-gradle-plugin
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.20"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.20"
|
||||||
classpath "org.jetbrains.kotlin:kotlin-android-extensions:1.8.20"
|
classpath "org.jetbrains.kotlin:kotlin-android-extensions:1.8.20"
|
||||||
|
|
Loading…
Reference in New Issue