From 200a3ca2ba7e44db5a38fd6a9fc82fce7037e5f9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jakob=20M=C3=B6ller?= <jakob.moeller@sap.com>
Date: Thu, 11 Jun 2020 16:58:11 +0200
Subject: [PATCH] update to include exception for not enough storage space on
 main directory (#389)

* Update to include Exception for not enough space

Signed-off-by: d067928 <jakob.moeller@sap.com>

* Update to include Exception for not enough space

Signed-off-by: d067928 <jakob.moeller@sap.com>
---
 .../NotEnoughSpaceOnDiskException.kt          | 12 ++++++
 .../exception/reporting/ErrorCodes.kt         |  1 +
 .../storage/FileStorageHelper.kt              | 38 ++++++++-----------
 .../storage/TracingRepository.kt              |  3 ++
 .../coronawarnapp/util/CachedKeyFileHolder.kt |  4 ++
 .../util/CachedKeyFileHolderTest.kt           |  2 +-
 6 files changed, 37 insertions(+), 23 deletions(-)
 create mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/NotEnoughSpaceOnDiskException.kt

diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/NotEnoughSpaceOnDiskException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/NotEnoughSpaceOnDiskException.kt
new file mode 100644
index 000000000..28ae9a039
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/NotEnoughSpaceOnDiskException.kt
@@ -0,0 +1,12 @@
+package de.rki.coronawarnapp.exception
+
+import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.exception.reporting.ErrorCodes
+import de.rki.coronawarnapp.exception.reporting.ReportedException
+
+class NotEnoughSpaceOnDiskException(cause: Throwable? = null) : ReportedException(
+    ErrorCodes.NOT_ENOUGH_AVAILABLE_SPACE_ON_DISK.code,
+    "the app detected that not enough storage space is available for the required operation",
+    cause,
+    R.string.errors_not_enough_device_storage
+)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/reporting/ErrorCodes.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/reporting/ErrorCodes.kt
index 9f62362d1..5b89a01d3 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/reporting/ErrorCodes.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/reporting/ErrorCodes.kt
@@ -20,5 +20,6 @@ enum class ErrorCodes(val code: Int) {
 
     // NONTECHNICAL
     NO_NETWORK_CONNECTIVITY(1),
+    NOT_ENOUGH_AVAILABLE_SPACE_ON_DISK(2),
     EXTERNAL_NAVIGATION(10),
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/FileStorageHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/FileStorageHelper.kt
index f1844b19f..44442e9e6 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/FileStorageHelper.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/FileStorageHelper.kt
@@ -1,8 +1,13 @@
 package de.rki.coronawarnapp.storage
 
+import android.content.Context
+import android.os.Build
+import android.os.storage.StorageManager
 import de.rki.coronawarnapp.CoronaWarnApplication
+import de.rki.coronawarnapp.exception.NotEnoughSpaceOnDiskException
 import timber.log.Timber
 import java.io.File
+import java.util.UUID
 import java.util.concurrent.TimeUnit
 
 /**
@@ -38,34 +43,23 @@ object FileStorageHelper {
      * Checks if internal store has free memory.
      * Threshold: FileStorageConstants.FREE_SPACE_THRESHOLD
      * Bound to .usableSpace due to API level restrictions (minimum required level - 23)
-     *
-     * TODO Check with UX team to handle insufficient space flow
      */
     fun checkFileStorageFreeSpace() {
-        val availableSpace = (keyExportDirectory.usableSpace / BYTES)
-            .also { logAvailableSpace(it) }
-
+        val availableSpace = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+            val storageManager = CoronaWarnApplication.getAppContext()
+                .getSystemService(Context.STORAGE_SERVICE) as StorageManager
+            val storageVolume = storageManager.primaryStorageVolume
+            val storageUUID =
+                UUID.fromString(storageVolume.uuid ?: StorageManager.UUID_DEFAULT.toString())
+            storageManager.getAllocatableBytes(storageUUID) / BYTES
+        } else {
+            keyExportDirectory.usableSpace / BYTES
+        }
         if (availableSpace < FileStorageConstants.FREE_SPACE_THRESHOLD) {
-            logInsufficientSpace(availableSpace)
+            throw NotEnoughSpaceOnDiskException()
         }
     }
 
-    /**
-     * Remove outdated key files from internal storage.
-     * Threshold: FileStorageConstants.DAYS_TO_KEEP
-     */
-    fun removeOutdatedFilesFromStorage() {
-        keyExportDirectory
-            .walk()
-            .filter(File::isDirectory)
-            .forEach { file: File ->
-                Unit
-                if (file != keyExportDirectory && file.isOutdated()) {
-                    file.checkAndRemove().also { logFileRemovalResult(file.name, it) }
-                }
-            }
-    }
-
     fun getAllFilesInKeyExportDirectory(): List<File> {
         return keyExportDirectory
             .walk(FileWalkDirection.BOTTOM_UP)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/TracingRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/TracingRepository.kt
index c94cc8347..c01854007 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/TracingRepository.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/TracingRepository.kt
@@ -2,6 +2,7 @@ package de.rki.coronawarnapp.storage
 
 import androidx.lifecycle.MutableLiveData
 import de.rki.coronawarnapp.exception.ExceptionCategory
+import de.rki.coronawarnapp.exception.TransactionException
 import de.rki.coronawarnapp.exception.reporting.report
 import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient
 import de.rki.coronawarnapp.risk.TimeVariables.getActiveTracingDaysInRetentionPeriod
@@ -52,6 +53,8 @@ object TracingRepository {
         try {
             RetrieveDiagnosisKeysTransaction.start()
             RiskLevelTransaction.start()
+        } catch (e: TransactionException) {
+            e.cause?.report(ExceptionCategory.EXPOSURENOTIFICATION)
         } catch (e: Exception) {
             e.report(ExceptionCategory.EXPOSURENOTIFICATION)
         }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/CachedKeyFileHolder.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/CachedKeyFileHolder.kt
index 883d0d03e..be5b2edf7 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/CachedKeyFileHolder.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/CachedKeyFileHolder.kt
@@ -23,6 +23,7 @@ import de.rki.coronawarnapp.BuildConfig
 import de.rki.coronawarnapp.CoronaWarnApplication
 import de.rki.coronawarnapp.http.WebRequestBuilder
 import de.rki.coronawarnapp.service.diagnosiskey.DiagnosisKeyConstants
+import de.rki.coronawarnapp.storage.FileStorageHelper
 import de.rki.coronawarnapp.storage.LocalData
 import de.rki.coronawarnapp.storage.keycache.KeyCacheEntity
 import de.rki.coronawarnapp.storage.keycache.KeyCacheRepository
@@ -67,6 +68,7 @@ object CachedKeyFileHolder {
      * @return list of all files from both the cache and the diff query
      */
     suspend fun asyncFetchFiles(currentDate: Date): List<File> = withContext(Dispatchers.IO) {
+        checkForFreeSpace()
         val serverDates = getDatesFromServer()
         // TODO remove last3HourFetch before Release
         if (BuildConfig.FLAVOR != "device" && isLast3HourFetchEnabled()) {
@@ -114,6 +116,8 @@ object CachedKeyFileHolder {
         }
     }
 
+    private fun checkForFreeSpace() = FileStorageHelper.checkFileStorageFreeSpace()
+
     /**
      * Calculates the missing days based on current missing entries in the cache
      */
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/CachedKeyFileHolderTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/CachedKeyFileHolderTest.kt
index a079159ca..d796b4c7e 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/CachedKeyFileHolderTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/CachedKeyFileHolderTest.kt
@@ -2,7 +2,6 @@ package de.rki.coronawarnapp.util
 
 import android.content.Context
 import de.rki.coronawarnapp.CoronaWarnApplication
-
 import de.rki.coronawarnapp.storage.keycache.KeyCacheRepository
 import io.mockk.MockKAnnotations
 import io.mockk.Runs
@@ -51,6 +50,7 @@ class CachedKeyFileHolderTest {
         coEvery { keyCacheRepository.getDates() } returns listOf()
         coEvery { keyCacheRepository.getFilesFromEntries() } returns listOf()
         every { CachedKeyFileHolder["isLast3HourFetchEnabled"]() } returns false
+        every { CachedKeyFileHolder["checkForFreeSpace"]() } returns Unit
         every { CachedKeyFileHolder["getDatesFromServer"]() } returns arrayListOf<String>()
 
         runBlocking {
-- 
GitLab