Improve gradle task configuration

1. Declare explicit dependency to allow incremental build for installation tasks
2. Eliminate lint errors
This commit is contained in:
JingMatrix
2025-11-02 18:40:45 +01:00
parent ed9164d9d8
commit 54f80717dc
4 changed files with 115 additions and 169 deletions
+108 -162
View File
@@ -3,6 +3,8 @@
* SPDX-License-Identifier: GPL-3.0-or-later * SPDX-License-Identifier: GPL-3.0-or-later
*/ */
import com.android.build.api.artifact.SingleArtifact
plugins { plugins {
alias(libs.plugins.android.application) alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android) alias(libs.plugins.kotlin.android)
@@ -62,6 +64,7 @@ android {
buildFeatures { prefab = true } buildFeatures { prefab = true }
buildTypes { buildTypes {
debug { isMinifyEnabled = false }
release { release {
isMinifyEnabled = true isMinifyEnabled = true
proguardFiles( proguardFiles(
@@ -91,187 +94,130 @@ dependencies {
implementation(libs.org.lsposed.libcxx.libcxx) implementation(libs.org.lsposed.libcxx.libcxx)
} }
afterEvaluate { androidComponents {
android.applicationVariants.forEach { variant -> onVariants(selector().all()) { variant ->
val variantName = variant.name val capitalized = variant.name.replaceFirstChar { it.uppercase() }
val capitalized = variantName.replaceFirstChar { it.uppercase() } val isDebug = variant.buildType == "debug"
val tempModuleDir = project.layout.buildDirectory.dir("tmp/module-${variantName}")
tasks.register("copyFiles${capitalized}") { // --- Define output locations and file names ---
dependsOn("assemble${capitalized}") // Stage all files in a temporary directory inside 'build' before zipping
val moduleFolder = project.rootDir.resolve("module") val tempModuleDir = project.layout.buildDirectory.dir("module/${variant.name}")
val buildDir = project.layout.buildDirectory val zipFileName = "TEESimulator-$verName-$gitCommitCount-$gitCommitHash-$capitalized.zip"
doLast { // Task 1: Prepare all module files in the temporary build directory.
val isDebug = variantName.contains("debug", ignoreCase = true) // Using Sync ensures that stale files from previous runs are removed.
// val apkFile = variant.outputs.first().outputFile val prepareModuleFilesTask =
tasks.register<Sync>("prepareModuleFiles${capitalized}") {
group = "TEESimulator Module Packaging"
description = "Prepares all files for the ${variant.name} module zip."
listOf("service.apk", "classes.dex").forEach { fileName -> if (isDebug) {
val oldFile = moduleFolder.resolve(fileName) dependsOn("package${capitalized}")
if (oldFile.exists()) oldFile.delete() } else {
dependsOn("minify${capitalized}WithR8")
}
dependsOn("strip${capitalized}DebugSymbols")
// The Sync task will automatically depend on the tasks that produce these
// artifacts.
// This is the correct way to establish the dependency chain.
if (isDebug) {
from(variant.artifacts.get(SingleArtifact.APK)) {
include("*.apk")
rename { "service.apk" }
}
} else {
from(
project.layout.buildDirectory.dir(
"intermediates/dex/${variant.name}/minify${capitalized}WithR8"
)
) {
include("classes.dex")
}
} }
// Select source file based on build type from(
val sourceFile = project.layout.buildDirectory.dir(
if (isDebug) { "intermediates/stripped_native_libs/${variant.name}/strip${capitalized}DebugSymbols/out/lib"
variant.outputs.first().outputFile )
} else { ) {
buildDir into("lib") // Place them in the 'lib' subfolder of the staging directory.
.get() include("**/libinject.so", "**/libTEESimulator.so")
.asFile }
.resolve("intermediates/dex/release/minifyReleaseWithR8/classes.dex")
}
val destFileName = if (isDebug) "service.apk" else "classes.dex" // Now, copy and process the files from 'module' directory.
sourceFile.copyTo(moduleFolder.resolve(destFileName), overwrite = true) val sourceModuleDir = rootProject.projectDir.resolve("module")
from(sourceModuleDir) {
exclude("module.prop") // Exclude the template file.
}
val soDir = // Copy and filter the module.prop template separately.
buildDir from(sourceModuleDir) {
.get() include("module.prop")
.asFile // Use expand() for simple key-value replacement.
.resolve( expand(
"intermediates/stripped_native_libs/$variantName/strip${capitalized}DebugSymbols/out/lib" "REPLACEMEVERCODE" to gitCommitCount.toString(),
) "REPLACEMEVER" to
"$verName ($gitCommitCount-$gitCommitHash-${variant.name})",
)
}
// apkFile.copyTo(moduleFolder.resolve("service.apk"), overwrite = true) // The destination for all the above 'from' operations.
into(tempModuleDir)
val allowedLibs = setOf("libinject.so", "libTEESimulator.so")
soDir
.walk()
.filter { it.isFile && it.name in allowedLibs }
.forEach { soFile ->
val abiFolder = soFile.parentFile.name
val destination = moduleFolder.resolve("lib/$abiFolder/${soFile.name}")
soFile.copyTo(destination, overwrite = true)
}
} }
}
// Prepare temp directory with all files // Task 2: Zip the prepared files from the temporary directory.
tasks.register("prepareModuleFiles${capitalized}") {
dependsOn("copyFiles${capitalized}")
val sourceDir = project.rootDir.resolve("module")
doLast {
val tempDir = tempModuleDir.get().asFile
// Clean and create temp directory
tempDir.deleteRecursively()
tempDir.mkdirs()
// Copy all files except module.prop
sourceDir
.walkTopDown()
.filter { it.isFile && it.name != "module.prop" }
.forEach { sourceFile ->
val relativePath = sourceFile.relativeTo(sourceDir)
val destFile = tempDir.resolve(relativePath)
destFile.parentFile.mkdirs()
sourceFile.copyTo(destFile, overwrite = true)
}
// Process module.prop
val sourceProp = sourceDir.resolve("module.prop")
val destProp = tempDir.resolve("module.prop")
val content = sourceProp.readText()
val processedContent =
content
.replace("REPLACEMEVERCODE", gitCommitCount.toString())
.replace(
"REPLACEMEVER",
"$verName ($gitCommitCount-$gitCommitHash-$variantName)",
)
destProp.writeText(processedContent)
}
}
// Zip task uses the temp directory
val zipTask = val zipTask =
tasks.register<Zip>("zip${capitalized}") { tasks.register<Zip>("zip${capitalized}") {
dependsOn("prepareModuleFiles${capitalized}") group = "TEESimulator Module Packaging"
archiveFileName.set( description = "Creates the flashable zip for the ${variant.name} module."
"TEESimulator-$verName-$gitCommitCount-$gitCommitHash-${capitalized}.zip" dependsOn(prepareModuleFilesTask)
)
archiveFileName.set(zipFileName)
destinationDirectory.set(project.rootDir.resolve("out")) destinationDirectory.set(project.rootDir.resolve("out"))
from(tempModuleDir) from(tempModuleDir) // Zip the entire contents of the staging directory.
} }
val pushTask = // Task 3: A helper function to create installation tasks for different root providers.
tasks.register<Exec>("push${capitalized}") { fun createInstallTasks(rootProvider: String, installCli: String) {
group = "TEESimulator Module Installation" val pushTask =
dependsOn(zipTask) tasks.register<Exec>("push${rootProvider}Module${capitalized}") {
commandLine( group = "TEESimulator Module Installation"
"adb", description =
"push", "Pushes the ${variant.name} module to the device for $rootProvider."
zipTask.get().archiveFile.get().asFile, dependsOn(zipTask)
"/data/local/tmp", commandLine(
) "adb",
description = "Pushes the $variantName module zip to the device." "push",
} zipTask.get().archiveFile.get().asFile,
"/data/local/tmp",
)
}
// --- Magisk Install Tasks --- val installTask =
val installMagiskTask = tasks.register<Exec>("install${rootProvider}${capitalized}") {
tasks.register<Exec>("installMagisk${capitalized}") { group = "TEESimulator Module Installation"
description = "Installs the ${variant.name} module via $rootProvider."
dependsOn(pushTask)
commandLine(
"adb",
"shell",
"su",
"-c",
"$installCli /data/local/tmp/$zipFileName",
)
}
tasks.register<Exec>("install${rootProvider}AndReboot${capitalized}") {
group = "TEESimulator Module Installation" group = "TEESimulator Module Installation"
dependsOn(pushTask) description = "Installs the ${variant.name} module via $rootProvider and reboots."
commandLine( dependsOn(installTask)
"adb", commandLine("adb", "reboot")
"shell",
"su",
"-c",
"magisk --install-module /data/local/tmp/${zipTask.get().archiveFileName.get()}",
)
description = "Installs the $variantName module via Magisk."
} }
tasks.register<Exec>("installMagiskAndReboot${capitalized}") {
group = "TEESimulator Module Installation"
dependsOn(installMagiskTask)
commandLine("adb", "reboot")
description = "Installs the $variantName module via Magisk and reboots."
} }
// --- KernelSU Install Tasks --- createInstallTasks("Magisk", "magisk --install-module")
val installKsuTask = createInstallTasks("Ksu", "ksud module install")
tasks.register<Exec>("installKsu${capitalized}") { createInstallTasks("Apatch", "/data/adb/apd module install")
group = "TEESimulator Module Installation"
dependsOn(pushTask)
commandLine(
"adb",
"shell",
"su",
"-c",
"ksud module install /data/local/tmp/${zipTask.get().archiveFileName.get()}",
)
description = "Installs the $variantName module via KernelSU."
}
tasks.register<Exec>("installKsuAndReboot${capitalized}") {
group = "TEESimulator Module Installation"
dependsOn(installKsuTask)
commandLine("adb", "reboot")
description = "Installs the $variantName module via KernelSU and reboots."
}
// --- APatch Install Tasks ---
val installApatchTask =
tasks.register<Exec>("installApatch${capitalized}") {
group = "TEESimulator Module Installation"
dependsOn(pushTask)
commandLine(
"adb",
"shell",
"su",
"-c",
"/data/adb/apd module install /data/local/tmp/${zipTask.get().archiveFileName.get()}",
)
description = "Installs the $variantName module via APatch."
}
tasks.register<Exec>("installApatchAndReboot${capitalized}") {
group = "TEESimulator Module Installation"
dependsOn(installApatchTask)
commandLine("adb", "reboot")
description = "Installs the $variantName module via APatch and reboots."
}
tasks["assemble${capitalized}"].finalizedBy("zip${capitalized}")
} }
} }
@@ -110,8 +110,8 @@ object AttestUtils {
val keyDescriptionSeq = ASN1Sequence.getInstance(ext.extnValue.octets) val keyDescriptionSeq = ASN1Sequence.getInstance(ext.extnValue.octets)
val encodables = keyDescriptionSeq.toArray() val encodables = keyDescriptionSeq.toArray()
val attestVersion = ASN1Integer.getInstance(encodables[0]).value.intValueExact() val attestVersion = ASN1Integer.getInstance(encodables[0]).value.toInt()
val keymasterVersion = ASN1Integer.getInstance(encodables[2]).value.intValueExact() val keymasterVersion = ASN1Integer.getInstance(encodables[2]).value.toInt()
var attestVerifiedBootHash: ByteArray? = null var attestVerifiedBootHash: ByteArray? = null
var attestOSVersion: Int? = null var attestOSVersion: Int? = null
@@ -132,7 +132,7 @@ object AttestUtils {
attestOSVersion = attestOSVersion =
ASN1Integer.getInstance(tagged.baseObject.toASN1Primitive()) ASN1Integer.getInstance(tagged.baseObject.toASN1Primitive())
.value .value
.intValueExact() .toInt()
} }
} }
} }
+2 -2
View File
@@ -1,8 +1,8 @@
[versions] [versions]
agp = "8.13.0" agp = "8.13.0"
annotation = "1.9.1" annotation = "1.9.1"
jdk18on = "1.81" jdk18on = "1.82"
kotlin = "2.2.10" kotlin = "2.2.21"
libcxx = "28.1.13356709" libcxx = "28.1.13356709"
ktfmt = "0.25.0" ktfmt = "0.25.0"
+2 -2
View File
@@ -1,7 +1,7 @@
id=tricky_store id=tricky_store
name=TEESimulator name=TEESimulator
version=REPLACEMEVER version=${REPLACEMEVER}
versionCode=REPLACEMEVERCODE versionCode=${REPLACEMEVERCODE}
author=JingMatrix, beakthoven author=JingMatrix, beakthoven
description=Software simulation for Android hardware-backed key pairs with key attestation description=Software simulation for Android hardware-backed key pairs with key attestation
updateJson=https://raw.githubusercontent.com/JingMatrix/TEESimulator/main/update.json updateJson=https://raw.githubusercontent.com/JingMatrix/TEESimulator/main/update.json