mirror of
https://gitee.com/zhangsken/AndroidIDE.git
synced 2026-10-16 07:49:44 +08:00
build: verify aapt2 ABI before packaging in jniLibs
This commit is contained in:
@@ -19,6 +19,7 @@ package com.itsaky.androidide.plugins.tasks
|
||||
|
||||
import FDroidConfig
|
||||
import com.itsaky.androidide.plugins.util.DownloadUtils
|
||||
import com.itsaky.androidide.plugins.util.ELFUtils
|
||||
import isFDroidBuild
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
@@ -72,6 +73,7 @@ abstract class SetupAapt2Task : DefaultTask() {
|
||||
|
||||
logger.info("Copying $aapt2 to $file")
|
||||
aapt2.copyTo(file, overwrite = true)
|
||||
assertAapt2Arch(file, ELFUtils.ElfAbi.forName(arch)!!)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -83,6 +85,15 @@ abstract class SetupAapt2Task : DefaultTask() {
|
||||
|
||||
val remoteUrl = AAPT2_DOWNLOAD_URL.format(DEFAULT_VERSION, arch)
|
||||
DownloadUtils.doDownload(file, remoteUrl, checksum, logger)
|
||||
logger.lifecycle("aapt2 arch: $arch")
|
||||
assertAapt2Arch(file, ELFUtils.ElfAbi.forName(arch)!!)
|
||||
}
|
||||
}
|
||||
|
||||
private fun assertAapt2Arch(aapt2: File, elfAbi: ELFUtils.ElfAbi) {
|
||||
val fileAbi = ELFUtils.getElfAbi(aapt2)
|
||||
check(fileAbi == elfAbi) {
|
||||
"Mismatched ABI for aapt2 binary. Required $elfAbi but found $fileAbi"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.plugins.util
|
||||
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
|
||||
/**
|
||||
* Utility methods for working with ELF binaries.
|
||||
*
|
||||
* @author Akash Yadav
|
||||
* @see <a href="https://en.wikipedia.org/wiki/Executable_and_Linkable_Format">Executable and Linkable Format</a>
|
||||
*/
|
||||
object ELFUtils {
|
||||
|
||||
/**
|
||||
* The magic number of an ELF binary.
|
||||
*/
|
||||
const val ELF_MAGIC_NUMBER: Int = 0x7F454C46
|
||||
|
||||
/**
|
||||
* 4-byte magic number of an ELF binary.
|
||||
*/
|
||||
val ELF_MAGIC_NUMBER_ARR = byteArrayOf(0x7F, 0x45, 0x4C, 0x46)
|
||||
|
||||
/**
|
||||
* `EI_OSABI` of an ELF binary. This enumeration only contains ABIs that are supported by AndroidIDE.
|
||||
*
|
||||
* @property abiName The name of CPU ABI.
|
||||
* @property abi The number representing the ABI (`e_machine`).
|
||||
*/
|
||||
enum class ElfAbi(val abiName: String, val abi: Byte) {
|
||||
ARMV7("armeabi-v7a", 0x28),
|
||||
AARCH64("arm64-v8a", 0xB7.toByte()),
|
||||
X86_64("x86_64", 0x3E);
|
||||
|
||||
companion object {
|
||||
fun forName(name: String) : ElfAbi? = ElfAbi.values().firstOrNull { it.abiName == name }
|
||||
fun forAbi(abi: Byte) : ElfAbi? = ElfAbi.values().firstOrNull { it.abi == abi }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the data in given input stream corresponds to an ELF binary.
|
||||
* This checks if the magic number (first 4 bytes) in the byte array is `0x7F454C46` i.e. `0x7F E L F`.
|
||||
*
|
||||
* @return `true` if the file is an ELF binary, `false` otherwise.
|
||||
*/
|
||||
fun isElf(bytes: ByteArray) : Boolean {
|
||||
if (bytes.size < 4) {
|
||||
return false
|
||||
}
|
||||
|
||||
for (i in 0..3) {
|
||||
if (bytes[i] != ELF_MAGIC_NUMBER_ARR[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the data in given input stream corresponds to an ELF binary.
|
||||
* This basically checks if the magic number in the input stream is `0x7F454C46` i.e. `0x7F E L F`.
|
||||
*
|
||||
* @return `true` if the file is an ELF binary, `false` otherwise.
|
||||
*/
|
||||
fun isElf(inputStream: InputStream) : Boolean {
|
||||
val bytes = ByteArray(4)
|
||||
val read = inputStream.read(bytes)
|
||||
if (read != 4) {
|
||||
return false
|
||||
}
|
||||
return isElf(inputStream.readNBytes(4))
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the given file is an ELF binary.
|
||||
*
|
||||
* @return `true` if the file is an ELF binary, `false` otherwise.
|
||||
*/
|
||||
fun isElf(file: File): Boolean {
|
||||
return file.inputStream().use { isElf(it) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the [ElfAbi] for the given file.
|
||||
*
|
||||
* @return The [ElfAbi] for the file, or `null` if the file is not an ELF binary.
|
||||
*/
|
||||
fun getElfAbi(file: File) : ElfAbi? {
|
||||
return file.inputStream().use { getElfAbi(it) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the [ElfAbi] from the given input stream.
|
||||
*
|
||||
* @return The [ElfAbi] for the input stream, or `null` if the input stream does not represent an ELF binary.
|
||||
*/
|
||||
fun getElfAbi(inputStream: InputStream) : ElfAbi? {
|
||||
val header = ByteArray(20)
|
||||
if (inputStream.read(header) < 20) {
|
||||
// incomplete data
|
||||
return null
|
||||
}
|
||||
|
||||
if (!isElf(header)) {
|
||||
// not an elf binary
|
||||
return null
|
||||
}
|
||||
|
||||
return ElfAbi.forAbi(header[18])
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user