From 8704daa5f8e7949d70523bfd10e276df88800608 Mon Sep 17 00:00:00 2001 From: Moxie Marlinspike Date: Wed, 17 Feb 2016 11:27:35 -0800 Subject: [PATCH] Add Dockerfile for an Android build environment // FREEBIE --- Dockerfile | 26 ++++++++++++++++ apkdiff/apkdiff.py | 78 ++++++++++++++++++++++++++++++++++++++++++++++ build.gradle | 14 ++++++++- 3 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 Dockerfile create mode 100755 apkdiff/apkdiff.py diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000..2b09bdb458 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,26 @@ +FROM ubuntu:14.04.3 + +RUN dpkg --add-architecture i386 && \ + apt-get update -y && \ + apt-get install -y software-properties-common && \ + add-apt-repository -y ppa:openjdk-r/ppa && \ + apt-get update -y && \ + apt-get install -y libc6:i386=2.19-0ubuntu6.7 libncurses5:i386=5.9+20140118-1ubuntu1 libstdc++6:i386=4.8.4-2ubuntu1~14.04.1 lib32z1=1:1.2.8.dfsg-1ubuntu1 wget openjdk-8-jdk=8u72-b15-1~trusty1 git unzip && \ + rm -rf /var/lib/apt/lists/* && \ + apt-get autoremove -y && \ + apt-get clean + +ENV ANDROID_SDK_FILENAME android-sdk_r24.4.1-linux.tgz +ENV ANDROID_SDK_URL https://dl.google.com/android/${ANDROID_SDK_FILENAME} +ENV ANDROID_API_LEVELS android-22 +ENV ANDROID_BUILD_TOOLS_VERSION 22.0.1 +ENV ANDROID_HOME /usr/local/android-sdk-linux +ENV PATH ${PATH}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools +RUN cd /usr/local/ && \ + wget -q ${ANDROID_SDK_URL} && \ + tar -xzf ${ANDROID_SDK_FILENAME} && \ + rm ${ANDROID_SDK_FILENAME} +RUN echo y | android update sdk --no-ui -a --filter ${ANDROID_API_LEVELS} +RUN echo y | android update sdk --no-ui -a --filter extra-android-m2repository,extra-android-support,extra-google-google_play_services,extra-google-m2repository +RUN echo y | android update sdk --no-ui -a --filter tools,platform-tools,build-tools-${ANDROID_BUILD_TOOLS_VERSION} +RUN rm -rf ${ANDROID_HOME}/tools && unzip ${ANDROID_HOME}/temp/*.zip -d ${ANDROID_HOME} diff --git a/apkdiff/apkdiff.py b/apkdiff/apkdiff.py new file mode 100755 index 0000000000..82d6b474c6 --- /dev/null +++ b/apkdiff/apkdiff.py @@ -0,0 +1,78 @@ +#! /usr/bin/env python + +import sys +from zipfile import ZipFile + +class ApkDiff: + + IGNORE_FILES = ["META-INF/CERT.RSA", "META-INF/CERT.SF", "META-INF/MANIFEST.MF"] + + def compare(self, sourceApk, destinationApk): + sourceZip = ZipFile(sourceApk, 'r') + destinationZip = ZipFile(destinationApk, 'r') + + if self.compareManifests(sourceZip, destinationZip) and self.compareEntries(sourceZip, destinationZip) == True: + print "APKs match!" + else: + print "APKs don't match!" + + def compareManifests(self, sourceZip, destinationZip): + sourceEntrySortedList = sorted(sourceZip.namelist()) + destinationEntrySortedList = sorted(destinationZip.namelist()) + + for ignoreFile in self.IGNORE_FILES: + while ignoreFile in sourceEntrySortedList: sourceEntrySortedList.remove(ignoreFile) + while ignoreFile in destinationEntrySortedList: destinationEntrySortedList.remove(ignoreFile) + + if len(sourceEntrySortedList) != len(destinationEntrySortedList): + print "Manifest lengths differ!" + + for (sourceEntryName, destinationEntryName) in zip(sourceEntrySortedList, destinationEntrySortedList): + if sourceEntryName != destinationEntryName: + print "Sorted manifests don't match, %s vs %s" % (sourceEntryName, destinationEntryName) + return False + + return True + + def compareEntries(self, sourceZip, destinationZip): + sourceInfoList = filter(lambda sourceInfo: sourceInfo.filename not in self.IGNORE_FILES, sourceZip.infolist()) + destinationInfoList = filter(lambda destinationInfo: destinationInfo.filename not in self.IGNORE_FILES, destinationZip.infolist()) + + if len(sourceInfoList) != len(destinationInfoList): + print "APK info lists of different length!" + return False + + for sourceEntryInfo in sourceInfoList: + for destinationEntryInfo in list(destinationInfoList): + if sourceEntryInfo.filename == destinationEntryInfo.filename: + sourceEntry = sourceZip.open(sourceEntryInfo, 'r') + destinationEntry = destinationZip.open(destinationEntryInfo, 'r') + + if self.compareFiles(sourceEntry, destinationEntry) != True: + print "APK entry %s does not match %s!" % (sourceEntryInfo.filename, destinationEntryInfo.filename) + return False + + destinationInfoList.remove(destinationEntryInfo) + break + + return True + + def compareFiles(self, sourceFile, destinationFile): + sourceChunk = sourceFile.read(1024) + destinationChunk = destinationFile.read(1024) + + while sourceChunk != "" and destinationChunk != "": + if sourceChunk != destinationChunk: + return False + + sourceChunk = sourceFile.read(1024) + destinationChunk = destinationFile.read(1024) + + return True + +if __name__ == '__main__': + if len(sys.argv) != 3: + print "Usage: apkdiff " + sys.exit(1) + + ApkDiff().compare(sys.argv[1], sys.argv[2]) diff --git a/build.gradle b/build.gradle index d7259f0f40..c251f6107d 100644 --- a/build.gradle +++ b/build.gradle @@ -163,7 +163,7 @@ android { minSdkVersion 9 targetSdkVersion 22 - buildConfigField "long", "BUILD_TIMESTAMP", System.currentTimeMillis() + "L" + buildConfigField "long", "BUILD_TIMESTAMP", getLastCommitTimestamp() + "L" buildConfigField "String", "TEXTSECURE_URL", "\"https://textsecure-service.whispersystems.org\"" buildConfigField "String", "USER_AGENT", "\"OWA\"" buildConfigField "String", "REDPHONE_MASTER_URL", "\"https://redphone-master.whispersystems.org\"" @@ -249,6 +249,18 @@ tasks.whenTaskAdded { task -> } } +def getLastCommitTimestamp() { + new ByteArrayOutputStream().withStream { os -> + def result = exec { + executable = 'git' + args = ['log', '-1', '--pretty=format:%ct'] + standardOutput = os + } + + return os.toString() + "000" + } +} + def Properties props = new Properties() def propFile = new File('signing.properties')