Status Update
Comments
ch...@google.com <ch...@google.com>
mk...@google.com <mk...@google.com> #2
The error posted in this issue has already been resolved on our 1.6 branch. You can try out version 1.6.73 by adding the following to your top-level build.gradle file:
buildscript {
repositories {
maven {
url '
}
}
dependencies {
classpath 'com.android.tools:r8:1.6.73' // Must be before the Gradle Plugin for Android.
classpath 'com.android.tools.build:gradle:X.Y.Z' // Your current AGP version.
}
}
This will probably not resolve the other issue that says 'because it is in conflict with an existing class with the same name'
lo...@clearscore.com <lo...@clearscore.com> #3
I can see that I didn't manage to reproduce the error. So, I've cloned the R8 repo and tried debugging it myself. First thing to note is that everything looks like it's working when I checkout master
and build it. On branch 1.6
though, I can see the error:
In the ProguardMapMinifier, checkAndAddMappedNames
is called with
type: com.google.android.play.core.internal.o
mappedName: Lcom/google/android/play/core/internal/k;
position: offset: 0, line: 126176, column: 1
The inverse of mappedNames
contains the mappedName
above, and also inverse.get(mappedName)
returns a DexType of com.google.android.play.core.internal.k
, which is different from the type and therefore fails.
I don't really know the codebase, but it looks like the issue might be in the computeMapping
method inside ProguardMapMinifier.java
, where calling seedMapper.getClassNaming(com.google.android.play.core.internal.o)
returns a ClassNamingForMapApplier
that has
originalName Lcom/google/android/play/core/internal/o;
renamedName Lcom/google/android/play/core/internal/k;
Hope this helps, let me know if I can provide more info.
mk...@google.com <mk...@google.com> #4
Was the Google Play core library added as a dependency to the app and tests? If yes, can I ask you to check the produced mapping file by R8 to see if the name that R8 reports an error on is in the mapping file. If that is the case, what is happening is that the library, which is already minified, is then minified again and we will almost certainly pick another one-letter name.
For simplicity, say there is only two classes: foo.bar.a foo.bar.b
If we, when we compile the app with R8 determine that foo.bar.a is not used, we will remove it (it will not be in the mapping file) and we will rename foo.bar.b -> foo.bar.a
When we then compile the tests, that has the original files, we will try and rename foo.bar.b to foo.bar.a, but, that class already exists and we do not have a mapping for it.
I'm almost certain the above is the case - if the Google Play core library was added as a dependency to the tests and we have something that maps to 'Lcom/google/android/play/core/appupdate/j in the mapping file. Can you confirm my suspicion?
lo...@gmail.com <lo...@gmail.com> #5
As far as I can see it is added only as implementation, never as testImplementation or androidTestImplementation. The PR that introduced it in the project is not really big, and it adds the Play library as implementation in one module and as api in another. In the mapping.txt, looking for com.google.android.play.core.appupdate.j, I can see:
com.google.android.play.core.appupdate.AppUpdateInfo -> com.google.android.play.core.appupdate.a:
com.google.android.play.core.appupdate.a -> com.google.android.play.core.appupdate.c:
com.google.android.play.core.appupdate.c -> com.google.android.play.core.appupdate.e:
com.google.android.play.core.appupdate.e -> com.google.android.play.core.appupdate.g:
com.google.android.play.core.appupdate.g -> com.google.android.play.core.appupdate.i:
com.google.android.play.core.appupdate.i -> com.google.android.play.core.appupdate.j:
The library is then only used in a robolectric test. It's worth mentioning that we use
mk...@google.com <mk...@google.com> #6
1) add implementation 'com.google.android.play:core:1.6.5'
2) set minifyEnabled = true
3) Add the following keep rules:
-keep,allowobfuscation class com.google.android.play.core.appupdate.c { *; } \n
-keeppackagenames
This will fail with an error similar to the one you are seeing:
```
Caused by: com.android.tools.r8.utils.AbortException: Error: 'com.google.android.play.core.internal.f' cannot be mapped to 'Lcom/google/android/play/core/internal/f;' because it is in conflict with an existing class with the same name. This usually happens when compiling a test application against a source application and having short generic names in the test application. Try giving 'Lcom/google/android/play/core/internal/f;' a more specific name or add a keep rule to keep 'com.google.android.play.core.internal.f'.
at com.android.tools.r8.utils.Reporter.failIfPendingErrors(Reporter.java:101)
at com.android.tools.r8.naming.ProguardMapMinifier.run(ProguardMapMinifier.java:124)
at com.android.tools.r8.R8.run(R8.java:740)
at com.android.tools.r8.R8.run(R8.java:243)
at com.android.tools.r8.R8.lambda$runForTesting$1(R8.java:234)
at com.android.tools.r8.utils.ExceptionUtils.withCompilationHandler(ExceptionUtils.java:65)
```
The problem is that play core is added as program files in the app (as usual for implementation), which allows R8 to shrink and minify what is not needed. That will move the names of the play core module inside all packages - in particular the appupdate package, where we now will have other mappings.
When compiling the tests, the app code is added on class-path, where now transform all classes on class-path to follow the new naming scheme, but here we will map to an existing name. This is not desirable. A solution to this problem is to not allow R8 to pick names of the original input program.
Adding the keep rule -keepnames class com.google.android.play.core.appupdate.* will make R8 pick the same names if the classes survive and successfully fixes the issue for me. Will work on a fix that does not require that keep rule and post back here when I have something working.
ap...@google.com <ap...@google.com> #7
Branch: master
commit 69f1d4d25429cc13e5b8028a7491c97e8ea37fc0
Author: Morten Krogh-Jespersen <mkroghj@google.com>
Date: Thu Mar 05 13:32:51 2020
Determine the use of not mapped types lazily for applymapping
When compiling an app with already minified input, like the play core
module, R8 will remove some classes and rename others with a high
probability of us rotating names. When running tests afterwards, we
would report an error if we found a mapping to a class that has no
mapping since such types could collide if both were used in the tests.
This CL pushes this tests to the NamingLens such that unused
references in the test will not throw an error. Also, the error is
lowered to a warning.
Bug: 149946708
Change-Id: I70e690532bd512fba870f82e1561955c85519e11
M src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
M src/main/java/com/android/tools/r8/naming/ApplyMappingError.java
M src/main/java/com/android/tools/r8/naming/MinifiedRenaming.java
M src/main/java/com/android/tools/r8/naming/NamingLens.java
M src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
A src/test/java/com/android/tools/r8/naming/ClassNameMinifierOriginalClassNameTest.java
M src/test/java/com/android/tools/r8/naming/applymapping/shared/NameClashTest.java
A src/test/java/com/android/tools/r8/naming/testclasses/A.java
A src/test/java/com/android/tools/r8/naming/testclasses/B.java
mk...@google.com <mk...@google.com> #8
lorenzo.quiroli@, can I ask you to try out 69f1d4d25429cc13e5b8028a7491c97e8ea37fc0 by adding the following to your top-level build.gradle file (and removing any special keep-rules that circumvent the issue):
buildscript {
repositories {
maven {
url "https://storage.googleapis.com/r8-releases/raw/master"
}
}
dependencies {
classpath 'com.android.tools:r8:69f1d4d25429cc13e5b8028a7491c97e8ea37fc0' // Must be before the Gradle Plugin for Android.
classpath 'com.android.tools.build:gradle:X.Y.Z' // Your current AGP version.
}
}
lo...@gmail.com <lo...@gmail.com> #9
I can confirm it's working now, wonderful! Would you be able to tell me in which release it will be included?
ap...@google.com <ap...@google.com> #10
Branch: 2.0
commit c9a6c5a9028dbe728fdb2c4da1117d8f26aa520d
Author: Morten Krogh-Jespersen <mkroghj@google.com>
Date: Fri Mar 06 13:59:43 2020
Version 2.0.47
Cherry pick: Determine the use of not mapped types lazily for
applymapping
CL:
Bug: 149946708
Change-Id: Ia8f168e43e4889fd2f8173da91270b3d0267345e
M src/main/java/com/android/tools/r8/Version.java
M src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
M src/main/java/com/android/tools/r8/naming/ApplyMappingError.java
M src/main/java/com/android/tools/r8/naming/MinifiedRenaming.java
M src/main/java/com/android/tools/r8/naming/NamingLens.java
M src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
A src/test/java/com/android/tools/r8/naming/ClassNameMinifierOriginalClassNameTest.java
M src/test/java/com/android/tools/r8/naming/applymapping/shared/NameClashTest.java
A src/test/java/com/android/tools/r8/naming/testclasses/A.java
A src/test/java/com/android/tools/r8/naming/testclasses/B.java
mk...@google.com <mk...@google.com> #11
It could either be included in 4.0 beta 3 or 4.0 stable, depending on the release schedule for Android Studio. It was not feasible to port back to the current release. You can point to the 2.0.47 version by adding the following to your top-level build.gradle file:
buildscript {
repositories {
maven {
url 'https://storage.googleapis.com/r8-releases/raw'
}
}
dependencies {
classpath 'com.android.tools:r8:2.0.47' // Must be before the Gradle Plugin for Android.
classpath 'com.android.tools.build:gradle:X.Y.Z' // Your current AGP version.
}
}
Description
```
AGPBI: {"kind":"error","text":"'java.lang.Object get(java.lang.Object)' and 'java.lang.Object create(java.lang.Object)' map to same name: 'a'","sources":[{}],"tool":"R8"}
AGPBI: {"kind":"error","text":"'void updatePreLayout(androidx.constraintlayout.widget.ConstraintLayout)' and 'void updatePostMeasure(androidx.constraintlayout.widget.ConstraintLayout)' map to same name: 'a'","sources":[{}],"tool":"R8"}
'java.lang.Object get(java.lang.Object)' and 'java.lang.Object create(java.lang.Object)' map to same name: 'a'
```
In my real project, the error has been surfaced by adding the Google Play core library to the project and resulted in the same exception but different error message:
```
'Lcom/google/android/play/core/appupdate/j;' because it is in conflict with an existing class with the same name. This usually happens when compiling a test application against a source application and having short generic names in the test application. Try giving 'Lcom/google/android/play/core/appupdate/j;' a more specific name or add a keep rule to keep 'com.google.android.play.core.appupdate.j'.
```
I've attached a repro sample. Simply unzip it and run `./gradlew connectedCheck` to reproduce the error.