Android Studio 3.1:使用 qoppapdf 库时执行任务 transformClassesWithDexBuilderForDebug 时出现 StackOverflowError

Android Studio 3.1: StackOverflowError when executing task transformClassesWithDexBuilderForDebug when using qoppapdf library

随着 Android Studio 3.1 的更新,我们的应用程序构建开始在所有机器上随机中断。在我的机器上,构建在 dexing 过程中以 WhosebugError 中断。当在 gradle.properties 中禁用 d8desugaring 时,构建通过。

问题似乎与我们在产品应用程序中使用了几年没有问题的 qoppapdf 库有关。使用新的 Android 项目可以重现该问题,其中库 jar 包含在 libs 目录中,而 multidex 用于 gradle。 Whosebug错误如下:

org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:transformClassesWithDexBuilderForDebug'.
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:100)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:70)
    at org.gradle.api.internal.tasks.execution.OutputDirectoryCreatingTaskExecuter.execute(OutputDirectoryCreatingTaskExecuter.java:51)
    at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:62)
    at org.gradle.api.internal.tasks.execution.ResolveTaskOutputCachingStateExecuter.execute(ResolveTaskOutputCachingStateExecuter.java:54)
    at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:60)
    at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:97)
    at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:87)
    at org.gradle.api.internal.tasks.execution.ResolveTaskArtifactStateTaskExecuter.execute(ResolveTaskArtifactStateTaskExecuter.java:52)
    at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:52)
    at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:54)
    at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
    at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:34)
    at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.run(DefaultTaskGraphExecuter.java:248)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:336)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:328)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:199)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:110)
    at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:241)
    at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:230)
    at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.processTask(DefaultTaskPlanExecutor.java:123)
    at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.access0(DefaultTaskPlanExecutor.java:79)
    at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.execute(DefaultTaskPlanExecutor.java:104)
    at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.execute(DefaultTaskPlanExecutor.java:98)
    at org.gradle.execution.taskgraph.DefaultTaskExecutionPlan.execute(DefaultTaskExecutionPlan.java:626)
    at org.gradle.execution.taskgraph.DefaultTaskExecutionPlan.executeWithTask(DefaultTaskExecutionPlan.java:581)
    at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.run(DefaultTaskPlanExecutor.java:98)
    at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
    at org.gradle.internal.concurrent.ManagedExecutorImpl.run(ManagedExecutorImpl.java:46)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.RuntimeException: com.android.build.api.transform.TransformException: com.android.builder.dexing.DexArchiveBuilderException: com.  android.builder.dexing.DexArchiveBuilderException: Failed to process C:\Projects\MyApplication\app\libs\qoppapdf.jar
    at com.android.builder.profile.Recorder$Block.handleException(Recorder.java:55)
    at com.android.builder.profile.ThreadRecorder.record(ThreadRecorder.java:104)
    at com.android.build.gradle.internal.pipeline.TransformTask.transform(TransformTask.java:212)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:73)
    at org.gradle.api.internal.project.taskfactory.IncrementalTaskAction.doExecute(IncrementalTaskAction.java:46)
    at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:39)
    at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:26)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.run(ExecuteActionsTaskExecuter.java:121)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:336)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:328)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:199)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:110)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:110)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:92)
    ... 32 more
Caused by: com.android.build.api.transform.TransformException: com.android.builder.dexing.DexArchiveBuilderException: com.android.builder.dexing.   DexArchiveBuilderException: Failed to process C:\Projects\MyApplication\app\libs\qoppapdf.jar
    at com.android.build.gradle.internal.transforms.DexArchiveBuilderTransform.transform(DexArchiveBuilderTransform.java:327)
    at com.android.build.gradle.internal.pipeline.TransformTask.call(TransformTask.java:221)
    at com.android.build.gradle.internal.pipeline.TransformTask.call(TransformTask.java:217)
    at com.android.builder.profile.ThreadRecorder.record(ThreadRecorder.java:102)
    ... 48 more
Caused by: com.android.builder.dexing.DexArchiveBuilderException: com.android.builder.dexing.DexArchiveBuilderException: Failed to process  C:\Projects\MyApplication\app\libs\qoppapdf.jar
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
    at java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:593)
    at java.util.concurrent.ForkJoinTask.reportException(ForkJoinTask.java:677)
    at java.util.concurrent.ForkJoinTask.join(ForkJoinTask.java:720)
    at com.android.ide.common.internal.WaitableExecutor.waitForTasksWithQuickFail(WaitableExecutor.java:146)
    at com.android.build.gradle.internal.transforms.DexArchiveBuilderTransform.transform(DexArchiveBuilderTransform.java:306)
    ... 51 more
Caused by: com.android.builder.dexing.DexArchiveBuilderException: Failed to process C:\Projects\MyApplication\app\libs\qoppapdf.jar
    at com.android.build.gradle.internal.transforms.DexArchiveBuilderTransform.launchProcessing(DexArchiveBuilderTransform.java:803)
    at com.android.build.gradle.internal.transforms.DexArchiveBuilderTransform.lambda$convertToDexArchive(DexArchiveBuilderTransform.java:728)
    at java.util.concurrent.ForkJoinTask$AdaptedCallable.exec(ForkJoinTask.java:1424)
    at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
    at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
    at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
    at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
Caused by: com.android.builder.dexing.DexArchiveBuilderException: Error while dexing.
    at com.android.builder.dexing.D8DexArchiveBuilder.getExceptionToRethrow(D8DexArchiveBuilder.java:169)
    at com.android.builder.dexing.D8DexArchiveBuilder.convert(D8DexArchiveBuilder.java:146)
    at com.android.build.gradle.internal.transforms.DexArchiveBuilderTransform.launchProcessing(DexArchiveBuilderTransform.java:798)
    ... 6 more
Caused by: java.lang.RuntimeException: java.lang.WhosebugError
    at com.android.tools.r8.R8.unwrapExecutionException(R8.java:501)
    at com.android.tools.r8.D8.run(D8.java:170)
    at com.android.tools.r8.D8.lambda$run(D8.java:91)
    at com.android.tools.r8.utils.ExceptionUtils.withCompilationHandler(ExceptionUtils.java:58)
    at com.android.tools.r8.utils.ExceptionUtils.withD8CompilationHandler(ExceptionUtils.java:45)
    at com.android.tools.r8.D8.run(D8.java:88)
    at com.android.builder.dexing.D8DexArchiveBuilder.convert(D8DexArchiveBuilder.java:144)
    ... 7 more
Caused by: java.lang.WhosebugError
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
    at java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:598)
    at java.util.concurrent.ForkJoinTask.get(ForkJoinTask.java:1005)
    at com.android.tools.r8.utils.ThreadUtils.awaitFutures(ThreadUtils.java:21)
    at com.android.tools.r8.ir.conversion.IRConverter.convertClassesToDex(IRConverter.java:315)
    at com.android.tools.r8.ir.conversion.IRConverter.convertToDex(IRConverter.java:225)
    at com.android.tools.r8.D8.optimize(D8.java:187)
    at com.android.tools.r8.D8.run(D8.java:158)
    ... 12 more
Caused by: java.lang.WhosebugError
    at java.util.HashMap.hash(HashMap.java:338)
    at java.util.HashMap.containsKey(HashMap.java:595)
    at java.util.HashSet.contains(HashSet.java:203)
    at com.android.tools.r8.ir.code.IRCode.depthFirstSorting(IRCode.java:264)
    at com.android.tools.r8.ir.code.IRCode.depthFirstSorting(IRCode.java:267)
    at com.android.tools.r8.ir.code.IRCode.depthFirstSorting(IRCode.java:267)

qoppapdf 库可以从这里下载 https://www.qoppa.com/android/pdfsdk/evaluate/。然后是位于 qpdftoolkit.zip 中的 qoppapdf.jarqoppapdf.jar 然后添加到项目的 libs 目录中。这是我用来重现构建的测试应用程序的非常基本的 build.gradle。与默认 build.gradle 的唯一区别是启用了 multidex:

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

android {
    compileSdkVersion 27
    defaultConfig {
        applicationId "net.vectorworks.myapplication"
        minSdkVersion 21
        targetSdkVersion 27

        multiDexEnabled true

        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation"org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
    implementation 'com.android.support:appcompat-v7:27.1.0'
    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
    implementation 'com.android.support:design:27.1.0'

    implementation 'com.android.support:multidex:1.0.3'

    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.1'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
}

删除应用程序内和 "global" .gradle 目录、构建目录、使 Android Studio 缓存无效以及重建应用程序都不能解决问题。我找到的唯一解决方案是在 gradle.properties:

中完全禁用 D8
android.enableD8=false

这会导致警告 The option 'android.enableD8' is deprecated and should not be used anymore. Use 'android.enableD8=true' to remove this warning. It will be removed in AGP version 3.3. 显然这不是一个长期的解决方案。任何帮助将不胜感激!

问题已通过 Google 问题跟踪器 issue 77307838 and issue 77626496 解决。 Googler ze...@google.com 写道:

I've reproduced this issue (with minimal java stack -Xss228k) and confirmed that is the same issue as b/77626496.

For very large graphs, the recursive register lookup and dominator tree construction may blow the stack.

请使用 1.2.9-dev 验证您的构建现在是否有效:

新版本为 1.2.9,哈希值 f027c89aa49b92245662457f9e6096611f2dfbc0:

repositories {
    ...
    mavenCentral()
    maven {
        url "http://storage.googleapis.com/r8-releases/raw/master/f027c89aa49b92245662457f9e6096611f2dfbc0"
    }
}
dependencies {
    classpath 'com.android.tools:r8:1.2.9-dev'
    classpath '...gradle...'
    ...
}

请注意,r8 类路径条目必须在 gradle 之前。

或者,如果您使用编译器,您可以获得 d8 jar 独立:
http://storage.googleapis.com/r8-releases/raw/master/f027c89aa49b92245662457f9e6096611f2dfbc0/d8.jar