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

createSessionId() executes on the Main (UI) thread in Android #113

Closed
jhansche opened this Issue Jun 13, 2013 · 3 comments

Comments

Projects
None yet
2 participants
@jhansche

jhansche commented Jun 13, 2013

The agent fails in startup() because createSessionId() accesses the network layer, and with Strict Mode enabled, any Network access from the Main/UI thread results in an exception being thrown. Because startup() fails, this.output is never created, and therefore shutdown() fails with a NullPointerException because this.output is null. This is the stack trace from startup():

 android.os.NetworkOnMainThreadException
    at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1117)
    at java.net.InetAddress.lookupHostByName(InetAddress.java:385)
    at java.net.InetAddress.getLocalHost(InetAddress.java:365)
    at org.jacoco.agent.rt.internal_9dd1198.Agent.createSessionId(Agent.java:179)
    at org.jacoco.agent.rt.internal_9dd1198.Agent.startup(Agent.java:122)
    at org.jacoco.agent.rt.internal_9dd1198.Agent.getInstance(Agent.java:56)
    at org.jacoco.agent.rt.internal_9dd1198.Offline.<clinit>(Offline.java:31)
    at com.example.MyApplication.$jacocoInit(MyApplication.java)
    at com.example.MyApplication.<clinit>(MyApplication.java)
    at java.lang.Class.newInstanceImpl(Native Method)
    at java.lang.Class.newInstance(Class.java:1319)
    at android.app.Instrumentation.newApplication(Instrumentation.java:983)
    at android.app.Instrumentation.newApplication(Instrumentation.java:968)
    at android.app.LoadedApk.makeApplication(LoadedApk.java:499)
    at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4364)
    at android.app.ActivityThread.access$1300(ActivityThread.java:141)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1294)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:137)
    at android.app.ActivityThread.main(ActivityThread.java:5041)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:511)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
    at dalvik.system.NativeStart.main(Native Method)

and the stacktrace in shutdown():

06-13 12:49:31.339 W/System.err( 2083): java.lang.NullPointerException
06-13 12:49:31.349 W/System.err( 2083):     at org.jacoco.agent.rt.internal_9dd1198.Agent.shutdown(Agent.java:143)
06-13 12:49:31.349 W/System.err( 2083):     at org.jacoco.agent.rt.internal_9dd1198.Agent$1.run(Agent.java:60)

This can be mitigated by adding the sessionid option to jacoco-agent.properties on the classpath -- which does allow the instrumentation to continue, and the jacoco.exec file does get generated. But it should still be avoided: possibly by catching the NetworkOnMainThreadException and fall back to a non-network session id technique. Or by checking the current StrictMode settings before attempting to use getLocalHost().

@marchof

This comment has been minimized.

Show comment
Hide comment
@marchof

marchof Jun 13, 2013

Member

JaCoCo cannot depend on Android APIs. It is a generic code coverage tool for Java.

What we can do is to modify the following method in Agent to catch java.lang.Exception exception:

private String createSessionId() {
    String host;
    try {
        host = InetAddress.getLocalHost().getHostName();
    } catch (final UnknownHostException e) {
        host = "unknownhost";
    }
    return host + "-" + AbstractRuntime.createRandomId();
}
Member

marchof commented Jun 13, 2013

JaCoCo cannot depend on Android APIs. It is a generic code coverage tool for Java.

What we can do is to modify the following method in Agent to catch java.lang.Exception exception:

private String createSessionId() {
    String host;
    try {
        host = InetAddress.getLocalHost().getHostName();
    } catch (final UnknownHostException e) {
        host = "unknownhost";
    }
    return host + "-" + AbstractRuntime.createRandomId();
}
@jhansche

This comment has been minimized.

Show comment
Hide comment
@jhansche

jhansche Jun 13, 2013

Aha, you're right. Sorry, forgot that this wasn't an Android-specific runtime agent. :) Assuming in your code snippet you intended to replace UnknownHostException with base Exception? I think that would work well. In my case, I simply created a property based on the ${maven.build.timestamp} and filter that property in my src/test/resources/jacoco-agent.properties file entry for sessionid:

            <properties>
                <jacoco.sessionid>jacoco-${maven.build.timestamp}</jacoco.sessionid>
            </properties>
sessionid = ${jacoco.sessionid}

This works for me and allows the tests to continue in the Android emulator. So replacing the real hostname with 'unknownhost' in the case of any Exception should allow it to work "out of the box"

jhansche commented Jun 13, 2013

Aha, you're right. Sorry, forgot that this wasn't an Android-specific runtime agent. :) Assuming in your code snippet you intended to replace UnknownHostException with base Exception? I think that would work well. In my case, I simply created a property based on the ${maven.build.timestamp} and filter that property in my src/test/resources/jacoco-agent.properties file entry for sessionid:

            <properties>
                <jacoco.sessionid>jacoco-${maven.build.timestamp}</jacoco.sessionid>
            </properties>
sessionid = ${jacoco.sessionid}

This works for me and allows the tests to continue in the Android emulator. So replacing the real hostname with 'unknownhost' in the case of any Exception should allow it to work "out of the box"

@marchof

This comment has been minimized.

Show comment
Hide comment
@marchof

marchof Jun 13, 2013

Member

Fixed in commit 54bf6f1. Should be available as 0.6.4-SNAPSHOT within the next hours.

Member

marchof commented Jun 13, 2013

Fixed in commit 54bf6f1. Should be available as 0.6.4-SNAPSHOT within the next hours.

@marchof marchof closed this Jun 13, 2013

@ghost ghost assigned marchof Aug 9, 2013

@jacoco jacoco locked and limited conversation to collaborators Jan 11, 2017

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.