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

Android O StrictMode: Untagged socket detected #3537

Closed
hameno opened this issue Aug 23, 2017 · 24 comments
Closed

Android O StrictMode: Untagged socket detected #3537

hameno opened this issue Aug 23, 2017 · 24 comments
Labels
android Relates to usage specifically on Android enhancement Feature not a bug
Milestone

Comments

@hameno
Copy link

hameno commented Aug 23, 2017

If we use StrictMode with VmPolicy detectAll() in Android O (Preview 6) we get errors in logcat like this:

08-23 14:41:03.439 E/StrictMode: null
                                 java.lang.Throwable: Untagged socket detected; use TrafficStats.setThreadSocketTag() to track all network usage
                                     at android.os.StrictMode.onUntaggedSocket(StrictMode.java:2010)
                                     at com.android.server.NetworkManagementSocketTagger.tag(NetworkManagementSocketTagger.java:78)
                                     at libcore.io.BlockGuardOs.tagSocket(BlockGuardOs.java:47)
                                     at libcore.io.BlockGuardOs.socket(BlockGuardOs.java:310)
                                     at libcore.io.IoBridge.socket(IoBridge.java:667)
                                     at java.net.PlainSocketImpl.socketCreate(PlainSocketImpl.java:116)
                                     at java.net.AbstractPlainSocketImpl.create(AbstractPlainSocketImpl.java:98)
                                     at java.net.Socket.createImpl(Socket.java:484)
                                     at java.net.Socket.getImpl(Socket.java:547)
                                     at java.net.Socket.setSoTimeout(Socket.java:1175)
                                     at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.java:221)
                                     at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:149)
                                     at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:195)
                                     at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:121)
                                     at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:100)
                                     at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42)
                                     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
                                     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
                                     at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)
                                     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
                                     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
                                     at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
                                     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
                                     at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:120)
                                     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
                                     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
                                     at <internal>
                                     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
                                     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
                                     at okhttp3.logging.HttpLoggingInterceptor.intercept(HttpLoggingInterceptor.java:211)
                                     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
                                     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
                                     at <internal>
                                     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
                                     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
                                     at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:185)
                                     at okhttp3.RealCall.execute(RealCall.java:69)
                                     at retrofit2.OkHttpCall.execute(OkHttpCall.java:180)
                                     at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall.execute(ExecutorCallAdapterFactory.java:91)
                                    at <internal>
                                     at <internal>
                                     at io.reactivex.internal.operators.observable.ObservableCreate.subscribeActual(ObservableCreate.java:40)
                                     at io.reactivex.Observable.subscribe(Observable.java:10903)
                                     at io.reactivex.internal.operators.observable.ObservableObserveOn.subscribeActual(ObservableObserveOn.java:45)
                                     at io.reactivex.Observable.subscribe(Observable.java:10903)
                                     at io.reactivex.internal.operators.observable.ObservableDoOnEach.subscribeActual(ObservableDoOnEach.java:42)
                                     at io.reactivex.Observable.subscribe(Observable.java:10903)
08-23 14:41:03.440 E/StrictMode:     at io.reactivex.internal.operators.observable.ObservableDefer.subscribeActual(ObservableDefer.java:39)
                                     at io.reactivex.Observable.subscribe(Observable.java:10903)
                                     at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeTask.run(ObservableSubscribeOn.java:96)
                                     at io.reactivex.Scheduler$DisposeTask.run(Scheduler.java:452)
                                     at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:61)
                                     at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:52)
                                     at java.util.concurrent.FutureTask.run(FutureTask.java:266)
                                     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
                                     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
                                     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
                                     at java.lang.Thread.run(Thread.java:764)

From what I can tell, this happens because the sockets are untagged - is that something okhttp might want to support?

@JakeWharton
Copy link
Member

It used to be supported and was removed. I looked at adding it back a few months ago, but it's weird because of HTTP/2. The easiest thing to do is probably tag them with a random int that we declare as being OkHttp and not bothering to differentiate per-request.

@swankjesse swankjesse added the bug Bug in existing code label Aug 30, 2017
@swankjesse swankjesse added this to the 3.9 milestone Aug 30, 2017
@swankjesse
Copy link
Member

I’m looking deeper into this. There’s a bunch of things that makes fixing this unsatisfying.

The way socket tagging works on Android is as follows:

  • Every thread gets a tag. Application code is supposed to set this with getAndSetThreadStatsTag().
  • When a socket is created, it inherits the tag of its creating thread.

This doesn’t map neatly to the HTTP protocol, or to OkHttp’s design. In particular:

  • OkHttp creates its own threads for async requests, and for HTTP/2. Who is responsible for assigning the tags for these threads?
  • HTTP/2 connections are be multiplexed across calls. Because multiple OkHttpClient instances can share a ConnectionPool, it’s even possible for an HTTP/2 connection to be shared by multiple OkHttpClients.

We could just blast a tag like 2007230 across all threads we touch, and the warning would disappear. But there would be negligible value to having such a tag.

I’m going to icebox this because all of the fixes I can imagine add considerable code and don’t provide additional value to the TrafficStats aggregate.

@swankjesse swankjesse reopened this Sep 3, 2017
@swankjesse swankjesse modified the milestones: Icebox, 3.9 Sep 3, 2017
@ojw28
Copy link

ojw28 commented Sep 11, 2017

there would be negligible value to having such a tag

Suppose a dev team sets penaltyDeath() for all strict mode violations in their internal app builds, so as to make it really obvious when a strict mode violation is introduced. OkHttp currently causes such app builds to die. I think "fixing" this has value in itself, even if the tag is arbitrary and adds no further value. So it seems worthwhile to set an arbitrary tag just to make the strict mode violation go away?

@yschimke
Copy link
Collaborator

yschimke commented Sep 11, 2017

If you don't need a SOCKS proxy configured, is this a suitable workaround for now? n.b. DelegatingSocketFactory is a test class, but you get the idea.

public class XxX {
  public static void main(String[] args) throws IOException {
    SocketFactory socketFactory = new DelegatingSocketFactory(SocketFactory.getDefault()) {
      @Override protected Socket configureSocket(Socket socket) throws IOException {
        // set android
        TrafficStats.tagSocket(socket);

        System.out.println("configured");

        return socket;
      }
    };
    OkHttpClient client = new OkHttpClient.Builder().socketFactory(socketFactory).build();

    Request req = new Request.Builder().url("https://google.com/robots.txt").build();
    try (Response response = client.newCall(req).execute()) {
      System.out.println(response.body.string().length());
    }
  }
}

@iam1492
Copy link

iam1492 commented Sep 26, 2017

Is there any update or workaround on this?

@JakeWharton
Copy link
Member

JakeWharton commented Sep 26, 2017 via email

@gaurav844
Copy link

i am facing same issue please help

@klgsnd
Copy link

klgsnd commented Dec 22, 2017

Hi @swankjesse ,
so have you decided which fix strategy to pursue ? BR

@yschimke
Copy link
Collaborator

The current policy which I don't think you will like is if you want to enable strict mode, you should also apply the workaround I posted above. There isn't a clean way to do this for library code like OkHttp given HTTP/2, and no current plans to implement tagging with an arbitrary number.

Worth keeping this open as 13 +1 suggests it's a popular topic.

ligi added a commit to walleth/walleth that referenced this issue Jan 29, 2018
klassm added a commit to klassm/andFHEM that referenced this issue Feb 17, 2018
Implement okhttp fix for Android >= Oreo, when all outgoing sockets
have to be tagged
See square/okhttp#3537
@nkeskinov
Copy link

nkeskinov commented Feb 28, 2018

The proposed workaround does not work for me. StrictMode now complains from the TrafficStats#tagSocket call:

02-28 11:53:16.353 E/StrictMode: null
java.lang.Throwable: Untagged socket detected; use TrafficStats.setThreadSocketTag() to track all network usage
    at android.os.StrictMode.onUntaggedSocket(StrictMode.java:2010)
    at com.android.server.NetworkManagementSocketTagger.tag(NetworkManagementSocketTagger.java:78)
    at dalvik.system.SocketTagger.tag(SocketTagger.java:55)
    at android.net.TrafficStats.tagSocket(TrafficStats.java:274)
    at com.foo.ApiService$1.configureSocket(ApiService.java:164)
    at com.foo.util.okhttp3.DelegatingSocketFactory.createSocket(DelegatingSocketFactory.java:36)
    ...

Setting an arbitrary tag through the DelegatingSocketFactory instead of calling TrafficStats#tagSocket, though, seems to work. How much worse is that workaround?

@zishanj
Copy link

zishanj commented Mar 26, 2018

I have tried @yschimke solution but it still gives me same error

@azizbekian
Copy link

As suggested in the warning message, I've applied TrafficStats.setThreadStatsTag(1) instead of TrafficStats.tagSocket(socket), the rest is the same as provided in the comment of yschimke.

@trycatchx
Copy link

Whether the latest version has fixed this problem?

@yschimke
Copy link
Collaborator

@zhangchaojiong No, you should use a workaround see comment by @azizbekian. See @swankjesse comment above for why we don't have a clean automatic solution for OkHttp.

@BulatMukhutdinov
Copy link

How I can set it up for picasso?

@yschimke
Copy link
Collaborator

I took a look at this again, even looking at Android specific code and a SocketFactory that sets the thread tag. But that implementation isn't called if we hit a proxy. Then the connect call might happen without that invocation.

So best workaround is problem implementing this in an EventListener.connectStart, if you are really keen this happens.

Closing for now as won't fix in OkHttp.

@jitendratiwari
Copy link

I am also facing same issuse so should I just add a tag and it will be resolved?

@regisd
Copy link

regisd commented Dec 15, 2020

To be clear, OKHttp doesn't spontaneously issue HTTP requests and cannot know what is the content it transports. The tagging should be done by the caller with TrafficStats.setThreadStatsTag() as indicated in https://stackoverflow.com/a/57963770/94363

@damienmabin
Copy link

If I use a 3rd party sdk that doesn't add the tag themself, is there a way to provide a "default tag strategy" to OkHttp so I don't need to wait on all 3rd party sdk to fix their tag themself ?

@yschimke
Copy link
Collaborator

@damienmabin not as far as I know.

@leinardi
Copy link

Firebase Crashlytics is affected by this issue... Is the only way removing detectUntaggedSockets() or is there some other workaround for 3rd party sdks like Crashlytics?

@yschimke
Copy link
Collaborator

If you can't change their socket factory, then removing detectUntaggedSockets() is the only option. Assuming no proxies involved, they could add this into the SDK, but I'm not sure they have the motivation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
android Relates to usage specifically on Android enhancement Feature not a bug
Projects
None yet
Development

No branches or pull requests