diff --git a/Corona-Warn-App/src/deviceForTesters/AndroidManifest.xml b/Corona-Warn-App/src/deviceForTesters/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..88a2064d0a9ce8cd0aeff6f6f8bbf950930d744f --- /dev/null +++ b/Corona-Warn-App/src/deviceForTesters/AndroidManifest.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android"> + + <queries> + <!-- See DebugLogger.isAutoLoggingEnabled --> + <package android:name="de.rki.coronawarnapp.els.autologger" /> + </queries> + +</manifest> diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/DebugLogger.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/DebugLogger.kt index ab7f0f1f689ab045fca88abbefb6e70b9cdc0e1f..3860af4b3168b998dd46e7f56eb9d9c0bfbfca8d 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/DebugLogger.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/DebugLogger.kt @@ -2,6 +2,7 @@ package de.rki.coronawarnapp.bugreporting.debuglog import android.annotation.SuppressLint import android.content.Context +import android.content.pm.PackageManager import android.util.Log import de.rki.coronawarnapp.bugreporting.censors.BugCensor import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebugLogStorageCheck @@ -62,13 +63,30 @@ class DebugLogger( ) } + private fun isAutoLoggingEnabled(): Boolean { + if (!CWADebug.isDeviceForTestersBuild) return false + + return try { + val autoLoggerPkg = "de.rki.coronawarnapp.els.autologger" + context.packageManager.getPackageInfo(autoLoggerPkg, 0) + Timber.tag(TAG).i("Autologger package is installed (%s).", autoLoggerPkg) + true + } catch (e: PackageManager.NameNotFoundException) { + Timber.tag(TAG).i("DeviceForTester build, but no autologger package installed.") + false + } catch (e: Exception) { + Timber.tag(TAG).e(e, "Failed to determiner if autologger package is installed.") + false + } + } + fun init() = try { val startLogger = when { triggerFile.exists() -> { Timber.tag(TAG).i("Trigger file exists, starting debug log.") true } - CWADebug.isDeviceForTestersBuild -> { + isAutoLoggingEnabled() -> { Timber.tag(TAG).i("Trigger file does not exist, but it's a tester build, starting debug log.") true } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/DebugLoggerTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/DebugLoggerTest.kt index 329aed6fb188a493fc6a7197f41e29b5ee9628f9..20309b770c3034c9cfe29faaf8f245e013842c6e 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/DebugLoggerTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/DebugLoggerTest.kt @@ -1,6 +1,7 @@ package de.rki.coronawarnapp.bugreporting.debuglog import android.app.Application +import android.content.pm.PackageManager import dagger.Lazy import de.rki.coronawarnapp.bugreporting.censors.BugCensor import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebugLogTree @@ -10,11 +11,14 @@ import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldNotBe import io.kotest.matchers.string.shouldEndWith import io.kotest.matchers.string.shouldStartWith +import io.mockk.Called import io.mockk.MockKAnnotations import io.mockk.coEvery import io.mockk.every import io.mockk.impl.annotations.MockK +import io.mockk.mockk import io.mockk.mockkObject +import io.mockk.verify import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.test.runBlockingTest @@ -31,6 +35,7 @@ import java.io.File class DebugLoggerTest : BaseIOTest() { @MockK lateinit var application: Application + @MockK lateinit var packageManager: PackageManager @MockK lateinit var component: ApplicationComponent @MockK lateinit var coronaTestCensor1: BugCensor @MockK lateinit var coronaTestCensor2: BugCensor @@ -51,6 +56,8 @@ class DebugLoggerTest : BaseIOTest() { testDir.exists() shouldBe true every { application.cacheDir } returns cacheDir + every { application.packageManager } returns packageManager + every { component.inject(any<DebugLogger>()) } answers { val logger = arg<DebugLogger>(0) logger.bugCensors = Lazy { setOf(coronaTestCensor1, coronaTestCensor2) } @@ -102,9 +109,13 @@ class DebugLoggerTest : BaseIOTest() { } @Test - fun `init calls start if it is a tester build`() = runBlockingTest { + fun `init calls start if it is a tester build and autologger pkg is installed`() = runBlockingTest { every { CWADebug.isDeviceForTestersBuild } returns true + every { + packageManager.getPackageInfo("de.rki.coronawarnapp.els.autologger", 0) + } returns mockk() + val instance = createInstance(scope = this).apply { init() setInjectionIsReady(component) @@ -116,6 +127,59 @@ class DebugLoggerTest : BaseIOTest() { instance.stop() } + @Test + fun `init does not call start on tester builds without the autologger pkg`() = runBlockingTest { + every { CWADebug.isDeviceForTestersBuild } returns true + + every { application.packageManager } returns mockk<PackageManager>().apply { + every { getPackageInfo(any<String>(), any()) } throws PackageManager.NameNotFoundException() + } + + val instance = createInstance(scope = this).apply { + init() + setInjectionIsReady(component) + isLogging.value shouldBe false + } + + runningLog.exists() shouldBe false + + instance.stop() + } + + @Test + fun `init does not call start on tester builds with ROM issues`() = runBlockingTest { + every { CWADebug.isDeviceForTestersBuild } returns true + + every { application.packageManager } throws SecurityException() + + val instance = createInstance(scope = this).apply { + init() + setInjectionIsReady(component) + isLogging.value shouldBe false + } + + runningLog.exists() shouldBe false + + instance.stop() + } + + @Test + fun `package check is not executed in PROD`() = runBlockingTest { + every { CWADebug.isDeviceForTestersBuild } returns false + + val instance = createInstance(scope = this).apply { + init() + setInjectionIsReady(component) + isLogging.value shouldBe false + } + + runningLog.exists() shouldBe false + + instance.stop() + + verify { packageManager wasNot Called } + } + @Test fun `start plants a tree and starts a logging coroutine`() = runBlockingTest { val instance = createInstance(scope = this).apply {