From ec207bfc8f507e7ee0948734cd399367214e122b Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Sun, 21 May 2023 11:49:57 +0100 Subject: [PATCH 1/9] Add tracing implementations of listeners --- gradle/libs.versions.toml | 2 + okhttp-android/build.gradle.kts | 5 +- .../android/TracingConnectionListener.kt | 47 +++++++++++++++++++ .../okhttp3/android/TracingInterceptor.kt | 37 +++++++++++++++ 4 files changed, 87 insertions(+), 4 deletions(-) create mode 100644 okhttp-android/src/main/kotlin/okhttp3/android/TracingConnectionListener.kt create mode 100644 okhttp-android/src/main/kotlin/okhttp3/android/TracingInterceptor.kt diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4d81e0c105c4..4a74a96376b6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,4 +1,5 @@ [versions] +androidx-tracing = "1.1.0" biz-aQute-bnd = "6.4.0" checkStyle = "10.9.3" com-squareup-moshi = "1.15.0" @@ -18,6 +19,7 @@ androidx-annotation = "androidx.annotation:annotation:1.6.0" androidx-espresso-core = "androidx.test.espresso:espresso-core:3.5.1" androidx-junit = "androidx.test.ext:junit:1.1.5" androidx-test-runner = "androidx.test:runner:1.5.2" +androidx-tracing-ktx = { module = "androidx.tracing:tracing-ktx", version.ref = "androidx-tracing" } animalsniffer-annotations = "org.codehaus.mojo:animal-sniffer-annotations:1.22" aqute-resolve = { module = "biz.aQute.bnd:biz.aQute.resolve", version.ref = "biz-aQute-bnd" } assertj-core = "org.assertj:assertj-core:3.24.2" diff --git a/okhttp-android/build.gradle.kts b/okhttp-android/build.gradle.kts index d9d6e59f7e28..5ff387d91a65 100644 --- a/okhttp-android/build.gradle.kts +++ b/okhttp-android/build.gradle.kts @@ -1,9 +1,6 @@ -import com.vanniktech.maven.publish.JavadocJar - plugins { id("com.android.library") kotlin("android") - id("de.mannodermaus.android-junit5") id("org.jetbrains.dokka") id("com.vanniktech.maven.publish.base") id("binary-compatibility-validator") @@ -14,7 +11,6 @@ android { defaultConfig { minSdk = 21 - targetSdk = 31 // Make sure to use the AndroidJUnitRunner (or a sub-class) in order to hook in the JUnit 5 Test Builder testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" @@ -47,6 +43,7 @@ dependencies { debugImplementation(libs.findbugs.jsr305) compileOnly(libs.animalsniffer.annotations) compileOnly(libs.robolectric.android) + implementation(libs.androidx.tracing.ktx) testImplementation(projects.okhttpTestingSupport) testImplementation(projects.mockwebserver3Junit5) diff --git a/okhttp-android/src/main/kotlin/okhttp3/android/TracingConnectionListener.kt b/okhttp-android/src/main/kotlin/okhttp3/android/TracingConnectionListener.kt new file mode 100644 index 000000000000..327d4c349358 --- /dev/null +++ b/okhttp-android/src/main/kotlin/okhttp3/android/TracingConnectionListener.kt @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2022 Block, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package okhttp3.android; + +import androidx.tracing.Trace +import java.util.concurrent.atomic.AtomicInteger +import okhttp3.Call +import okhttp3.Connection +import okhttp3.ConnectionListener +import okhttp3.Route +import okio.IOException + +/** + * Tracing implementation of ConnectionListener that marks the lifetime of each connection + * in perfetto traces. + */ +class TracingConnectionListener : ConnectionListener() { + private val idGenerator = AtomicInteger(0) + + override fun connectStart(route: Route, call: Call) { + Trace.beginAsyncSection(route.tracingTag, idGenerator.incrementAndGet()) + } + + override fun connectFailed(route: Route, call: Call, failure: IOException) { + Trace.endAsyncSection(route.tracingTag, idGenerator.incrementAndGet()) + } + + override fun connectionClosed(connection: Connection) { + Trace.endAsyncSection(connection.route().tracingTag, idGenerator.incrementAndGet()) + } + + val Route.tracingTag: String + get() = this.address.url.host +} diff --git a/okhttp-android/src/main/kotlin/okhttp3/android/TracingInterceptor.kt b/okhttp-android/src/main/kotlin/okhttp3/android/TracingInterceptor.kt new file mode 100644 index 000000000000..f4785b257a3f --- /dev/null +++ b/okhttp-android/src/main/kotlin/okhttp3/android/TracingInterceptor.kt @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022 Block, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package okhttp3.android; + +import androidx.tracing.trace +import okhttp3.Interceptor +import okhttp3.Request +import okhttp3.Response + +/** + * Tracing implementation of Interceptor that marks each Call in a perfetto + * trace. + */ +class TracingInterceptor : Interceptor { + override fun intercept(chain: Interceptor.Chain): Response { + return trace(chain.request().tracingTag) { + chain.proceed(chain.request()) + } + } + + val Request.tracingTag: String + get() = url.encodedPath.take(127) +} From 84c5638a1435a2cf7f2aa62e16b3b25acd150502 Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Sun, 21 May 2023 12:38:20 +0100 Subject: [PATCH 2/9] Add companion --- .../src/main/kotlin/okhttp3/logging/LoggingEventListener.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/okhttp-logging-interceptor/src/main/kotlin/okhttp3/logging/LoggingEventListener.kt b/okhttp-logging-interceptor/src/main/kotlin/okhttp3/logging/LoggingEventListener.kt index dfd894a70102..5df6932d0199 100644 --- a/okhttp-logging-interceptor/src/main/kotlin/okhttp3/logging/LoggingEventListener.kt +++ b/okhttp-logging-interceptor/src/main/kotlin/okhttp3/logging/LoggingEventListener.kt @@ -181,4 +181,6 @@ class LoggingEventListener private constructor( ) : EventListener.Factory { override fun create(call: Call): EventListener = LoggingEventListener(logger) } + + companion object } From 3a04d6855b75f2ee9901b97d17d66e312da5db86 Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Tue, 31 Dec 2024 16:48:46 +0000 Subject: [PATCH 3/9] merge conflicts --- okhttp/build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/okhttp/build.gradle.kts b/okhttp/build.gradle.kts index 7a562870cf62..78251b30aaa4 100644 --- a/okhttp/build.gradle.kts +++ b/okhttp/build.gradle.kts @@ -97,6 +97,7 @@ kotlin { compileOnly(libs.conscrypt.openjdk) implementation(libs.androidx.annotation) implementation(libs.androidx.startup.runtime) + implementation(libs.androidx.tracing.ktx) } } From 5b256a8be4343bb331a0fc85070d54aac7ee1fd7 Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Tue, 31 Dec 2024 17:03:30 +0000 Subject: [PATCH 4/9] cleanups --- .../okhttp3/android/TracingConnectionListener.kt | 15 ++++++++++++--- .../kotlin/okhttp3/android/TracingInterceptor.kt | 2 +- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/okhttp/src/androidMain/kotlin/okhttp3/android/TracingConnectionListener.kt b/okhttp/src/androidMain/kotlin/okhttp3/android/TracingConnectionListener.kt index 327d4c349358..ed94e427215c 100644 --- a/okhttp/src/androidMain/kotlin/okhttp3/android/TracingConnectionListener.kt +++ b/okhttp/src/androidMain/kotlin/okhttp3/android/TracingConnectionListener.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package okhttp3.android; +package okhttp3.android import androidx.tracing.Trace import java.util.concurrent.atomic.AtomicInteger @@ -30,15 +30,24 @@ import okio.IOException class TracingConnectionListener : ConnectionListener() { private val idGenerator = AtomicInteger(0) - override fun connectStart(route: Route, call: Call) { + override fun connectStart( + route: Route, + call: Call, + ) { Trace.beginAsyncSection(route.tracingTag, idGenerator.incrementAndGet()) } - override fun connectFailed(route: Route, call: Call, failure: IOException) { + override fun connectFailed( + route: Route, + call: Call, + failure: IOException, + ) { + // TODO same id Trace.endAsyncSection(route.tracingTag, idGenerator.incrementAndGet()) } override fun connectionClosed(connection: Connection) { + // TODO same id Trace.endAsyncSection(connection.route().tracingTag, idGenerator.incrementAndGet()) } diff --git a/okhttp/src/androidMain/kotlin/okhttp3/android/TracingInterceptor.kt b/okhttp/src/androidMain/kotlin/okhttp3/android/TracingInterceptor.kt index f4785b257a3f..c57837d2b3fd 100644 --- a/okhttp/src/androidMain/kotlin/okhttp3/android/TracingInterceptor.kt +++ b/okhttp/src/androidMain/kotlin/okhttp3/android/TracingInterceptor.kt @@ -14,7 +14,7 @@ * limitations under the License. * */ -package okhttp3.android; +package okhttp3.android import androidx.tracing.trace import okhttp3.Interceptor From 72a3a68d2bb16168f8386b93bafa324b51898d04 Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Sat, 4 Jan 2025 14:29:13 +0000 Subject: [PATCH 5/9] Fixes --- .../okhttp/android/testapp/MainActivity.kt | 8 +- okhttp/api/android/okhttp.api | 37 +++++++- okhttp/api/jvm/okhttp.api | 5 +- .../AndroidxTracingConnectionListener.kt | 90 +++++++++++++++++++ ...eptor.kt => AndroidxTracingInterceptor.kt} | 18 ++-- .../android/TracingConnectionListener.kt | 56 ------------ .../kotlin/okhttp3/Connection.kt | 3 + .../kotlin/okhttp3/ConnectionListener.kt | 2 + .../internal/connection/CallConnectionUser.kt | 7 +- .../internal/connection/ConnectPlan.kt | 14 ++- .../internal/connection/ConnectionUser.kt | 6 +- .../internal/connection/PoolConnectionUser.kt | 6 +- .../internal/connection/RealConnection.kt | 2 + 13 files changed, 178 insertions(+), 76 deletions(-) create mode 100644 okhttp/src/androidMain/kotlin/okhttp3/android/AndroidxTracingConnectionListener.kt rename okhttp/src/androidMain/kotlin/okhttp3/android/{TracingInterceptor.kt => AndroidxTracingInterceptor.kt} (68%) delete mode 100644 okhttp/src/androidMain/kotlin/okhttp3/android/TracingConnectionListener.kt diff --git a/android-test-app/src/main/kotlin/okhttp/android/testapp/MainActivity.kt b/android-test-app/src/main/kotlin/okhttp/android/testapp/MainActivity.kt index cf896359b4b1..ba20c378bde0 100644 --- a/android-test-app/src/main/kotlin/okhttp/android/testapp/MainActivity.kt +++ b/android-test-app/src/main/kotlin/okhttp/android/testapp/MainActivity.kt @@ -19,10 +19,13 @@ import android.os.Bundle import androidx.activity.ComponentActivity import okhttp3.Call import okhttp3.Callback +import okhttp3.ConnectionPool import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.Response +import okhttp3.android.AndroidxTracingConnectionListener +import okhttp3.android.AndroidxTracingInterceptor import okhttp3.internal.platform.AndroidPlatform import okio.IOException @@ -30,7 +33,10 @@ class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - val client = OkHttpClient() + val client = OkHttpClient.Builder() + .connectionPool(ConnectionPool(connectionListener = AndroidxTracingConnectionListener())) + .addNetworkInterceptor(AndroidxTracingInterceptor()) + .build() // Ensure we are compiling against the right variant println(AndroidPlatform.isSupported) diff --git a/okhttp/api/android/okhttp.api b/okhttp/api/android/okhttp.api index 5dabeaa98ce9..48445680425b 100644 --- a/okhttp/api/android/okhttp.api +++ b/okhttp/api/android/okhttp.api @@ -354,6 +354,7 @@ public final class okhttp3/CipherSuite$Companion { } public abstract interface class okhttp3/Connection { + public abstract fun getId ()J public abstract fun handshake ()Lokhttp3/Handshake; public abstract fun protocol ()Lokhttp3/Protocol; public abstract fun route ()Lokhttp3/Route; @@ -364,8 +365,8 @@ public abstract class okhttp3/ConnectionListener { public static final field Companion Lokhttp3/ConnectionListener$Companion; public fun ()V public fun connectEnd (Lokhttp3/Connection;Lokhttp3/Route;Lokhttp3/Call;)V - public fun connectFailed (Lokhttp3/Route;Lokhttp3/Call;Ljava/io/IOException;)V - public fun connectStart (Lokhttp3/Route;Lokhttp3/Call;)V + public fun connectFailed (JLokhttp3/Route;Lokhttp3/Call;Ljava/io/IOException;)V + public fun connectStart (JLokhttp3/Route;Lokhttp3/Call;)V public fun connectionAcquired (Lokhttp3/Connection;Lokhttp3/Call;)V public fun connectionClosed (Lokhttp3/Connection;)V public fun connectionReleased (Lokhttp3/Connection;Lokhttp3/Call;)V @@ -1304,3 +1305,35 @@ public final class okhttp3/android/AndroidAsyncDns$Companion { public final fun getIPv6 ()Lokhttp3/android/AndroidAsyncDns; } +public final class okhttp3/android/AndroidxTracingConnectionListener : okhttp3/ConnectionListener { + public static final field Companion Lokhttp3/android/AndroidxTracingConnectionListener$Companion; + public fun ()V + public fun (Lokhttp3/ConnectionListener;Lkotlin/jvm/functions/Function1;)V + public synthetic fun (Lokhttp3/ConnectionListener;Lkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun connectEnd (Lokhttp3/Connection;Lokhttp3/Route;Lokhttp3/Call;)V + public fun connectFailed (JLokhttp3/Route;Lokhttp3/Call;Ljava/io/IOException;)V + public fun connectStart (JLokhttp3/Route;Lokhttp3/Call;)V + public fun connectionAcquired (Lokhttp3/Connection;Lokhttp3/Call;)V + public fun connectionClosed (Lokhttp3/Connection;)V + public fun connectionReleased (Lokhttp3/Connection;Lokhttp3/Call;)V + public final fun getTraceLabel ()Lkotlin/jvm/functions/Function1; + public fun noNewExchanges (Lokhttp3/Connection;)V +} + +public final class okhttp3/android/AndroidxTracingConnectionListener$Companion { + public final fun getDefaultTracingLabel (Lokhttp3/Route;)Ljava/lang/String; +} + +public final class okhttp3/android/AndroidxTracingInterceptor : okhttp3/Interceptor { + public static final field Companion Lokhttp3/android/AndroidxTracingInterceptor$Companion; + public fun ()V + public fun (Lkotlin/jvm/functions/Function1;)V + public synthetic fun (Lkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun getTraceLabel ()Lkotlin/jvm/functions/Function1; + public fun intercept (Lokhttp3/Interceptor$Chain;)Lokhttp3/Response; +} + +public final class okhttp3/android/AndroidxTracingInterceptor$Companion { + public final fun getDefaultTracingLabel (Lokhttp3/Request;)Ljava/lang/String; +} + diff --git a/okhttp/api/jvm/okhttp.api b/okhttp/api/jvm/okhttp.api index fcc0709091a4..7ef220781244 100644 --- a/okhttp/api/jvm/okhttp.api +++ b/okhttp/api/jvm/okhttp.api @@ -354,6 +354,7 @@ public final class okhttp3/CipherSuite$Companion { } public abstract interface class okhttp3/Connection { + public abstract fun getId ()J public abstract fun handshake ()Lokhttp3/Handshake; public abstract fun protocol ()Lokhttp3/Protocol; public abstract fun route ()Lokhttp3/Route; @@ -364,8 +365,8 @@ public abstract class okhttp3/ConnectionListener { public static final field Companion Lokhttp3/ConnectionListener$Companion; public fun ()V public fun connectEnd (Lokhttp3/Connection;Lokhttp3/Route;Lokhttp3/Call;)V - public fun connectFailed (Lokhttp3/Route;Lokhttp3/Call;Ljava/io/IOException;)V - public fun connectStart (Lokhttp3/Route;Lokhttp3/Call;)V + public fun connectFailed (JLokhttp3/Route;Lokhttp3/Call;Ljava/io/IOException;)V + public fun connectStart (JLokhttp3/Route;Lokhttp3/Call;)V public fun connectionAcquired (Lokhttp3/Connection;Lokhttp3/Call;)V public fun connectionClosed (Lokhttp3/Connection;)V public fun connectionReleased (Lokhttp3/Connection;Lokhttp3/Call;)V diff --git a/okhttp/src/androidMain/kotlin/okhttp3/android/AndroidxTracingConnectionListener.kt b/okhttp/src/androidMain/kotlin/okhttp3/android/AndroidxTracingConnectionListener.kt new file mode 100644 index 000000000000..826dda486275 --- /dev/null +++ b/okhttp/src/androidMain/kotlin/okhttp3/android/AndroidxTracingConnectionListener.kt @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2024 Block, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package okhttp3.android + +import androidx.tracing.Trace +import okhttp3.Call +import okhttp3.Connection +import okhttp3.ConnectionListener +import okhttp3.Route +import okhttp3.android.AndroidxTracingInterceptor.Companion.MAX_TRACE_LABEL_LENGTH +import okio.IOException + +/** + * Tracing implementation of ConnectionListener that marks the lifetime of each connection + * in Perfetto traces. + */ +class AndroidxTracingConnectionListener( + private val delegate: ConnectionListener = NONE, + val traceLabel: (Route) -> String = { it.defaultTracingLabel }, +) : ConnectionListener() { + override fun connectStart( + connectionId: Long, + route: Route, + call: Call, + ) { + Trace.beginAsyncSection(labelForTrace(route), connectionId.toInt()) + delegate.connectStart(connectionId, route, call) + } + + override fun connectFailed( + connectionId: Long, + route: Route, + call: Call, + failure: IOException, + ) { + Trace.endAsyncSection(labelForTrace(route), connectionId.toInt()) + delegate.connectFailed(connectionId, route, call, failure) + } + + override fun connectEnd( + connection: Connection, + route: Route, + call: Call, + ) { + delegate.connectEnd(connection, route, call) + } + + override fun connectionClosed(connection: Connection) { + Trace.endAsyncSection(labelForTrace(connection.route()), connection.id.toInt()) + delegate.connectionClosed(connection) + } + + private fun labelForTrace(route: Route): String = traceLabel(route).take(MAX_TRACE_LABEL_LENGTH) + + override fun connectionAcquired( + connection: Connection, + call: Call, + ) { + delegate.connectionAcquired(connection, call) + } + + override fun connectionReleased( + connection: Connection, + call: Call, + ) { + delegate.connectionReleased(connection, call) + } + + override fun noNewExchanges(connection: Connection) { + delegate.noNewExchanges(connection) + } + + companion object { + val Route.defaultTracingLabel: String + get() = this.address.url.host + } +} diff --git a/okhttp/src/androidMain/kotlin/okhttp3/android/TracingInterceptor.kt b/okhttp/src/androidMain/kotlin/okhttp3/android/AndroidxTracingInterceptor.kt similarity index 68% rename from okhttp/src/androidMain/kotlin/okhttp3/android/TracingInterceptor.kt rename to okhttp/src/androidMain/kotlin/okhttp3/android/AndroidxTracingInterceptor.kt index c57837d2b3fd..ca2dd8f090c8 100644 --- a/okhttp/src/androidMain/kotlin/okhttp3/android/TracingInterceptor.kt +++ b/okhttp/src/androidMain/kotlin/okhttp3/android/AndroidxTracingInterceptor.kt @@ -22,16 +22,22 @@ import okhttp3.Request import okhttp3.Response /** - * Tracing implementation of Interceptor that marks each Call in a perfetto - * trace. + * Tracing implementation of Interceptor that marks each Call in a Perfetto + * trace. Typically used as a network interceptor. */ -class TracingInterceptor : Interceptor { +class AndroidxTracingInterceptor(val traceLabel: (Request) -> String = { it.defaultTracingLabel }) : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { - return trace(chain.request().tracingTag) { + return trace(traceLabel(chain.request()).take(MAX_TRACE_LABEL_LENGTH)) { chain.proceed(chain.request()) } } - val Request.tracingTag: String - get() = url.encodedPath.take(127) + companion object { + internal const val MAX_TRACE_LABEL_LENGTH = 127 + + val Request.defaultTracingLabel: String + get() { + return url.encodedPath + } + } } diff --git a/okhttp/src/androidMain/kotlin/okhttp3/android/TracingConnectionListener.kt b/okhttp/src/androidMain/kotlin/okhttp3/android/TracingConnectionListener.kt deleted file mode 100644 index ed94e427215c..000000000000 --- a/okhttp/src/androidMain/kotlin/okhttp3/android/TracingConnectionListener.kt +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2022 Block, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package okhttp3.android - -import androidx.tracing.Trace -import java.util.concurrent.atomic.AtomicInteger -import okhttp3.Call -import okhttp3.Connection -import okhttp3.ConnectionListener -import okhttp3.Route -import okio.IOException - -/** - * Tracing implementation of ConnectionListener that marks the lifetime of each connection - * in perfetto traces. - */ -class TracingConnectionListener : ConnectionListener() { - private val idGenerator = AtomicInteger(0) - - override fun connectStart( - route: Route, - call: Call, - ) { - Trace.beginAsyncSection(route.tracingTag, idGenerator.incrementAndGet()) - } - - override fun connectFailed( - route: Route, - call: Call, - failure: IOException, - ) { - // TODO same id - Trace.endAsyncSection(route.tracingTag, idGenerator.incrementAndGet()) - } - - override fun connectionClosed(connection: Connection) { - // TODO same id - Trace.endAsyncSection(connection.route().tracingTag, idGenerator.incrementAndGet()) - } - - val Route.tracingTag: String - get() = this.address.url.host -} diff --git a/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Connection.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Connection.kt index 20dda3de9dc7..6e7eaceaaa12 100644 --- a/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Connection.kt +++ b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Connection.kt @@ -67,6 +67,9 @@ import java.net.Socket * been found. But only complete the stream once its data stream has been exhausted. */ interface Connection { + /** Unique id of this connection, assigned at the time of the attempt. */ + val id: Long + /** Returns the route used by this connection. */ fun route(): Route diff --git a/okhttp/src/commonJvmAndroid/kotlin/okhttp3/ConnectionListener.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/ConnectionListener.kt index 458e5ac4e219..d08fa7c2ab8e 100644 --- a/okhttp/src/commonJvmAndroid/kotlin/okhttp3/ConnectionListener.kt +++ b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/ConnectionListener.kt @@ -30,6 +30,7 @@ abstract class ConnectionListener { * Invoked as soon as a call causes a connection to be started. */ open fun connectStart( + connectionId: Long, route: Route, call: Call, ) {} @@ -38,6 +39,7 @@ abstract class ConnectionListener { * Invoked when a connection fails to be established. */ open fun connectFailed( + connectionId: Long, route: Route, call: Call, failure: IOException, diff --git a/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/CallConnectionUser.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/CallConnectionUser.kt index 8a28086a4933..933dc0858481 100644 --- a/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/CallConnectionUser.kt +++ b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/CallConnectionUser.kt @@ -36,18 +36,19 @@ internal class CallConnectionUser( call.client.routeDatabase.connected(route) } - override fun connectStart(route: Route) { + override fun connectStart(connectionId: Long, route: Route) { eventListener.connectStart(call, route.socketAddress, route.proxy) - poolConnectionListener.connectStart(route, call) + poolConnectionListener.connectStart(connectionId, route, call) } override fun connectFailed( + connectionId: Long, route: Route, protocol: Protocol?, e: IOException, ) { eventListener.connectFailed(call, route.socketAddress, route.proxy, null, e) - poolConnectionListener.connectFailed(route, call, e) + poolConnectionListener.connectFailed(connectionId, route, call, e) } override fun secureConnectStart() { diff --git a/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/ConnectPlan.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/ConnectPlan.kt index a2815f5c1de3..f7e4b9774eaf 100644 --- a/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/ConnectPlan.kt +++ b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/ConnectPlan.kt @@ -24,6 +24,7 @@ import java.net.Socket import java.net.UnknownServiceException import java.security.cert.X509Certificate import java.util.concurrent.TimeUnit +import java.util.concurrent.atomic.AtomicLong import javax.net.ssl.SSLPeerUnverifiedException import javax.net.ssl.SSLSocket import okhttp3.CertificatePinner @@ -78,6 +79,8 @@ class ConnectPlan( internal val connectionSpecIndex: Int, internal val isTlsFallback: Boolean, ) : RoutePlanner.Plan, ExchangeCodec.Carrier { + private val id = idGenerator.incrementAndGet() + /** True if this connect was canceled; typically because it lost a race. */ @Volatile private var canceled = false @@ -135,7 +138,7 @@ class ConnectPlan( // Tell the call about the connecting call so async cancels work. user.addPlanToCancel(this) try { - user.connectStart(route) + user.connectStart(id, route) connectSocket() success = true @@ -149,7 +152,7 @@ class ConnectPlan( e, ) } - user.connectFailed(route, null, e) + user.connectFailed(id, route, null, e) return ConnectResult(plan = this, throwable = e) } finally { user.removePlanToCancel(this) @@ -231,6 +234,7 @@ class ConnectPlan( sink = sink, pingIntervalMillis = pingIntervalMillis, connectionListener = connectionPool.connectionListener, + id = id, ) this.connection = connection connection.start() @@ -240,7 +244,7 @@ class ConnectPlan( success = true return ConnectResult(plan = this) } catch (e: IOException) { - user.connectFailed(route, null, e) + user.connectFailed(id, route, null, e) if (!retryOnConnectionFailure || !retryTlsHandshake(e)) { retryTlsConnection = null @@ -333,7 +337,7 @@ class ConnectPlan( ProtocolException( "Too many tunnel connections attempted: $MAX_TUNNEL_ATTEMPTS", ) - user.connectFailed(route, null, failure) + user.connectFailed(id, route, null, failure) return ConnectResult(plan = this, throwable = failure) } } @@ -565,5 +569,7 @@ class ConnectPlan( companion object { private const val NPE_THROW_WITH_NULL = "throw with null exception" private const val MAX_TUNNEL_ATTEMPTS = 21 + + private val idGenerator = AtomicLong(0) } } diff --git a/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/ConnectionUser.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/ConnectionUser.kt index d6856c0d118f..a09f16ee59d0 100644 --- a/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/ConnectionUser.kt +++ b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/ConnectionUser.kt @@ -35,7 +35,10 @@ interface ConnectionUser { fun updateRouteDatabaseAfterSuccess(route: Route) - fun connectStart(route: Route) + fun connectStart( + connectionId: Long, + route: Route, + ) fun secureConnectStart() @@ -52,6 +55,7 @@ interface ConnectionUser { ) fun connectFailed( + connectionId: Long, route: Route, protocol: Protocol?, e: IOException, diff --git a/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/PoolConnectionUser.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/PoolConnectionUser.kt index 94b5677680cf..bcdac1b440dd 100644 --- a/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/PoolConnectionUser.kt +++ b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/PoolConnectionUser.kt @@ -39,7 +39,10 @@ object PoolConnectionUser : ConnectionUser { override fun updateRouteDatabaseAfterSuccess(route: Route) { } - override fun connectStart(route: Route) { + override fun connectStart( + connectionId: Long, + route: Route, + ) { } override fun secureConnectStart() { @@ -61,6 +64,7 @@ object PoolConnectionUser : ConnectionUser { } override fun connectFailed( + connectionId: Long, route: Route, protocol: Protocol?, e: IOException, diff --git a/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/RealConnection.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/RealConnection.kt index b2048715f906..eb8d92b3bb7a 100644 --- a/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/RealConnection.kt +++ b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/RealConnection.kt @@ -84,6 +84,7 @@ class RealConnection( private val sink: BufferedSink, private val pingIntervalMillis: Int, internal val connectionListener: ConnectionListener, + override val id: Long, ) : Http2Connection.Listener(), Connection, ExchangeCodec.Carrier { private var http2Connection: Http2Connection? = null @@ -496,6 +497,7 @@ class RealConnection( }.buffer(), pingIntervalMillis = 0, ConnectionListener.NONE, + 0L, ) result.idleAtNs = idleAtNs return result From cdd392d7216301afa6a65974275b03d3217bbc2f Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Sat, 4 Jan 2025 14:45:34 +0000 Subject: [PATCH 6/9] Fixes --- .../src/main/kotlin/okhttp3/RecordingConnectionListener.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/RecordingConnectionListener.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/RecordingConnectionListener.kt index 96f63d5d1a2c..845383eabb43 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/RecordingConnectionListener.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/RecordingConnectionListener.kt @@ -137,11 +137,13 @@ open class RecordingConnectionListener( } override fun connectStart( + connectionId: Long, route: Route, call: Call, ) = logEvent(ConnectionEvent.ConnectStart(System.nanoTime(), route, call)) override fun connectFailed( + connectionId: Long, route: Route, call: Call, failure: IOException, From 61cd52701762c13780645aa2f2fd66d93cbb4d09 Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Sat, 4 Jan 2025 14:46:03 +0000 Subject: [PATCH 7/9] Fixes --- .../main/kotlin/okhttp/android/testapp/MainActivity.kt | 9 +++++---- .../okhttp3/internal/connection/CallConnectionUser.kt | 5 ++++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/android-test-app/src/main/kotlin/okhttp/android/testapp/MainActivity.kt b/android-test-app/src/main/kotlin/okhttp/android/testapp/MainActivity.kt index ba20c378bde0..27a69ff48fb3 100644 --- a/android-test-app/src/main/kotlin/okhttp/android/testapp/MainActivity.kt +++ b/android-test-app/src/main/kotlin/okhttp/android/testapp/MainActivity.kt @@ -33,10 +33,11 @@ class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - val client = OkHttpClient.Builder() - .connectionPool(ConnectionPool(connectionListener = AndroidxTracingConnectionListener())) - .addNetworkInterceptor(AndroidxTracingInterceptor()) - .build() + val client = + OkHttpClient.Builder() + .connectionPool(ConnectionPool(connectionListener = AndroidxTracingConnectionListener())) + .addNetworkInterceptor(AndroidxTracingInterceptor()) + .build() // Ensure we are compiling against the right variant println(AndroidPlatform.isSupported) diff --git a/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/CallConnectionUser.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/CallConnectionUser.kt index 933dc0858481..f2428b5f4691 100644 --- a/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/CallConnectionUser.kt +++ b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/CallConnectionUser.kt @@ -36,7 +36,10 @@ internal class CallConnectionUser( call.client.routeDatabase.connected(route) } - override fun connectStart(connectionId: Long, route: Route) { + override fun connectStart( + connectionId: Long, + route: Route, + ) { eventListener.connectStart(call, route.socketAddress, route.proxy) poolConnectionListener.connectStart(connectionId, route, call) } From a29e793896ad4379f85d8b5595d6041949402317 Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Sat, 4 Jan 2025 15:49:04 +0000 Subject: [PATCH 8/9] Fix KotlinSourceModernTest --- okhttp/src/commonJvmAndroid/kotlin/okhttp3/Connection.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Connection.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Connection.kt index 6e7eaceaaa12..af7e558004fb 100644 --- a/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Connection.kt +++ b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Connection.kt @@ -69,6 +69,7 @@ import java.net.Socket interface Connection { /** Unique id of this connection, assigned at the time of the attempt. */ val id: Long + get() = 0L /** Returns the route used by this connection. */ fun route(): Route From 61d361efed30850b80ee499ef2b3c2a038050a90 Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Sat, 4 Jan 2025 16:24:50 +0000 Subject: [PATCH 9/9] Fixes --- okhttp/api/android/okhttp.api | 2 +- okhttp/api/jvm/okhttp.api | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/okhttp/api/android/okhttp.api b/okhttp/api/android/okhttp.api index 48445680425b..1024ad21f611 100644 --- a/okhttp/api/android/okhttp.api +++ b/okhttp/api/android/okhttp.api @@ -354,7 +354,7 @@ public final class okhttp3/CipherSuite$Companion { } public abstract interface class okhttp3/Connection { - public abstract fun getId ()J + public fun getId ()J public abstract fun handshake ()Lokhttp3/Handshake; public abstract fun protocol ()Lokhttp3/Protocol; public abstract fun route ()Lokhttp3/Route; diff --git a/okhttp/api/jvm/okhttp.api b/okhttp/api/jvm/okhttp.api index 7ef220781244..48f01da72c22 100644 --- a/okhttp/api/jvm/okhttp.api +++ b/okhttp/api/jvm/okhttp.api @@ -354,7 +354,7 @@ public final class okhttp3/CipherSuite$Companion { } public abstract interface class okhttp3/Connection { - public abstract fun getId ()J + public fun getId ()J public abstract fun handshake ()Lokhttp3/Handshake; public abstract fun protocol ()Lokhttp3/Protocol; public abstract fun route ()Lokhttp3/Route;