From 27f6f1bf4a92ecef5c5b605fd5e3221e34116e8e Mon Sep 17 00:00:00 2001 From: Aitor Camacho Date: Tue, 3 Jan 2023 19:25:23 +0100 Subject: [PATCH] Update scripts for Android build - Use d8 instead of dx due to deprecation - Use apksigner instead of jarsigner for signature scheme v2 required by newer SDKs - Move apk signing to be last step (required for signature scheme v2) - Force uncompressed arsc files (required for SDK versions 30 and up) - Add '--tool-api' argument for selecting build tools version - Add permission for reading external storage in manifest VK-GL-CTS Issue: 4163 Components: Framework Change-Id: Iea4429f861148168ffe680cdf9a497cb467b8d6a --- android/package/AndroidManifest.xml | 1 + external/vulkancts/README.md | 4 +- scripts/android/build_apk.py | 113 +++++++++++++++++++++++------------- 3 files changed, 77 insertions(+), 41 deletions(-) diff --git a/android/package/AndroidManifest.xml b/android/package/AndroidManifest.xml index 53b1108..ddd8919 100644 --- a/android/package/AndroidManifest.xml +++ b/android/package/AndroidManifest.xml @@ -35,6 +35,7 @@ + diff --git a/external/vulkancts/README.md b/external/vulkancts/README.md index 1ba58f6..b66b139 100644 --- a/external/vulkancts/README.md +++ b/external/vulkancts/README.md @@ -224,7 +224,9 @@ Test log will be written into TestResults.qpa ### Android - adb push /external/vulkancts/mustpass/master/vk-default.txt /sdcard/vk-default.txt +For Android build using SDK 29 or greater, it is recommended to use `/sdcard/Documents/` instead of `/sdcard/` due to scoped storage. + + adb push /external/vulkancts/mustpass/main/vk-default.txt /sdcard/vk-default.txt adb shell In device shell: diff --git a/scripts/android/build_apk.py b/scripts/android/build_apk.py index cad3269..b39d4b7 100644 --- a/scripts/android/build_apk.py +++ b/scripts/android/build_apk.py @@ -44,38 +44,40 @@ from build.config import * from build.build import * class SDKEnv: - def __init__(self, path): + def __init__(self, path, desired_version): self.path = path - self.buildToolsVersion = SDKEnv.selectBuildToolsVersion(self.path) + self.buildToolsVersion = SDKEnv.selectBuildToolsVersion(self.path, desired_version) @staticmethod def getBuildToolsVersions (path): buildToolsPath = os.path.join(path, "build-tools") - versions = [] + versions = {} if os.path.exists(buildToolsPath): for item in os.listdir(buildToolsPath): m = re.match(r'^([0-9]+)\.([0-9]+)\.([0-9]+)$', item) if m != None: - versions.append((int(m.group(1)), int(m.group(2)), int(m.group(3)))) + versions[int(m.group(1))] = (int(m.group(1)), int(m.group(2)), int(m.group(3))) return versions @staticmethod - def selectBuildToolsVersion (path): - preferred = [(25, 0, 2)] + def selectBuildToolsVersion (path, preferred): versions = SDKEnv.getBuildToolsVersions(path) if len(versions) == 0: return (0,0,0) - for candidate in preferred: - if candidate in versions: - return candidate + if preferred == -1: + return max(versions.values()) + + if preferred in versions: + return versions[preferred] # Pick newest - versions.sort() - return versions[-1] + newest_version = max(versions.values()) + print("Couldn't find Android Tool version %d, %d was selected." % (preferred, newest_version[0])) + return newest_version def getPlatformLibrary (self, apiVersion): return os.path.join(self.path, "platforms", "android-%d" % apiVersion, "android.jar") @@ -169,19 +171,20 @@ class Environment: self.ndk = ndk class Configuration: - def __init__(self, env, buildPath, abis, nativeApi, minApi, nativeBuildType, gtfTarget, verbose, layers, angle): + def __init__(self, env, buildPath, abis, nativeApi, javaApi, minApi, nativeBuildType, gtfTarget, verbose, layers, angle): self.env = env self.sourcePath = DEQP_DIR self.buildPath = buildPath self.abis = abis self.nativeApi = nativeApi - self.javaApi = 28 + self.javaApi = javaApi self.minApi = minApi self.nativeBuildType = nativeBuildType self.gtfTarget = gtfTarget self.verbose = verbose self.layers = layers self.angle = angle + self.dCompilerName = "d8" self.cmakeGenerator = selectFirstAvailableGenerator([NINJA_GENERATOR, MAKEFILE_GENERATOR, NMAKE_GENERATOR]) def check (self): @@ -203,12 +206,20 @@ class Configuration: if self.env.sdk.buildToolsVersion == (0,0,0): raise Exception("No build tools directory found at %s" % os.path.join(self.env.sdk.path, "build-tools")) - androidBuildTools = ["aapt", "zipalign", "dx"] + if not os.path.exists(os.path.join(self.env.sdk.path, "platforms", "android-%d" % self.javaApi)): + raise Exception("No SDK with api version %d directory found at %s for Java Api" % (self.javaApi, os.path.join(self.env.sdk.path, "platforms"))) + + # Try to find first d8 since dx was deprecated + if which(self.dCompilerName, [self.env.sdk.getBuildToolsPath()]) == None: + print("Couldn't find %s, will try to find dx", self.dCompilerName) + self.dCompilerName = "dx" + + androidBuildTools = ["aapt", "zipalign", "apksigner", self.dCompilerName] for tool in androidBuildTools: if which(tool, [self.env.sdk.getBuildToolsPath()]) == None: - raise Exception("Missing Android build tool: %s" % tool) + raise Exception("Missing Android build tool: %s in %s" % (tool, self.env.sdk.getBuildToolsPath())) - requiredToolsInPath = ["javac", "jar", "jarsigner", "keytool"] + requiredToolsInPath = ["javac", "jar", "keytool"] for tool in requiredToolsInPath: if which(tool) == None: raise Exception("%s not in PATH" % tool) @@ -426,6 +437,9 @@ class PackageDescription: def getClassesJarPath (self): return [BuildRoot(), self.appDirName, "bin", "classes.jar"] + def getClassesDexDirectory (self): + return [BuildRoot(), self.appDirName, "bin",] + def getClassesDexPath (self): return [BuildRoot(), self.appDirName, "bin", "classes.dex"] @@ -549,19 +563,23 @@ class BuildDex (BuildStep): return [self.package.getClassesDexPath()] def update (self, config): - dxPath = which("dx", [config.env.sdk.getBuildToolsPath()]) - srcPaths = resolvePaths(config, self.getInputs()) - dexPath = resolvePath(config, self.package.getClassesDexPath()) + dxPath = which(config.dCompilerName, [config.env.sdk.getBuildToolsPath()]) + dexPath = resolvePath(config, self.package.getClassesDexDirectory()) jarPaths = [resolvePath(config, self.package.getClassesJarPath())] for lib in self.libraries: jarPaths.append(resolvePath(config, lib.getClassesJarPath())) - executeAndLog(config, [ - dxPath, - "--dex", - "--output", dexPath - ] + jarPaths) + args = [ dxPath ] + if config.dCompilerName == "d8": + args.append("--lib") + args.append(config.env.sdk.getPlatformLibrary(config.javaApi)) + else: + args.append("--dex") + args.append("--output") + args.append(dexPath) + + executeAndLog(config, args + jarPaths) class CreateKeystore (BuildStep): def __init__ (self): @@ -576,7 +594,7 @@ class CreateKeystore (BuildStep): def update (self, config): executeAndLog(config, [ "keytool", - "-genkey", + "-genkeypair", "-keystore", resolvePath(config, self.keystorePath), "-storepass", "android", "-alias", "androiddebugkey", @@ -623,6 +641,7 @@ class BuildBaseAPK (BuildStep): "-M", resolvePath(config, self.package.getManifestPath()), "-I", config.env.sdk.getPlatformLibrary(config.javaApi), "-F", dstPath, + "-0", "arsc" # arsc files need to be uncompressed for SDK version 30 and up ] for resPath in self.getResPaths(): @@ -777,8 +796,8 @@ class AddNativeLibsToAPK (BuildStep): class SignAPK (BuildStep): def __init__ (self, package): self.package = package - self.srcPath = AddNativeLibsToAPK(self.package, []).getOutputs()[0] - self.dstPath = [BuildRoot(), self.package.getAppDirName(), "tmp", "signed.apk"] + self.srcPath = AlignAPK(self.package).getOutputs()[0] + self.dstPath = [BuildRoot(), getBuildRootRelativeAPKPath(self.package)] self.keystorePath = CreateKeystore().getOutputs()[0] def getInputs (self): @@ -788,27 +807,31 @@ class SignAPK (BuildStep): return [self.dstPath] def update (self, config): + apksigner = which("apksigner", [config.env.sdk.getBuildToolsPath()]) srcPath = resolvePath(config, self.srcPath) dstPath = resolvePath(config, self.dstPath) executeAndLog(config, [ - "jarsigner", - "-keystore", resolvePath(config, self.keystorePath), - "-storepass", "android", - "-keypass", "android", - "-signedjar", dstPath, - srcPath, - "androiddebugkey" + apksigner, + "sign", + "--ks", resolvePath(config, self.keystorePath), + "--ks-key-alias", "androiddebugkey", + "--ks-pass", "pass:android", + "--key-pass", "pass:android", + "--min-sdk-version", str(config.minApi), + "--max-sdk-version", str(config.javaApi), + "--out", dstPath, + srcPath ]) def getBuildRootRelativeAPKPath (package): return os.path.join(package.getAppDirName(), package.getAppName() + ".apk") -class FinalizeAPK (BuildStep): +class AlignAPK (BuildStep): def __init__ (self, package): self.package = package - self.srcPath = SignAPK(self.package).getOutputs()[0] - self.dstPath = [BuildRoot(), getBuildRootRelativeAPKPath(self.package)] + self.srcPath = AddNativeLibsToAPK(self.package, []).getOutputs()[0] + self.dstPath = [BuildRoot(), self.package.getAppDirName(), "tmp", "aligned.apk"] self.keystorePath = CreateKeystore().getOutputs()[0] def getInputs (self): @@ -862,8 +885,8 @@ def getBuildStepsForPackage (abis, package, libraries = []): # Finalize APK steps.append(CreateKeystore()) + steps.append(AlignAPK(package)) steps.append(SignAPK(package)) - steps.append(FinalizeAPK(package)) return steps @@ -921,6 +944,16 @@ def parseArgs (): dest='nativeApi', default=28, help="Android API level to target in native code") + parser.add_argument('--java-api', + type=int, + dest='javaApi', + default=28, + help="Android API level to target in Java code") + parser.add_argument('--tool-api', + type=int, + dest='toolApi', + default=-1, + help="Android Tools level to target (-1 being maximum present)") parser.add_argument('--min-api', type=int, dest='minApi', @@ -990,10 +1023,10 @@ if __name__ == "__main__": args = parseArgs() ndk = NDKEnv(os.path.realpath(args.ndkPath)) - sdk = SDKEnv(os.path.realpath(args.sdkPath)) + sdk = SDKEnv(os.path.realpath(args.sdkPath), args.toolApi) buildPath = os.path.realpath(args.buildRoot) env = Environment(sdk, ndk) - config = Configuration(env, buildPath, abis=args.abis, nativeApi=args.nativeApi, minApi=args.minApi, nativeBuildType=args.nativeBuildType, gtfTarget=args.gtfTarget, + config = Configuration(env, buildPath, abis=args.abis, nativeApi=args.nativeApi, javaApi=args.javaApi, minApi=args.minApi, nativeBuildType=args.nativeBuildType, gtfTarget=args.gtfTarget, verbose=args.verbose, layers=args.layers, angle=args.angle) try: -- 2.7.4