Search code examples
androidcrashlytics-androidandroid-strictmode

Crashlytics with StrictMode enabled (detect all) gives "untagged socket detected"


I've tried adding Crashlytics to my app, which already has StrictMode enabled with detectAll(). The result was Untagged socket detected; use TrafficStats.setThreadSocketTag() to track all network usage.

Full Stack:

E/StrictMode: null
java.lang.Throwable: Untagged socket detected; use TrafficStats.setThreadSocketTag() to track all network usage
    at android.os.StrictMode.onUntaggedSocket(StrictMode.java:2012)
    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 com.android.okhttp.internal.io.RealConnection.connectSocket(RealConnection.java:139)
    at com.android.okhttp.internal.io.RealConnection.connect(RealConnection.java:112)
    at com.android.okhttp.internal.http.StreamAllocation.findConnection(StreamAllocation.java:184)
    at com.android.okhttp.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:126)
    at com.android.okhttp.internal.http.StreamAllocation.newStream(StreamAllocation.java:95)
    at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:281)
    at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:224)
    at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:461)
    at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:407)
    at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:538)
    at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.getResponseCode(DelegatingHttpsURLConnection.java:105)
    at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.getResponseCode(Unknown Source:0)
    at io.fabric.sdk.android.services.network.HttpRequest.code(HttpRequest.java:1357)
    at io.fabric.sdk.android.services.settings.DefaultSettingsSpiCall.handleResponse(DefaultSettingsSpiCall.java:104)
    at io.fabric.sdk.android.services.settings.DefaultSettingsSpiCall.invoke(DefaultSettingsSpiCall.java:88)
    at io.fabric.sdk.android.services.settings.DefaultSettingsController.loadSettingsData(DefaultSettingsController.java:88)
    at io.fabric.sdk.android.services.settings.DefaultSettingsController.loadSettingsData(DefaultSettingsController.java:65)
    at io.fabric.sdk.android.services.settings.Settings.loadSettingsData(Settings.java:153)
    at io.fabric.sdk.android.Onboarding.retrieveSettingsData(Onboarding.java:126)
    at io.fabric.sdk.android.Onboarding.doInBackground(Onboarding.java:99)
    at io.fabric.sdk.android.Onboarding.doInBackground(Onboarding.java:45)
    at io.fabric.sdk.android.InitializationTask.doInBackground(InitializationTask.java:63)
    at io.fabric.sdk.android.InitializationTask.doInBackground(InitializationTask.java:28)
    at io.fabric.sdk.android.services.concurrency.AsyncTask$2.call(AsyncTask.java:311)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:457)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    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)
W/System.err: StrictMode VmPolicy violation with POLICY_DEATH; shutting down.

I tried to create a new project and it was the same, the code in MainActivity in the test project:

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    setCrashlytics();
    setStrictMode();
}

private void setCrashlytics() {
    Fabric.with(this, new Crashlytics());
}

private void setStrictMode() {
    if (BuildConfig.DEBUG) {
        StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                .detectAll()
                .penaltyLog()
                .build());
        StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
                .detectAll()
                .penaltyLog()
                .penaltyDeath()
                .build());
    }
}

I did see that Okhttp has this issue (as well as other libs) but I do not know if that is relevant.
I'll add a workaround as an answer (basically don't use detectAll()), but I wonder if there is a proper solution for this, maybe there's a way to add the tag to the socket?


Solution

  • A workaround is to not use detectAll(), I've copied the the code of detectAll() (from Crashlytics) and modified it; however I had to remove part of code since there are classes that are inaccessible.
    I'm not a huge fan of this workaround but I'm not sure there's a better solution.

    private void setStrictMode() {
        if (BuildConfig.DEBUG) {
            StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                    .detectAll()   // detectDiskReads, detectDiskWrites, detectNetwork
                    .penaltyLog()
                    .build());
    
            StrictMode.setVmPolicy(getStrictModeBuilder().build());
        }
    }
    
    private StrictMode.VmPolicy.Builder getStrictModeBuilder() {
        StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
    
        builder.detectLeakedSqlLiteObjects();
    
        final int sdkInt = Build.VERSION.SDK_INT;
        if (sdkInt >= Build.VERSION_CODES.HONEYCOMB) {
            builder.detectActivityLeaks();
            builder.detectLeakedClosableObjects();
        }
    
        if (sdkInt >= Build.VERSION_CODES.JELLY_BEAN) {
            builder.detectLeakedRegistrationObjects();
        }
    
        if (sdkInt >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
            builder.detectFileUriExposure();
        }
    
        if (sdkInt >= Build.VERSION_CODES.O) {
            builder.detectContentUriWithoutPermission();
        }
    
        builder.penaltyLog().penaltyDeath();
        return builder;
    }
    

    Option two - remove the penaltyDeath() from the VmPolicy - this is what I'm currently doing:

    private void setStrictMode() {
    if (BuildConfig.DEBUG) {
        StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                .detectAll()   // detectDiskReads, detectDiskWrites, detectNetwork
                .penaltyLog()
                .build());
    
        StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
                    .detectAll()
                    .penaltyLog()
                    .build());
    }