Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge develop branch #1849

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
2284a01
RUM-1308: Add more HTTP methods to RUM
0xnm Jan 16, 2024
8c57aad
Merge pull request #1826 from DataDog/nogorodnikov/rum-1308/add-more-…
0xnm Jan 17, 2024
c29effe
Update RUM Schema
0xnm Jan 17, 2024
3d5e3d6
Merge pull request #1828 from DataDog/nogorodnikov/update-rum-schema-…
0xnm Jan 17, 2024
2238f81
Make a copy of attributes before passing them to RUM event
0xnm Jan 18, 2024
8145782
Merge pull request #1830 from DataDog/nogorodnikov/make-a-copy-of-att…
0xnm Jan 22, 2024
14025c5
RUM-1702: Start session when RUM is initialized
0xnm Jan 22, 2024
c63258e
[RUM-2258] Fix frame rate vital for variable refresh rate displays
plousada Dec 28, 2023
dcdb95c
Small refactor to frame listener
plousada Jan 2, 2024
f41093c
Address PR comments.
plousada Jan 22, 2024
2bc3526
Merge pull request #1832 from DataDog/nogorodnikov/rum-1702/start-ses…
0xnm Jan 23, 2024
423bc2f
Make a copy of attributes before passing them to RUM event
0xnm Jan 18, 2024
d1200bd
Merge pull request #1838 from DataDog/xgouchet/cherry_pick_1830
xgouchet Jan 24, 2024
6d7ccbe
Prepare 2.5.1
xgouchet Jan 24, 2024
8a44f37
Merge pull request #1839 from DataDog/xgouchet/prepare_2.5.1
xgouchet Jan 24, 2024
b24509a
RUM-2600: Add traversal flag to snapshot items
jonathanmos Jan 23, 2024
62f730e
Merge pull request #1837 from DataDog/jmoskovich/RUM-2600/add-snapsho…
jonathanmos Jan 25, 2024
2367d09
Merge tag '2.5.1' into xgouchet/merge_2.5.1
xgouchet Jan 25, 2024
da03dd9
Merge pull request #1842 from DataDog/xgouchet/merge_2.5.1
xgouchet Jan 25, 2024
8873500
Add tests to cover S and R versions
plousada Jan 22, 2024
c925c52
Merge pull request #1806 from DataDog/plousada/RUM-2258/fix_over_60fp…
plousada Jan 26, 2024
0e6f41a
Merge branch 'develop' into sr-web-view-support/merge/develop
mariusc83 Feb 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 2.5.1 / 2024-01-24

* [BUGFIX] RUM: Prevent crash due to concurrent modification of custom attributes. See [#1838](https://github.com/DataDog/dd-sdk-android/pull/1838)

# 2.5.0 / 2024-01-15

* [FEATURE] Add accessor for current session id. See [#1810](https://github.com/DataDog/dd-sdk-android/pull/1810)
Expand Down
7 changes: 7 additions & 0 deletions detekt_custom.yml
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,7 @@ datadog:
- "android.content.res.Resources.Theme.resolveAttribute(kotlin.Int, android.util.TypedValue?, kotlin.Boolean)"
- "android.database.DatabaseErrorHandler.onCorruption(android.database.sqlite.SQLiteDatabase?)"
- "android.database.DefaultDatabaseErrorHandler.constructor()"
- "android.hardware.display.DisplayManager.getDisplay(kotlin.Int)"
- "android.net.ConnectivityManager.NetworkCallback.onCapabilitiesChanged(android.net.Network, android.net.NetworkCapabilities)"
- "android.net.ConnectivityManager.NetworkCallback.onLost(android.net.Network)"
- "android.net.ConnectivityManager.getNetworkCapabilities(android.net.Network?)"
Expand Down Expand Up @@ -352,6 +353,7 @@ datadog:
- "android.util.TypedValue.constructor()"
- "android.view.Choreographer.postFrameCallback(android.view.Choreographer.FrameCallback)"
- "android.view.Display.getSize(android.graphics.Point?)"
- "android.view.FrameMetrics.getMetric(kotlin.Int)"
- "android.view.inspector.WindowInspector.getGlobalWindowViews()"
- "android.view.MotionEvent.recycle()"
- "android.view.MotionEvent.getPointerId(kotlin.Int)"
Expand All @@ -370,9 +372,11 @@ datadog:
- "android.view.ViewTreeObserver.removeOnDrawListener(android.view.ViewTreeObserver.OnDrawListener?)"
- "android.view.ViewTreeObserver.removeOnGlobalLayoutListener()"
- "android.view.ViewTreeObserver.removeOnGlobalLayoutListener(android.view.ViewTreeObserver.OnGlobalLayoutListener)"
- "android.view.Window.addOnFrameMetricsAvailableListener(android.view.Window.OnFrameMetricsAvailableListener, android.os.Handler?)"
- "android.view.Window.Callback.dispatchKeyEvent(android.view.KeyEvent?)"
- "android.view.Window.Callback.dispatchTouchEvent(android.view.MotionEvent?)"
- "android.view.Window.Callback.onMenuItemSelected(kotlin.Int, android.view.MenuItem)"
- "android.view.Window.removeOnFrameMetricsAvailableListener(android.view.Window.OnFrameMetricsAvailableListener?)"
- "android.view.View.getChildAt(kotlin.Int)"
- "android.view.View.hashCode()"
- "androidx.collection.LruCache.size()"
Expand Down Expand Up @@ -931,6 +935,7 @@ datadog:
- "kotlin.collections.MutableMap.remove(kotlin.String)"
- "kotlin.collections.MutableMap.safeMapValuesToJson(com.datadog.android.api.InternalLogger)"
- "kotlin.collections.MutableMap.toMap()"
- "kotlin.collections.MutableMap.toMutableMap()"
- "kotlin.collections.MutableMap?.forEach(kotlin.Function1)"
- "kotlin.collections.MutableSet.add(com.datadog.android.api.feature.FeatureContextUpdateReceiver?)"
- "kotlin.collections.MutableSet.add(com.datadog.android.core.internal.persistence.ConsentAwareStorage.Batch)"
Expand Down Expand Up @@ -1010,13 +1015,15 @@ datadog:
- "kotlin.Char.isLowerCase()"
- "kotlin.Char.titlecase(java.util.Locale)"
- "kotlin.CharArray.constructor(kotlin.Int, kotlin.Function1)"
- "kotlin.Double.coerceAtMost(kotlin.Double)"
- "kotlin.Double.isNaN()"
- "kotlin.Double.pow(kotlin.Int)"
- "kotlin.Double.rangeTo(kotlin.Double)"
- "kotlin.Double.toFloat()"
- "kotlin.Double.toInt()"
- "kotlin.Double.toLong()"
- "kotlin.Float.percent()"
- "kotlin.Float.toDouble()"
- "kotlin.Float.toFloat()"
- "kotlin.Float.toInt()"
- "kotlin.Float.toLong()"
Expand Down
209 changes: 164 additions & 45 deletions features/dd-sdk-android-rum/api/apiSurface

Large diffs are not rendered by default.

1,043 changes: 665 additions & 378 deletions features/dd-sdk-android-rum/api/dd-sdk-android-rum.api

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
"source": {
"type": "string",
"description": "The source of this event",
"enum": ["android", "ios", "browser", "flutter", "react-native", "roku"],
"enum": ["android", "ios", "browser", "flutter", "react-native", "roku", "unity"],
"readOnly": true
},
"view": {
Expand Down Expand Up @@ -127,7 +127,7 @@
"connectivity": {
"type": "object",
"description": "Device connectivity properties",
"required": ["status", "interfaces"],
"required": ["status"],
"properties": {
"status": {
"type": "string",
Expand All @@ -144,6 +144,12 @@
},
"readOnly": true
},
"effective_type": {
"type": "string",
"description": "Cellular connection type reflecting the measured network performance",
"enum": ["slow_2g", "2g", "3g", "4g"],
"readOnly": true
},
"cellular": {
"type": "object",
"description": "Cellular connectivity properties",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "rum/_view-container-schema.json",
"title": "ViewContainerSchema",
"type": "object",
"description": "View Container schema for views that are nested (webviews in mobile)",
"properties": {
"container": {
"type": "object",
"description": "View Container properties (view wrapping the current view)",
"required": ["view", "source"],
"properties": {
"view": {
"type": "object",
"description": "Attributes of the view's container",
"required": ["id"],
"properties": {
"id": {
"type": "string",
"description": "ID of the parent view",
"pattern": "^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$",
"readOnly": true
}
},
"readOnly": true
},
"source": {
"type": "string",
"description": "Source of the parent view",
"enum": ["android", "ios", "browser", "flutter", "react-native", "roku", "unity"],
"readOnly": true
}
},
"readOnly": true
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"$ref": "_common-schema.json"
},
{
"$ref": "_parent-view-schema.json"
"$ref": "_view-container-schema.json"
},
{
"required": ["type", "action"],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"$ref": "_action-child-schema.json"
},
{
"$ref": "_parent-view-schema.json"
"$ref": "_view-container-schema.json"
},
{
"required": ["type", "error"],
Expand Down Expand Up @@ -123,7 +123,7 @@
"method": {
"type": "string",
"description": "HTTP method of the resource",
"enum": ["POST", "GET", "HEAD", "PUT", "DELETE", "PATCH"],
"enum": ["POST", "GET", "HEAD", "PUT", "DELETE", "PATCH", "TRACE", "OPTIONS", "CONNECT"],
"readOnly": true
},
"status_code": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"$ref": "_action-child-schema.json"
},
{
"$ref": "_parent-view-schema.json"
"$ref": "_view-container-schema.json"
},
{
"required": ["type", "long_task"],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"$ref": "_action-child-schema.json"
},
{
"$ref": "_parent-view-schema.json"
"$ref": "_view-container-schema.json"
},
{
"required": ["type", "resource"],
Expand Down Expand Up @@ -43,7 +43,7 @@
"method": {
"type": "string",
"description": "HTTP method of the resource",
"enum": ["POST", "GET", "HEAD", "PUT", "DELETE", "PATCH"],
"enum": ["POST", "GET", "HEAD", "PUT", "DELETE", "PATCH", "TRACE", "OPTIONS", "CONNECT"],
"readOnly": true
},
"url": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"$ref": "_common-schema.json"
},
{
"$ref": "_parent-view-schema.json"
"$ref": "_view-container-schema.json"
},
{
"required": ["type", "view", "_dd"],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import android.os.Looper
import com.datadog.android.Datadog
import com.datadog.android.api.InternalLogger
import com.datadog.android.api.SdkCore
import com.datadog.android.api.feature.Feature
import com.datadog.android.api.feature.FeatureSdkCore
import com.datadog.android.core.InternalSdkCore
import com.datadog.android.core.sampling.RateBasedSampler
Expand All @@ -30,6 +31,7 @@ object Rum {
* @param sdkCore SDK instance to register feature in. If not provided, default SDK instance
* will be used.
*/
@Suppress("ReturnCount")
@JvmOverloads
@JvmStatic
fun enable(rumConfiguration: RumConfiguration, sdkCore: SdkCore = Datadog.getInstance()) {
Expand All @@ -52,18 +54,35 @@ object Rum {
return
}

if (sdkCore.getFeature(Feature.RUM_FEATURE_NAME) != null) {
sdkCore.internalLogger.log(
InternalLogger.Level.WARN,
InternalLogger.Target.USER,
{ RUM_FEATURE_ALREADY_ENABLED }
)
return
}

val rumFeature = RumFeature(
sdkCore = sdkCore as FeatureSdkCore,
sdkCore = sdkCore,
applicationId = rumConfiguration.applicationId,
configuration = rumConfiguration.featureConfiguration
)

sdkCore.registerFeature(rumFeature)

val rumMonitor = createMonitor(sdkCore, rumFeature)
GlobalRumMonitor.registerIfAbsent(
monitor = createMonitor(sdkCore, rumFeature),
monitor = rumMonitor,
sdkCore
)

// TODO RUM-0000 there is a small chance of application crashing between RUM monitor
// registration and the moment SDK init is processed, in this case we will miss this crash
// (it won't activate new session). Ideally we should start session when monitor is created
// and before it is registered, but with current code (internal RUM scopes using the
// `GlobalRumMonitor`) it is impossible to break cycle dependency.
rumMonitor.start()
}

// region private
Expand Down Expand Up @@ -104,5 +123,8 @@ object Rum {
"You're trying to create a RumMonitor instance, " +
"but the RUM application id was empty. No RUM data will be sent."

internal const val RUM_FEATURE_ALREADY_ENABLED =
"RUM Feature is already enabled in this SDK core, ignoring the call to enable it."

// endregion
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,20 @@ enum class RumResourceMethod {
/**
* PATCH Method.
*/
PATCH
PATCH,

/**
* TRACE Method.
*/
TRACE,

/**
* OPTIONS Method.
*/
OPTIONS,

/**
* CONNECT Method.
*/
CONNECT
}
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ internal class RumActionScope(

val actualType = type
attributes.putAll(GlobalRumMonitor.get(sdkCore).getAttributes())
val eventAttributes = attributes.toMutableMap()
val rumContext = getRumContext()

// make a copy so that closure captures at the state as of now
Expand Down Expand Up @@ -250,7 +251,7 @@ internal class RumActionScope(
null
}
),
view = ActionEvent.View(
view = ActionEvent.ActionEventView(
id = rumContext.viewId.orEmpty(),
name = rumContext.viewName,
url = rumContext.viewUrl.orEmpty()
Expand Down Expand Up @@ -288,7 +289,7 @@ internal class RumActionScope(
brand = datadogContext.deviceInfo.deviceBrand,
architecture = datadogContext.deviceInfo.architecture
),
context = ActionEvent.Context(additionalProperties = attributes),
context = ActionEvent.Context(additionalProperties = eventAttributes),
dd = ActionEvent.Dd(
session = ActionEvent.DdSession(
plan = ActionEvent.Plan.PLAN_1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,15 @@

package com.datadog.android.rum.internal.domain.scope

import android.app.ActivityManager
import androidx.annotation.WorkerThread
import com.datadog.android.api.InternalLogger
import com.datadog.android.api.feature.Feature
import com.datadog.android.api.storage.DataWriter
import com.datadog.android.core.InternalSdkCore
import com.datadog.android.core.internal.net.FirstPartyHostHeaderTypeResolver
import com.datadog.android.rum.DdRumContentProvider
import com.datadog.android.rum.RumSessionListener
import com.datadog.android.rum.internal.AppStartTimeProvider
import com.datadog.android.rum.internal.DefaultAppStartTimeProvider
import com.datadog.android.rum.internal.domain.RumContext
import com.datadog.android.rum.internal.domain.Time
import com.datadog.android.rum.internal.vitals.VitalMonitor
import java.util.concurrent.TimeUnit

@Suppress("LongParameterList")
internal class RumApplicationScope(
Expand All @@ -33,8 +27,7 @@ internal class RumApplicationScope(
private val cpuVitalMonitor: VitalMonitor,
private val memoryVitalMonitor: VitalMonitor,
private val frameRateVitalMonitor: VitalMonitor,
private val sessionListener: RumSessionListener?,
private val appStartTimeProvider: AppStartTimeProvider = DefaultAppStartTimeProvider()
private val sessionListener: RumSessionListener?
) : RumScope, RumViewChangedListener {

private var rumContext = RumContext(applicationId = applicationId)
Expand Down Expand Up @@ -62,7 +55,6 @@ internal class RumApplicationScope(
}

private var lastActiveViewInfo: RumViewInfo? = null
private var isSentAppStartedEvent = false

// region RumScope

Expand All @@ -87,10 +79,6 @@ internal class RumApplicationScope(
}
}

if (!isSentAppStartedEvent) {
sendApplicationStartEvent(event.eventTime, writer)
}

delegateToChildren(event, writer)

return this
Expand Down Expand Up @@ -166,37 +154,9 @@ internal class RumApplicationScope(
}
}

@WorkerThread
private fun sendApplicationStartEvent(eventTime: Time, writer: DataWriter<Any>) {
val processImportance = DdRumContentProvider.processImportance
val isForegroundProcess = processImportance ==
ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
if (isForegroundProcess) {
val processStartTimeNs = appStartTimeProvider.appStartTimeNs
// processStartTime is the time in nanoseconds since VM start. To get a timestamp, we want
// to convert it to milliseconds since epoch provided by System.currentTimeMillis.
// To do so, we take the offset of those times in the event time, which should be consistent,
// then add that to our processStartTime to get the correct value.
val timestampNs = (
TimeUnit.MILLISECONDS.toNanos(eventTime.timestamp) - eventTime.nanoTime
) + processStartTimeNs
val applicationLaunchViewTime = Time(
timestamp = TimeUnit.NANOSECONDS.toMillis(timestampNs),
nanoTime = processStartTimeNs
)
val startupTime = eventTime.nanoTime - processStartTimeNs
val appStartedEvent =
RumRawEvent.ApplicationStarted(applicationLaunchViewTime, startupTime)
delegateToChildren(appStartedEvent, writer)
isSentAppStartedEvent = true
}
}

// endregion

companion object {
internal const val LAST_ACTIVE_VIEW_GONE_WARNING_MESSAGE = "Attempting to start a new " +
"session on the last known view (%s) failed because that view has been disposed. "
internal const val MULTIPLE_ACTIVE_SESSIONS_ERROR = "Application has multiple active " +
"sessions when starting a new session"
}
Expand Down