1 /*
2  * Copyright 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.baselineprofile.gradle.utils
18 
19 import com.android.build.api.AndroidPluginVersion
20 import com.android.build.api.variant.Variant
21 import org.gradle.api.DefaultTask
22 import org.gradle.api.Project
23 import org.gradle.api.file.DirectoryProperty
24 import org.gradle.api.provider.Property
25 import org.gradle.api.tasks.Input
26 import org.gradle.api.tasks.OutputDirectory
27 import org.gradle.api.tasks.TaskAction
28 import org.gradle.work.DisableCachingByDefault
29 
30 internal class R8Utils(private val project: Project) {
31 
32     companion object {
33         private const val PROPERTY_R8_REWRITE_BASELINE_PROFILE_RULES =
34             "android.experimental.art-profile-r8-rewriting"
35         private const val PROPERTY_R8_DEX_LAYOUT_OPTIMIZATION =
36             "android.experimental.r8.dex-startup-optimization"
37     }
38 
39     @Suppress("UnstableApiUsage")
setRulesRewriteForVariantEnablednull40     fun setRulesRewriteForVariantEnabled(variant: Variant, value: Boolean) {
41 
42         // Checks the AGP min version to support this.
43         if (project.agpVersion() < AndroidPluginVersion(8, 1, 0).alpha(8)) {
44             if (!project.isGradleSyncRunning()) {
45                 throw IllegalStateException(
46                     """
47                 Unable to set baseline profile rules rewrite property in module `${project.path}`
48                 due to minimum AGP version requirement not met. This functionality requires at
49                 least AGP version 8.1.0. Please check your module build.gradle file and ensure
50                 the property `baselineProfileRulesRewrite` is not set.
51                 """
52                         .trimIndent()
53                 )
54             }
55             return
56         }
57 
58         // TODO: Note that currently there needs to be at least a baseline profile,
59         //  even if empty. For this reason we always add a src set that points to
60         //  an empty file. This can removed after b/271158087 is fixed.
61         if (value) GenerateDummyBaselineProfileTask.setupForVariant(project, variant)
62 
63         // Sets the experimental property
64         variant.experimentalProperties.put(PROPERTY_R8_REWRITE_BASELINE_PROFILE_RULES, value)
65     }
66 
67     @Suppress("UnstableApiUsage")
setDexLayoutOptimizationEnablednull68     fun setDexLayoutOptimizationEnabled(variant: Variant, value: Boolean) {
69 
70         // Checks the AGP min version to support this.
71         if (project.agpVersion() < AndroidPluginVersion(8, 1, 0).alpha(11)) {
72             if (!project.isGradleSyncRunning()) {
73                 throw IllegalStateException(
74                     """
75                 Unable to set dex layout optimization property in module `${project.path}` due to
76                 minimum AGP version requirement not met. This functionality requires at least AGP
77                 version 8.1.0. Please check your module build.gradle file and ensure the property
78                 `dexLayoutOptimization` is not set.
79                 """
80                         .trimIndent()
81                 )
82             }
83         }
84 
85         // Sets the experimental property
86         variant.experimentalProperties.put(PROPERTY_R8_DEX_LAYOUT_OPTIMIZATION, value)
87     }
88 }
89 
90 @DisableCachingByDefault(because = "Not worth caching.")
91 abstract class GenerateDummyBaselineProfileTask : DefaultTask() {
92 
93     companion object {
setupForVariantnull94         internal fun setupForVariant(project: Project, variant: Variant) {
95             val taskProvider =
96                 project.tasks.maybeRegister<GenerateDummyBaselineProfileTask>(
97                     "generate",
98                     variant.name,
99                     "profileForR8RuleRewrite"
100                 ) {
101                     it.outputDir.set(
102                         project.layout.buildDirectory.dir(
103                             "$INTERMEDIATES_BASE_FOLDER/${variant.name}/empty/"
104                         )
105                     )
106                     it.variantName.set(variant.name)
107                 }
108             @Suppress("UnstableApiUsage")
109             variant.sources.baselineProfiles?.addGeneratedSourceDirectory(
110                 taskProvider,
111                 GenerateDummyBaselineProfileTask::outputDir
112             )
113         }
114     }
115 
116     @get:OutputDirectory abstract val outputDir: DirectoryProperty
117 
118     @get:Input abstract val variantName: Property<String>
119 
120     @TaskAction
execnull121     fun exec() {
122         outputDir.file("empty-baseline-prof.txt").get().asFile.writeText("Lignore/This;")
123     }
124 }
125