1buildscript {
2    repositories {
3        google()
4        jcenter()
5    }
6    dependencies {
7        classpath libraries.android_tools
8    }
9}
10
11description = 'Conscrypt: Android Benchmarks'
12
13ext {
14    androidHome = "$System.env.ANDROID_HOME"
15    androidSdkInstalled = file("$androidHome").exists()
16    androidVersionCode = 1
17    androidVersionName = "$version"
18    androidMinSdkVersion = 26
19    androidTargetSdkVersion = 26
20}
21
22if (androidSdkInstalled) {
23    apply plugin: 'com.android.library'
24
25    android {
26        compileSdkVersion androidTargetSdkVersion
27
28        compileOptions {
29            sourceCompatibility androidMinJavaVersion
30            targetCompatibility androidMinJavaVersion
31        }
32
33        defaultConfig {
34            minSdkVersion androidMinSdkVersion
35            targetSdkVersion androidTargetSdkVersion
36            versionCode androidVersionCode
37            versionName androidVersionName
38        }
39        lintOptions {
40            // Some Caliper classes reference packages that don't exist on Android
41            disable 'InvalidPackage'
42        }
43        sourceSets.main {
44            java {
45                srcDirs = [
46                        "src/main/java"
47                ]
48            }
49        }
50    }
51
52    configurations {
53        // For the depsJar task, we need to create a config we can pull libraries from to
54        // make the complete JAR. Some we do not want the transitive dependencies because
55        // they are already included on the Android system.
56        depsJarApi
57        depsJarApi.transitive = true
58
59        depsJarImplementation
60        depsJarImplementation.transitive = false
61
62        implementation.extendsFrom(depsJarApi)
63        implementation.extendsFrom(depsJarImplementation)
64    }
65
66    dependencies {
67        depsJarApi project(path: ':conscrypt-android'),
68                   libraries.bouncycastle_provider,
69                   libraries.bouncycastle_apis
70
71        depsJarImplementation project(':conscrypt-benchmark-base'),
72                              project(path: ":conscrypt-testing", configuration: "runtime"),
73                              project(':conscrypt-libcore-stub')
74
75        implementation 'com.google.caliper:caliper:1.0-beta-2'
76    }
77
78    // This task bundles up everything we're going to send to the device into a single jar.
79    // We need to include all the Conscrypt code plus the Bouncy Castle jar because the platform
80    // version of Bouncy Castle is jarjared.
81    //
82    // Since we're examining the contents of the archive files, we need to prevent evaluation of
83    // the .aar and .jar contents before the actual archives are built. To do this we create a
84    // configure task where the "from" contents is set inside a doLast stanza to ensure it is run
85    // after the execution phase of the "assemble" task.
86    def configureDepsJar = tasks.register("configureDepsJar") {
87        dependsOn assemble, \
88                  configurations.depsJarApi.artifacts, \
89                  configurations.depsJarImplementation.artifacts
90        doLast {
91            depsJar.from {
92                [
93                    configurations.depsJarApi,
94                    configurations.depsJarImplementation,
95                    configurations.archives.artifacts.file
96                ].collect { config ->
97                    config.findResults { archive ->
98                        // For Android library archives (.aar), we need to expand the classes.jar
99                        // inside as well as including all the jni libraries.
100                        if (archive.name.endsWith(".aar")) {
101                            [
102                                zipTree(archive).matching {
103                                    include 'classes.jar'
104                                }.collect { file ->
105                                    zipTree(file)
106                                },
107                                zipTree(archive).matching {
108                                    include '**/*.so'
109                                }
110                            ]
111                        } else if (archive.name.endsWith(".jar")) {
112                            // Bouncy Castle signs their jar, which causes our combined jar to fail
113                            // to verify.  Just strip out the signature files.
114                            zipTree(archive).matching {
115                                exclude 'META-INF/*.SF'
116                                exclude 'META-INF/*.DSA'
117                                exclude 'META-INF/*.EC'
118                                exclude 'META-INF/*.RSA'
119                            }
120                        }
121                    }
122                }
123            }
124        }
125    }
126
127    def depsJar = tasks.register("depsJar", Jar) {
128        dependsOn configureDepsJar
129        archiveName = 'bundled-deps.jar'
130    }
131
132    def getAndroidDeviceAbi = tasks.register("getAndroidDeviceAbi") {
133        doLast {
134            new ByteArrayOutputStream().withStream { os ->
135                def result = exec {
136                    executable android.adbExecutable
137                    args 'shell', 'getprop', 'ro.product.cpu.abi'
138                    standardOutput = os
139                }
140                project.ext.androidDeviceAbi = os.toString().trim()
141                project.ext.androidDevice64Bit = androidDeviceAbi.contains('64')
142            }
143        }
144    }
145
146    def configureExtractNativeLib = tasks.register("configureExtractNativeLib") {
147        dependsOn getAndroidDeviceAbi, depsJar
148        doLast {
149            extractNativeLib.from {
150                zipTree(depsJar.archivePath).matching {
151                    include "jni/${androidDeviceAbi}/*.so"
152                }.collect {
153                    // Using collect flattens out the directory.
154                    it
155                }
156            }
157        }
158    }
159
160    def extractNativeLib = tasks.register("extractNativeLib", Copy) {
161        dependsOn configureExtractNativeLib
162        into "$buildDir/extracted-native-libs"
163    }
164
165    def configurePushNativeLibrary = tasks.register("configurePushNativeLibrary") {
166        dependsOn extractNativeLib
167        doLast {
168            project.ext.nativeLibPath = "/system/lib${androidDevice64Bit ? '64' : ''}/libconscrypt_jni.so"
169            pushNativeLibrary.args 'push', "${extractNativeLib.destinationDir}/libconscrypt_jni.so", nativeLibPath
170        }
171    }
172
173    def pushNativeLibrary = tasks.register("pushNativeLibrary", Exec) {
174        dependsOn configurePushNativeLibrary
175        pushNativeLibrary.executable android.adbExecutable
176    }
177
178    def runBenchmarks = tasks.register("runBenchmarks") {
179        dependsOn depsJar, pushNativeLibrary
180        doLast {
181            // Execute the benchmarks
182            exec {
183                workingDir "${rootDir}"
184                environment PATH: "${android.sdkDirectory}/build-tools/${android.buildToolsVersion}:$System.env.PATH"
185                environment JACK_JAR: "${android.sdkDirectory}/build-tools/${android.buildToolsVersion}/jack.jar"
186
187                executable 'java'
188                args '-cp', 'benchmark-android/vogar.jar', 'vogar.Vogar'
189                args '--classpath', depsJar.archivePath
190                args '--benchmark'
191                args '--language=JN'
192                args '--mode=app_process'
193                args 'org.conscrypt.CaliperAlpnBenchmark'
194                args 'org.conscrypt.CaliperClientSocketBenchmark'
195                args 'org.conscrypt.CaliperEngineHandshakeBenchmark'
196                args 'org.conscrypt.CaliperEngineWrapBenchmark'
197            }
198            // Clean up the native library
199            exec {
200                executable android.adbExecutable
201                args 'shell', 'rm', '-f', nativeLibPath
202            }
203        }
204    }
205} else {
206    logger.warn('Android SDK has not been detected. The Android Benchmark module will not be built.')
207
208    // Disable all tasks
209    tasks.configureEach {
210        it.enabled = false
211    }
212}
213