NotePad
NotePad copied to clipboard
Reproducible Builds
I've checked your app if its build is reproducible (see: Reproducible bulds, special client support and more in our repo), but while I was able to successfully generate the APK using ./gradlew assembleRelease, the differences to the one provided at your latest release were huge. Was that APK really built from the commit the tag points to? If so, did I miss some build options? And if not, which commit was it?
Diff of the APK from v1.3.0:
-------------------------------
--- /dev/fd/63 2024-07-16 21:10:27.609164389 +0200
+++ /dev/fd/62 2024-07-16 21:10:27.609164389 +0200
@@ -3,13 +3,13 @@
META-INF/version-control-info.textproto
32-bit CRC value (hex): 3e025220
assets/dexopt/baseline.prof
- 32-bit CRC value (hex): 9e76dea3
+ 32-bit CRC value (hex): b2d5b33d
assets/dexopt/baseline.profm
- 32-bit CRC value (hex): 2e4a83d2
+ 32-bit CRC value (hex): 7eafce21
classes.dex
- 32-bit CRC value (hex): fd7a9870
+ 32-bit CRC value (hex): 0faaa458
classes2.dex
- 32-bit CRC value (hex): aace86d8
+ 32-bit CRC value (hex): 79df616a
lib/arm64-v8a/libandroidx.graphics.path.so
32-bit CRC value (hex): 9734baa0
lib/arm64-v8a/libdatastore_shared_counter.so
@@ -1277,10 +1277,4 @@
res/zz.png
32-bit CRC value (hex): 0ef1b92c
resources.arsc
The Dex diff was huuuuge. baseline.prof always differs when classes.dex does (as it contains its hash).
We'd appreciate if you could help making your build reproducible. We've prepared some hints on reproducible builds for that.
Looking forward to your reply!
@mshdabiola any word?
Hello 👋
Yes it was build with the latest tag
Where are your having problems
Yes it was build with the latest tag
At a clean tree, exactly from that commit, no reuse of artifacts from prior builds (as e.g. Android Studio does it if you do not run "clean project" first)?
Where are your having problems
With the diff :) As long as there's a diff, the two APKs are not identical. I've linked to the details from the initial comment here. Only if those APKs are identical one can be sure the shipped APK corresponds exactly to the code it says to correspond to – which confirms nothing was added, altered or removed.
If I get your point right, the APK you reproduce is different from mine?
It will be different because I used my signing key to sign my own apk
If I get your point right, the APK you reproduce is different from mine?
Yupp.
It will be different because I used my signing key to sign my own apk
(sigh) have you meanwhile taken a look at behind those links? And at the diff above? Nope, signing is not part of this. Actually, to put it into easy terms, your signing is transferred to my APK at the end of the process – because if the rest would be identical, after adding the same signing my APK should verify. That's how RB works.
So if the Dex has huge differences, that has nothing at all to do with signing, but rather with building. Reasons could be:
- built from different commits
- one build is from a "dirty tree" (artifacts from previous builds being reused, and things like that)
- different configuration. I've built with
./gradlew assembleReleaseat the commandline; how did you build? I've asked that before already, but maybe with Android Studio, but not having runclean projectbefore triggering the build? And did you maybe use different parameters? I see a lot of stuff in your build workflow. Is some of that required before runningassembleRelease– or don't you even runassembleReleasebut something else?
Here's basically what I do:
// remove the call to the signingConfig as we need an UNSIGNED APK:
sed -r '/signingConfigs.getByName/d' -i app/build.gradle.kts
// build the APK
./gradlew assembleRelease
Taking a closer look at your app/build.gradle.kts, I see a lot of googlePlayImplementation calls – but cannot find any flavors defined. Checking with your Github workflows, the build seems to sed out some stuff (some of the references not present, like mlkit or google-services – so the sed -i -e '/mlkit/,+14d' -e '/google-services/d' -e '/firebase/d' build.gradle.kts cannot work as mlkit is not matched. So how exactly do you build? What replaces are needed? Maybe you'd consider establishing build flavors – or are they established outside app/build.gradle.kts and one could simply call ./gradlew assembleFossRelease?
Update: yeah, ./gradlew assembleFossReliantRelease works and should build the flavor (assembleRelease built all flavors and I had just picked the app/build/outputs/apk/fossReliant/release/app-fossReliant-release-unsigned.apk). But while this reduces build time (as the other flavor has not to be build), the outcome for the FossReliant APK is the same as before:
-rw-r--r-- 0.0 unx 120 b- 118 defN 1981-01-01 01:01:02 3e025220 META-INF/version-control-info.textproto
- -rw-r--r-- 0.0 unx 10786 b- 10786 stor 1981-01-01 01:01:02 9e76dea3 assets/dexopt/baseline.prof
- -rw-r--r-- 0.0 unx 652 b- 652 stor 1981-01-01 01:01:02 2e4a83d2 assets/dexopt/baseline.profm
- -rw-r--r-- 0.0 unx 2001772 b- 993061 defN 1981-01-01 01:01:02 fd7a9870 classes.dex
- -rw-r--r-- 0.0 unx 2650776 b- 1271967 defN 1981-01-01 01:01:02 aace86d8 classes2.dex
+ -rw-r--r-- 0.0 unx 11483 b- 11483 stor 1981-01-01 01:01:02 b2d5b33d assets/dexopt/baseline.prof
+ -rw-r--r-- 0.0 unx 643 b- 643 stor 1981-01-01 01:01:02 7eafce21 assets/dexopt/baseline.profm
+ -rw-r--r-- 0.0 unx 2008212 b- 996292 defN 1981-01-01 01:01:02 0faaa458 classes.dex
+ -rw-r--r-- 0.0 unx 2525748 b- 1206942 defN 1981-01-01 01:01:02 79df616a classes2.dex
-rw-r--r-- 0.0 unx 10096 b- 10096 stor 1981-01-01 01:01:02 9734baa0 lib/arm64-v8a/libandroidx.graphics.path.so
As you didn't reply to my previous comment from August, @mshdabiola – are you not interested in having reproducible builds established? It provides another level of security. If you don't want that, just let us know and we drop your app from the queue. Would be a pity, though.
Looks like I had success with 1.3.6 finally: adding some steps from your workflow (removing the firebase references; seems you've added those steps there in December), the diff got much smaller. What remained indicated a non-deterministic build (what we call a "flaky build"), so I added our "shaker" (basically building in a loop until the build matches or runs into a timeout). It succeeded on the 4th round.
So congrats: 1.3.6 has the green shield up, signaling it succeeded to be a reproducible build :partying_face: :crossed_fingers: it will stay such (with flaky builds it's always a bit tricky). So here's your welcome toot:
Thanks for making this possible!