Skip to content

Commit aae1542

Browse files
authored
Implement AAR size measurement. (#805)
* Implement AAR size measurement. The new task `generateAarSizeMeasurements` generates either a table or a JSON report with the size, in bytes, of the release AAR generated by each subproject. It follows the same logic, and has the same flags, as `generateApkSizeMeasurements`.
1 parent 7eb2a51 commit aae1542

File tree

5 files changed

+223
-1
lines changed

5 files changed

+223
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Copyright 2019 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
16+
package com.google.firebase.gradle.plugins.measurement.aarsize
17+
18+
/** A helper class that generates the AAR size measurement JSON report. */
19+
class AarSizeJsonBuilder {
20+
21+
private static final String PULL_REQUEST_TABLE = "AndroidPullRequests"
22+
private static final String PULL_REQUEST_COLUMN = "pull_request_id"
23+
private static final String AAR_SIZE_TABLE = "AndroidAarSizes"
24+
private static final String SDK_COLUMN = "sdk_id"
25+
private static final String AAR_SIZE_COLUMN = "aar_size"
26+
27+
// This comes in as a String and goes out as a String, so we might as well keep it a String
28+
private final String pullRequestNumber
29+
private final List<Tuple2<Integer, Integer>> sdkAarSizes
30+
31+
AarSizeJsonBuilder(pullRequestNumber) {
32+
this.pullRequestNumber = pullRequestNumber
33+
this.sdkAarSizes = []
34+
}
35+
36+
def addAarSize(sdkId, size) {
37+
sdkAarSizes.add(new Tuple2(sdkId, size))
38+
}
39+
40+
def toJsonString() {
41+
if (sdkAarSizes.isEmpty()) {
42+
throw new IllegalStateException("Empty - No sizes were added")
43+
}
44+
45+
def sizes = sdkAarSizes.collect {
46+
"[$pullRequestNumber, $it.first, $it.second]"
47+
}.join(", ")
48+
49+
def json = """
50+
{
51+
tables: [
52+
{
53+
table_name: "$PULL_REQUEST_TABLE",
54+
column_names: ["$PULL_REQUEST_COLUMN"],
55+
replace_measurements: [[$pullRequestNumber]],
56+
},
57+
{
58+
table_name: "$AAR_SIZE_TABLE",
59+
column_names: ["$PULL_REQUEST_COLUMN", "$SDK_COLUMN", "$AAR_SIZE_COLUMN"],
60+
replace_measurements: [$sizes],
61+
},
62+
],
63+
}
64+
"""
65+
66+
return json
67+
}
68+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright 2019 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
16+
package com.google.firebase.gradle.plugins.measurement.aarsize
17+
18+
/** A helper class that generates the human-readable, AAR size measurement table. */
19+
class AarSizeTableBuilder {
20+
21+
private final List<Tuple> sdkAarSizes = []
22+
23+
def addAarSize(projectName, size) {
24+
sdkAarSizes.add(new Tuple(projectName, size))
25+
}
26+
27+
def toTableString() {
28+
if (sdkAarSizes.isEmpty()) {
29+
throw new IllegalStateException("Rempty - No sizes added")
30+
}
31+
32+
def table = "|---------------- AAR Sizes --------------|\n"
33+
table += "|--------- project ---------|-- size in bytes --|\n"
34+
35+
table += sdkAarSizes.collect {
36+
sprintf("|%-33s|%,21d|", it.get(0), it.get(1))
37+
}.join("\n")
38+
39+
return table
40+
}
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
// Copyright 2019 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
16+
package com.google.firebase.gradle.plugins.measurement.aarsize
17+
18+
import org.gradle.api.DefaultTask
19+
import org.gradle.api.Project
20+
import org.gradle.api.Task
21+
import org.gradle.api.tasks.InputFile
22+
import org.gradle.api.tasks.Optional
23+
import org.gradle.api.tasks.OutputFile
24+
import org.gradle.api.tasks.TaskAction
25+
26+
/**
27+
* Generates size measurements after building the release aar's.
28+
*
29+
* <p>This task can run in two modes. The first mode, enabled when running the task with the
30+
* {@code pull_request} flag set, is a dependency of {@link UploadMeasurementsTask} and generates
31+
* a JSON file with measurement information. The second mode, enabled when running the task without
32+
* flags, outputs a table to standard out with more human-readable information. See the README for
33+
* more details.
34+
*
35+
* <p>This task has two properties, a required ignore SDK map file, as input, and the optional
36+
* report file, as output. The map is used to ignore SDKs that shouldn't be included in the report.
37+
* The report path is where the output should be stored. These properties are not used when the task
38+
* is run in the second, human-friendly mode. However, they are still required to be specified.
39+
*/
40+
public class GenerateMeasurementsTask extends DefaultTask {
41+
42+
/**
43+
* The file for storing the report.
44+
*
45+
* <p>This may be any type recognized by Gradle as a file. The contents, if any, will be
46+
* overwritten by the new report.
47+
*/
48+
@OutputFile
49+
@Optional
50+
File reportFile
51+
52+
@Override
53+
Task configure(Closure closure) {
54+
outputs.upToDateWhen { false }
55+
dependsOn "assemble"
56+
return super.configure(closure)
57+
}
58+
59+
@TaskAction
60+
def generate() {
61+
def subprojects = [:]
62+
project.rootProject.subprojects.collect { Project it ->
63+
def aars = it.fileTree('build') {
64+
include '**/*release.aar'
65+
}
66+
if (aars.size() > 1) {
67+
def msg = "${it.name} produced more than one AAR"
68+
throw new IllegalStateException(msg)
69+
}
70+
def name = it.name
71+
if (it.parent != project.rootProject) {
72+
name = "${it.parent.name}:${it.name}"
73+
}
74+
aars.each { File f ->
75+
subprojects[name] = f.length()
76+
}
77+
}
78+
if (project.hasProperty("pull_request")) {
79+
def pullRequestNumber = project.properties["pull_request"]
80+
generateJson(pullRequestNumber, subprojects)
81+
} else {
82+
generateTable(subprojects)
83+
}
84+
}
85+
86+
private def generateJson(pullRequestNumber, subprojects) {
87+
def builder = new AarSizeJsonBuilder(pullRequestNumber)
88+
subprojects.each { name, aarSize ->
89+
builder.addAarSize(name, aarSize)
90+
}
91+
92+
reportFile.withWriter {
93+
it.write(builder.toJsonString())
94+
}
95+
}
96+
97+
private def generateTable(subprojects) {
98+
def builder = new AarSizeTableBuilder()
99+
subprojects.each { name, aarSize ->
100+
builder.addAarSize(name, aarSize)
101+
}
102+
103+
project.logger.quiet(builder.toTableString())
104+
}
105+
}

tools/measurement/apksize/apksize.gradle

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
// limitations under the License.
1414

1515
import com.google.firebase.gradle.plugins.measurement.apksize.GenerateMeasurementsTask
16+
import com.google.firebase.gradle.plugins.measurement.aarsize.GenerateMeasurementsTask as GenerateAarMeasurementTask
1617
import com.google.firebase.gradle.plugins.measurement.UploadMeasurementsTask
1718

1819
apply plugin: "com.android.application"
@@ -42,6 +43,13 @@ task generateApkSizeMeasurements(type: GenerateMeasurementsTask) {
4243
reportFile = file("$buildDir/size-report.json")
4344
}
4445

46+
task generateAarSizeMeasurements(type: GenerateAarMeasurementTask) {
47+
description 'Builds release aar artifacts and calculates AAR sizes.'
48+
group 'Measurements'
49+
50+
dependsOn (":publishAllToBuildDir")
51+
}
52+
4553
/**
4654
* This task uploads the report produced by the generate measurements task to a SQL database.
4755
*

tools/measurement/apksize/default.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ android {
3030
defaultConfig {
3131
applicationId 'com.google.apksize'
3232
minSdkVersion project.targetSdkVersion
33-
multiDexEnabled true
33+
multiDexEnabled true
3434
targetSdkVersion project.targetSdkVersion
3535
versionCode 1
3636
versionName '1.0'

0 commit comments

Comments
 (0)