Bug 1260241 - Part 1: Implement Fennec packaging in Python. r?glandium draft
authorNick Alexander <nalexander@mozilla.com>
Sat, 26 Mar 2016 14:25:40 -0700
changeset 345331 ad2de0559461d8750b76dab4df57c489a363d2b1
parent 345330 ef88cda78b4fd2f76cc04929fd2bda0d785f413f
child 345332 5b3f315132f4bf6b671a62fb2c71136165576fe2
push id14050
push usernalexander@mozilla.com
push dateMon, 28 Mar 2016 20:40:35 +0000
reviewersglandium
bugs1260241
milestone48.0a1
Bug 1260241 - Part 1: Implement Fennec packaging in Python. r?glandium A few notes: * This doesn't accommodate general OMNIJAR_NAME definitions. The current name (assets/omni.ja) is baked into the product in a few places, and is very unlikely to change, so let's not address that right now. * This makes the package-manifest.in file authoritative for what goes into assets/, libs/, and the APK root. Previously, package-manifest.in wrote into assets/ and libs/ but upload-files-APK.mk also had a convoluted DIST_FILES filtering process to work through before a file actually made it into the APK. * This is intentional about repackaging. It simplifies the repackage step rather than trying to make unpackage-then-repackage the same as just package. I pretty much never get repackaging correct the first time; this should help. (I've manually tested it.) * This doesn't yet store (rather than deflate) szipped libraries in assets/. MozReview-Commit-ID: LYXiJuqOezj
mobile/android/installer/package-manifest.in
python/moz.build
python/mozbuild/mozbuild/action/package_fennec_apk.py
python/mozbuild/mozbuild/test/action/data/package_fennec_apk/assets/asset.txt
python/mozbuild/mozbuild/test/action/data/package_fennec_apk/classes.dex
python/mozbuild/mozbuild/test/action/data/package_fennec_apk/input1.ap_
python/mozbuild/mozbuild/test/action/data/package_fennec_apk/input1/res/res.txt
python/mozbuild/mozbuild/test/action/data/package_fennec_apk/input1/resources.arsc
python/mozbuild/mozbuild/test/action/data/package_fennec_apk/input2.apk
python/mozbuild/mozbuild/test/action/data/package_fennec_apk/input2/assets/asset.txt
python/mozbuild/mozbuild/test/action/data/package_fennec_apk/input2/assets/omni.ja
python/mozbuild/mozbuild/test/action/data/package_fennec_apk/input2/classes.dex
python/mozbuild/mozbuild/test/action/data/package_fennec_apk/input2/lib/lib.txt
python/mozbuild/mozbuild/test/action/data/package_fennec_apk/input2/res/res.txt
python/mozbuild/mozbuild/test/action/data/package_fennec_apk/input2/resources.arsc
python/mozbuild/mozbuild/test/action/data/package_fennec_apk/input2/root_file.txt
python/mozbuild/mozbuild/test/action/data/package_fennec_apk/lib/lib.txt
python/mozbuild/mozbuild/test/action/data/package_fennec_apk/omni.ja
python/mozbuild/mozbuild/test/action/data/package_fennec_apk/root_file.txt
python/mozbuild/mozbuild/test/action/test_package_fennec_apk.py
toolkit/mozapps/installer/upload-files-APK.mk
--- a/mobile/android/installer/package-manifest.in
+++ b/mobile/android/installer/package-manifest.in
@@ -34,21 +34,23 @@
 @BINPATH@/@DLL_PREFIX@dmd@DLL_SUFFIX@
 #endif
 #ifndef MOZ_FOLD_LIBS
 @BINPATH@/@DLL_PREFIX@plc4@DLL_SUFFIX@
 @BINPATH@/@DLL_PREFIX@plds4@DLL_SUFFIX@
 @BINPATH@/@DLL_PREFIX@nspr4@DLL_SUFFIX@
 #endif
 @BINPATH@/@DLL_PREFIX@lgpllibs@DLL_SUFFIX@
+#ifdef MOZ_OMX_PLUGIN
 @BINPATH@/@DLL_PREFIX@omxplugin@DLL_SUFFIX@
 @BINPATH@/@DLL_PREFIX@omxplugingb@DLL_SUFFIX@
 @BINPATH@/@DLL_PREFIX@omxplugingb235@DLL_SUFFIX@
 @BINPATH@/@DLL_PREFIX@omxpluginhc@DLL_SUFFIX@
 @BINPATH@/@DLL_PREFIX@omxpluginkk@DLL_SUFFIX@
+#endif
 @BINPATH@/@DLL_PREFIX@xul@DLL_SUFFIX@
 
 @BINPATH@/@DLL_PREFIX@nssckbi@DLL_SUFFIX@
 @BINPATH@/@DLL_PREFIX@nss3@DLL_SUFFIX@
 #ifndef MOZ_FOLD_LIBS
 @BINPATH@/@DLL_PREFIX@nssutil3@DLL_SUFFIX@
 @BINPATH@/@DLL_PREFIX@smime3@DLL_SUFFIX@
 @BINPATH@/@DLL_PREFIX@ssl3@DLL_SUFFIX@
--- a/python/moz.build
+++ b/python/moz.build
@@ -23,16 +23,17 @@ PYTHON_UNIT_TESTS += [
     'mach/mach/test/test_conditions.py',
     'mach/mach/test/test_config.py',
     'mach/mach/test/test_entry_point.py',
     'mach/mach/test/test_error_output.py',
     'mach/mach/test/test_logger.py',
     'mozbuild/dumbmake/test/test_dumbmake.py',
     'mozbuild/mozbuild/test/action/test_buildlist.py',
     'mozbuild/mozbuild/test/action/test_generate_browsersearch.py',
+    'mozbuild/mozbuild/test/action/test_package_fennec_apk.py',
     'mozbuild/mozbuild/test/backend/test_android_eclipse.py',
     'mozbuild/mozbuild/test/backend/test_build.py',
     'mozbuild/mozbuild/test/backend/test_configenvironment.py',
     'mozbuild/mozbuild/test/backend/test_recursivemake.py',
     'mozbuild/mozbuild/test/backend/test_visualstudio.py',
     'mozbuild/mozbuild/test/compilation/test_warnings.py',
     'mozbuild/mozbuild/test/configure/test_configure.py',
     'mozbuild/mozbuild/test/configure/test_options.py',
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/action/package_fennec_apk.py
@@ -0,0 +1,105 @@
+# 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/.
+
+'''
+Script to produce an Android package (.apk) for Fennec.
+'''
+
+from __future__ import absolute_import, print_function
+
+import argparse
+import os
+import sys
+
+from mozpack.copier import Jarrer
+from mozpack.files import (
+    DeflatedFile,
+    File,
+    FileFinder,
+)
+from mozpack.mozjar import JarReader
+
+
+def package_fennec_apk(inputs=[], omni_ja=None, classes_dex=None,
+                       lib_dirs=[], assets_dirs=[], root_files=[],
+                       verbose=False):
+    jarrer = Jarrer(optimize=False)
+
+    # First, take input files.  The contents of the later files overwrites the
+    # content of earlier files.
+    for input in inputs:
+        jar = JarReader(input)
+        for path in jar.entries.iterkeys():
+            if jarrer.contains(path):
+                jarrer.remove(path)
+            jarrer.add(path, DeflatedFile(jar[path]))
+
+    def add(path, file):
+        abspath = os.path.abspath(file.path)
+        if verbose:
+            print('Packaging %s from %s' % (path, file.path))
+        if not os.path.exists(abspath):
+            raise ValueError('File %s not found (looked for %s)' % \
+                             (file.path, abspath))
+        if jarrer.contains(path):
+            jarrer.remove(path)
+        jarrer.add(path, file)
+
+    for assets_dir in assets_dirs:
+        finder = FileFinder(assets_dir)
+        for p, f in finder.find('**'):
+            add(os.path.join('assets', p), f)
+
+    for lib_dir in lib_dirs:
+        finder = FileFinder(lib_dir)
+        for p, f in finder.find('**'):
+            add(os.path.join('lib', p), f)
+
+    for root_file in root_files:
+        add(os.path.basename(root_file), File(root_file))
+
+    # TODO: verify OMNIJAR_NAME is assets/omni.ja.
+    if omni_ja:
+        add(os.path.join('assets', 'omni.ja'), File(omni_ja))
+
+    if classes_dex:
+        add('classes.dex', File(classes_dex))
+
+    return jarrer
+
+
+def main(args):
+    parser = argparse.ArgumentParser()
+    parser.add_argument('--verbose', '-v', default=False, action='store_true',
+                        help='be verbose')
+    parser.add_argument('--inputs', nargs='+',
+                        help='Input skeleton AP_ or APK file(s).')
+    parser.add_argument('-o', '--output',
+                        help='Output APK file.')
+    parser.add_argument('--omnijar', default=None,
+                        help='Optional omni.ja to pack into APK file.')
+    parser.add_argument('--classes-dex', default=None,
+                        help='Optional classes.dex to pack into APK file.')
+    parser.add_argument('--lib-dirs', nargs='*',
+                        help='Optional lib/ dirs to pack into APK file.')
+    parser.add_argument('--assets-dirs', nargs='*',
+                        help='Optional assets/ dirs to pack into APK file.')
+    parser.add_argument('--root-files', nargs='*',
+                        help='Optional files to pack into APK file root.')
+    args = parser.parse_args(args)
+
+    jarrer = package_fennec_apk(inputs=args.inputs,
+                                omni_ja=args.omnijar,
+                                classes_dex=args.classes_dex,
+                                lib_dirs=args.lib_dirs,
+                                assets_dirs=args.assets_dirs,
+                                root_files=args.root_files,
+                                verbose=args.verbose)
+    jarrer.copy(args.output)
+
+    return 0
+
+
+if __name__ == '__main__':
+    sys.exit(main(sys.argv[1:]))
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/action/data/package_fennec_apk/assets/asset.txt
@@ -0,0 +1,1 @@
+assets/asset.txt
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/action/data/package_fennec_apk/classes.dex
@@ -0,0 +1,1 @@
+classes.dex
\ No newline at end of file
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..915be683b1ff5d0bb155ce7796b4fc28fc57ca2c
GIT binary patch
literal 503
zc$^FHW@h1H0D;RhD?J#H01JZ*Ls4q6erO0M19RVpuVLrDe+?_G;AUWC`N{~C76GaW
z0O|(O9AMogYBFp>K%OuVb3=6lv0h0<3EYtHA219#eMVbD*YJwImo8i4-br0TdSGKA
zjyeuBR(sz4NKqggg!v%G=9d;F0}W0rDozHQT!!7`%)Elq5<`7d4FTSaOmfV){44=w
z2{62M1ksQXV1+my!}lPQaQPo%5>PF}l14kIN$}9XXCN-0BO5psVjxO5utLHC!%S8-
PkUnN0d=I2QflUDb25xUW
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/action/data/package_fennec_apk/input1/res/res.txt
@@ -0,0 +1,1 @@
+input1/res/res.txt
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/action/data/package_fennec_apk/input1/resources.arsc
@@ -0,0 +1,1 @@
+input1/resources.arsc
\ No newline at end of file
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3003f5ae960fbc8ca6ba692a966c737f1e7443c6
GIT binary patch
literal 1649
zc$^FHW@h1H0D%WHD?J#H06T*WLt=4pYDuwvXb2|*^O6r=!!$2`3oEVQW?*Fb%E-XL
zA_7zv05kwZb1>Wi8gSXI)=(74lK^4?gaKemucV>`Y|;XtNwya-Ogeo=TSM3IlE03g
zpRQ(GK$WVfY7E$Tg!?YObmRgV55jy1<MVU#GWD_&;m&lxG(0n}ptQtDA5{aw@TWk-
zUpr^H3jx_6%ndX=IR~V=ST7~D0&MbHpvkwtf5l-kl4^vpVv$uSVaftDHYYO)5}?{Z
zSK<v&kZ%6FmewE#2}2zP(hbD$uml;RjWaCIpY&l$+&igDNDnC>U!z4d$WcY9&{*C@
zD3(FG*E82vAv+4B8;IeK0vY0h(^2|fx@;JZ`Uo_3wFduukU9})>;jF<FD*(28k|^E
zoD4SkD9~hg9I>m9svcqXXQ0_zew8hUr5s+6+4=b;@oAYksc=W10vhdsGvT19=L+y<
zWRhdXm2V`VECGhMjvyMIi&!Da6C-RvhT+OX5W|3K8J09UA`C;yQLK<0h1FDCSqItF
z1qf5&83~_Dapf3fGyeifl>EaA$v=1u#LO$m;TQtc0?9e7kVKCs5Ha%&vePC(O@ikl
zd<NpmG00AP3Dg3~Kdg|XkH=}4xd+*4>P!r%c?q9^xbh9MfpriAQF0M0Bp2Z^6EnXc
gn|TXlCTi|sh2$O#BU#x%+PHvFm6?ITj2XlO09?Oywg3PC
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/action/data/package_fennec_apk/input2/assets/asset.txt
@@ -0,0 +1,1 @@
+input2/assets/asset.txt
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/action/data/package_fennec_apk/input2/assets/omni.ja
@@ -0,0 +1,1 @@
+input2/assets/omni.ja
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/action/data/package_fennec_apk/input2/classes.dex
@@ -0,0 +1,1 @@
+input2/classes.dex
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/action/data/package_fennec_apk/input2/lib/lib.txt
@@ -0,0 +1,1 @@
+input2/lib/lib.txt
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/action/data/package_fennec_apk/input2/res/res.txt
@@ -0,0 +1,1 @@
+input2/res/res.txt
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/action/data/package_fennec_apk/input2/resources.arsc
@@ -0,0 +1,1 @@
+input/resources.arsc
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/action/data/package_fennec_apk/input2/root_file.txt
@@ -0,0 +1,1 @@
+input2/root_file.txt
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/action/data/package_fennec_apk/lib/lib.txt
@@ -0,0 +1,1 @@
+lib/lib.txt
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/action/data/package_fennec_apk/omni.ja
@@ -0,0 +1,1 @@
+omni.ja
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/action/data/package_fennec_apk/root_file.txt
@@ -0,0 +1,1 @@
+root_file.txt
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/action/test_package_fennec_apk.py
@@ -0,0 +1,68 @@
+# -*- coding: utf-8 -*-
+
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+from __future__ import unicode_literals
+
+import os
+import unittest
+
+import mozunit
+
+from mozbuild.action.package_fennec_apk import (
+    package_fennec_apk as package,
+)
+from mozpack.mozjar import JarReader
+import mozpack.path as mozpath
+
+
+test_data_path = mozpath.abspath(mozpath.dirname(__file__))
+test_data_path = mozpath.join(test_data_path, 'data', 'package_fennec_apk')
+
+
+def data(name):
+    return os.path.join(test_data_path, name)
+
+
+class TestPackageFennecAPK(unittest.TestCase):
+    """
+    Unit tests for package_fennec_apk.py.
+    """
+
+    def test_arguments(self):
+        # Language repacks take updated resources from an ap_ and pack them
+        # into an apk.  Make sure the second input overrides the first.
+        jarrer = package(inputs=[],
+                         omni_ja=data('omni.ja'),
+                         classes_dex=data('classes.dex'),
+                         assets_dirs=[data('assets')],
+                         lib_dirs=[data('lib')],
+                         root_files=[data('root_file.txt')])
+
+        # omni.ja ends up in assets/omni.ja.
+        self.assertEquals(jarrer['assets/omni.ja'].read().strip(), 'omni.ja')
+
+        # Everything else is in place.
+        for name in ('classes.dex',
+                     'assets/asset.txt',
+                     'lib/lib.txt',
+                     'root_file.txt'):
+            self.assertEquals(jarrer[name].read().strip(), name)
+
+    def test_inputs(self):
+        # Language repacks take updated resources from an ap_ and pack them
+        # into an apk.  Make sure the second input overrides the first.
+        jarrer = package(inputs=[data('input2.apk'), data('input1.ap_')])
+
+        files1 = JarReader(data('input1.ap_')).entries.keys()
+        files2 = JarReader(data('input2.apk')).entries.keys()
+        for name in files2:
+            self.assertTrue(name in files1 or
+                            jarrer[name].read().startswith('input2/'))
+        for name in files1:
+            self.assertTrue(jarrer[name].read().startswith('input1/'))
+
+
+if __name__ == '__main__':
+    mozunit.main()
--- a/toolkit/mozapps/installer/upload-files-APK.mk
+++ b/toolkit/mozapps/installer/upload-files-APK.mk
@@ -3,69 +3,27 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 # This file should ONLY be included from upload-files.mk. It was
 # split into its own file to increase comprehension of
 # upload-files.mk.
 
 include $(MOZILLA_DIR)/config/android-common.mk
 
-DIST_FILES =
-
-# Place the files in the order they are going to be opened by the linker
-ifndef MOZ_FOLD_LIBS
-DIST_FILES += \
-  libnspr4.so \
-  libplc4.so \
-  libplds4.so \
-  libmozsqlite3.so \
-  libnssutil3.so \
-  $(NULL)
-endif
-DIST_FILES += libnss3.so
-ifndef MOZ_FOLD_LIBS
-DIST_FILES += \
-  libssl3.so \
-  libsmime3.so \
-  $(NULL)
-endif
-DIST_FILES += \
-  liblgpllibs.so \
-  libxul.so \
-  libnssckbi.so \
-  libfreebl3.so \
-  libsoftokn3.so \
-  resources.arsc \
-  AndroidManifest.xml \
-  chrome \
-  components \
-  defaults \
-  modules \
-  hyphenation \
-  res \
-  lib \
-  extensions \
+# Files packed into the APK root.  Packing files into the APK root is not
+# supported by modern Android build systems, including Gradle, so don't add to
+# this list without Android peer approval.
+ROOT_FILES := \
   application.ini \
   package-name.txt \
   ua-update.json \
   platform.ini \
-  greprefs.js \
-  browserconfig.properties \
-  blocklist.xml \
-  chrome.manifest \
-  update.locale \
   removed-files \
   $(NULL)
 
-NON_DIST_FILES = \
-  classes.dex \
-  $(NULL)
-
-DIST_FILES += $(MOZ_CHILD_PROCESS_NAME)
-
 GECKO_APP_AP_PATH = $(topobjdir)/mobile/android/base
 
 ifdef ENABLE_TESTS
 INNER_ROBOCOP_PACKAGE=true
 ifeq ($(MOZ_BUILD_APP),mobile/android)
 UPLOAD_EXTRA_FILES += robocop.apk
 UPLOAD_EXTRA_FILES += geckoview_library/geckoview_library.zip
 UPLOAD_EXTRA_FILES += geckoview_library/geckoview_assets.zip
@@ -156,32 +114,19 @@ INNER_MAKE_GECKOLIBS_AAR= \
     '$(ABS_DIST)'
 else
 INNER_MAKE_GECKOLIBS_AAR=echo 'Android geckolibs.aar packaging requires packaging geckoview'
 endif # MOZ_DISABLE_GECKOVIEW
 else
 INNER_MAKE_GECKOLIBS_AAR=echo 'Android geckolibs.aar packaging is disabled'
 endif # MOZ_ANDROID_GECKOLIBS_AAR
 
-ifdef MOZ_OMX_PLUGIN
-DIST_FILES += libomxplugin.so libomxplugingb.so libomxplugingb235.so \
-              libomxpluginhc.so libomxpluginkk.so
-endif
-
-SO_LIBRARIES := $(filter %.so,$(DIST_FILES))
-# These libraries are placed in the assets/$(ANDROID_CPU_ARCH) directory by packager.py.
-ASSET_SO_LIBRARIES := $(addprefix assets/$(ANDROID_CPU_ARCH)/,$(filter-out libmozglue.so $(MOZ_CHILD_PROCESS_NAME),$(SO_LIBRARIES)))
-
-DIST_FILES := $(filter-out $(SO_LIBRARIES),$(DIST_FILES))
-NON_DIST_FILES += libmozglue.so $(MOZ_CHILD_PROCESS_NAME) $(ASSET_SO_LIBRARIES)
-
 ifdef MOZ_ENABLE_SZIP
-# These libraries are szipped in-place in the
-# assets/$(ANDROID_CPU_ARCH) directory.
-SZIP_LIBRARIES := $(ASSET_SO_LIBRARIES)
+# These libraries are szipped in-place in assets/$(ANDROID_CPU_ARCH).
+SZIP_LIBRARIES := $(wildcard $(STAGEPATH)$(MOZ_PKG_DIR)/assets/$(ANDROID_CPU_ARCH)/*.so)
 endif
 
 ifndef COMPILE_ENVIRONMENT
 # Any Fennec binary libraries we download are already szipped.
 ALREADY_SZIPPED=1
 endif
 
 # Fennec's OMNIJAR_NAME can include a directory; for example, it might
@@ -197,83 +142,65 @@ endif
 OMNIJAR_DIR := $(dir $(OMNIJAR_NAME))
 OMNIJAR_NAME := $(notdir $(OMNIJAR_NAME))
 
 # We force build an ap_ that does not check dependencies below.
 # Language repacks take advantage of this unchecked dependency ap_ to
 # insert additional resources (translated strings) into the ap_
 # without the build system's participation.  This can do the wrong
 # thing if there are resource changes in between build time and
-# package time.  We try to prevent mismatched resources by erroring
-# out if the compiled resource IDs are not the same as the resource
-# IDs being packaged.  If we're doing a single locale repack, however,
-# we don't have a complete object directory, so we can't compare
-# resource IDs.
-
-# A note on the res/ directory.  We unzip the ap_ during packaging,
-# which produces the res/ directory.  This directory is then included
-# in the final package.  When we unpack (during locale repacks), we
-# need to remove the res/ directory because these resources confuse
-# the l10n packaging script that updates omni.ja: the script tries to
-# localize the contents of the res/ directory, which fails.  Instead,
-# after the l10n packaging script completes, we build the ap_
-# described above (which includes freshly localized Android resources)
-# and the res/ directory is taken from the ap_ as part of the regular
-# packaging.
-
+# package time.
 PKG_SUFFIX = .apk
 
 INNER_SZIP_LIBRARIES = \
-  $(if $(ALREADY_SZIPPED),,$(foreach lib,$(SZIP_LIBRARIES),host/bin/szip $(MOZ_SZIP_FLAGS) $(STAGEPATH)$(MOZ_PKG_DIR)$(_BINPATH)/$(lib) && )) true
-
-ifdef MOZ_BUILD_MOBILE_ANDROID_WITH_GRADLE
-INNER_CHECK_R_TXT=echo 'No R.txt checking for you!'
-else
-INNER_CHECK_R_TXT=\
-  ((test ! -f $(GECKO_APP_AP_PATH)/R.txt && echo "*** Warning: The R.txt that is being packaged might not agree with the R.txt that was built. This is normal during l10n repacks.") || \
-    diff $(GECKO_APP_AP_PATH)/R.txt $(GECKO_APP_AP_PATH)/gecko-nodeps/R.txt >/dev/null || \
-    (echo "*** Error: The R.txt that was built and the R.txt that is being packaged are not the same. Rebuild mobile/android/base and re-package." && exit 1))
-endif
+  $(if $(ALREADY_SZIPPED),,$(foreach lib,$(SZIP_LIBRARIES),host/bin/szip $(MOZ_SZIP_FLAGS) $(lib) &&)) true
 
-# Insert $(STAGEPATH)$(MOZ_PKG_DIR)$(_BINPATH)/classes.dex into
-# $(ABS_DIST)/gecko.ap_, producing $(ABS_DIST)/gecko.apk.
-INNER_MAKE_APK = \
-  ( cd $(STAGEPATH)$(MOZ_PKG_DIR)$(_BINPATH) && \
-    unzip -o $(ABS_DIST)/gecko.ap_ && \
-    rm $(ABS_DIST)/gecko.ap_ && \
-    $(ZIP) -r9D $(ABS_DIST)/gecko.ap_ assets && \
-    $(ZIP) $(if $(ALREADY_SZIPPED),-0 ,$(if $(MOZ_ENABLE_SZIP),-0 ))$(ABS_DIST)/gecko.ap_ $(ASSET_SO_LIBRARIES) && \
-    $(ZIP) -r9D $(ABS_DIST)/gecko.ap_ $(DIST_FILES) -x $(NON_DIST_FILES) $(SZIP_LIBRARIES) && \
-    $(if $(filter-out ./,$(OMNIJAR_DIR)), \
-      mkdir -p $(OMNIJAR_DIR) && mv $(OMNIJAR_NAME) $(OMNIJAR_DIR) && ) \
-    $(ZIP) -0 $(ABS_DIST)/gecko.ap_ $(OMNIJAR_DIR)$(OMNIJAR_NAME)) && \
-  rm -f $(ABS_DIST)/gecko.apk && \
-  cp $(ABS_DIST)/gecko.ap_ $(ABS_DIST)/gecko.apk && \
-  $(ZIP) -j0 $(ABS_DIST)/gecko.apk $(STAGEPATH)$(MOZ_PKG_DIR)$(_BINPATH)/classes.dex && \
-  $(RELEASE_JARSIGNER) $(ABS_DIST)/gecko.apk && \
-  $(ZIPALIGN) -f -v 4 $(ABS_DIST)/gecko.apk $(PACKAGE)
+INNER_FENNEC_PACKAGE = \
+  $(INNER_SZIP_LIBRARIES) && \
+  $(MAKE) -C $(GECKO_APP_AP_PATH) gecko-nodeps.ap_ && \
+  $(PYTHON) -m mozbuild.action.package_fennec_apk \
+    --verbose \
+    --inputs \
+      $(GECKO_APP_AP_PATH)/gecko-nodeps.ap_ \
+    --omnijar $(STAGEPATH)$(MOZ_PKG_DIR)/$(OMNIJAR_NAME) \
+    --classes-dex $(GECKO_APP_AP_PATH)/classes.dex \
+    --lib-dirs $(STAGEPATH)$(MOZ_PKG_DIR)/lib \
+    --assets-dirs $(STAGEPATH)$(MOZ_PKG_DIR)/assets \
+    --root-files $(foreach f,$(ROOT_FILES),$(STAGEPATH)$(MOZ_PKG_DIR)/$(f)) \
+    --output $(PACKAGE:.apk=-unsigned-unaligned.apk) && \
+  $(call RELEASE_SIGN_ANDROID_APK,$(PACKAGE:.apk=-unsigned-unaligned.apk),$(PACKAGE))
 
-ifeq ($(MOZ_BUILD_APP),mobile/android)
+ifndef UNPACKAGE
+# Packaging produces many optional artifacts.
 INNER_MAKE_PACKAGE = \
-  $(INNER_SZIP_LIBRARIES) && \
-  make -C $(GECKO_APP_AP_PATH) gecko-nodeps.ap_ && \
-  cp $(GECKO_APP_AP_PATH)/gecko-nodeps.ap_ $(ABS_DIST)/gecko.ap_ && \
-  $(INNER_CHECK_R_TXT) && \
-  $(INNER_MAKE_APK) && \
+  $(INNER_FENNEC_PACKAGE) && \
   $(INNER_ROBOCOP_PACKAGE) && \
   $(INNER_INSTALL_BOUNCER_PACKAGE) && \
   $(INNER_MAKE_GECKOLIBS_AAR) && \
   $(INNER_MAKE_GECKOVIEW_LIBRARY)
+else
+# Re-packaging only replaces Android resources and the omnijar before
+# (re-)signing.
+INNER_MAKE_PACKAGE = \
+  $(MAKE) -C $(GECKO_APP_AP_PATH) gecko-nodeps.ap_ && \
+  $(PYTHON) -m mozbuild.action.package_fennec_apk \
+    --verbose \
+    --inputs \
+      $(UNPACKAGE) \
+      $(GECKO_APP_AP_PATH)/gecko-nodeps.ap_ \
+    --omnijar $(OMNIJAR_NAME) \
+    --output $(PACKAGE:.apk=-unsigned-unaligned.apk) && \
+  $(call RELEASE_SIGN_ANDROID_APK,$(PACKAGE:.apk=-unsigned-unaligned.apk),$(PACKAGE))
 endif
 
 # Language repacks root the resources contained in assets/omni.ja
 # under assets/, but the repacks expect them to be rooted at /.
 # Therefore, we we move the omnijar back to / so the resources are
 # under the root here, in INNER_UNMAKE_PACKAGE. See comments about
 # OMNIJAR_NAME earlier in this file and in configure.in.
 
-INNER_UNMAKE_PACKAGE	= \
+INNER_UNMAKE_PACKAGE = \
   mkdir $(MOZ_PKG_DIR) && \
   ( cd $(MOZ_PKG_DIR) && \
-    $(UNZIP) $(UNPACKAGE) && \
-    rm -rf res \
+    $(UNZIP) $(UNPACKAGE) $(OMNIJAR_DIR)$(OMNIJAR_NAME) && \
     $(if $(filter-out ./,$(OMNIJAR_DIR)), \
-      && mv $(OMNIJAR_DIR)$(OMNIJAR_NAME) $(OMNIJAR_NAME)) )
+      mv $(OMNIJAR_DIR)$(OMNIJAR_NAME) $(OMNIJAR_NAME), \
+      true) )