TeamAmaze / AmazeFileManager

Material design file manager for Android
https://teamamaze.xyz
GNU General Public License v3.0
5.36k stars 1.58k forks source link

TransactionTooLarge when pulling from SD Card #3078

Open jus4ru opened 2 years ago

jus4ru commented 2 years ago

Issue explanation (write below this line)

I'm getting a considerable amount of app breaking errors stemming from SD card usage.

Exception

java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size 1318820 bytes
    at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1720)
    at android.app.ContextImpl.startService(ContextImpl.java:1670)
    at android.content.ContextWrapper.startService(ContextWrapper.java:720)
    at android.content.ContextWrapper.startService(ContextWrapper.java:720)
    at com.amaze.filemanager.asynchronous.management.ServiceWatcherUtil.runService(ServiceWatcherUtil.java:195)
    at com.amaze.filemanager.asynchronous.asynctasks.PrepareCopyTask.startService(PrepareCopyTask.java:206)
    at com.amaze.filemanager.asynchronous.asynctasks.PrepareCopyTask.finishCopying(PrepareCopyTask.java:345)
    at com.amaze.filemanager.asynchronous.asynctasks.PrepareCopyTask.onEndDialog(PrepareCopyTask.java:283)
    at com.amaze.filemanager.asynchronous.asynctasks.PrepareCopyTask.replaceFiles(PrepareCopyTask.java:319)
    at com.amaze.filemanager.asynchronous.asynctasks.PrepareCopyTask.lambda$showDialog$2(PrepareCopyTask.java:241)
    at com.amaze.filemanager.asynchronous.asynctasks.PrepareCopyTask.lambda$showDialog$2$PrepareCopyTask(Unknown Source:0)
    at com.amaze.filemanager.asynchronous.asynctasks.-$$Lambda$PrepareCopyTask$75dSuI7LFbSJVQGrHk_P9Ju86wU.onClick(Unknown Source:12)
    at com.afollestad.materialdialogs.MaterialDialog.onClick(MaterialDialog.java:433)
    at android.view.View.performClick(View.java:7455)
    at android.view.View.performClickInternal(View.java:7432)
    at android.view.View.access$3600(View.java:810)
    at android.view.View$PerformClick.run(View.java:28312)
    at android.os.Handler.handleCallback(Handler.java:938)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:223)
    at android.app.ActivityThread.main(ActivityThread.java:7669)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
Caused by: android.os.TransactionTooLargeException: data parcel size 1318820 bytes
    at android.os.BinderProxy.transactNative(Native Method)
    at android.os.BinderProxy.transact(BinderProxy.java:550)
    at android.app.IActivityManager$Stub$Proxy.startService(IActivityManager.java:5877)
    at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1700)
    ... 23 more


mgarciaisaia commented 2 years ago

I first got an exception like this one by trying to move (cut & paste) 31944 files from internal storage to the SD card.

Then I was able to move 31944 files from one directory in internal storage to another, empty one, also in the internal storage. So Amaze can move 31944 files in one shot.

After that I got an exception like this one trying to move those same 31944 files from the new internal storage directory to an empty directory in the SD card. I tried with two different target directories to see if there was something about file paths' length, but the data parcel size in the exception was the same for both cases - so it doesn't seem to have to do with file names.

I can test any other scenarios you may come up with, if that's useful.

mgarciaisaia commented 2 years ago

I've spent a while taking a look at this issue.

Problem

Android's Binder defines a hard-coded limit of 1MB for IPC transaction buffers (or something like that). (source: https://developer.android.com/reference/android/os/TransactionTooLargeException) We're trying to start an Intent with the list of files to move/copy, and - with ~30k paths - it's easy to hit 1MB (1MB / 30k ~= 35 bytes per path object).

Alternatives

Questions

The byte size of an Intent object can be obtained by this piece of code:

Intent intent = new Intent(context.get(), CopyService.class);
// ... set stuff on intent ...
Parcel parcel = Parcel.obtain();

parcel.writeParcelable(intent, 0);
Log.e("The intent lenght is " + parcel.dataSize() + " bytes");