Skip to content

TransferWorkerObserver$attachObserverForPendingTransfer$1.invokeSuspend (API 25) #2840

@onseok

Description

@onseok

Before opening, please confirm:

Language and Async Model

Kotlin

Amplify Categories

Storage

Gradle script dependencies

// libs.versions.toml
[versions]
aws = "2.16.0"

[libraries]
aws-storage-s3 = { group = "com.amplifyframework", name = "aws-storage-s3", version.ref = "aws" }
aws-auth-cognito = { group = "com.amplifyframework", name = "aws-auth-cognito", version.ref = "aws" }
aws-core-kotlin = { group = "com.amplifyframework", name = "core-kotlin", version.ref = "aws" }

// build.gradle.kts (Module: app)
implementation(libs.aws.storage.s3)
implementation(libs.aws.auth.cognito)

// build.gradle.kts (Module: sync)
implementation(libs.aws.storage.s3)
implementation(libs.aws.core.kotlin)

Environment information

# Put output below this line
------------------------------------------------------------
Gradle 8.7
------------------------------------------------------------

Build time:   2024-03-22 15:52:46 UTC
Revision:     650af14d7653aa949fce5e886e685efc9cf97c10

Kotlin:       1.9.22
Groovy:       3.0.17
Ant:          Apache Ant(TM) version 1.10.13 compiled on January 4 2023
JVM:          17.0.10 (Amazon.com Inc. 17.0.10+7-LTS)
OS:           Mac OS X 14.3.1 aarch64

Please include any relevant guides or documentation you're referencing

https://docs.amplify.aws/gen1/android/build-a-backend/storage/upload/#upload-files

Upload files with StoragePath

Describe the bug

The amplify version that i am using is 2.16.0, and I can't re-produce the problem because I counter it on Firebase Crashlytics.
But it occurs when I use workmanager for upload log files periodically using PeriodicWorkRequest.

Reproduction steps (if applicable)

No response

Code Snippet

// Put your code below this line.

// This is a simplified version of the code.
import android.content.Context
import androidx.hilt.work.HiltWorker
import androidx.work.CoroutineWorker
import androidx.work.ForegroundInfo
import androidx.work.WorkerParameters
import com.amplifyframework.kotlin.core.Amplify
import com.sample.sync.initializers.logSyncForegroundInfo
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext
import java.io.File
import com.amplifyframework.storage.StoragePath
import com.sample.core.data.AppDispatchers.IO
import com.sample.core.data.Dispatcher
import com.sample.sync.BuildConfig
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.FlowPreview
import timber.log.Timber
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale

@HiltWorker
class LogUploadWorker @AssistedInject constructor(
    @Assisted private val appContext: Context,
    @Assisted workerParams: WorkerParameters,
    @Dispatcher(IO) private val ioDispatcher: CoroutineDispatcher
) : CoroutineWorker(appContext, workerParams) {

    override suspend fun getForegroundInfo(): ForegroundInfo =
        appContext.logSyncForegroundInfo()

    override suspend fun doWork(): Result = withContext(ioDispatcher) {
        try {
            val externalFilesDirPath = inputData.getString("externalFilesDirPath")
            val externalFilesDir = externalFilesDirPath?.let { File(it) }
            if (externalFilesDir != null && externalFilesDir.exists()) {
                uploadLogFiles(externalFilesDir)
            }
        } catch (e: Exception) {
            Timber.e("Log upload exception: ${e.message}")
            Result.retry()
        }
        Result.success()
    }

    @OptIn(ExperimentalCoroutinesApi::class, FlowPreview::class)
    private suspend fun uploadLogFiles(externalFilesDir: File) {
        val curFiles = externalFilesDir.listFiles()?.filter { file ->
            System.currentTimeMillis() - file.lastModified() < TWO_WEEK_TIME_MILLIS
        }?.sortedByDescending { it.lastModified() }

        if (curFiles.isNullOrEmpty()) {
            Timber.i("No log files or directory found.")
            return
        }
        
        val environmentPrefix = if (BuildConfig.DEBUG) "debug" else "release"
        val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())

        curFiles.forEach { file ->
            val date = dateFormat.format(Date(file.lastModified()))
            val fileIndex = file.name.substringBefore("_logs.txt").takeLastWhile { it.isDigit() }
            val key = "$environmentPrefix/sample/$date/log$fileIndex.txt"

            try {
                val result = Amplify.Storage.uploadFile(
                    StoragePath.fromString("public/$key"),
                    file
                ).result()
                Timber.i("Log file upload successful: ${result.path}")
            } catch (error: Exception) {
                Timber.e("Log file upload failed: ${error.message} - ${error.cause}")
            }
        }
    }

    companion object {
        private const val TWO_WEEK_TIME_MILLIS = 14 * 24 * 60 * 60 * 1000L

        fun startUpUploadWork(
            externalFilesDirPath: File?
        ) = PeriodicWorkRequestBuilder<LogUploadWorker>(
            1, TimeUnit.HOURS,
            5, TimeUnit.MINUTES
        )
            .setConstraints(LogSyncConstraints)
            .setBackoffCriteria(
                BackoffPolicy.LINEAR,
                MIN_BACKOFF_MILLIS,
                TimeUnit.MILLISECONDS
            )
            .setInputData(
                Data.Builder()
                    .putString("externalFilesDirPath", externalFilesDirPath?.absolutePath)
                    .build()
            )
            .build()
    }
}

Log output

// Put your logs below this line
TransferWorkerObserver$attachObserverForPendingTransfer$1.invokeSuspend
Fatal Exception: java.lang.IllegalStateException: Couldn't read row 912, col 0 from CursorWindow.  Make sure the Cursor is initialized correctly before accessing data from it.
       at android.database.CursorWindow.nativeGetLong(CursorWindow.java)
       at android.database.CursorWindow.getLong(CursorWindow.java:511)
       at android.database.CursorWindow.getInt(CursorWindow.java:578)
       at android.database.AbstractWindowedCursor.getInt(AbstractWindowedCursor.java:69)
       at com.amplifyframework.storage.s3.transfer.TransferWorkerObserver$attachObserverForPendingTransfer$1.invokeSuspend(TransferWorkerObserver.kt:82)
       at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:9)
       at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:97)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
       at java.lang.Thread.run(Thread.java:761)

o9.J Dispatcher:
       at java.lang.Object.wait(Object.java)
       at java.lang.Thread.parkFor$(Thread.java:2127)
       at sun.misc.Unsafe.park(Unsafe.java:325)
       at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:201)
       at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:432)
       at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:333)
       at java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:908)
       at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1057)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1118)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
       at java.lang.Thread.run(Thread.java:761)

Firebase Background Thread #1:
       at java.lang.Object.wait(Object.java)
       at java.lang.Thread.parkFor$(Thread.java:2127)
       at sun.misc.Unsafe.park(Unsafe.java:325)
       at java.util.concurrent.locks.LockSupport.park(LockSupport.java:161)
       at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2035)
       at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:413)
       at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1058)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1118)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
       at com.google.firebase.concurrent.CustomThreadFactory.lambda$newThread$0(CustomThreadFactory.java:290)
       at java.lang.Thread.run(Thread.java:761)

o9.J Dispatcher:
       at java.lang.Object.wait(Object.java)
       at java.lang.Thread.parkFor$(Thread.java:2127)
       at sun.misc.Unsafe.park(Unsafe.java:325)
       at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:201)
       at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:432)
       at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:333)
       at java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:908)
       at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1057)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1118)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
       at java.lang.Thread.run(Thread.java:761)

DefaultDispatcher-worker-6:
       at java.lang.Object.wait(Object.java)
       at java.lang.Thread.parkFor$(Thread.java:2127)
       at sun.misc.Unsafe.park(Unsafe.java:325)
       at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:324)
       at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.park(CoroutineScheduler.kt:301)
       at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.tryPark(CoroutineScheduler.kt:301)
       at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:301)
       at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:301)


o9.J Dispatcher:
       at java.lang.Object.wait(Object.java)
       at java.lang.Thread.parkFor$(Thread.java:2127)
       at sun.misc.Unsafe.park(Unsafe.java:325)
       at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:201)
       at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:432)
       at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:333)
       at java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:908)
       at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1057)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1118)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
       at java.lang.Thread.run(Thread.java:761)

o9.J Dispatcher:
       at java.lang.Object.wait(Object.java)
       at java.lang.Thread.parkFor$(Thread.java:2127)
       at sun.misc.Unsafe.park(Unsafe.java:325)
       at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:201)
       at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:432)
       at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:333)
       at java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:908)
       at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1057)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1118)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
       at java.lang.Thread.run(Thread.java:761)

DefaultDispatcher-worker-7:
       at java.lang.Object.wait(Object.java)
       at java.lang.Thread.parkFor$(Thread.java:2127)
       at sun.misc.Unsafe.park(Unsafe.java:325)
       at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:324)
       at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.park(CoroutineScheduler.kt:301)
       at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.tryPark(CoroutineScheduler.kt:301)
       at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:301)
       at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:301)

FinalizerWatchdogDaemon:
       at java.lang.Thread.sleep(Thread.java)
       at java.lang.Thread.sleep(Thread.java:371)
       at java.lang.Thread.sleep(Thread.java:313)
       at java.lang.Daemons$FinalizerWatchdogDaemon.sleepFor(Daemons.java:314)
       at java.lang.Daemons$FinalizerWatchdogDaemon.waitForFinalization(Daemons.java:336)
       at java.lang.Daemons$FinalizerWatchdogDaemon.run(Daemons.java:253)
       at java.lang.Thread.run(Thread.java:761)

WM.task-2:
       at java.lang.Object.wait(Object.java)
       at java.lang.Thread.parkFor$(Thread.java:2127)
       at sun.misc.Unsafe.park(Unsafe.java:325)
       at java.util.concurrent.locks.LockSupport.park(LockSupport.java:161)
       at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2035)
       at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:413)
       at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1058)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1118)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
       at java.lang.Thread.run(Thread.java:761)

pool-12-thread-1:
       at java.lang.Object.wait(Object.java)
       at java.lang.Thread.parkFor$(Thread.java:2127)
       at sun.misc.Unsafe.park(Unsafe.java:325)
       at java.util.concurrent.locks.LockSupport.park(LockSupport.java:161)
       at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2035)
       at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:413)
       at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1058)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1118)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
       at java.lang.Thread.run(Thread.java:761)

HeapTaskDaemon:
       at dalvik.system.VMRuntime.runHeapTasks(VMRuntime.java)
       at java.lang.Daemons$HeapTaskDaemon.run(Daemons.java:433)
       at java.lang.Thread.run(Thread.java:761)

// ...

amplifyconfiguration.json

No response

GraphQL Schema

// Put your schema below this line

Additional information and screenshots

Additional information

  • Device: Infos_Duple
  • Android Version: Nougat 7.1.2

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingstorageRelated to the Storage category/plugins

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions