Bug description
After upgrading the aws-android-sdk-mobile-client from 2.12.6 to 2.13.1 the code which uploaded image to S3 against TransferUtility stopped working. It was hanging up in WAITING_FOR_NETWORK state.
How To Reproduce
No special circumstances took place: wi-fi connection with internet was available.
The s3 file upload was initiated with the following code (which worked on aws-sdk 2.13.0 and 2.12.6)
val s3Client = AmazonS3Client(AWSMobileClient.getInstance(), region((context)))
val observer = TransferUtility.builder().s3Client(s3Client)
.context(context)
.awsConfiguration(AWSMobileClient.getInstance().configuration)
.build()
.upload(bucketName(context), name, file)
observer.setTransferListener(listener)
The transfer listener was like this
TransferListener {
override fun onStateChanged(id: Int, state: TransferState?) {
Log.i(TAG, "Upload state changed to ${state?.name}")
}
override fun onError(id: Int, ex: java.lang.Exception) {
Log.e(TAG, "Failed to upload to S3, job id $jobId", ex)
}
override fun onProgressChanged(id: Int, bytesCurrent: Long, bytesTotal: Long) {
showProgressNotification(bytesCurrent.toInt(), bytesTotal.toInt())
}
}
When upload started, the app received only one onStateChanged with WAITING_FOR_NETWORK state and no other updates reported to TransferListener. File was not uploaded to S3 bucket.
Affected AWS service(s)
S3
Expected behavior
File should be uploaded with progress updates reported to TransferListener
Environment Information (please complete the following information):
2.13.1Xiaomi Mi5s and Samsung Galaxy J7 (2016)Additional context
There was such message in the logs (com.amazonaws.mobileconnectors.s3.transferutility.UploadTask):
2019-04-12 17:04:49.831 9610-16011/com.ehawk.repath.staging E/UploadTask:
TransferUtilityException: [com.amazonaws.mobileconnectors.s3.transferutility.TransferUtilityException: TransferNetworkLossHandler is not created. Please call `TransferNetworkLossHandler.getInstance(Context)` to instantiate it before retrieving]
2019-04-12 17:05:23.249 9610-16011/com.ehawk.repath.staging I/UploadTask: Network not connected. Setting the state to WAITING_FOR_NETWORK.
After that UploadTask.call() finished and no actual upload happened
Questions:
TransferNetworkLossHandler for being able to use TransferUtility?Application.onCreate() a valid point to create/register this?@nchorniy Sorry for the inconvenience caused.
1) Is it now mandatory to register TransferNetworkLossHandler for being able to use TransferUtility?
No, it is not. TransferNetworkLossHandler is designed to be an optional component. I have made the necessary changes to check for TransferNetworkLossHandler optional. See #900 for more details.
2) Is there any examples of how that should be done? Is Application.onCreate() a valid point to create/register this?
getApplicationContext().startService(new Intent(getApplicationContext(), TransferService.class));
TransferService creates and registers a TransferNetworkLossHandler and takes care of app background/foreground transitions. However, if you do not want to start a service, you could create an object of TransferNetworkLossHandler and register it like any other BroadcastReceiver.
@kvasukib We did that in our application, e.g. getApplicationContext().startService(new Intent(getApplicationContext(), TransferService.class)), but that crashed when the Application.onCreate() was executed when the app is in background:
Process: com.ehawk.repath.staging, PID: 22366
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6065)
java.lang.RuntimeException: Unable to create application com.package.TrackerApplication: java.lang.IllegalStateException: Not allowed to start service Intent { cmp=com.ehawk.repath.staging/com.amazonaws.mobileconnectors.s3.transferutility.TransferService }: app is in background uid UidRecord{1eb515a u0a344 TRNB idle procs:1 seq(0,0,0)}
at android.app.ActivityThread.-wrap1(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1764)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
As a workaround, we replaced the code which started TransferService with this line: registerReceiver(TransferNetworkLossHandler.getInstance(applicationContext), IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION))
We suggest to:
1) update the documentation which suggests to do the action which can lead to a crash
2) adapt TransferNetworkLossHandler for API >= 28 where CONNECTIVITY_ACTION is not recommended to use: https://developer.android.com/reference/android/net/ConnectivityManager#CONNECTIVITY_ACTION
@nchorniy Thank you for the quick response. TransferService is a background service, hence you are hitting the exception on device running Oreo and above when the service is started when the app is in background. So I would recommend registering the TransferNetworkLossHandler as you did.
To Adapt TransferNetworkLossHandler for API >= 28, I will use this GitHub issue to track that request. Thank you for pointing it out.
UPDATE:
I looked into the three alternatives that Android recommends to use instead of CONNECTIVITY_ACTION, however the alternatives are introduced in a later version of Android (22, 23 and 24) whereas AWS SDK for Android supports API Level of 10. So I will continue my search on what alternatives we could use to still support a lower minimum SDK. Also, please feel free to comment on this issue if you find any other alternative.
Most helpful comment
@kvasukib We did that in our application, e.g.
getApplicationContext().startService(new Intent(getApplicationContext(), TransferService.class)), but that crashed when theApplication.onCreate()was executed when the app is in background:As a workaround, we replaced the code which started
TransferServicewith this line:registerReceiver(TransferNetworkLossHandler.getInstance(applicationContext), IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION))We suggest to:
1) update the documentation which suggests to do the action which can lead to a crash
2) adapt
TransferNetworkLossHandlerfor API >= 28 whereCONNECTIVITY_ACTIONis not recommended to use: https://developer.android.com/reference/android/net/ConnectivityManager#CONNECTIVITY_ACTION