Backed out 6 changesets (bug 1417232) for failing in /python/mozbuild/mozbuild/test/configure/lint.py::Lint::test_mobile_android r=backout on a CLOSED TREE
authorshindli <shindli@mozilla.com>
Fri, 08 Dec 2017 01:25:05 +0200
changeset 709585 7642e86127fc68af0d3aff6e23093a3abf431136
parent 709584 3f6d2b219c78ad11f7e5343c5456c4770bd76b71
child 709586 a84da742f85b69c1f58eeeb1bdb4d35faf200256
push id92697
push userbmo:rchien@mozilla.com
push dateFri, 08 Dec 2017 10:29:33 +0000
reviewersbackout
bugs1417232
milestone59.0a1
backs out06e72cdd94a5897eb4fb396fad8df8ade3b69f7d
036308b8fe6b513fc2dd5718550b510d2a1bda21
bb63e12fea6f36a3dff971dcfaf0ad856df0fedc
d0a9d2d4c5b70e02a026d30ceae93451f1cfd28e
b613dde03d995e8286694a71189c4d769383431d
8699e19b02e534610cc8b3d8eb78741669fa2d95
Backed out 6 changesets (bug 1417232) for failing in /python/mozbuild/mozbuild/test/configure/lint.py::Lint::test_mobile_android r=backout on a CLOSED TREE Backed out changeset 06e72cdd94a5 (bug 1417232) Backed out changeset 036308b8fe6b (bug 1417232) Backed out changeset bb63e12fea6f (bug 1417232) Backed out changeset d0a9d2d4c5b7 (bug 1417232) Backed out changeset b613dde03d99 (bug 1417232) Backed out changeset 8699e19b02e5 (bug 1417232)
build/sparse-profiles/taskgraph
mobile/android/app/build.gradle
mobile/android/base/Makefile.in
mobile/android/gradle.configure
mobile/android/mach_commands.py
taskcluster/ci/build/android-stuff.yml
taskcluster/ci/toolchain/linux.yml
testing/mochitest/Makefile.in
testing/mochitest/mochitest_options.py
testing/mozharness/configs/builds/releng_base_android_64_builds.py
toolkit/mozapps/installer/upload-files-APK.mk
--- a/build/sparse-profiles/taskgraph
+++ b/build/sparse-profiles/taskgraph
@@ -25,19 +25,16 @@ path:tools/lint/
 
 # for new-style try pushes
 path:try_task_config.json
 
 # Moz.build files are read in filesystem mode
 glob:**/moz.build
 glob:**/*.mozbuild
 
-# Moz.configure files could trigger changes
-glob:**/*.configure
-
 # Tooltool manifests also need to be opened. Assume they
 # are all somewhere in "tooltool-manifests" directories.
 glob:**/tooltool-manifests/**
 
 # For scheduling android-gradle-dependencies.
 path:mobile/android/config/
 glob:**/*.gradle
 
--- a/mobile/android/app/build.gradle
+++ b/mobile/android/app/build.gradle
@@ -371,16 +371,70 @@ android.applicationVariants.all { varian
         configureVariantWithGeckoBinaries(variant)
     }
 }
 
 android.applicationVariants.all { variant ->
     configureVariantWithJNIWrappers(variant, "Fennec")
 }
 
+// Bug 1299015: Complain to treeherder if checkstyle, lint, or unittest fails.  It's not obvious
+// how to listen to individual errors in most cases, so we just link to the reports for now.
+def makeTaskExecutionListener(artifactRootUrl) {
+    return new TaskExecutionListener() {
+        void beforeExecute(Task task) {
+            // Do nothing.
+        }
+
+        void afterExecute(Task task, TaskState state) {
+            if (!state.failure) {
+                return
+            }
+
+            // Link to the failing report.  The task path and the report path
+            // depend on the android-lint task in
+            // taskcluster/ci/android-stuff/kind.yml.  It's not possible to link
+            // directly, so for now consumers will need to copy-paste the URL.
+            switch (task.path) {
+            case ':app:checkstyle':
+                def url = "${artifactRootUrl}/public/android/checkstyle/checkstyle.xml"
+                println "TEST-UNEXPECTED-FAIL | android-checkstyle | Checkstyle rule violations were found. See the report at: $url"
+                break
+
+            case ':app:lintOfficialPhotonDebug':
+                def url = "${artifactRootUrl}/public/android/lint/lint-results-officialPhotonDebug.html"
+                println "TEST-UNEXPECTED-FAIL | android-lint | Lint found errors in the project; aborting build. See the report at: $url"
+                break
+
+            case ':app:testOfficialPhotonDebugUnitTest':
+                def url = "${artifactRootUrl}/public/android/unittest/officialPhotonDebug/index.html"
+                println "TEST-UNEXPECTED-FAIL | android-test | There were failing tests. See the reports at: $url"
+                break
+
+            case ':app:findbugsHtmlOfficialPhotonDebug':
+                def url = "${artifactRootUrl}/public/android/findbugs/findbugs-officialPhotonDebug-output.html"
+                println "TEST-UNEXPECTED-FAIL | android-findbugs | Findbugs found issues in the project. See the report at: $url"
+                break
+
+            case ':app:findbugsXmlOfficialPhotonDebug':
+                def url = "${artifactRootUrl}/public/android/findbugs/findbugs-officialPhotonDebug-output.xml"
+                println "TEST-UNEXPECTED-FAIL | android-findbugs | Findbugs found issues in the project. See the report at: $url"
+                break
+            }
+        }
+    }
+}
+
+// TASK_ID and RUN_ID are provided by docker-worker; see
+// https://docs.taskcluster.net/manual/execution/workers/docker-worker.
+if (System.env.TASK_ID && System.env.RUN_ID) {
+    def artifactRootUrl = "https://queue.taskcluster.net/v1/task/${System.env.TASK_ID}/runs/${System.env.RUN_ID}/artifacts"
+    gradle.addListener(makeTaskExecutionListener(artifactRootUrl))
+}
+
 if (gradle.startParameter.taskNames.any { it.endsWith('UnitTest') }) {
     // Approach cribbed from https://github.com/rwinch/jce-checker.
     int maxKeyLen = javax.crypto.Cipher.getMaxAllowedKeyLength("AES")
     if (maxKeyLen <= 128) {
         throw new GradleException(
             "Android unit tests require " +
             "Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy, see " +
             "http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html")
--- a/mobile/android/base/Makefile.in
+++ b/mobile/android/base/Makefile.in
@@ -231,17 +231,22 @@ library_jars += $(ANDROID_SDK)/optional/
 endif # MOZ_INSTALL_TRACKING
 
 library_jars := $(subst $(NULL) ,:,$(strip $(library_jars)))
 
 ifdef MOZ_BUILD_MOBILE_ANDROID_WITH_GRADLE
 define gradle_command
 $(1): $(2)
 	@$$(TOUCH) $$@
-	$$(topsrcdir)/mach android assemble-app
+	$$(topsrcdir)/mach gradle \
+		geckoview:generateJNIWrappersForGeneratedRelease \
+		app:generateJNIWrappersForFennecOfficialPhotonDebug \
+		app:assembleOfficialPhotonDebug \
+		app:assembleOfficialPhotonDebugAndroidTest \
+		-x lint
 endef
 
 # .gradle.deps: .aapt.deps FORCE
 $(eval $(call gradle_command,.gradle.deps,.aapt.deps FORCE))
 
 classes.dex: .gradle.deps
 	$(REPORT_BUILD)
 	cp $(gradle_dir)/app/intermediates/transforms/dex/officialPhoton/debug/folders/1000/1f/main/classes.dex $@
@@ -498,17 +503,17 @@ ifdef MOZ_BUILD_MOBILE_ANDROID_WITH_GRAD
 # depend on the generated resources that incorporate l10n, principally
 # strings.xml.
 
 # .gradle.nodeps: AndroidManifest.xml generated/preprocessed/org/mozilla/gecko/AppConstants.java ... FORCE
 $(eval $(call gradle_command,.gradle.nodeps,AndroidManifest.xml $(constants_PP_JAVAFILES) FORCE))
 
 .aapt.nodeps: .gradle.nodeps FORCE
 	@$(TOUCH) $@
-	cp $(GRADLE_ANDROID_APP_APK) gecko-nodeps.ap_
+	cp $(gradle_dir)/app/outputs/apk/app-official-photon-debug.apk gecko-nodeps.ap_
 	cp $(gradle_dir)/app/intermediates/transforms/dex/officialPhoton/debug/folders/1000/1f/main/classes.dex classes.dex
 else
 # .aapt.nodeps: AndroidManifest.xml FORCE
 $(eval $(call aapt_command,.aapt.nodeps,AndroidManifest.xml FORCE,gecko-nodeps.ap_,gecko-nodeps/,gecko-nodeps/))
 endif
 
 # Override the Java settings with some specific android settings
 include $(topsrcdir)/config/android-common.mk
--- a/mobile/android/gradle.configure
+++ b/mobile/android/gradle.configure
@@ -31,166 +31,16 @@ def gradle(value, build_env):
     if not isfile(gradle):
         die('GRADLE must be executable: %s', gradle)
 
     return gradle
 
 set_config('GRADLE', gradle)
 
 
-@dependable
-@imports(_from='itertools', _import='chain')
-def gradle_android_build_config():
-    def capitalize(s):
-        # str.capitalize lower cases trailing letters.
-        if s:
-            return s[0].upper() + s[1:]
-        else:
-            return s
-
-    # It's not really possible to abstract the GeckoView details just yet; post
-    # Android-Gradle plugin 3.0+, the configurations can be more sensible and
-    # we'll do this work.
-    def variant(productFlavors, buildType):
-        return namespace(
-            productFlavors=productFlavors,
-            buildType=buildType,
-            # Like 'OfficialWithoutGeckoBinariesPhotonDebug'
-            name = ''.join(capitalize(t) for t in chain(productFlavors, (buildType, )))
-        )
-
-    return namespace(
-        app=namespace(
-            variant=variant(('official', 'photon'), 'debug'),
-        ),
-    )
-
-
-@depends(gradle_android_build_config)
-def gradle_android_app_variant_name(build_config):
-    '''Like "officialPhotonDebug".'''
-    def uncapitalize(s):
-        if s:
-            return s[0].lower() + s[1:]
-        else:
-            return s
-
-    return uncapitalize(build_config.app.variant.name)
-
-set_config('GRADLE_ANDROID_APP_VARIANT_NAME', gradle_android_app_variant_name)
-
-
-@depends(gradle_android_build_config)
-def gradle_android_app_tasks(build_config):
-    '''Gradle tasks run by |mach android assemble-app|.'''
-    return [
-        'geckoview:generateJNIWrappersForGeneratedRelease',
-        'app:generateJNIWrappersForFennec{app.variant.name}'.format(app=build_config.app),
-        'app:assemble{app.variant.name}'.format(app=build_config.app),
-        'app:assemble{app.variant.name}AndroidTest'.format(app=build_config.app),
-    ]
-
-set_config('GRADLE_ANDROID_APP_TASKS', gradle_android_app_tasks)
-
-
-@depends(gradle_android_build_config, check_build_environment)
-def gradle_android_app_apks(build_config, build_env):
-    '''Paths to APK files produced by |mach android assemble-app|.'''
-    flavor = '-'.join(build_config.app.variant.productFlavors)
-    buildType = build_config.app.variant.buildType
-    f = '{}/gradle/build/mobile/android/app/outputs/apk/app-{}-{}.apk'
-    g = '{}/gradle/build/mobile/android/app/outputs/apk/app-{}-{}-androidTest.apk'
-    return namespace(app_apk=f.format(build_env.topobjdir, flavor, buildType),
-                     app_androidTest_apk=g.format(build_env.topobjdir, flavor, buildType))
-
-set_config('GRADLE_ANDROID_APP_APK', gradle_android_app_apks.app_apk)
-set_config('GRADLE_ANDROID_APP_ANDROIDTEST_APK', gradle_android_app_apks.app_androidTest_apk)
-
-
-@depends(gradle_android_build_config)
-def gradle_android_test_tasks(build_config):
-    '''Gradle tasks run by |mach android test|.'''
-    return [
-        'app:test{app.variant.name}UnitTest'.format(app=build_config.app),
-    ]
-
-set_config('GRADLE_ANDROID_TEST_TASKS', gradle_android_test_tasks)
-
-
-@depends(gradle_android_build_config)
-def gradle_android_lint_tasks(build_config):
-    '''Gradle tasks run by |mach android lint|.'''
-    return [
-        'app:lint{app.variant.name}'.format(app=build_config.app),
-    ]
-
-set_config('GRADLE_ANDROID_LINT_TASKS', gradle_android_lint_tasks)
-
-
-@depends(gradle_android_build_config)
-def gradle_android_checkstyle_tasks(build_config):
-    '''Gradle tasks run by |mach android checkstyle|.'''
-    return [
-        'app:checkstyle',
-    ]
-
-set_config('GRADLE_ANDROID_CHECKSTYLE_TASKS', gradle_android_checkstyle_tasks)
-
-
-@depends(gradle_android_build_config)
-def gradle_android_findbugs_tasks(build_config):
-    '''Gradle tasks run by |mach android findbugs|.'''
-    return [
-        'app:findbugsXml{app.variant.name}'.format(app=build_config.app),
-        'app:findbugsHtml{app.variant.name}'.format(app=build_config.app),
-    ]
-
-set_config('GRADLE_ANDROID_FINDBUGS_TASKS', gradle_android_findbugs_tasks)
-
-
-@depends(gradle_android_build_config)
-def gradle_android_archive_geckoview_tasks(build_config):
-    '''Gradle tasks run by |mach android archive-geckoview|.'''
-    return [
-        'geckoview:assembleWithGeckoBinaries',
-        'geckoview_example:assembleWithGeckoBinaries',
-        'geckoview_example:assembleWithGeckoBinariesAndroidTest',
-        'geckoview:uploadArchives',
-    ]
-
-set_config('GRADLE_ANDROID_ARCHIVE_GECKOVIEW_TASKS', gradle_android_archive_geckoview_tasks)
-
-
-@depends(
-    gradle_android_build_config,
-    gradle_android_app_tasks,
-    gradle_android_test_tasks,
-    gradle_android_lint_tasks,
-    gradle_android_checkstyle_tasks,
-    gradle_android_findbugs_tasks,
-    gradle_android_archive_geckoview_tasks,
-)
-@imports(_from='itertools', _import='imap')
-@imports(_from='itertools', _import='chain')
-@imports(_from='itertools', _import='ifilterfalse')
-def gradle_android_dependencies_tasks(build_config, *tasks):
-    '''Gradle tasks run by |mach android dependencies|.'''
-    # The union, plus a bit more, of all of the Gradle tasks
-    # invoked by the android-* automation jobs.
-    def withoutGeckoBinaries(task):
-        return task.replace('withGeckoBinaries', 'withoutGeckoBinaries')
-
-    def isUploadArchives(task):
-        return 'uploadArchives' in task
-
-    return list(ifilterfalse(isUploadArchives, imap(withoutGeckoBinaries, chain(*tasks))))
-
-set_config('GRADLE_ANDROID_DEPENDENCIES_TASKS', gradle_android_dependencies_tasks)
-
-
 # Automation uses this to change log levels, not use the daemon, and use
 # offline mode.
 option(env='GRADLE_FLAGS', default='', help='Flags to pass to Gradle.')
 
 @depends('GRADLE_FLAGS')
 def gradle_flags(value):
     return value[0] if value else ''
 
--- a/mobile/android/mach_commands.py
+++ b/mobile/android/mach_commands.py
@@ -35,77 +35,56 @@ def REMOVED(cls):
 
     See https://developer.mozilla.org/en-US/docs/Simple_Firefox_for_Android_build#Developing_Firefox_for_Android_in_Android_Studio_or_IDEA_IntelliJ.
     """
     return False
 
 
 @CommandProvider
 class MachCommands(MachCommandBase):
-    def _root_url(self, artifactdir=None, objdir=None):
-        if 'TASK_ID' in os.environ and 'RUN_ID' in os.environ:
-            return 'https://queue.taskcluster.net/v1/task/{}/runs/{}/artifacts/{}'.format(os.environ['TASK_ID'], os.environ['RUN_ID'], artifactdir)
-        else:
-            return os.path.join(self.topobjdir, objdir)
-
-
     @Command('android', category='devenv',
         description='Run Android-specific commands.',
         conditions=[conditions.is_android])
     def android(self):
         pass
 
 
-    @SubCommand('android', 'assemble-app',
-        """Assemble Firefox for Android.
-        See http://firefox-source-docs.mozilla.org/build/buildsystem/toolchains.html#firefox-for-android-with-gradle""")
-    @CommandArgument('args', nargs=argparse.REMAINDER)
-    def android_assemble_app(self, args):
-        ret = self.gradle(self.substs['GRADLE_ANDROID_APP_TASKS'] + ['-x', 'lint', '--continue'] + args, verbose=True)
-
-        return ret
-
-
     @SubCommand('android', 'test',
         """Run Android local unit tests.
         See https://developer.mozilla.org/en-US/docs/Mozilla/Android-specific_test_suites#android-test""")
     @CommandArgument('args', nargs=argparse.REMAINDER)
     def android_test(self, args):
-        ret = self.gradle(self.substs['GRADLE_ANDROID_TEST_TASKS'] + ["--continue"] + args, verbose=True)
+        gradle_targets = [
+            'app:testOfficialPhotonDebugUnitTest',
+        ]
+        ret = self.gradle(gradle_targets + ["--continue"] + args, verbose=True)
 
         # Findbug produces both HTML and XML reports.  Visit the
         # XML report(s) to report errors and link to the HTML
         # report(s) for human consumption.
         import itertools
         import xml.etree.ElementTree as ET
 
         from mozpack.files import (
             FileFinder,
         )
 
-        root_url = self._root_url(
-            artifactdir='public/android/unittest',
-            objdir='gradle/build/mobile/android/app/reports/tests')
+        if 'TASK_ID' in os.environ and 'RUN_ID' in os.environ:
+            root_url = "https://queue.taskcluster.net/v1/task/{}/runs/{}/artifacts/public/android/unittest".format(os.environ['TASK_ID'], os.environ['RUN_ID'])
+        else:
+            root_url = os.path.join(self.topobjdir, 'gradle/build/mobile/android/app/reports/tests')
 
-        reports = (self.substs['GRADLE_ANDROID_APP_VARIANT_NAME'],)
+        reports = ('officialPhotonDebug',)
         for report in reports:
             finder = FileFinder(os.path.join(self.topobjdir, 'gradle/build/mobile/android/app/test-results/', report))
             for p, _ in finder.find('TEST-*.xml'):
                 f = open(os.path.join(finder.base, p), 'rt')
                 tree = ET.parse(f)
                 root = tree.getroot()
 
-                # Log reports for Tree Herder "Job Details".
-                print('TinderboxPrint: report<br/><a href="{}/{}/index.html">HTML {} report</a>, visit "Inspect Task" link for details'.format(root_url, report, report))
-
-                # And make the report display as soon as possible.
-                failed = root.findall('testcase/error') or root.findall('testcase/failure')
-                if failed:
-                    print('TEST-UNEXPECTED-FAIL | android-test | There were failing tests. See the reports at: {}/{}/index.html'.format(root_url, report))
-
                 print('SUITE-START | android-test | {} {}'.format(report, root.get('name')))
 
                 for testcase in root.findall('testcase'):
                     name = testcase.get('name')
                     print('TEST-START | {}'.format(name))
 
                     # Schema cribbed from
                     # http://llg.cubic.org/docs/junit/.  There's no
@@ -127,191 +106,194 @@ class MachCommands(MachCommandBase):
                         for line in ET.tostring(skipped).strip().splitlines():
                             print('TEST-INFO | {} | {}'.format(name, line))
 
                     if not error_count:
                         print('TEST-PASS | {}'.format(name))
 
                 print('SUITE-END | android-test | {} {}'.format(report, root.get('name')))
 
+            title = report
+            print("TinderboxPrint: report<br/><a href='{}/{}/index.html'>HTML {} report</a>, visit \"Inspect Task\" link for details".format(root_url, report, title))
+
         return ret
 
 
     @SubCommand('android', 'lint',
         """Run Android lint.
         See https://developer.mozilla.org/en-US/docs/Mozilla/Android-specific_test_suites#android-lint""")
     @CommandArgument('args', nargs=argparse.REMAINDER)
     def android_lint(self, args):
-        ret = self.gradle(self.substs['GRADLE_ANDROID_LINT_TASKS'] + ["--continue"] + args, verbose=True)
+        gradle_targets = [
+            'app:lintOfficialPhotonDebug',
+        ]
+        ret = self.gradle(gradle_targets + ["--continue"] + args, verbose=True)
 
         # Android Lint produces both HTML and XML reports.  Visit the
         # XML report(s) to report errors and link to the HTML
         # report(s) for human consumption.
         import xml.etree.ElementTree as ET
 
-        root_url = self._root_url(
-            artifactdir='public/android/lint',
-            objdir='gradle/build/mobile/android/app/reports')
+        if 'TASK_ID' in os.environ and 'RUN_ID' in os.environ:
+            root_url = "https://queue.taskcluster.net/v1/task/{}/runs/{}/artifacts/public/android/lint".format(os.environ['TASK_ID'], os.environ['RUN_ID'])
+        else:
+            root_url = os.path.join(self.topobjdir, 'gradle/build/mobile/android/app/reports')
 
-        reports = (self.substs['GRADLE_ANDROID_APP_VARIANT_NAME'],)
+        reports = ('officialPhotonDebug',)
         for report in reports:
             f = open(os.path.join(self.topobjdir, 'gradle/build/mobile/android/app/reports/lint-results-{}.xml'.format(report)), 'rt')
             tree = ET.parse(f)
             root = tree.getroot()
 
-            # Log reports for Tree Herder "Job Details".
-            html_report_url = '{}/lint-results-{}.html'.format(root_url, report)
-            xml_report_url = '{}/lint-results-{}.xml'.format(root_url, report)
-            print('TinderboxPrint: report<br/><a href="{}">HTML {} report</a>, visit "Inspect Task" link for details'.format(html_report_url, report))
-            print('TinderboxPrint: report<br/><a href="{}">XML {} report</a>, visit "Inspect Task" link for details'.format(xml_report_url, report))
-
-            # And make the report display as soon as possible.
-            if root.findall("issue[@severity='Error']"):
-                print('TEST-UNEXPECTED-FAIL | android-lint | Lint found errors in the project; aborting build. See the report at: {}'.format(html_report_url))
-
             print('SUITE-START | android-lint | {}'.format(report))
             for issue in root.findall("issue[@severity='Error']"):
                 # There's no particular advantage to formatting the
                 # error, so for now let's just output the <issue> XML
                 # tag.
                 for line in ET.tostring(issue).strip().splitlines():
                     print('TEST-UNEXPECTED-FAIL | {}'.format(line))
                 ret |= 1
             print('SUITE-END | android-lint | {}'.format(report))
 
+            title = report
+            print("TinderboxPrint: report<br/><a href='{}/lint-results-{}.html'>HTML {} report</a>, visit \"Inspect Task\" link for details".format(root_url, report, title))
+            print("TinderboxPrint: report<br/><a href='{}/lint-results-{}.xml'>XML {} report</a>, visit \"Inspect Task\" link for details".format(root_url, report, title))
+
         return ret
 
 
     @SubCommand('android', 'checkstyle',
         """Run Android checkstyle.
         See https://developer.mozilla.org/en-US/docs/Mozilla/Android-specific_test_suites#android-checkstyle""")
     @CommandArgument('args', nargs=argparse.REMAINDER)
     def android_checkstyle(self, args):
-        ret = self.gradle(self.substs['GRADLE_ANDROID_CHECKSTYLE_TASKS'] + ["--continue"] + args, verbose=True)
+        gradle_targets = [
+            'app:checkstyle',
+        ]
+        ret = self.gradle(gradle_targets + ["--continue"] + args, verbose=True)
 
         # Checkstyle produces both HTML and XML reports.  Visit the
         # XML report(s) to report errors and link to the HTML
         # report(s) for human consumption.
         import xml.etree.ElementTree as ET
 
         f = open(os.path.join(self.topobjdir, 'gradle/build/mobile/android/app/reports/checkstyle/checkstyle.xml'), 'rt')
         tree = ET.parse(f)
         root = tree.getroot()
 
-        # Now the reports, linkified.
-        root_url = self._root_url(
-            artifactdir='public/android/checkstyle',
-            objdir='gradle/build/mobile/android/app/reports/checkstyle')
-
-        # Log reports for Tree Herder "Job Details".
-        print('TinderboxPrint: report<br/><a href="{}/checkstyle.html">HTML checkstyle report</a>, visit "Inspect Task" link for details'.format(root_url))
-        print('TinderboxPrint: report<br/><a href="{}/checkstyle.xml">XML checkstyle report</a>, visit "Inspect Task" link for details'.format(root_url))
-
-        # And make the report display as soon as possible.
-        if root.findall('file/error'):
-            ret |= 1
-
-        if ret:
-            print('TEST-UNEXPECTED-FAIL | android-checkstyle | Checkstyle rule violations were found. See the report at: {}/checkstyle.html'.format(root_url))
-
         print('SUITE-START | android-checkstyle')
         for file in root.findall('file'):
             name = file.get('name')
 
             print('TEST-START | {}'.format(name))
             error_count = 0
             for error in file.findall('error'):
                 # There's no particular advantage to formatting the
                 # error, so for now let's just output the <error> XML
                 # tag.
                 print('TEST-UNEXPECTED-FAIL | {}'.format(name))
                 for line in ET.tostring(error).strip().splitlines():
                     print('TEST-UNEXPECTED-FAIL | {}'.format(line))
                 error_count += 1
+                ret |= 1
 
             if not error_count:
                 print('TEST-PASS | {}'.format(name))
         print('SUITE-END | android-checkstyle')
 
+        # Now the reports, linkified.
+        if 'TASK_ID' in os.environ and 'RUN_ID' in os.environ:
+            root_url = "https://queue.taskcluster.net/v1/task/{}/runs/{}/artifacts/public/android/checkstyle".format(os.environ['TASK_ID'], os.environ['RUN_ID'])
+        else:
+            root_url = os.path.join(self.topobjdir, 'gradle/build/mobile/android/app/reports/checkstyle')
+
+        print("TinderboxPrint: report<br/><a href='{}/checkstyle.html'>HTML checkstyle report</a>, visit \"Inspect Task\" link for details".format(root_url))
+        print("TinderboxPrint: report<br/><a href='{}/checkstyle.xml'>XML checkstyle report</a>, visit \"Inspect Task\" link for details".format(root_url))
+
         return ret
 
 
     @SubCommand('android', 'findbugs',
         """Run Android findbugs.
         See https://developer.mozilla.org/en-US/docs/Mozilla/Android-specific_test_suites#android-findbugs""")
     @CommandArgument('args', nargs=argparse.REMAINDER)
     def android_findbugs(self, dryrun=False, args=[]):
-        ret = self.gradle(self.substs['GRADLE_ANDROID_FINDBUGS_TASKS'] + ["--continue"] + args, verbose=True)
+        gradle_targets = [
+            'app:findbugsXmlOfficialPhotonDebug',
+            'app:findbugsHtmlOfficialPhotonDebug',
+        ]
+        ret = self.gradle(gradle_targets + ["--continue"] + args, verbose=True)
 
         # Findbug produces both HTML and XML reports.  Visit the
         # XML report(s) to report errors and link to the HTML
         # report(s) for human consumption.
         import xml.etree.ElementTree as ET
 
-        root_url = self._root_url(
-            artifactdir='public/android/findbugs',
-            objdir='gradle/build/mobile/android/app/reports/findbugs')
+        if 'TASK_ID' in os.environ and 'RUN_ID' in os.environ:
+            root_url = "https://queue.taskcluster.net/v1/task/{}/runs/{}/artifacts/public/artifacts/findbugs".format(os.environ['TASK_ID'], os.environ['RUN_ID'])
+        else:
+            root_url = os.path.join(self.topobjdir, 'gradle/build/mobile/android/app/reports/findbugs')
 
-        reports = (self.substs['GRADLE_ANDROID_APP_VARIANT_NAME'],)
+        reports = ('findbugs-officialPhotonDebug-output.xml',)
         for report in reports:
             try:
-                f = open(os.path.join(self.topobjdir, 'gradle/build/mobile/android/app/reports/findbugs', 'findbugs-{}-output.xml'.format(report)), 'rt')
+                f = open(os.path.join(self.topobjdir, 'gradle/build/mobile/android/app/reports/findbugs', report), 'rt')
             except IOError:
                 continue
 
             tree = ET.parse(f)
             root = tree.getroot()
 
-            # Log reports for Tree Herder "Job Details".
-            html_report_url = '{}/findbugs-{}-output.html'.format(root_url, report)
-            xml_report_url = '{}/findbugs-{}-output.xml'.format(root_url, report)
-            print('TinderboxPrint: report<br/><a href="{}">HTML {} report</a>, visit "Inspect Task" link for details'.format(html_report_url, report))
-            print('TinderboxPrint: report<br/><a href="{}">XML {} report</a>, visit "Inspect Task" link for details'.format(xml_report_url, report))
-
-            # And make the report display as soon as possible.
-            if root.findall("./BugInstance"):
-                print('TEST-UNEXPECTED-FAIL | android-findbugs | Findbugs found issues in the project. See the report at: {}'.format(html_report_url))
-
             print('SUITE-START | android-findbugs | {}'.format(report))
             for error in root.findall('./BugInstance'):
                 # There's no particular advantage to formatting the
                 # error, so for now let's just output the <error> XML
                 # tag.
                 print('TEST-UNEXPECTED-FAIL | {}:{} | {}'.format(report, error.get('type'), error.find('Class').get('classname')))
                 for line in ET.tostring(error).strip().splitlines():
                     print('TEST-UNEXPECTED-FAIL | {}:{} | {}'.format(report, error.get('type'), line))
                 ret |= 1
             print('SUITE-END | android-findbugs | {}'.format(report))
 
+            title = report.replace('findbugs-', '').replace('-output.xml', '')
+            print("TinderboxPrint: report<br/><a href='{}/{}'>HTML {} report</a>, visit \"Inspect Task\" link for details".format(root_url, report.replace('.xml', '.html'), title))
+            print("TinderboxPrint: report<br/><a href='{}/{}'>XML {} report</a>, visit \"Inspect Task\" link for details".format(root_url, report, title))
+
         return ret
 
 
     @SubCommand('android', 'gradle-dependencies',
         """Collect Android Gradle dependencies.
         See http://firefox-source-docs.mozilla.org/build/buildsystem/toolchains.html#firefox-for-android-with-gradle""")
     @CommandArgument('args', nargs=argparse.REMAINDER)
     def android_gradle_dependencies(self, args):
+        # The union, plus a bit more, of all of the Gradle tasks
+        # invoked by the android-* automation jobs.
+        gradle_targets = [
+            'app:checkstyle',
+            'app:assembleOfficialPhotonRelease',
+            'app:assembleOfficialPhotonDebug',
+            'app:assembleOfficialPhotonDebugAndroidTest',
+            'app:findbugsXmlOfficialPhotonDebug',
+            'app:findbugsHtmlOfficialPhotonDebug',
+            'app:lintOfficialPhotonDebug',
+            # Does not include Gecko binaries -- see mobile/android/gradle/with_gecko_binaries.gradle.
+            'geckoview:assembleWithoutGeckoBinaries',
+            # So that we pick up the test dependencies for the builders.
+            'geckoview_example:assembleWithoutGeckoBinaries',
+            'geckoview_example:assembleWithoutGeckoBinariesAndroidTest',
+        ]
         # We don't want to gate producing dependency archives on clean
         # lint or checkstyle, particularly because toolchain versions
         # can change the outputs for those processes.
-        self.gradle(self.substs['GRADLE_ANDROID_DEPENDENCIES_TASKS'] + ["--continue"] + args, verbose=True)
+        ret = self.gradle(gradle_targets + ["--continue"] + args, verbose=True)
 
         return 0
 
 
-    @SubCommand('android', 'archive-geckoview',
-        """Create GeckoView archives.
-        See http://firefox-source-docs.mozilla.org/build/buildsystem/toolchains.html#firefox-for-android-with-gradle""")
-    @CommandArgument('args', nargs=argparse.REMAINDER)
-    def android_archive_geckoview(self, args):
-        ret = self.gradle(self.substs['GRADLE_ANDROID_ARCHIVE_GECKOVIEW_TASKS'] + ["--continue"] + args, verbose=True)
-
-        return ret
-
-
     @Command('gradle', category='devenv',
         description='Run gradle.',
         conditions=[conditions.is_android])
     @CommandArgument('-v', '--verbose', action='store_true',
         help='Verbose output for what commands the build is running.')
     @CommandArgument('args', nargs=argparse.REMAINDER)
     def gradle(self, args, verbose=False):
         if not verbose:
--- a/taskcluster/ci/build/android-stuff.yml
+++ b/taskcluster/ci/build/android-stuff.yml
@@ -36,17 +36,16 @@ android-test/opt:
     toolchains:
         - android-gradle-dependencies
         - android-sdk-linux
         - proguard-jar
     optimization:
         skip-unless-changed:
             - "mobile/android/base/**"
             - "mobile/android/config/**"
-            - "mobile/android/gradle.configure"
             - "mobile/android/tests/background/junit4/**"
             - "**/*.gradle"
 
 android-lint/opt:
     description: "Android lint"
     index:
         product: mobile
         job-name: android-lint
@@ -92,20 +91,19 @@ android-lint/opt:
         - proguard-jar
     optimization:
         skip-unless-changed:
             - "mobile/android/**/*.java"
             - "mobile/android/**/*.jpeg"
             - "mobile/android/**/*.jpg"
             - "mobile/android/**/*.png"
             - "mobile/android/**/*.svg"
-            - "mobile/android/**/*.xml"
+            - "mobile/android/**/*.xml"  # Manifest & android resources
             - "mobile/android/**/Makefile.in"
             - "mobile/android/config/**"
-            - "mobile/android/gradle.configure"
             - "mobile/android/**/moz.build"
             - "**/*.gradle"
 
 android-checkstyle/opt:
     description: "Android checkstyle"
     index:
         product: mobile
         job-name: android-checkstyle
@@ -147,17 +145,16 @@ android-checkstyle/opt:
         - android-sdk-linux
         - proguard-jar
     optimization:
         skip-unless-changed:
             - "mobile/android/**/checkstyle.xml"
             - "mobile/android/**/*.java"
             - "mobile/android/**/Makefile.in"
             - "mobile/android/config/**"
-            - "mobile/android/gradle.configure"
             - "mobile/android/**/moz.build"
             - "**/*.gradle"
 
 android-findbugs/opt:
     description: "Android findbugs"
     index:
         product: mobile
         job-name: android-findbugs
@@ -198,11 +195,10 @@ android-findbugs/opt:
         - android-gradle-dependencies
         - android-sdk-linux
         - proguard-jar
     optimization:
         skip-unless-changed:
             - "mobile/android/**/*.java"
             - "mobile/android/**/Makefile.in"
             - "mobile/android/config/**"
-            - "mobile/android/gradle.configure"
             - "mobile/android/**/moz.build"
             - "**/*.gradle"
--- a/taskcluster/ci/toolchain/linux.yml
+++ b/taskcluster/ci/toolchain/linux.yml
@@ -308,17 +308,16 @@ linux64-android-gradle-dependencies:
         script: android-gradle-dependencies.sh
         sparse-profile: null
         resources:
             - 'taskcluster/scripts/misc/tooltool-download.sh'
             - 'taskcluster/scripts/misc/android-gradle-dependencies/**'
             - '**/*.gradle'
             - 'mobile/android/config/mozconfigs/android-api-16-gradle-dependencies/**'
             - 'mobile/android/config/mozconfigs/common*'
-            - 'mobile/android/gradle.configure'
         toolchain-artifact: public/build/android-gradle-dependencies.tar.xz
         toolchain-alias: android-gradle-dependencies
     toolchains:
         # Aliases aren't allowed for toolchains depending on toolchains.
         - linux64-android-sdk-linux-repack
         - linux64-proguard-jar-repack
 
 linux64-rust-1.22:
--- a/testing/mochitest/Makefile.in
+++ b/testing/mochitest/Makefile.in
@@ -20,17 +20,17 @@ libs::
 
 # On Android only, include a release signed Robocop APK in the test package.
 ifeq ($(MOZ_BUILD_APP),mobile/android)
 include $(topsrcdir)/config/android-common.mk
 
 ifndef MOZ_BUILD_MOBILE_ANDROID_WITH_GRADLE
 robocop_apk := $(topobjdir)/mobile/android/tests/browser/robocop/robocop-debug-unsigned-unaligned.apk
 else
-robocop_apk := $(GRADLE_ANDROID_APP_ANDROIDTEST_APK)
+robocop_apk := $(topobjdir)/gradle/build/mobile/android/app/outputs/apk/app-official-photon-debug-androidTest.apk
 endif
 
 stage-package-android:
 	$(NSINSTALL) -D $(_DEST_DIR)
 	$(call RELEASE_SIGN_ANDROID_APK,$(robocop_apk),$(_DEST_DIR)/robocop.apk)
 
 stage-package: stage-package-android
 endif
--- a/testing/mochitest/mochitest_options.py
+++ b/testing/mochitest/mochitest_options.py
@@ -998,17 +998,19 @@ class AndroidArguments(ArgumentContainer
             if not os.path.exists(options.robocopIni):
                 parser.error(
                     "Unable to find specified robocop .ini manifest '%s'" %
                     options.robocopIni)
             options.robocopIni = os.path.abspath(options.robocopIni)
 
             if not options.robocopApk and build_obj:
                 if build_obj.substs.get('MOZ_BUILD_MOBILE_ANDROID_WITH_GRADLE'):
-                    options.robocopApk = build_obj.substs.get('GRADLE_ANDROID_APP_ANDROIDTEST_APK')
+                    options.robocopApk = os.path.join(build_obj.topobjdir, 'gradle', 'build',
+                                                      'mobile', 'android', 'app', 'outputs', 'apk',
+                                                      'app-official-photon-debug-androidTest.apk')
                 else:
                     options.robocopApk = os.path.join(build_obj.topobjdir, 'mobile', 'android',
                                                       'tests', 'browser',
                                                       'robocop', 'robocop-debug.apk')
 
         if options.robocopApk != "":
             if not os.path.exists(options.robocopApk):
                 parser.error(
--- a/testing/mozharness/configs/builds/releng_base_android_64_builds.py
+++ b/testing/mozharness/configs/builds/releng_base_android_64_builds.py
@@ -125,13 +125,15 @@ config = {
                       ],
     'src_mozconfig': 'mobile/android/config/mozconfigs/android/nightly',
     #########################################################################
 
     # It's not obvious, but postflight_build is after packaging, so the Gecko
     # binaries are in the object directory, ready to be packaged into the
     # GeckoView AAR.
     'postflight_build_mach_commands': [
-        ['android',
-         'archive-geckoview',
+        ['gradle',
+         'geckoview:assembleWithGeckoBinaries',
+         'geckoview_example:assembleWithGeckoBinaries',
+         'uploadArchives',
         ],
     ],
 }
--- a/toolkit/mozapps/installer/upload-files-APK.mk
+++ b/toolkit/mozapps/installer/upload-files-APK.mk
@@ -27,17 +27,17 @@ ifeq ($(MOZ_BUILD_APP),mobile/android)
 UPLOAD_EXTRA_FILES += robocop.apk
 
 # Robocop/Robotium tests, Android Background tests, and Fennec need to
 # be signed with the same key, which means release signing them all.
 
 ifndef MOZ_BUILD_MOBILE_ANDROID_WITH_GRADLE
 robocop_apk := $(topobjdir)/mobile/android/tests/browser/robocop/robocop-debug-unsigned-unaligned.apk
 else
-robocop_apk := $(GRADLE_ANDROID_APP_ANDROIDTEST_APK)
+robocop_apk := $(topobjdir)/gradle/build/mobile/android/app/outputs/apk/app-official-photon-debug-androidTest.apk
 endif
 
 INNER_ROBOCOP_PACKAGE= \
   $(call RELEASE_SIGN_ANDROID_APK,$(robocop_apk),$(ABS_DIST)/robocop.apk)
 endif
 else
 INNER_ROBOCOP_PACKAGE=echo 'Testing is disabled - No Android Robocop for you'
 endif