A way to customize coverageFile argument when running RemoteAndroidTest

Hi, I’m suffering permission denial issue when running jacoco test report task, using Android Studio.

I work on device manufacturer, so I have ongoing device can be rooted.
API level is 29

I configured jacoco with instrumented test to get coverage report.

In my build.gradle (app), I got

apply plugin: 'jacoco'

jacoco {
    reportsDir = file("${buildDir}/reports")
}

task coverageReport(type: JacocoReport, dependsOn: ['testDebugUnitTest', 'createDebugCoverageReport']) {
    group = "Reporting"
    description = "Generate Jacoco coverage reports"

    def coverageSourceDirs = ['src/main']

    getClassDirectories().setFrom (fileTree(
            dir: "${buildDir}/intermediates/classes/dev/debug",
            excludes: ['**/R.class',
                       '**/R$*.class',
                       '**/BuildConfig.*',
                       '**/Manifest*.*',
                       'com/android/**/*.class']
    ))

    getSourceDirectories().setFrom ( files(coverageSourceDirs) )
    getExecutionData().setFrom (files("${buildDir}/jacoco/testDebugUnitTest.exec"))

    reports {
        xml.enabled = true
        html.enabled = true
    }
}

And in android block,

android {
  buildTypes {
    debug {
      testCoverageEnabled true
    }
  }
}

When I run this command, I got internal error that indicates coverage.ec file generation failed due to permission denial from target device.

Run command

gradlew -i createDebugAndroidTestCoverageReport

In gradle console,

It start am instrument with below command and finished succesfully:

[RemoteAndroidTest]: Running am instrument -w -r   -e coverageFile /data/data/PACKAGENAME/coverage.ec -e coverage true PACKAGENAME/androidx.test.runner.AndroidJUnitRunner on DEVICENAME
Starting 224 tests on DEVICENAME
...

But coverage.ec file from target device is zero-sized file.

when I start am instrument by manually:

INSTRUMENTATION_RESULT: stream=

Time: 10.697

OK (224 tests)


Error: Failed to generate Emma/JaCoCo coverage.
INSTRUMENTATION_CODE: -1

adb logcat says:

10-07 04:16:56.380  4237  4263 E CoverageListener: Failed to generate Emma/JaCoCo coverage. 
10-07 04:16:56.380  4237  4263 E CoverageListener: java.lang.reflect.InvocationTargetException
10-07 04:16:56.380  4237  4263 E CoverageListener: 	at java.lang.reflect.Method.invoke(Native Method)
10-07 04:16:56.380  4237  4263 E CoverageListener: 	at androidx.test.internal.runner.listener.CoverageListener.generateCoverageReport(CoverageListener.java:101)
10-07 04:16:56.380  4237  4263 E CoverageListener: 	at androidx.test.internal.runner.listener.CoverageListener.instrumentationRunFinished(CoverageListener.java:70)
10-07 04:16:56.380  4237  4263 E CoverageListener: 	at androidx.test.internal.runner.TestExecutor.reportRunEnded(TestExecutor.java:92)
10-07 04:16:56.380  4237  4263 E CoverageListener: 	at androidx.test.internal.runner.TestExecutor.execute(TestExecutor.java:65)
10-07 04:16:56.380  4237  4263 E CoverageListener: 	at androidx.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:392)
10-07 04:16:56.380  4237  4263 E CoverageListener: 	at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2196)
10-07 04:16:56.380  4237  4263 E CoverageListener: Caused by: java.io.FileNotFoundException: /data/data/PACKAGE NAME/coverage.ec: open failed: EACCES (Permission denied)

Checked user name of process:

shell        29622   980 5 05:15:33 pts/0 00:00:00 app_process /system/bin com.android.commands.am.Am instrument -w -r -e coverageFile /data/data/PACKAGENAME/coverage.ec -e coverage true PACKAGENAME/androidx.test.runner.AndroidJUnitRunner

It runs with “shell” user, which can not access /data/data/PACKAGENAME/ directory…

drwx------   4 system         system          4096 2020-10-07 05:15 PACKAGENAME

But regardless user, it fails with permission denial.
Tried with “adb root” but nothing changes.

root         32621 32130 15 05:17:49 pts/1 00:00:00 app_process /system/bin com.android.commands.am.Am instrument -w -r -e coverageFile /data/data/PACKAGENAME/coverage.ec -e coverage true PACKAGENAME/androidx.test.runner.AndroidJUnitRunner

in Manifest, I have system uid

<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:sharedUserId="android.uid.system" ...

In conclusion, it is caused because:

  • JUnit runner runs with “shell” or “root” user, but directory is only opened to user “system”

So, I’m wondering if there’s any way to configure “coverageFile” argument when task runs “am instrument”.

Any tips or workaround trick will be very appreciated.

Thanks…

You can configure “coverageFile” argument as below (for example):

defaultConfig {
    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    testInstrumentationRunnerArguments coverageFile: "/data/user/10/com.bmwgroup.apinext.chinaappstore/coverage1.ec"
}