Bug 1106593: Proguard third-party libraries that ship with Fennec. r=nalexander

This applies Proguard to third-party libraries such as the Android
support-v4 library and the Google Play Services libraries.
Previously, these were not Proguarded, bloating the Fennec APK.

Technically, this required a few work-arounds, including:

* stripping library debug information with a early Proguard
  invocation;
* altering the optimizations tried; and
* reducing the number of Proguard passes.

--HG--
rename : mobile/android/config/proguard.cfg => mobile/android/config/proguard/proguard.cfg
extra : rebase_source : 6d638695b6c8f759578aba5f1eda668fc9c28e9d
extra : amend_source : 96a475c0739c4b44a3df3fdfd2c59321836d9694
This commit is contained in:
Chris Kitching 2014-12-05 11:50:48 -08:00
parent 51e12cda6f
commit 1b1aa5dd75
4 changed files with 133 additions and 19 deletions

View File

@ -60,14 +60,20 @@ GARBAGE += \
GARBAGE_DIRS += classes db jars res sync services generated
JAVA_BOOTCLASSPATH = \
# The bootclasspath is functionally identical to the classpath, but allows the
# classes given to redefine classes in core packages, such as java.lang.
# android.jar is here as it provides Android's definition of the Java Standard
# Library. The compatability lib here tweaks a few of the core classes to paint
# over changes in behaviour between versions.
JAVA_BOOTCLASSPATH := \
$(ANDROID_SDK)/android.jar \
$(ANDROID_COMPAT_LIB) \
$(NULL)
JAVA_BOOTCLASSPATH := $(subst $(NULL) ,:,$(strip $(JAVA_BOOTCLASSPATH)))
# If native devices are enabled, add Google Play Services and some of the v7 compat libraries
# If native devices are enabled, add Google Play Services and some of the v7
# compat libraries.
ifdef MOZ_NATIVE_DEVICES
JAVA_CLASSPATH += \
$(GOOGLE_PLAY_SERVICES_LIB) \
@ -78,6 +84,24 @@ endif
JAVA_CLASSPATH := $(subst $(NULL) ,:,$(strip $(JAVA_CLASSPATH)))
# Library jars that we're bundling: these are subject to Proguard before inclusion
# into classes.dex.
java_bundled_libs := \
$(ANDROID_COMPAT_LIB) \
$(NULL)
ifdef MOZ_NATIVE_DEVICES
java_bundled_libs += \
$(GOOGLE_PLAY_SERVICES_LIB) \
$(ANDROID_MEDIAROUTER_LIB) \
$(ANDROID_APPCOMPAT_LIB) \
$(NULL)
endif
java_bundled_libs := $(subst $(NULL) ,:,$(strip $(java_bundled_libs)))
# All the jars we're compiling from source. (not to be confused with
# java_bundled_libs, which holds the jars which we're including as binaries).
ALL_JARS = \
constants.jar \
gecko-R.jar \
@ -102,24 +126,20 @@ ALL_JARS += ../stumbler/stumbler.jar
generated/org/mozilla/mozstumbler/R.java: .aapt.deps ;
endif
# The list of jars in Java classpath notation (colon-separated).
all_jars_classpath := $(subst $(NULL) ,:,$(strip $(ALL_JARS)))
include $(topsrcdir)/config/config.mk
# Note that we're going to set up a dependency directly between embed_android.dex and the java files
# Instead of on the .class files, since more than one .class file might be produced per .java file
# Sync dependencies are provided in a single jar. Sync classes themselves are delivered as source,
# because Android resource classes must be compiled together in order to avoid overlapping resource
# indices.
library_jars = \
$(JAVA_CLASSPATH) \
$(JAVA_BOOTCLASSPATH) \
library_jars := \
$(ANDROID_SDK)/android.jar \
$(NULL)
library_jars := $(subst $(NULL) ,:,$(strip $(library_jars)))
classes.dex: .proguard.deps
$(REPORT_BUILD)
$(DX) --dex --output=classes.dex jars-proguarded $(subst :, ,$(ANDROID_COMPAT_LIB):$(JAVA_CLASSPATH))
$(DX) --dex --output=classes.dex jars-proguarded
ifdef MOZ_DISABLE_PROGUARD
PROGUARD_PASSES=0
@ -135,6 +155,8 @@ else
endif
endif
proguard_config_dir=$(topsrcdir)/mobile/android/config/proguard
# This stanza ensures that the set of GeckoView classes does not depend on too
# much of Fennec, where "too much" is defined as the set of potentially
# non-GeckoView classes that GeckoView already depended on at a certain point in
@ -148,19 +170,41 @@ classycle_jar := $(topsrcdir)/mobile/android/build/classycle/classycle-1.4.1.jar
$(ALL_JARS)
@$(TOUCH) $@
# We touch the target file before invoking Proguard so that Proguard's
# outputs are fresher than the target, preventing a subsequent
# invocation from thinking Proguard's outputs are stale. This is safe
# because Make removes the target file if any recipe command fails.
.proguard.deps: .geckoview.deps $(ALL_JARS) $(topsrcdir)/mobile/android/config/proguard.cfg
# First, we delete debugging information from libraries. Having line-number
# information for libraries for which we lack the source isn't useful, so this
# saves us a bit of space. Importantly, Proguard has a bug causing it to
# sometimes corrupt this information if present (which it does for some of the
# included libraries). This corruption prevents dex from completing, so we need
# to get rid of it. This prevents us from seeing line numbers in stack traces
# for stack frames inside libraries.
#
# This step can occur much earlier than the main Proguard pass: it needs only
# gecko-R.jar to have been compiled (as that's where the library R.java files
# end up), but it does block the main Proguard pass.
.bundled.proguard.deps: gecko-R.jar $(proguard_config_dir)/strip-libs.cfg
$(REPORT_BUILD)
@$(TOUCH) $@
java \
-Xmx512m -Xms128m \
-jar $(ANDROID_SDK_ROOT)/tools/proguard/lib/proguard.jar \
@$(topsrcdir)/mobile/android/config/proguard.cfg \
@$(proguard_config_dir)/strip-libs.cfg \
-injars $(subst ::,:,$(java_bundled_libs))\
-outjars bundled-jars-nodebug \
-libraryjars $(library_jars):gecko-R.jar
# We touch the target file before invoking Proguard so that Proguard's
# outputs are fresher than the target, preventing a subsequent
# invocation from thinking Proguard's outputs are stale. This is safe
# because Make removes the target file if any recipe command fails.
.proguard.deps: .geckoview.deps .bundled.proguard.deps $(ALL_JARS) $(proguard_config_dir)/proguard.cfg
$(REPORT_BUILD)
@$(TOUCH) $@
java \
-Xmx512m -Xms128m \
-jar $(ANDROID_SDK_ROOT)/tools/proguard/lib/proguard.jar \
@$(proguard_config_dir)/proguard.cfg \
-optimizationpasses $(PROGUARD_PASSES) \
-injars $(subst ::,:,$(subst $(NULL) ,:,$(strip $(ALL_JARS)))) \
-injars $(subst ::,:,$(all_jars_classpath)):bundled-jars-nodebug \
-outjars jars-proguarded \
-libraryjars $(library_jars)

View File

@ -0,0 +1,19 @@
# Rules to prevent Google Play Services from exploding
# (From http://developer.android.com/google/play-services/setup.html#Proguard
# With the reference to "Object" changed so it'll actually *work*...)
-keep class * extends java.util.ListResourceBundle {
protected java.lang.Object[][] getContents();
}
-keep public class com.google.android.gms.common.internal.safeparcel.SafeParcelable {
public static final *** NULL;
}
-keepnames @com.google.android.gms.common.annotation.KeepName class *
-keepclassmembernames class * {
@com.google.android.gms.common.annotation.KeepName *;
}
-keepnames class * implements android.os.Parcelable {
public static final ** CREATOR;
}

View File

@ -110,6 +110,11 @@
-optimizations !class/merging/horizontal
-optimizations !class/merging/vertical
# This optimisation causes corrupt bytecode if we run more than two passes.
# Testing shows that running the extra passes of everything else saves us
# more than this optimisation does, so bye bye!
-optimizations !code/allocation/variable
# Keep miscellaneous targets.
# Keep the annotation.
@ -207,3 +212,9 @@
# Suppress warnings about missing descriptor classes.
#-dontnote **,!ch.boye.**,!org.mozilla.gecko.sync.**
-include "play-services-keeps.cfg"
# Don't print spurious warnings from the support library.
# See: http://stackoverflow.com/questions/22441366/note-android-support-v4-text-icucompatics-cant-find-dynamically-referenced-cl
-dontnote android.support.**

View File

@ -0,0 +1,40 @@
# Proguard step for stripping debug information.
#
# This is useful to work around a bug in the way Proguard handles debug information: it
# sometimes corrupts it. Classes with corrupt debug information cannot be dexed, but
# classes with *no* debug information can be. There's no way to configure Proguard to
# delete debug information on a per-class basis, so we need this special extra step for
# stripping debug information only from those classes for which the Proguard bug is
# encountered.
#
# Currently, this pass is applied to all bundled library jars for which we are not
# compiling the source. This is slightly more than is strictly necessary to work around
# the Proguard bug, but such debug information is of negligible value and stripping it
# too slightly simplifies the makefile and saves us a handful of kilobytes of binary size.
#
# Configuring Proguard to do nothing except strip metadata is done by having it run only
# the obfuscation pass, but with a configuration that prevents it from renaming any classes.
# It then attempts to delete class metadata, so we further configure it not to do so for
# anything except the problematic debug information.
# Run only the obfuscator.
-dontoptimize
-dontshrink
-dontpreverify
-verbose
# Don't rename anything.
-keeppackagenames
# Seriously, don't rename anything.
-keep class *
-keepclassmembers class * {
*;
}
# Don't delete other useful metadata.
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,*Annotation*,EnclosingMethod
# Don't print spurious warnings from the support library.
# See: http://stackoverflow.com/questions/22441366/note-android-support-v4-text-icucompatics-cant-find-dynamically-referenced-cl
-dontnote android.support.**