blob: 7e5df850a70fcfc672d86b615a3fbb59c038f32c [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.build.gradle.internal.tasks
import com.android.build.api.component.impl.ComponentPropertiesImpl
import com.android.build.gradle.internal.dsl.BaseAppModuleExtension
import com.android.build.gradle.internal.scope.InternalArtifactType
import com.android.build.gradle.internal.tasks.factory.VariantTaskCreationAction
import com.google.common.annotations.VisibleForTesting
import com.android.bundle.AppIntegrityConfigOuterClass.AppIntegrityConfig
import org.gradle.api.file.Directory
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.CacheableTask
import org.gradle.api.tasks.InputDirectory
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.PathSensitive
import org.gradle.api.tasks.PathSensitivity
import org.gradle.api.tasks.TaskProvider
import org.w3c.dom.Document
import java.io.File
import java.io.FileNotFoundException
import java.io.Serializable
import java.nio.file.Files
import javax.xml.parsers.DocumentBuilderFactory
import javax.inject.Inject
private const val CONFIG_FILE_NAME = "IntegrityConfig.xml"
/**
* Task that parses app_integrity_config.proto from an XML file.
*/
@CacheableTask
abstract class ParseIntegrityConfigTask : NonIncrementalTask() {
@get:InputDirectory
@get:Optional
@get:PathSensitive(PathSensitivity.NONE)
abstract val integrityConfigDir: DirectoryProperty
@get:OutputFile
abstract val appIntegrityConfigProto: RegularFileProperty
public override fun doTaskAction() {
getWorkerFacadeWithWorkers().use {
it.submit(
ParseIntegrityConfigRunnable::class.java,
Params(
integrityConfigDir.orNull?.asFile,
appIntegrityConfigProto.asFile.get()
)
)
}
}
@VisibleForTesting
data class Params(
val integrityConfigDir: File?,
val appIntegrityConfigProto: File
) : Serializable
@VisibleForTesting
class ParseIntegrityConfigRunnable @Inject constructor(private val params: Params) :
Runnable {
override fun run() {
params.integrityConfigDir?.let {
if (!it.isDirectory) {
throw FileNotFoundException("Could not find directory ${it.absolutePath}")
}
val doc = loadXML(it.resolve(CONFIG_FILE_NAME))
val configProto = IntegrityConfigParser(doc).parseConfig()
storeProto(configProto, params.appIntegrityConfigProto)
} ?: run {
Files.deleteIfExists(params.appIntegrityConfigProto.toPath())
}
}
private fun loadXML(xmlFile: File): Document {
val documentFactory = DocumentBuilderFactory.newInstance()
val documentBuilder = documentFactory.newDocumentBuilder()
return documentBuilder.parse(xmlFile)
}
private fun storeProto(configProto: AppIntegrityConfig, output: File) {
Files.newOutputStream(output.toPath()).use { outputStream ->
configProto.writeTo(outputStream)
}
}
}
class CreationAction(componentProperties: ComponentPropertiesImpl) :
VariantTaskCreationAction<ParseIntegrityConfigTask, ComponentPropertiesImpl>(
componentProperties
) {
override val name: String
get() = computeTaskName("parse", "IntegrityConfig")
override val type: Class<ParseIntegrityConfigTask>
get() = ParseIntegrityConfigTask::class.java
override fun handleProvider(
taskProvider: TaskProvider<ParseIntegrityConfigTask>
) {
super.handleProvider(taskProvider)
creationConfig.artifacts.setInitialProvider(
taskProvider,
ParseIntegrityConfigTask::appIntegrityConfigProto
).withName("AppIntegrityConfig.pb").on(InternalArtifactType.APP_INTEGRITY_CONFIG)
}
override fun configure(
task: ParseIntegrityConfigTask
) {
super.configure(task)
task.integrityConfigDir.set(getIntegrityConfigFolder(creationConfig))
}
private fun getIntegrityConfigFolder(component: ComponentPropertiesImpl): Provider<out Directory> =
(component.globalScope.extension as BaseAppModuleExtension).bundle.integrityConfigDir
}
}