LCP Decryption Fails for Large PDF (~180MB) with OutOfMemoryError in LcpDecryptorKt.decryptFully
Describe the bug
I am encountering a java.lang.OutOfMemoryError when attempting to decrypt a large LCP-protected resource using the readium-lcp module.
I tried with android:largeHeap="true in Manifest, Still app getting crash issue
Here is the The stack trace:
java.lang.OutOfMemoryError: Failed to allocate a 189462448 byte allocation with 25099808 free bytes and 23MB until OOM, target footprint 603979776, growth limit 603979776 at java.util.Arrays.copyOfRange(Arrays.java:3870) at kotlin.collections.ArraysKt___ArraysJvmKt.copyOfRange(_ArraysJvm.kt:1475) at org.readium.r2.lcp.LcpDecryptorKt.decryptFully(LcpDecryptor.kt:281) at org.readium.r2.lcp.LcpDecryptorKt.access$decryptFully(LcpDecryptor.kt:1) at org.readium.r2.lcp.LcpDecryptorKt$decryptFully$1.invokeSuspend(Unknown Source:14) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:100) at android.os.Handler.handleCallback(Handler.java:959) at android.os.Handler.dispatchMessage(Handler.java:100) at android.os.Looper.loopOnce(Looper.java:232) at android.os.Looper.loop(Looper.java:317) at android.app.ActivityThread.main(ActivityThread.java:8705) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:580) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:886) Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@b4fa5e1, Dispatchers.Main.immediate]
How to reproduce?
Trying to open PDF books After download
Readium version
3.1.2
Android API version
Android 15
Additional context
The stack trace indicates that the library is attempting to allocate a very large ByteArrayin memory using Arrays.copyOfRange within the decryptFully function, which is the root cause of the OOM crash.
Are you using the PDFium adapter? It doesn't support range requests, so reading and decrypting the whole file is the expected behavior.
val publicationOpener = PublicationOpener( publicationParser = DefaultPublicationParser( context, assetRetriever = assetRetriever, httpClient = httpClient, pdfFactory = PdfiumDocumentFactory(context) ), contentProtections = contentProtections )
Yes @qnga ,I'm using the PDFium adapter. Since it needs to load the entire file, it crashes on large PDFs. Are there any other parsers in Readium that support for large LCP files, or any workaround to avoid loading everything into memory?
cc @mickael-menu
We've got an adapter for PsPdfKit. It supports range requests but it is paid.
For more information:
- https://github.com/readium/kotlin-toolkit/tree/develop/readium/adapters/pdfium
- https://github.com/readium/kotlin-toolkit/tree/develop/readium/adapters/pspdfkit