tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

build.gradle (24614B)


      1 plugins {
      2    alias(libs.plugins.kotlin.android)
      3    id 'com.android.library'
      4    id 'checkstyle'
      5    id 'org.mozilla.apilint'
      6 }
      7 
      8 import groovy.json.JsonOutput
      9 
     10 // The SDK binding generation tasks depend on the JAR creation task of the
     11 // :annotations project.
     12 evaluationDependsOn(':annotations')
     13 
     14 android {
     15    buildToolsVersion = project.ext.buildToolsVersion
     16    compileSdk {
     17        version = release(project.ext.compileSdkMajorVersion) { minorApiLevel = project.ext.compileSdkMinorVersion }
     18    }
     19 
     20    useLibrary 'android.test.runner'
     21    useLibrary 'android.test.base'
     22    useLibrary 'android.test.mock'
     23 
     24    defaultConfig {
     25        targetSdk project.ext.targetSdkVersion
     26        minSdk project.ext.minSdkVersion
     27        manifestPlaceholders = project.ext.manifestPlaceholders
     28 
     29        versionCode project.ext.versionCode
     30        versionName project.ext.versionName
     31        consumerProguardFiles 'proguard-rules.txt'
     32 
     33        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
     34 
     35        buildConfigField 'String', "GRE_MILESTONE", "\"${mozconfig.substs.GRE_MILESTONE}\""
     36        buildConfigField 'String', "MOZ_APP_BASENAME", "\"${mozconfig.substs.MOZ_APP_BASENAME}\"";
     37 
     38        // For the benefit of future archaeologists:
     39        // GRE_BUILDID is exactly the same as MOZ_APP_BUILDID unless you're running
     40        // on XULRunner, which is never the case on Android.
     41        buildConfigField 'String', "MOZ_APP_BUILDID", "\"${project.ext.buildId}\"";
     42        buildConfigField 'String', "MOZ_APP_ID", "\"${mozconfig.substs.MOZ_APP_ID}\"";
     43        buildConfigField 'String', "MOZ_APP_NAME", "\"${mozconfig.substs.MOZ_APP_NAME}\"";
     44        buildConfigField 'String', "MOZ_APP_VENDOR", "\"${mozconfig.substs.MOZ_APP_VENDOR}\"";
     45        buildConfigField 'String', "MOZ_APP_VERSION", "\"${mozconfig.substs.MOZ_APP_VERSION}\"";
     46        buildConfigField 'String', "MOZ_APP_DISPLAYNAME", "\"${mozconfig.substs.MOZ_APP_DISPLAYNAME}\"";
     47        buildConfigField 'String', "MOZ_APP_UA_NAME", "\"${mozconfig.substs.MOZ_APP_UA_NAME}\"";
     48        buildConfigField 'String', "MOZ_UPDATE_CHANNEL", "\"${mozconfig.substs.MOZ_UPDATE_CHANNEL}\"";
     49        buildConfigField 'boolean', "TOR_BROWSER", mozconfig.substs.TOR_BROWSER ? 'true' : 'false';
     50 
     51        // MOZILLA_VERSION is oddly quoted from autoconf, but we don't have to handle it specially in Gradle.
     52        buildConfigField 'String', "MOZILLA_VERSION", "\"${mozconfig.substs.MOZILLA_VERSION}\"";
     53        buildConfigField 'String', "OMNIJAR_NAME", "\"${mozconfig.substs.OMNIJAR_NAME}\"";
     54 
     55        // Keep in sync with actual user agent in nsHttpHandler::BuildUserAgent
     56        buildConfigField 'String', "USER_AGENT_GECKOVIEW_MOBILE", "\"Mozilla/5.0 (Android \" + android.os.Build.VERSION.RELEASE + \"; Mobile; rv:\" + ${mozconfig.defines.MOZILLA_UAVERSION} + \") Gecko/\" + ${mozconfig.defines.MOZILLA_UAVERSION} + \" Firefox/\" + ${mozconfig.defines.MOZILLA_UAVERSION}";
     57        buildConfigField 'String', "USER_AGENT_GECKOVIEW_MOBILE_ANDROID_10", "\"Mozilla/5.0 (Android 10; Mobile; rv:\" + ${mozconfig.defines.MOZILLA_UAVERSION} + \") Gecko/\" + ${mozconfig.defines.MOZILLA_UAVERSION} + \" Firefox/\" + ${mozconfig.defines.MOZILLA_UAVERSION}";
     58 
     59        buildConfigField 'int', 'MIN_SDK_VERSION', mozconfig.substs.MOZ_ANDROID_MIN_SDK_VERSION;
     60 
     61        // Is the underlying compiled C/C++ code compiled with --enable-debug?
     62        buildConfigField 'boolean', 'DEBUG_BUILD', mozconfig.substs.MOZ_DEBUG ? 'true' : 'false';
     63 
     64        // See this wiki page for more details about channel specific build defines:
     65        // https://wiki.mozilla.org/Platform/Channel-specific_build_defines
     66        // This makes no sense for GeckoView and should be removed as soon as possible.
     67        buildConfigField 'boolean', 'RELEASE_OR_BETA', mozconfig.substs.RELEASE_OR_BETA ? 'true' : 'false';
     68        // This makes no sense for GeckoView and should be removed as soon as possible.
     69        buildConfigField 'boolean', 'NIGHTLY_BUILD', mozconfig.substs.NIGHTLY_BUILD ? 'true' : 'false';
     70        // This makes no sense for GeckoView and should be removed as soon as possible.
     71        buildConfigField 'boolean', 'MOZ_CRASHREPORTER', mozconfig.substs.MOZ_CRASHREPORTER ? 'true' : 'false';
     72 
     73        buildConfigField 'int', 'MOZ_ANDROID_CONTENT_SERVICE_COUNT', mozconfig.substs.MOZ_ANDROID_CONTENT_SERVICE_COUNT;
     74 
     75        // Official corresponds, roughly, to whether this build is performed on
     76        // Mozilla's continuous integration infrastructure. You should disable
     77        // developer-only functionality when this flag is set.
     78        // This makes no sense for GeckoView and should be removed as soon as possible.
     79        buildConfigField 'boolean', 'MOZILLA_OFFICIAL', mozconfig.substs.MOZILLA_OFFICIAL ? 'true' : 'false';
     80 
     81        // This env variable signifies whether we are running an isolated process build.
     82        buildConfigField 'boolean', 'MOZ_ANDROID_CONTENT_SERVICE_ISOLATED_PROCESS', mozconfig.substs.MOZ_ANDROID_CONTENT_SERVICE_ISOLATED_PROCESS ? 'true' : 'false';
     83    }
     84 
     85    lintOptions {
     86        abortOnError = false
     87    }
     88 
     89    sourceSets {
     90        main {
     91            java {
     92                if (!mozconfig.substs.MOZ_ANDROID_HLS_SUPPORT) {
     93                    exclude 'org/mozilla/gecko/media/GeckoHlsAudioRenderer.java'
     94                    exclude 'org/mozilla/gecko/media/GeckoHlsPlayer.java'
     95                    exclude 'org/mozilla/gecko/media/GeckoHlsRendererBase.java'
     96                    exclude 'org/mozilla/gecko/media/GeckoHlsVideoRenderer.java'
     97                    exclude 'org/mozilla/gecko/media/Utils.java'
     98                }
     99 
    100                if (mozconfig.substs.MOZ_WEBRTC) {
    101                    srcDir "${topsrcdir}/dom/media/systemservices/android_video_capture/java/src"
    102                    srcDir "${topsrcdir}/third_party/libwebrtc/sdk/android/api"
    103                    srcDir "${topsrcdir}/third_party/libwebrtc/sdk/android/src"
    104                    srcDir "${topsrcdir}/third_party/libwebrtc/rtc_base/java"
    105                }
    106 
    107                srcDir "${topobjdir}/mobile/android/geckoview/src/main/java"
    108            }
    109 
    110            resources {
    111                if (mozconfig.substs.MOZ_ASAN) {
    112                    // If this is an ASAN build, include a `wrap.sh` for Android 8.1+ devices.  See
    113                    // https://developer.android.com/ndk/guides/wrap-script.
    114                    srcDir "${topsrcdir}/mobile/android/geckoview/src/asan/resources"
    115                }
    116            }
    117 
    118            assets {
    119                // This should contain only `omni.ja`.
    120                srcDir "${topobjdir}/dist/geckoview/assets"
    121            }
    122 
    123            jniLibs {
    124                if (!mozconfig.substs.MOZ_ANDROID_FAT_AAR_ARCHITECTURES) {
    125                    srcDir "${topobjdir}/dist/geckoview/lib"
    126                } else {
    127                    srcDir "${topobjdir}/dist/fat-aar/output/jni"
    128                }
    129            }
    130 
    131            debug {
    132                manifest.srcFile "${topobjdir}/mobile/android/geckoview/src/main/AndroidManifest_overlay.xml"
    133            }
    134 
    135            release {
    136                manifest.srcFile "${topobjdir}/mobile/android/geckoview/src/main/AndroidManifest_overlay.xml"
    137            }
    138        }
    139    }
    140 
    141    buildFeatures {
    142        buildConfig = true
    143        aidl = true
    144    }
    145 
    146    publishing {
    147        singleVariant('debug')
    148    }
    149 
    150    namespace = 'org.mozilla.geckoview'
    151 }
    152 
    153 tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile) {
    154    // Translate Kotlin messages like "w: ..." and "e: ..." into
    155    // "...: warning: ..." and "...: error: ...", to make Treeherder understand.
    156    def listener = {
    157        if (it.startsWith("e: warnings found")) {
    158            return
    159        }
    160 
    161        if (it.startsWith('w: ') || it.startsWith('e: ')) {
    162            def matches = (it =~ /([ew]): (.+): \((\d+), (\d+)\): (.*)/)
    163            if (!matches) {
    164                logger.quiet "kotlinc message format has changed!"
    165                if (it.startsWith('w: ')) {
    166                    // For warnings, don't continue because we don't want to throw an
    167                    // exception. For errors, we want the exception so that the new error
    168                    // message format gets translated properly.
    169                    return
    170                }
    171            }
    172            def (_, type, file, line, column, message) = matches[0]
    173            type = (type == 'w') ? 'warning' : 'error'
    174            // Use logger.lifecycle, which does not go through stderr again.
    175            logger.lifecycle "$file:$line:$column: $type: $message"
    176        }
    177    } as StandardOutputListener
    178 
    179    compilerOptions {
    180        allWarningsAsErrors = true
    181    }
    182 
    183    doFirst {
    184        logging.addStandardErrorListener(listener)
    185    }
    186    doLast {
    187        logging.removeStandardErrorListener(listener)
    188    }
    189 }
    190 
    191 def projectVersion = project.ext.gleanVersion
    192 
    193 configurations {
    194    api {
    195        outgoing {
    196            if (!mozconfig.substs.MOZ_ANDROID_GECKOVIEW_LITE) {
    197                // The omni build provides glean-native
    198                capability("org.mozilla.telemetry:glean-native:${project.ext.gleanVersion}")
    199            }
    200            afterEvaluate {
    201                // Implicit capability
    202                capability("org.mozilla.geckoview:${computeArtifactId()}:${projectVersion}")
    203            }
    204        }
    205    }
    206    // TODO: This is a workaround for a bug that was fixed in Gradle 7.
    207    // The variant resolver _should_ pick the RuntimeOnly configuration when building
    208    // the tests as those define the implicit :geckoview capability but it doesn't,
    209    // so we manually define it here.
    210    runtimeOnly {
    211        outgoing {
    212            afterEvaluate {
    213                capability("org.mozilla.geckoview:geckoview:${projectVersion}")
    214            }
    215        }
    216    }
    217 }
    218 
    219 dependencies {
    220    implementation libs.androidx.annotation
    221    implementation libs.androidx.annotation.experimental
    222    implementation libs.androidx.collection
    223    implementation libs.androidx.core
    224    implementation libs.androidx.lifecycle.common
    225    implementation libs.androidx.lifecycle.process
    226    implementation libs.play.services.fido
    227    implementation "org.yaml:snakeyaml:2.2"
    228 
    229    if (mozconfig.substs.MOZ_ANDROID_HLS_SUPPORT) {
    230        implementation project(":exoplayer2")
    231    }
    232 
    233    testImplementation platform(libs.junit.bom)
    234    testImplementation libs.junit4
    235    testRuntimeOnly libs.junit.platform.launcher
    236    testRuntimeOnly libs.junit.vintage
    237    testImplementation libs.robolectric
    238 
    239    androidTestImplementation libs.androidx.core.ktx
    240    androidTestImplementation libs.androidx.test.espresso.core
    241    androidTestImplementation libs.androidx.test.junit
    242    androidTestImplementation libs.androidx.test.rules
    243    androidTestImplementation libs.androidx.test.runner
    244    androidTestImplementation libs.kotlinx.coroutines.test
    245    androidTestImplementation 'com.koushikdutta.async:androidasync:3.1.0'
    246 }
    247 
    248 apply from: "${topsrcdir}/mobile/android/gradle/with_gecko_binaries.gradle"
    249 
    250 android.libraryVariants.all { variant ->
    251    configureVariantWithGeckoBinaries(variant)
    252 
    253    // Javadoc and Sources JAR configuration cribbed from
    254    // https://github.com/mapbox/mapbox-gl-native/blob/d169ea55c1cfa85cd8bf19f94c5f023569f71810/platform/android/MapboxGLAndroidSDK/build.gradle#L85
    255    // informed by
    256    // https://code.tutsplus.com/tutorials/creating-and-publishing-an-android-library--cms-24582,
    257    // and amended from numerous Stackoverflow posts.
    258    def name = variant.name
    259    def classpathFilesProvider = variant.javaCompileProvider.flatMap { compileTask ->
    260        project.provider { compileTask.classpath.files }
    261    }
    262 
    263    def classpathFilesProviderFiles = project.provider {
    264        files(classpathFilesProvider.get())
    265    }
    266 
    267    def androidLintProperty = project.provider { project.hasProperty('android-lint') }
    268 
    269    def javadoc = task "javadoc${name.capitalize()}"(type: Javadoc) {
    270        failOnError = false
    271        description = "Generate Javadoc for build variant $name"
    272        destinationDir = new File(destinationDir, variant.baseName)
    273 
    274        // The javadoc task will not re-run if the previous run is still up-to-date,
    275        // this is a problem for the javadoc lint, which needs to read the output of the task
    276        // to determine if there are warnings or errors. To force that we pass a -Pandroid-lint
    277        // parameter to all lints that can be used here to force running the task every time.
    278 
    279        outputs.upToDateWhen {
    280            !androidLintProperty.get()
    281        }
    282 
    283        doFirst {
    284            classpath = classpathFilesProviderFiles.get()
    285        }
    286 
    287        def results = []
    288        def listener = {
    289            if (!it.toLowerCase().contains("warning:") && !it.toLowerCase().contains("error:")) {
    290              // Likely not an error or a warning
    291              return
    292            }
    293            // Like '/abs/path/to/topsrcdir/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/ContentBlocking.java:480: warning: no @return'
    294            def matches = (it =~ /(.+):(\d+):.*(warning|error)(.*)/)
    295            if (!matches) {
    296                // could not parse, let's add it anyway since it's a warning or error
    297                results << [path: "parsing-failed", lineno: 0, level: "error", message: it]
    298                return
    299            }
    300            def (_, file, line, level, message) = matches[0]
    301            results << [path: file, lineno: line, level: level, message: message]
    302        } as StandardOutputListener
    303 
    304        doFirst {
    305            logging.addStandardErrorListener(listener)
    306        }
    307 
    308        def reportsDir = file("$buildDir/reports")
    309        def reportsJsonFile = file("$buildDir/reports/javadoc-results-${name}.json")
    310 
    311        doLast {
    312            logging.removeStandardErrorListener(listener)
    313 
    314            // We used to treat Javadoc warnings as errors here; now we rely on the
    315            // `android-javadoc` linter to fail in the face of Javadoc warnings.
    316            def resultsJson = JsonOutput.toJson(results)
    317 
    318            reportsDir.mkdirs()
    319            reportsJsonFile.write(resultsJson)
    320        }
    321 
    322        source = variant.sourceSets.collect({ it.java.srcDirs })
    323        exclude '**/R.java', '**/BuildConfig.java'
    324        include 'org/mozilla/geckoview/**.java'
    325        options.addPathOption('sourcepath').setValue(
    326             variant.sourceSets.collect({ it.java.srcDirs }).flatten() +
    327             variant.generateBuildConfigProvider.get().sourceOutputDir.asFile.get() +
    328             variant.aidlCompileProvider.get().sourceOutputDir.asFile.get()
    329        )
    330        options.addStringOption("Xmaxwarns", "1000")
    331        if (!project.hasProperty('android-lint')) {
    332            // It's not helpful to produce 100s of lint warnings during regular
    333            // builds.  (When linting, it is helpful.)
    334            options.addBooleanOption("Xdoclint:-missing", true)
    335        }
    336 
    337        classpath += files(android.getBootClasspath())
    338        classpath += variant.javaCompileProvider.get().classpath
    339 
    340        options.memberLevel = JavadocMemberLevel.PROTECTED
    341        options.source = 11
    342        options.links("https://developer.android.com/reference")
    343 
    344        options.docTitle = "GeckoView ${mozconfig.substs.MOZ_APP_VERSION} API"
    345        options.header = "GeckoView ${mozconfig.substs.MOZ_APP_VERSION} API"
    346        options.noTimestamp = true
    347        options.noQualifiers = ['java.lang']
    348        options.tags = ['hide:a:']
    349    }
    350 
    351    def javadocJar = task("javadocJar${name.capitalize()}", type: Jar, dependsOn: javadoc) {
    352        archiveClassifier = 'javadoc'
    353        from javadoc.destinationDir
    354    }
    355 
    356    // This task is used by `mach android geckoview-docs`.
    357    task("javadocCopyJar${name.capitalize()}", type: Copy) {
    358        from(javadocJar.destinationDirectory) {
    359            include 'geckoview-*-javadoc.jar'
    360            rename { _ -> 'geckoview-javadoc.jar' }
    361        }
    362        into javadocJar.destinationDirectory
    363        dependsOn javadocJar
    364    }
    365 
    366    def sourcesJar = task("sourcesJar${name.capitalize()}", type: Jar) {
    367        archiveClassifier = 'sources'
    368        description = "Generate Javadoc for build variant $name"
    369        destinationDirectory =
    370            file("${topobjdir}/mobile/android/geckoview/sources/${variant.baseName}")
    371        from files(variant.sourceSets.collect({ it.java.srcDirs }).flatten())
    372    }
    373 
    374    task("checkstyle${name.capitalize()}", type: Checkstyle) {
    375        classpath = variant.javaCompileProvider.get().classpath
    376        // TODO: cleanup and include all sources
    377        source = ['src/main/java/']
    378        include '**/*.java'
    379 
    380    }
    381 }
    382 
    383 checkstyle {
    384    configDirectory = file(".")
    385    configFile = file("checkstyle.xml")
    386    toolVersion = "8.36.2"
    387 }
    388 
    389 android.libraryVariants.all { variant ->
    390    if (variant.name == mozconfig.substs.GRADLE_ANDROID_GECKOVIEW_VARIANT_NAME) {
    391        configureLibraryVariantWithJNIWrappers(variant, "Generated")
    392    }
    393 }
    394 
    395 apply plugin: 'maven-publish'
    396 
    397 version = getVersionNumber()
    398 println("GeckoView version = " + version)
    399 group = 'org.mozilla.geckoview'
    400 
    401 def computeArtifactId() {
    402    def id = "geckoview" + project.ext.artifactSuffix
    403 
    404    if (!mozconfig.substs.MOZ_ANDROID_GECKOVIEW_LITE) {
    405        id += "-omni"
    406    }
    407 
    408    if (mozconfig.substs.MOZILLA_OFFICIAL && !mozconfig.substs.MOZ_ANDROID_FAT_AAR_ARCHITECTURES) {
    409        // In automation, per-architecture artifacts identify
    410        // the architecture; multi-architecture artifacts don't.
    411        // When building locally, we produce a "skinny AAR" with
    412        // one target architecture masquerading as a "fat AAR"
    413        // to enable Gradle composite builds to substitute this
    414        // project into consumers easily.
    415        id += "-${mozconfig.substs.ANDROID_CPU_ARCH}"
    416    }
    417 
    418    return id
    419 }
    420 
    421 publishing {
    422    publications {
    423        android.libraryVariants.all { variant ->
    424            "${variant.name}"(MavenPublication) {
    425                from components.findByName(variant.name)
    426 
    427                pom {
    428                    afterEvaluate {
    429                        artifactId = computeArtifactId()
    430                    }
    431 
    432                    url = 'https://geckoview.dev'
    433 
    434                    licenses {
    435                        license {
    436                            name = 'The Mozilla Public License, v. 2.0'
    437                            url = 'http://mozilla.org/MPL/2.0/'
    438                            distribution = 'repo'
    439                        }
    440                    }
    441 
    442                    scm {
    443                        if (gradle.mozconfig.substs.MOZ_INCLUDE_SOURCE_INFO) {
    444                            // URL is like "https://hg.mozilla.org/mozilla-central/rev/1e64b8a0c546a49459d404aaf930d5b1f621246a".
    445                            connection = "scm:hg:${gradle.mozconfig.source_repo.MOZ_SOURCE_REPO}"
    446                            url = gradle.mozconfig.source_repo.MOZ_SOURCE_URL
    447                            tag = gradle.mozconfig.source_repo.MOZ_SOURCE_STAMP
    448                        } else {
    449                            // Default to mozilla-central.
    450                            connection = 'scm:hg:https://hg.mozilla.org/mozilla-central/'
    451                            url = 'https://hg.mozilla.org/mozilla-central/'
    452                        }
    453                    }
    454                }
    455 
    456                // Javadoc and sources for developer ergononomics.
    457                artifact tasks["javadocJar${variant.name.capitalize()}"]
    458                artifact tasks["sourcesJar${variant.name.capitalize()}"]
    459            }
    460        }
    461    }
    462    repositories {
    463        maven {
    464            url = "${topobjdir}/gradle/maven"
    465        }
    466    }
    467 }
    468 
    469 afterEvaluate {
    470    // The bundle tasks are only present when the particular configuration is
    471    // being built, so this task might not exist.  (This is due to the way the
    472    // Android Gradle plugin defines things during configuration.)
    473    def bundle = tasks.findByName('bundleReleaseAar')
    474    if (!bundle) {
    475        return
    476    }
    477 
    478    // Remove default configuration, which is the release configuration, when
    479    // building.  This makes `gradle install` install the deubg artifacts, not
    480    // the release artifacts (which are not suitable for distribution.)
    481    def Configuration archivesConfig = project.getConfigurations().getByName('archives')
    482    archivesConfig.artifacts.removeAll { it.extension.equals('aar') }
    483 
    484    // For now, ensure Kotlin is only used in tests.
    485    android.sourceSets.all { sourceSet ->
    486        if (sourceSet.name.startsWith('test') || sourceSet.name.startsWith('androidTest')) {
    487            return
    488        }
    489        (sourceSet.java.srcDirs + sourceSet.kotlin.srcDirs).each {
    490            if (!fileTree(it, { include '**/*.kt' }).empty) {
    491                throw new GradleException("Kotlin used in non-test directory ${it.path}")
    492            }
    493        }
    494    }
    495 }
    496 
    497 // Bug 1353055 - Strip 'vars' debugging information to agree with moz.build.
    498 apply from: "${topsrcdir}/mobile/android/gradle/debug_level.gradle"
    499 android.libraryVariants.all configureVariantDebugLevel
    500 
    501 def androidBootClasspath = provider {
    502    android.bootClasspath.findAll { it.name.startsWith('android.jar') }
    503 }
    504 
    505 def bindingsDir = "${topobjdir}/widget/android/bindings"
    506 
    507 def generateSdkBindingsArgsProvider = project.provider { project.hasProperty('generate_sdk_bindings_args') ? project.generate_sdk_bindings_args : false }
    508 // There's nothing specific to the :geckoview project here -- this just needs to
    509 // be somewhere where the Android plugin is available so that we can fish the
    510 // path to "android.jar".
    511 tasks.register("generateSDKBindings", JavaExec) {
    512    classpath project(':annotations').jar.archiveFile
    513    classpath project(':annotations').compileJava.classpath
    514    classpath project(':annotations').sourceSets.main.runtimeClasspath
    515 
    516    // To use the lint APIs: "Lint must be invoked with the System property
    517    // com.android.tools.lint.bindir pointing to the ANDROID_SDK tools
    518    // directory"
    519    systemProperties = [
    520        'com.android.tools.lint.bindir': "${android.sdkDirectory}/tools",
    521    ]
    522 
    523    mainClass = 'org.mozilla.gecko.annotationProcessors.SDKProcessor'
    524 
    525    // Configure the arguments at evaluation-time, not at configuration-time.
    526    doFirst {
    527        // We only want to generate bindings for the main framework JAR,
    528        // but not any of the additional android.test libraries.
    529        args androidBootClasspath.get()
    530        args 29
    531        args bindingsDir
    532 
    533        // From -Pgenerate_sdk_bindings_args=... on command line; missing in
    534        // `android-gradle-dependencies` toolchain task.
    535        if (generateSdkBindingsArgsProvider.get()) {
    536            args generateSdkBindingsArgsProvider.get().split(';')
    537        }
    538    }
    539 
    540    workingDir "${topsrcdir}/widget/android/bindings"
    541 
    542    // The `annotations` inputs are already captured via `classpath`.  It's
    543    // possible to be clever here and list inputs from the provided arguments,
    544    // but using the input directory will make it easier to remove the argument
    545    // passing entirely (in favour of crawling the directory directly).
    546    inputs.dir("${topsrcdir}/widget/android/bindings")
    547 
    548    outputs.dir("${topobjdir}/widget/android/bindings")
    549 
    550    dependsOn project(':annotations').jar
    551    dependsOn rootProject.verifyGleanVersion
    552 }
    553 
    554 apiLint {
    555    // TODO: Change this to `org` after hiding org.mozilla.gecko
    556    packageFilter = 'org.mozilla.geckoview'
    557    changelogFileName = 'src/main/java/org/mozilla/geckoview/doc-files/CHANGELOG.md'
    558    // Put those files in ${buildDir}/intermediates/javac/<variant>
    559    // instead of ${buildDir}/intermediates/javac/<variant>/compile<Variant>JavaWithJavac/classes
    560    jsonResultFileName = '../../apilint-result.json'
    561    apiOutputFileName = '../../api.txt'
    562    skipClassesRegex = [
    563        '^org.mozilla.geckoview.BuildConfig$',
    564        '^org.mozilla.geckoview.R$',
    565    ]
    566    lintFilters = ['GV']
    567    deprecationAnnotation = 'org.mozilla.geckoview.DeprecationSchedule'
    568    libraryVersion = mozconfig.substs.MOZILLA_VERSION.split('\\.')[0] as Integer
    569    allowedPackages = [
    570        'java',
    571        'android',
    572        'androidx',
    573        'org.json',
    574        'org.mozilla.geckoview',
    575    ]
    576    helpCommand = { variantName -> "\$ ./mach gradle :geckoview:apiUpdateFile${variantName}" }
    577 }
    578 
    579 // generateDebugLintModel and other lint tasks that depend on it check the geckoview assets folder
    580 // too which is used by machStagePackage task in parallel. This is a temporary fix to allow building
    581 // from root folder and should be replaced by a proper input and output dependency definition
    582 // or with an AGP update.
    583 tasks.configureEach { task ->
    584    if (task.name.toLowerCase().contains("lint")) {
    585        dependsOn(":machStagePackage")
    586    }
    587 }