-
Notifications
You must be signed in to change notification settings - Fork 81
feat(pans): integrate PANS metrics collection with OpenTelemetry #1467
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,88 @@ | ||
| public final class io/opentelemetry/android/instrumentation/pans/AppNetworkUsage { | ||
| public fun <init> (Ljava/lang/String;ILjava/lang/String;JJLio/opentelemetry/api/common/Attributes;)V | ||
| public final fun component1 ()Ljava/lang/String; | ||
| public final fun component2 ()I | ||
| public final fun component3 ()Ljava/lang/String; | ||
| public final fun component4 ()J | ||
| public final fun component5 ()J | ||
| public final fun component6 ()Lio/opentelemetry/api/common/Attributes; | ||
| public final fun copy (Ljava/lang/String;ILjava/lang/String;JJLio/opentelemetry/api/common/Attributes;)Lio/opentelemetry/android/instrumentation/pans/AppNetworkUsage; | ||
| public static synthetic fun copy$default (Lio/opentelemetry/android/instrumentation/pans/AppNetworkUsage;Ljava/lang/String;ILjava/lang/String;JJLio/opentelemetry/api/common/Attributes;ILjava/lang/Object;)Lio/opentelemetry/android/instrumentation/pans/AppNetworkUsage; | ||
| public fun equals (Ljava/lang/Object;)Z | ||
| public final fun getAttributes ()Lio/opentelemetry/api/common/Attributes; | ||
| public final fun getBytesReceived ()J | ||
| public final fun getBytesTransmitted ()J | ||
| public final fun getNetworkType ()Ljava/lang/String; | ||
| public final fun getPackageName ()Ljava/lang/String; | ||
| public final fun getUid ()I | ||
| public fun hashCode ()I | ||
| public fun toString ()Ljava/lang/String; | ||
| } | ||
|
|
||
| public final class io/opentelemetry/android/instrumentation/pans/NetworkAvailability { | ||
| public fun <init> (Ljava/lang/String;ZILio/opentelemetry/api/common/Attributes;)V | ||
| public synthetic fun <init> (Ljava/lang/String;ZILio/opentelemetry/api/common/Attributes;ILkotlin/jvm/internal/DefaultConstructorMarker;)V | ||
| public final fun component1 ()Ljava/lang/String; | ||
| public final fun component2 ()Z | ||
| public final fun component3 ()I | ||
| public final fun component4 ()Lio/opentelemetry/api/common/Attributes; | ||
| public final fun copy (Ljava/lang/String;ZILio/opentelemetry/api/common/Attributes;)Lio/opentelemetry/android/instrumentation/pans/NetworkAvailability; | ||
| public static synthetic fun copy$default (Lio/opentelemetry/android/instrumentation/pans/NetworkAvailability;Ljava/lang/String;ZILio/opentelemetry/api/common/Attributes;ILjava/lang/Object;)Lio/opentelemetry/android/instrumentation/pans/NetworkAvailability; | ||
| public fun equals (Ljava/lang/Object;)Z | ||
| public final fun getAttributes ()Lio/opentelemetry/api/common/Attributes; | ||
| public final fun getNetworkType ()Ljava/lang/String; | ||
| public final fun getSignalStrength ()I | ||
| public fun hashCode ()I | ||
| public final fun isAvailable ()Z | ||
| public fun toString ()Ljava/lang/String; | ||
| } | ||
|
|
||
| public final class io/opentelemetry/android/instrumentation/pans/PANSMetrics { | ||
| public fun <init> ()V | ||
| public fun <init> (Ljava/util/List;Ljava/util/List;Ljava/util/List;)V | ||
| public synthetic fun <init> (Ljava/util/List;Ljava/util/List;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V | ||
| public final fun component1 ()Ljava/util/List; | ||
| public final fun component2 ()Ljava/util/List; | ||
| public final fun component3 ()Ljava/util/List; | ||
| public final fun copy (Ljava/util/List;Ljava/util/List;Ljava/util/List;)Lio/opentelemetry/android/instrumentation/pans/PANSMetrics; | ||
| public static synthetic fun copy$default (Lio/opentelemetry/android/instrumentation/pans/PANSMetrics;Ljava/util/List;Ljava/util/List;Ljava/util/List;ILjava/lang/Object;)Lio/opentelemetry/android/instrumentation/pans/PANSMetrics; | ||
| public fun equals (Ljava/lang/Object;)Z | ||
| public final fun getAppNetworkUsage ()Ljava/util/List; | ||
| public final fun getNetworkAvailability ()Ljava/util/List; | ||
| public final fun getPreferenceChanges ()Ljava/util/List; | ||
| public fun hashCode ()I | ||
| public fun toString ()Ljava/lang/String; | ||
| } | ||
|
|
||
| public final class io/opentelemetry/android/instrumentation/pans/PansInstrumentation : io/opentelemetry/android/instrumentation/AndroidInstrumentation { | ||
| public static final field Companion Lio/opentelemetry/android/instrumentation/pans/PansInstrumentation$Companion; | ||
| public fun <init> ()V | ||
| public fun getName ()Ljava/lang/String; | ||
| public fun install (Lio/opentelemetry/android/instrumentation/InstallationContext;)V | ||
| } | ||
|
|
||
| public final class io/opentelemetry/android/instrumentation/pans/PansInstrumentation$Companion { | ||
| } | ||
|
|
||
| public final class io/opentelemetry/android/instrumentation/pans/PreferenceChange { | ||
| public fun <init> (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;JLio/opentelemetry/api/common/Attributes;)V | ||
| public synthetic fun <init> (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;JLio/opentelemetry/api/common/Attributes;ILkotlin/jvm/internal/DefaultConstructorMarker;)V | ||
| public final fun component1 ()Ljava/lang/String; | ||
| public final fun component2 ()I | ||
| public final fun component3 ()Ljava/lang/String; | ||
| public final fun component4 ()Ljava/lang/String; | ||
| public final fun component5 ()J | ||
| public final fun component6 ()Lio/opentelemetry/api/common/Attributes; | ||
| public final fun copy (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;JLio/opentelemetry/api/common/Attributes;)Lio/opentelemetry/android/instrumentation/pans/PreferenceChange; | ||
| public static synthetic fun copy$default (Lio/opentelemetry/android/instrumentation/pans/PreferenceChange;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;JLio/opentelemetry/api/common/Attributes;ILjava/lang/Object;)Lio/opentelemetry/android/instrumentation/pans/PreferenceChange; | ||
| public fun equals (Ljava/lang/Object;)Z | ||
| public final fun getAttributes ()Lio/opentelemetry/api/common/Attributes; | ||
| public final fun getNewPreference ()Ljava/lang/String; | ||
| public final fun getOldPreference ()Ljava/lang/String; | ||
| public final fun getPackageName ()Ljava/lang/String; | ||
| public final fun getTimestamp ()J | ||
| public final fun getUid ()I | ||
| public fun hashCode ()I | ||
| public fun toString ()Ljava/lang/String; | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| plugins { | ||
| id("otel.android-library-conventions") | ||
| id("otel.publish-conventions") | ||
| id("jacoco") | ||
| } | ||
|
|
||
| description = "OpenTelemetry Android PANS (Per-Application Network Selection) instrumentation" | ||
|
|
||
| android { | ||
| namespace = "io.opentelemetry.android.instrumentation.pans" | ||
|
|
||
| defaultConfig { | ||
| consumerProguardFiles("consumer-rules.pro") | ||
| } | ||
|
|
||
| testOptions { | ||
| unitTests.isReturnDefaultValues = true | ||
| unitTests.isIncludeAndroidResources = true | ||
| } | ||
| } | ||
|
|
||
| dependencies { | ||
| api(platform(libs.opentelemetry.platform.alpha)) // Required for sonatype publishing | ||
| implementation(project(":instrumentation:android-instrumentation")) | ||
| implementation(project(":services")) | ||
| implementation(project(":common")) | ||
| implementation(project(":agent-api")) | ||
| implementation(libs.androidx.core) | ||
| implementation(libs.opentelemetry.semconv.incubating) | ||
| implementation(libs.opentelemetry.sdk) | ||
| implementation(libs.opentelemetry.instrumentation.api) | ||
| implementation(libs.auto.service.annotations) | ||
|
|
||
| ksp(libs.auto.service.processor) | ||
|
|
||
| testImplementation(project(":test-common")) | ||
| testImplementation(libs.robolectric) | ||
| testImplementation(libs.androidx.test.core) | ||
| testImplementation(libs.mockk) | ||
| } | ||
|
|
||
| // Jacoco coverage configuration | ||
| jacoco { | ||
| toolVersion = "0.8.8" | ||
| } | ||
|
|
||
| tasks.register("jacocoTestReport") { | ||
| dependsOn("testDebugUnitTest") | ||
|
|
||
| doLast { | ||
| println("✅ Jacoco Test Report Generated") | ||
| println("📊 Coverage Report Location: build/reports/coverage/") | ||
| } | ||
| } | ||
|
|
||
| // Task to check coverage | ||
| tasks.register("checkCoverage") { | ||
| dependsOn("jacocoTestReport") | ||
|
|
||
| doLast { | ||
| println( | ||
| """ | ||
| ╔════════════════════════════════════════════════════════════════╗ | ||
| ║ PANS INSTRUMENTATION TEST COVERAGE ║ | ||
| ║ Target: 80% Coverage ║ | ||
| ╚════════════════════════════════════════════════════════════════╝ | ||
| """.trimIndent(), | ||
| ) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| # Keep the PANS instrumentation classes | ||
| -keep class io.opentelemetry.android.instrumentation.pans.** { *; } | ||
| -keepnames class io.opentelemetry.android.instrumentation.pans.** { *; } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||
| xmlns:tools="http://schemas.android.com/tools"> | ||
|
|
||
| <!-- Required to access network statistics data --> | ||
| <!-- This permission is intended for system/automotive apps --> | ||
| <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" | ||
| tools:ignore="ProtectedPermissions" /> | ||
|
|
||
| <!-- Required to check current network state and changes --> | ||
| <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> | ||
|
|
||
| <!-- Required for internet connectivity --> | ||
| <uses-permission android:name="android.permission.INTERNET" /> | ||
|
|
||
| </manifest> | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,122 @@ | ||||||||||||||||||
| /* | ||||||||||||||||||
| * Copyright The OpenTelemetry Authors | ||||||||||||||||||
| * SPDX-License-Identifier: Apache-2.0 | ||||||||||||||||||
| */ | ||||||||||||||||||
|
|
||||||||||||||||||
| package io.opentelemetry.android.instrumentation.pans | ||||||||||||||||||
|
|
||||||||||||||||||
| import android.content.Context | ||||||||||||||||||
| import android.content.pm.PackageManager | ||||||||||||||||||
| import android.net.ConnectivityManager | ||||||||||||||||||
| import android.net.NetworkCapabilities | ||||||||||||||||||
| import android.util.Log | ||||||||||||||||||
| import androidx.annotation.RequiresApi | ||||||||||||||||||
| import androidx.core.content.ContextCompat | ||||||||||||||||||
|
|
||||||||||||||||||
| /** | ||||||||||||||||||
| * Wrapper around Android's ConnectivityManager for monitoring network state and preferences. | ||||||||||||||||||
| * This class provides utilities to detect available networks and their capabilities. | ||||||||||||||||||
| * Note: Most methods require API level 23+ for proper functionality. | ||||||||||||||||||
| */ | ||||||||||||||||||
| @RequiresApi(23) | ||||||||||||||||||
| internal class ConnectivityManagerWrapper( | ||||||||||||||||||
| private val context: Context, | ||||||||||||||||||
| ) { | ||||||||||||||||||
| private val connectivityManager = | ||||||||||||||||||
| context.getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager | ||||||||||||||||||
|
|
||||||||||||||||||
| /** | ||||||||||||||||||
| * Checks if a specific network capability is available. | ||||||||||||||||||
| * OEM_PAID and OEM_PRIVATE are network capabilities that indicate OEM-managed networks. | ||||||||||||||||||
| */ | ||||||||||||||||||
| fun hasNetworkCapability(capabilityType: Int): Boolean { | ||||||||||||||||||
| return try { | ||||||||||||||||||
| val network = connectivityManager?.activeNetwork ?: return false | ||||||||||||||||||
| val capabilities = connectivityManager.getNetworkCapabilities(network) ?: return false | ||||||||||||||||||
| capabilities.hasCapability(capabilityType) | ||||||||||||||||||
| } catch (e: Exception) { | ||||||||||||||||||
| Log.w(TAG, "Error checking network capability: $capabilityType", e) | ||||||||||||||||||
| false | ||||||||||||||||||
| } | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| /** | ||||||||||||||||||
| * Gets all available networks with their capabilities. | ||||||||||||||||||
| */ | ||||||||||||||||||
|
||||||||||||||||||
| */ | |
| */ | |
| // SuppressLint("WrongConstant") is used here because CAP_OEM_PAID (19) and CAP_OEM_PRIVATE (20) | |
| // are not recognized as valid network capability constants by the linter. These constants are | |
| // defined for forward compatibility with Android API 31+ (Android 12), where they represent | |
| // OEM-managed network capabilities. On earlier API levels, these values may not be supported, | |
| // but the code is protected by try/catch blocks and @RequiresApi(23). Developers should be | |
| // aware that use of these constants may not be valid on all Android versions. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment states that
PACKAGE_USAGE_STATSpermission is "intended for system/automotive apps" (line 6), but the PR description doesn't specify that this instrumentation is only for system/automotive apps.This is a protected permission that normal apps cannot obtain through runtime permission requests. This should be clearly documented in the module's README or main documentation that:
This is important for setting correct expectations for users of this library.