Bug 874132 - Second reland Part 3: Replace uses of apkbuilder with zip and custom debug signing tool. r=jmaher,mfinkle
authorNick Alexander <nalexander@mozilla.com>
Thu, 20 Jun 2013 11:50:28 -0700
changeset 135861 e51c7d3d5b9de4f9605d40fde19e8c40ba02cd66
parent 135860 448ba56d9ba483bd9246a7bd7e8fdfc46bc45668
child 135862 ad548e637ac10a4c9a5eaf0d6945cadb5f514d82
push id24852
push userryanvm@gmail.com
push dateThu, 20 Jun 2013 23:22:28 +0000
treeherdermozilla-central@b3cbafd5eb99 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjmaher, mfinkle
bugs874132
milestone24.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 874132 - Second reland Part 3: Replace uses of apkbuilder with zip and custom debug signing tool. r=jmaher,mfinkle This incorporates follow-ups including: rename the debug key; check if key alias exists rather than just testing for keystore existence; set $(AIDL). Renaming the debug key works around an un-confirmed JDK bug in jarsigner, where '-debug' and 'debug' compare the same.
build/mobile/robocop/Makefile.in
build/mobile/sutagent/android/Makefile.in
build/mobile/sutagent/android/fencp/Makefile.in
build/mobile/sutagent/android/ffxcp/Makefile.in
build/mobile/sutagent/android/watcher/Makefile.in
config/android-common.mk
mobile/android/base/Makefile.in
mobile/android/build.mk
mobile/android/debug_sign_tool.py
testing/testsuite-targets.mk
toolkit/mozapps/installer/packager.mk
--- a/build/mobile/robocop/Makefile.in
+++ b/build/mobile/robocop/Makefile.in
@@ -8,16 +8,18 @@ srcdir      = @srcdir@
 VPATH       = @srcdir@
 
 mobile-tests := mobile/android/base/tests
 TESTPATH     := $(topsrcdir)/$(mobile-tests)
 dir-tests    := $(DEPTH)/$(mobile-tests)
 
 include $(DEPTH)/config/autoconf.mk
 
+ANDROID_APK_NAME := robocop-debug
+
 ROBOTIUM_PATH = $(srcdir)/robotium-solo-3.6.jar
 
 JAVAFILES = \
   R.java \
   $(NULL)
 
 RES_FILES = \
   res/values/strings.xml \
@@ -76,49 +78,55 @@ MOCHITEST_ROBOCOP_FILES := \
   $(wildcard $(TESTPATH)/*.xml) \
   $(NULL)
 
 GARBAGE += \
   AndroidManifest.xml \
   $(java-tests-dep) \
   $(_JAVA_HARNESS) \
   classes.dex \
-  robocop.ap_ \
-  robocop-debug-signed.apk \
-  robocop-debug-signed-unaligned.apk \
+  $(ANDROID_APK_NAME).ap_ \
+  $(ANDROID_APK_NAME)-unsigned-unaligned.apk \
+  $(ANDROID_APK_NAME)-unaligned.apk \
+  $(ANDROID_APK_NAME).apk \
   $(robocop-deps) \
   $(NULL)
 
 DEFINES += \
   -DANDROID_PACKAGE_NAME=$(ANDROID_PACKAGE_NAME) \
   $(NULL)
 
 JAVA_CLASSPATH = $(ANDROID_SDK)/android.jar:$(ROBOTIUM_PATH)
 
 include $(topsrcdir)/config/rules.mk
 
 # Override rules.mk java flags with the android specific ones
 include $(topsrcdir)/config/android-common.mk
 
 GENERATED_DIRS_tools = classes $(dir-tests)
 
-libs:: robocop-debug-signed.apk
+tools:: $(ANDROID_APK_NAME).apk
 
-classes.dex: robocop.ap_
+classes.dex: $(ANDROID_APK_NAME).ap_
 classes.dex: $(robocop-deps)
 classes.dex: $(java-harness-dep)
 classes.dex: $(java-tests-dep)
 	$(JAVAC) $(JAVAC_FLAGS) -d classes $(JAVAFILES) $(_JAVA_HARNESS) $(java-tests-dep)
 	$(DX) --dex --output=$@ classes $(ROBOTIUM_PATH) $(ANDROID_COMPT_LIB)
 
-robocop.ap_: AndroidManifest.xml $(TESTPATH)/assets/*
+$(ANDROID_APK_NAME).ap_: AndroidManifest.xml $(TESTPATH)/assets/*
 	$(AAPT) package -f -M $< -I $(ANDROID_SDK)/android.jar -I . -S res -A $(TESTPATH)/assets -F $@ -J ./
 
-robocop-debug-signed-unaligned.apk: robocop.ap_ classes.dex
-	$(APKBUILDER) $@ -v $(APKBUILDER_FLAGS) -z robocop.ap_ -f classes.dex
+$(ANDROID_APK_NAME)-unsigned-unaligned.apk: $(ANDROID_APK_NAME).ap_ classes.dex
+	cp $< $@
+	$(ZIP) -0 $@ classes.dex
 
-robocop-debug-signed.apk: robocop-debug-signed-unaligned.apk
-	$(ZIPALIGN) -f -v 4 $^ $@
+$(ANDROID_APK_NAME)-unaligned.apk: $(ANDROID_APK_NAME)-unsigned-unaligned.apk
+	cp $< $@
+	$(DEBUG_JARSIGNER) $@
+
+$(ANDROID_APK_NAME).apk: $(ANDROID_APK_NAME)-unaligned.apk
+	$(ZIPALIGN) -f -v 4 $< $@
 
 # PP_java-tests not fully usable here
 # Intermediate step toward a library rule.
 $(dir-tests)/%.java: $(TESTPATH)/%.java.in $(call mkdir_deps,$(dir-tests))
 	$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $< > $@
--- a/build/mobile/sutagent/android/Makefile.in
+++ b/build/mobile/sutagent/android/Makefile.in
@@ -4,16 +4,18 @@
 
 DEPTH		= @DEPTH@
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
+ANDROID_APK_NAME := sutAgentAndroid
+
 JAVAFILES = \
   AlertLooperThread.java \
   ASMozStub.java \
   CmdWorkerThread.java \
   DataWorkerThread.java \
   DoAlert.java \
   DoCommand.java \
   FindProcThread.java \
@@ -34,45 +36,44 @@ RES_FILES = \
   res/drawable/ic_stat_warning.png \
   res/layout/main.xml \
   res/values/strings.xml \
   $(NULL)
 
 GARBAGE += \
   AndroidManifest.xml  \
   classes.dex  \
-  sutAgentAndroid.apk  \
-  sutAgentAndroid.ap_ \
-  sutAgentAndroid-unsigned-unaligned.apk \
-  sutAgentAndroid-unaligned.apk \
+  $(ANDROID_APK_NAME).ap_ \
+  $(ANDROID_APK_NAME)-unsigned-unaligned.apk \
+  $(ANDROID_APK_NAME)-unaligned.apk \
+  $(ANDROID_APK_NAME).apk \
   $(NULL)
 
 GARBAGE_DIRS += network-libs
 
 EXTRA_JARS = $(srcdir)/network-libs/commons-net-2.0.jar:$(srcdir)/network-libs/jmdns.jar
 
 JAVA_CLASSPATH = $(ANDROID_SDK)/android.jar:$(EXTRA_JARS)
 
 include $(topsrcdir)/config/rules.mk
 
 # include Android specific java flags - using these instead of what's in rules.mk
 include $(topsrcdir)/config/android-common.mk
 
-tools:: sutAgentAndroid.apk
+tools:: $(ANDROID_APK_NAME).apk
 
 classes.dex: $(JAVAFILES)
 	$(JAVAC) $(JAVAC_FLAGS) -d classes  $(addprefix $(srcdir)/,$(JAVAFILES))
 	$(DX) --dex --output=$@ classes $(subst :, ,$(EXTRA_JARS))
 
-sutAgentAndroid.ap_: $(srcdir)/AndroidManifest.xml
+$(ANDROID_APK_NAME).ap_: AndroidManifest.xml
 	$(AAPT) package -f -M $< -I $(ANDROID_SDK)/android.jar -S res -F $@
 
-sutAgentAndroid-unsigned-unaligned.apk: sutAgentAndroid.ap_ classes.dex
-	$(APKBUILDER) $@ -v $(APKBUILDER_FLAGS) -z sutAgentAndroid.ap_ -f classes.dex
-
-sutAgentAndroid-unaligned.apk: sutAgentAndroid-unsigned-unaligned.apk
+$(ANDROID_APK_NAME)-unsigned-unaligned.apk: $(ANDROID_APK_NAME).ap_ classes.dex
 	cp $< $@
-ifdef JARSIGNER
-	$(JARSIGNER) $@
-endif
+	$(ZIP) -0 $@ classes.dex
 
-sutAgentAndroid.apk: sutAgentAndroid-unaligned.apk
-	$(ZIPALIGN) -f -v 4 sutAgentAndroid-unaligned.apk $@
+$(ANDROID_APK_NAME)-unaligned.apk: $(ANDROID_APK_NAME)-unsigned-unaligned.apk
+	cp $< $@
+	$(DEBUG_JARSIGNER) $@
+
+$(ANDROID_APK_NAME).apk: $(ANDROID_APK_NAME)-unaligned.apk
+	$(ZIPALIGN) -f -v 4 $< $@
--- a/build/mobile/sutagent/android/fencp/Makefile.in
+++ b/build/mobile/sutagent/android/fencp/Makefile.in
@@ -4,16 +4,18 @@
 
 DEPTH		= @DEPTH@
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
+ANDROID_APK_NAME := FenCP
+
 JAVAFILES = \
   DirCursor.java \
   FenCP.java \
   FenCPFP.java \
   FileCursor.java \
   R.java \
   $(NULL)
 
@@ -23,40 +25,42 @@ RES_FILES = \
   res/drawable-mdpi/icon.png \
   res/layout/main.xml \
   res/values/strings.xml \
   $(NULL)
 
 GARBAGE += \
   AndroidManifest.xml  \
   classes.dex  \
-  FenCP.apk  \
+  $(ANDROID_APK_NAME).ap_ \
+  $(ANDROID_APK_NAME)-unsigned-unaligned.apk \
+  $(ANDROID_APK_NAME)-unaligned.apk \
+  $(ANDROID_APK_NAME).apk \
   $(NULL)
 
 GARBAGE_DIRS += network-libs
 
 JAVA_CLASSPATH = $(ANDROID_SDK)/android.jar
 
 include $(topsrcdir)/config/rules.mk
 
 # include Android specific java flags - using these instead of what's in rules.mk
 include $(topsrcdir)/config/android-common.mk
 
-tools:: FenCP.apk
+tools:: $(ANDROID_APK_NAME).apk
 
 classes.dex: $(JAVAFILES)
 	$(JAVAC) $(JAVAC_FLAGS) -d classes  $(addprefix $(srcdir)/,$(JAVAFILES))
 	$(DX) --dex --output=$@ classes
 
-FenCP.ap_: $(srcdir)/AndroidManifest.xml
-	$(AAPT) package -f -M $(srcdir)/AndroidManifest.xml -I $(ANDROID_SDK)/android.jar  -S res -F $@
+$(ANDROID_APK_NAME).ap_: AndroidManifest.xml
+	$(AAPT) package -f -M $< -I $(ANDROID_SDK)/android.jar -S res -F $@
 
-FenCP-unsigned-unaligned.apk: FenCP.ap_ classes.dex
-	$(APKBUILDER) $@ -v $(APKBUILDER_FLAGS) -z FenCP.ap_ -f classes.dex
+$(ANDROID_APK_NAME)-unsigned-unaligned.apk: $(ANDROID_APK_NAME).ap_ classes.dex
+	cp $< $@
+	$(ZIP) -0 $@ classes.dex
 
-FenCP-unaligned.apk: FenCP-unsigned-unaligned.apk
-	cp  FenCP-unsigned-unaligned.apk $@
-ifdef JARSIGNER
-  $(JARSIGNER) $@
-endif
+$(ANDROID_APK_NAME)-unaligned.apk: $(ANDROID_APK_NAME)-unsigned-unaligned.apk
+	cp $< $@
+	$(DEBUG_JARSIGNER) $@
 
-FenCP.apk: FenCP-unaligned.apk
-	$(ZIPALIGN) -f -v 4 FenCP-unaligned.apk $@
+$(ANDROID_APK_NAME).apk: $(ANDROID_APK_NAME)-unaligned.apk
+	$(ZIPALIGN) -f -v 4 $< $@
--- a/build/mobile/sutagent/android/ffxcp/Makefile.in
+++ b/build/mobile/sutagent/android/ffxcp/Makefile.in
@@ -4,16 +4,18 @@
 
 DEPTH		= @DEPTH@
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
+ANDROID_APK_NAME := FfxCP
+
 JAVAFILES = \
   DirCursor.java \
   ffxcp.java \
   FfxCPFP.java \
   FileCursor.java \
   R.java \
   $(NULL)
 
@@ -23,40 +25,42 @@ RES_FILES = \
   res/drawable-mdpi/icon.png \
   res/layout/main.xml \
   res/values/strings.xml \
   $(NULL)
 
 GARBAGE += \
   AndroidManifest.xml  \
   classes.dex  \
-  FfxCP.apk  \
+  $(ANDROID_APK_NAME).ap_ \
+  $(ANDROID_APK_NAME)-unsigned-unaligned.apk \
+  $(ANDROID_APK_NAME)-unaligned.apk \
+  $(ANDROID_APK_NAME).apk \
   $(NULL)
 
 GARBAGE_DIRS += network-libs
 
 JAVA_CLASSPATH = $(ANDROID_SDK)/android.jar
 
 include $(topsrcdir)/config/rules.mk
 
 # include Android specific java flags - using these instead of what's in rules.mk
 include $(topsrcdir)/config/android-common.mk
 
-tools:: FfxCP.apk
+tools:: $(ANDROID_APK_NAME).apk
 
 classes.dex: $(JAVAFILES)
 	$(JAVAC) $(JAVAC_FLAGS) -d classes  $(addprefix $(srcdir)/,$(JAVAFILES))
 	$(DX) --dex --output=$@ classes
 
-FfxCP.ap_: $(srcdir)/AndroidManifest.xml
-	$(AAPT) package -f -M $(srcdir)/AndroidManifest.xml -I $(ANDROID_SDK)/android.jar  -S res -F $@
+$(ANDROID_APK_NAME).ap_: AndroidManifest.xml
+	$(AAPT) package -f -M $< -I $(ANDROID_SDK)/android.jar -S res -F $@
 
-FfxCP-unsigned-unaligned.apk: FfxCP.ap_ classes.dex
-	$(APKBUILDER) $@ -v $(APKBUILDER_FLAGS) -z FfxCP.ap_ -f classes.dex
+$(ANDROID_APK_NAME)-unsigned-unaligned.apk: $(ANDROID_APK_NAME).ap_ classes.dex
+	cp $< $@
+	$(ZIP) -0 $@ classes.dex
 
-FfxCP-unaligned.apk: FfxCP-unsigned-unaligned.apk
-	cp  FfxCP-unsigned-unaligned.apk $@
-ifdef JARSIGNER
-  $(JARSIGNER) $@
-endif
+$(ANDROID_APK_NAME)-unaligned.apk: $(ANDROID_APK_NAME)-unsigned-unaligned.apk
+	cp $< $@
+	$(DEBUG_JARSIGNER) $@
 
-FfxCP.apk: FfxCP-unaligned.apk
-	$(ZIPALIGN) -f -v 4 FfxCP-unaligned.apk $@
+$(ANDROID_APK_NAME).apk: $(ANDROID_APK_NAME)-unaligned.apk
+	$(ZIPALIGN) -f -v 4 $< $@
--- a/build/mobile/sutagent/android/watcher/Makefile.in
+++ b/build/mobile/sutagent/android/watcher/Makefile.in
@@ -4,16 +4,18 @@
 
 DEPTH		= @DEPTH@
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
+ANDROID_APK_NAME := Watcher
+
 JAVAFILES = \
   IWatcherService.java \
   RedirOutputThread.java \
   R.java \
   WatcherMain.java \
   WatcherReceiver.java \
   WatcherService.java \
   $(NULL)
@@ -27,46 +29,43 @@ RES_FILES = \
   res/drawable-mdpi/ateamlogo.png \
   res/layout/main.xml \
   res/values/strings.xml \
   $(NULL)
 
 GARBAGE += \
   AndroidManifest.xml  \
   classes.dex  \
-  Watcher.apk  \
+  $(ANDROID_APK_NAME).ap_ \
+  $(ANDROID_APK_NAME)-unsigned-unaligned.apk \
+  $(ANDROID_APK_NAME)-unaligned.apk \
+  $(ANDROID_APK_NAME).apk \
   $(NULL)
 
 GARBAGE_DIRS += res classes network-libs
 
 JAVA_CLASSPATH = $(ANDROID_SDK)/android.jar
 
 include $(topsrcdir)/config/rules.mk
 
 # include Android specific java flags - using these instead of what's in rules.mk
 include $(topsrcdir)/config/android-common.mk
 
-tools:: Watcher.apk
+tools:: $(ANDROID_APK_NAME).apk
 
 classes.dex: $(JAVAFILES)
 	$(NSINSTALL) -D classes
 	$(JAVAC) $(JAVAC_FLAGS) -d classes  $(addprefix $(srcdir)/,$(JAVAFILES))
 	$(DX) --dex --output=$@ classes
 
-Watcher.ap_: $(srcdir)/AndroidManifest.xml
-	$(AAPT) package -f -M $(srcdir)/AndroidManifest.xml -I $(ANDROID_SDK)/android.jar  -S res -F $@
+$(ANDROID_APK_NAME).ap_: AndroidManifest.xml
+	$(AAPT) package -f -M $< -I $(ANDROID_SDK)/android.jar -S res -F $@
 
-Watcher-unsigned-unaligned.apk: Watcher.ap_ classes.dex
-	$(APKBUILDER) $@ -v $(APKBUILDER_FLAGS) -z Watcher.ap_ -f classes.dex
+$(ANDROID_APK_NAME)-unsigned-unaligned.apk: $(ANDROID_APK_NAME).ap_ classes.dex
+	cp $< $@
+	$(ZIP) -0 $@ classes.dex
 
-Watcher-unaligned.apk: Watcher-unsigned-unaligned.apk
-	cp  Watcher-unsigned-unaligned.apk $@
-ifdef JARSIGNER
-  $(JARSIGNER) $@
-endif
+$(ANDROID_APK_NAME)-unaligned.apk: $(ANDROID_APK_NAME)-unsigned-unaligned.apk
+	cp $< $@
+	$(DEBUG_JARSIGNER) $@
 
-Watcher.apk: Watcher-unaligned.apk
-	$(ZIPALIGN) -f -v 4 Watcher-unaligned.apk $@
-
-export::
-	$(NSINSTALL) -D res
-	@(cd $(srcdir)/res && tar $(TAR_CREATE_FLAGS) - *) | (cd $(DEPTH)/build/mobile/sutagent/android/watcher/res && tar -xf -)
-
+$(ANDROID_APK_NAME).apk: $(ANDROID_APK_NAME)-unaligned.apk
+	$(ZIPALIGN) -f -v 4 $< $@
--- a/config/android-common.mk
+++ b/config/android-common.mk
@@ -9,22 +9,21 @@ ifndef ANDROID_SDK
 endif
 
 ifndef JAVA_CLASSPATH
   $(error JAVA_CLASSPATH must be defined before including android-common.mk)
 endif
 
 DX=$(ANDROID_BUILD_TOOLS)/dx
 AAPT=$(ANDROID_BUILD_TOOLS)/aapt
-APKBUILDER=$(ANDROID_SDK)/../../tools/apkbuilder
+AIDL=$(ANDROID_BUILD_TOOLS)/aidl
+ADB=$(ANDROID_PLATFORM_TOOLS)/adb
 ZIPALIGN=$(ANDROID_SDK)/../../tools/zipalign
-
-ifdef JARSIGNER
-  APKBUILDER_FLAGS += -u
-endif
+# DEBUG_JARSIGNER always debug signs.
+DEBUG_JARSIGNER=$(PYTHON) $(call core_abspath,$(topsrcdir)/mobile/android/debug_sign_tool.py)
 
 # For Android, this defaults to $(ANDROID_SDK)/android.jar
 ifndef JAVA_BOOTCLASSPATH
   JAVA_BOOTCLASSPATH = $(ANDROID_SDK)/android.jar:$(ANDROID_COMPAT_LIB)
 endif
 
 # For Android, we default to 1.5
 ifndef JAVA_VERSION
--- a/mobile/android/base/Makefile.in
+++ b/mobile/android/base/Makefile.in
@@ -1217,17 +1217,17 @@ jars/webrtc.jar: $(addprefix $(srcdir)/,
 	$(JAR) cMf jars/webrtc.jar -C classes/webrtc .
 endif
 
 jars:
 	@echo "MKDIR jars"
 	$(NSINSTALL) -D jars
 
 $(AIDL_AUTOGEN_FILES): %.java: %.aidl
-	$(ANDROID_PLATFORM_TOOLS)/aidl -I$(srcdir)/braille $<
+	$(AIDL) -I$(srcdir)/braille $<
 
 CLASSES_WITH_JNI= \
     org.mozilla.gecko.GeckoAppShell \
     org.mozilla.gecko.GeckoJavaSampler \
     org.mozilla.gecko.gfx.NativePanZoomController \
     org.mozilla.gecko.ANRReporter \
     $(NULL)
 
--- a/mobile/android/build.mk
+++ b/mobile/android/build.mk
@@ -1,48 +1,52 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 include  $(topsrcdir)/toolkit/mozapps/installer/package-name.mk
 
-installer: 
+installer:
 	@$(MAKE) -C mobile/android/installer installer
 
 package:
 	@$(MAKE) -C mobile/android/installer
 
 fast-package:
 	@$(MAKE) package MOZ_FAST_PACKAGE=1
 
 ifeq ($(OS_TARGET),Android)
+# $(ADB) is defined in config/android-common.mk, but that file is not
+# in scope when this file is read, so we define it locally.
+ADB=$(ANDROID_PLATFORM_TOOLS)/adb
+
 ifneq ($(MOZ_ANDROID_INSTALL_TARGET),)
 ANDROID_SERIAL = $(MOZ_ANDROID_INSTALL_TARGET)
 endif
 ifneq ($(ANDROID_SERIAL),)
 export ANDROID_SERIAL
 else
 # Determine if there's more than one device connected
-android_devices=$(filter device,$(shell $(ANDROID_PLATFORM_TOOLS)/adb devices))
+android_devices=$(filter device,$(shell $(ADB) devices))
 ifeq ($(android_devices),)
 install::
 	@echo "No devices are connected.  Connect a device or start an emulator."
 	@exit 1
 else
 ifneq ($(android_devices),device)
 install::
 	@echo "Multiple devices are connected. Define ANDROID_SERIAL to specify the install target."
-	$(ANDROID_PLATFORM_TOOLS)/adb devices
+	$(ADB) devices
 	@exit 1
 endif
 endif
 endif
 
 install::
-	$(ANDROID_PLATFORM_TOOLS)/adb install -r $(DIST)/$(PKG_PATH)$(PKG_BASENAME).apk
+	$(ADB) install -r $(DIST)/$(PKG_PATH)$(PKG_BASENAME).apk
 else
 	@echo "Mobile can't be installed directly."
 	@exit 1
 endif
 
 deb: package
 	@$(MAKE) -C mobile/android/installer deb
 
--- a/mobile/android/debug_sign_tool.py
+++ b/mobile/android/debug_sign_tool.py
@@ -31,85 +31,111 @@ log.addHandler(sh)
 
 
 class DebugKeystore:
     """
     A thin abstraction on top of an Android debug key store.
     """
     def __init__(self, keystore):
         self._keystore = os.path.abspath(os.path.expanduser(keystore))
-        self._alias = 'debug'
+        self._alias = 'androiddebugkey'
         self.verbose = False
         self.keytool = 'keytool'
         self.jarsigner = 'jarsigner'
 
     @property
     def keystore(self):
         return self._keystore
 
     @property
     def alias(self):
         return self._alias
 
-    def _ensure_keystore(self):
-        if os.path.exists(self.keystore):
-            if self.verbose:
-                log.debug('Keystore exists at %s' % self.keystore)
+    def _check(self, args):
+        if self.verbose:
+            subprocess.check_call(args)
         else:
-            self.create_keystore()
+            subprocess.check_output(args)
 
-    def create_keystore(self):
+    def keystore_contains_alias(self):
+        args = [ self.keytool,
+                 '-list',
+                 '-keystore', self.keystore,
+                 '-storepass', 'android',
+                 '-alias', self.alias,
+               ]
+        if self.verbose:
+            args.append('-v')
+        contains = True
+        try:
+            self._check(args)
+        except subprocess.CalledProcessError as e:
+            contains = False
+        if self.verbose:
+            log.info('Keystore %s %s alias %s' %
+                     (self.keystore,
+                      'contains' if contains else 'does not contain',
+                      self.alias))
+        return contains
+
+    def create_alias_in_keystore(self):
         try:
             path = os.path.dirname(self.keystore)
             os.makedirs(path)
         except OSError as exception:
             if exception.errno != errno.EEXIST:
                 raise
 
         args = [ self.keytool,
-                 '-genkey',
-                 '-v',
+                 '-genkeypair',
                  '-keystore', self.keystore,
                  '-storepass', 'android',
                  '-alias', self.alias,
                  '-keypass', 'android',
                  '-dname', 'CN=Android Debug,O=Android,C=US',
                  '-keyalg', 'RSA',
                  '-validity', '365',
                ]
-        subprocess.check_call(args)
         if self.verbose:
-            log.info('Created keystore at %s' % self.keystore)
+            args.append('-v')
+        self._check(args)
+        if self.verbose:
+            log.info('Created alias %s in keystore %s' %
+                     (self.alias, self.keystore))
 
     def sign(self, apk):
-        self._ensure_keystore()
+        if not self.keystore_contains_alias():
+            self.create_alias_in_keystore()
 
         args = [ self.jarsigner,
                  '-digestalg', 'SHA1',
                  '-sigalg', 'MD5withRSA',
                  '-keystore', self.keystore,
                  '-storepass', 'android',
                  apk,
                  self.alias,
                ]
-        subprocess.check_call(args)
         if self.verbose:
-            log.info('Signed %s with keystore at %s' % (apk, self.keystore))
+            args.append('-verbose')
+        self._check(args)
+        if self.verbose:
+            log.info('Signed %s with alias %s from keystore %s' %
+                     (apk, self.alias, self.keystore))
 
 
 def parse_args(argv):
     parser = ArgumentParser(description='Sign Android packages using an Android debug keystore.')
     parser.add_argument('apks', nargs='+',
                         metavar='APK',
                         help='Android packages to be signed')
-    parser.add_argument('-q', '--quiet',
+    parser.add_argument('-v', '--verbose',
                         dest='verbose',
-                        default=True,
-                        action='store_false',
-                        help='quiet output')
+                        default=False,
+                        action='store_true',
+                        help='verbose output')
     parser.add_argument('--keytool',
                         metavar='PATH',
                         default='keytool',
                         help='path to Java keytool')
     parser.add_argument('--jarsigner',
                         metavar='PATH',
                         default='jarsigner',
                         help='path to Java jarsigner')
@@ -130,19 +156,20 @@ def main():
 
     keystore = DebugKeystore(args.keystore)
     keystore.verbose = args.verbose
     keystore.keytool = args.keytool
     keystore.jarsigner = args.jarsigner
 
     if args.force:
         try:
-            keystore.create_keystore()
+            keystore.create_alias_in_keystore()
         except subprocess.CalledProcessError as e:
-            log.error('Failed to force-create keystore')
+            log.error('Failed to force-create alias %s in keystore %s' %
+                      (keystore.alias, keystore.keystore))
             log.error(e)
             return 1
 
     for apk in args.apks:
         try:
             keystore.sign(apk)
         except subprocess.CalledProcessError as e:
             log.error('Failed to sign %s', apk)
--- a/testing/testsuite-targets.mk
+++ b/testing/testsuite-targets.mk
@@ -61,17 +61,17 @@ RUN_MOCHITEST_REMOTE = \
     --console-level=INFO --log-file=./$@.log --file-level=INFO $(DM_FLAGS) --dm_trans=$(DM_TRANS) \
     --app=$(TEST_PACKAGE_NAME) --deviceIP=${TEST_DEVICE} --xre-path=${MOZ_HOST_BIN} \
     --testing-modules-dir=$(call core_abspath,_tests/modules) \
     $(SYMBOLS_PATH) $(TEST_PATH_ARG) $(EXTRA_TEST_ARGS)
 
 RUN_MOCHITEST_ROBOCOP = \
   rm -f ./$@.log && \
   $(PYTHON) _tests/testing/mochitest/runtestsremote.py \
-    --robocop-apk=$(DEPTH)/build/mobile/robocop/robocop-debug-signed.apk \
+    --robocop-apk=$(DEPTH)/build/mobile/robocop/robocop-debug.apk \
     --robocop-ids=$(DEPTH)/mobile/android/base/fennec_ids.txt \
     --robocop-ini=$(DEPTH)/build/mobile/robocop/robocop.ini \
     --console-level=INFO --log-file=./$@.log --file-level=INFO $(DM_FLAGS) --dm_trans=$(DM_TRANS) \
     --app=$(TEST_PACKAGE_NAME) --deviceIP=${TEST_DEVICE} --xre-path=${MOZ_HOST_BIN} \
     $(SYMBOLS_PATH) $(TEST_PATH_ARG) $(EXTRA_TEST_ARGS)
 
 ifndef NO_FAIL_ON_TEST_ERRORS
 define check_test_error_internal
--- a/toolkit/mozapps/installer/packager.mk
+++ b/toolkit/mozapps/installer/packager.mk
@@ -242,20 +242,22 @@ INNER_UNMAKE_PACKAGE = $(error Try using
 endif #Create an RPM file
 
 
 ifeq ($(MOZ_PKG_FORMAT),APK)
 
 JAVA_CLASSPATH = $(ANDROID_SDK)/android.jar
 include $(MOZILLA_DIR)/config/android-common.mk
 
+# DEBUG_JARSIGNER is defined by android-common.mk and always debug
+# signs.  We want to release sign if possible.
 ifdef MOZ_SIGN_CMD
-JARSIGNER := $(MOZ_SIGN_CMD) -f jar
+RELEASE_JARSIGNER := $(MOZ_SIGN_CMD) -f jar
 else
-JARSIGNER ?= echo
+RELEASE_JARSIGNER := $(DEBUG_JARSIGNER)
 endif
 
 DIST_FILES =
 
 # Place the files in the order they are going to be opened by the linker
 DIST_FILES += libmozalloc.so
 ifndef MOZ_FOLD_LIBS
 DIST_FILES += \
@@ -322,20 +324,22 @@ endif
 GECKO_APP_AP_PATH = $(call core_abspath,$(DEPTH)/mobile/android/base)
 
 ifdef ENABLE_TESTS
 INNER_ROBOCOP_PACKAGE=echo
 ifeq ($(MOZ_BUILD_APP),mobile/android)
 UPLOAD_EXTRA_FILES += robocop.apk
 UPLOAD_EXTRA_FILES += fennec_ids.txt
 ROBOCOP_PATH = $(call core_abspath,$(_ABS_DIST)/../build/mobile/robocop)
+# Robocop and Fennec need to be signed with the same key, which means
+# release signing them both.
 INNER_ROBOCOP_PACKAGE= \
   $(NSINSTALL) $(GECKO_APP_AP_PATH)/fennec_ids.txt $(_ABS_DIST) && \
-  cp $(ROBOCOP_PATH)/robocop-debug-signed-unaligned.apk $(_ABS_DIST)/robocop-unaligned.apk && \
-  $(JARSIGNER) $(_ABS_DIST)/robocop-unaligned.apk && \
+  cp $(ROBOCOP_PATH)/robocop-debug-unsigned-unaligned.apk $(_ABS_DIST)/robocop-unaligned.apk && \
+  $(RELEASE_JARSIGNER) $(_ABS_DIST)/robocop-unaligned.apk && \
   $(ZIPALIGN) -f -v 4 $(_ABS_DIST)/robocop-unaligned.apk $(_ABS_DIST)/robocop.apk
 endif
 else
 INNER_ROBOCOP_PACKAGE=echo 'Testing is disabled - No Robocop for you'
 endif
 
 ifdef MOZ_OMX_PLUGIN
 DIST_FILES += libomxplugin.so libomxplugingb.so libomxplugingb235.so libomxpluginhc.so libomxpluginsony.so libomxpluginfroyo.so libomxpluginjb-htc.so
@@ -365,19 +369,20 @@ INNER_MAKE_PACKAGE	= \
     mv libmozglue.so $(MOZ_CHILD_PROCESS_NAME) lib/$(ABI_DIR) && \
     mv $(SO_LIBRARIES) assets && \
     unzip -o $(_ABS_DIST)/gecko.ap_ && \
     rm $(_ABS_DIST)/gecko.ap_ && \
     $(ZIP) -0 $(_ABS_DIST)/gecko.ap_ $(ASSET_SO_LIBRARIES) && \
     $(ZIP) -r9D $(_ABS_DIST)/gecko.ap_ $(DIST_FILES) -x $(NON_DIST_FILES) $(SZIP_LIBRARIES) && \
     $(ZIP) -0 $(_ABS_DIST)/gecko.ap_ $(OMNIJAR_NAME)) && \
   rm -f $(_ABS_DIST)/gecko.apk && \
-  $(APKBUILDER) $(_ABS_DIST)/gecko.apk -v $(APKBUILDER_FLAGS) -z $(_ABS_DIST)/gecko.ap_ -f $(STAGEPATH)$(MOZ_PKG_DIR)$(_BINPATH)/classes.dex && \
+  cp $(_ABS_DIST)/gecko.ap_ $(_ABS_DIST)/gecko.apk && \
+  $(ZIP) -j0 $(_ABS_DIST)/gecko.apk $(STAGEPATH)$(MOZ_PKG_DIR)$(_BINPATH)/classes.dex && \
   cp $(_ABS_DIST)/gecko.apk $(_ABS_DIST)/gecko-unsigned-unaligned.apk && \
-  $(JARSIGNER) $(_ABS_DIST)/gecko.apk && \
+  $(RELEASE_JARSIGNER) $(_ABS_DIST)/gecko.apk && \
   $(ZIPALIGN) -f -v 4 $(_ABS_DIST)/gecko.apk $(PACKAGE) && \
   $(INNER_ROBOCOP_PACKAGE)
 
 INNER_UNMAKE_PACKAGE	= \
   mkdir $(MOZ_PKG_DIR) && \
   ( cd $(MOZ_PKG_DIR) && \
     $(UNZIP) $(UNPACKAGE) && \
     mv lib/$(ABI_DIR)/libmozglue.so . && \