diff --git a/app/build.gradle.kts b/app/build.gradle.kts index bb4a05a8f..e9b963d65 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -39,11 +39,6 @@ android { dataBinding = true } - dependenciesInfo { - includeInApk = false - includeInBundle = false - } - packagingOptions { resources { excludes += "/META-INF/*" diff --git a/buildSrc/src/main/java/Codegen.kt b/buildSrc/src/main/java/Codegen.kt index 6e5a4bd12..2d806fe78 100644 --- a/buildSrc/src/main/java/Codegen.kt +++ b/buildSrc/src/main/java/Codegen.kt @@ -1,11 +1,9 @@ - import java.io.ByteArrayOutputStream import java.io.File -import java.io.FileInputStream +import java.io.InputStream import java.io.PrintStream import java.security.SecureRandom import java.util.* -import java.util.zip.GZIPOutputStream import javax.crypto.Cipher import javax.crypto.CipherOutputStream import javax.crypto.spec.IvParameterSpec @@ -54,7 +52,7 @@ private fun chain(vararg iters: Iterable) = sequence { private fun PrintStream.byteField(name: String, bytes: ByteArray) { println("public static byte[] $name() {") print("byte[] buf = {") - print(bytes.joinToString(",") { "(byte)(${it.toInt() and 0xff})" }) + print(bytes.joinToString(",") { it.toString() }) println("};") println("return buf;") println("}") @@ -192,10 +190,8 @@ fun genStubManifest(srcDir: File, outDir: File): String { names.addAll(c3.subList(0, 10)) names.shuffle(RANDOM) - // Decapitalize as older Android versions do not allow capitalized package names // Distinct by lower case to support case insensitive file systems - val pkgNames = names.map { it.decapitalize(Locale.ROOT) } - .distinctBy { it.toLowerCase(Locale.ROOT) } + val pkgNames = names.distinctBy { it.toLowerCase(Locale.ROOT) } var idx = 0 fun genCmpName() = "${pkgNames[idx++]}.${names.random(kRANDOM)}" @@ -247,15 +243,8 @@ fun genStubManifest(srcDir: File, outDir: File): String { return genXml } -fun genEncryptedResources(res: File, outDir: File) { +fun genEncryptedResources(res: InputStream, outDir: File) { val mainPkgDir = File(outDir, "com/topjohnwu/magisk") - // Rename R.java - val r = File(mainPkgDir, "R.java").let { - val txt = it.readText() - it.delete() - txt - } - File(mainPkgDir, "R2.java").writeText(r.replace("class R", "class R2")) // Generate iv and key val iv = ByteArray(16) @@ -267,9 +256,8 @@ fun genEncryptedResources(res: File, outDir: File) { cipher.init(Cipher.ENCRYPT_MODE, SecretKeySpec(key, "AES"), IvParameterSpec(iv)) val bos = ByteArrayOutputStream() - FileInputStream(res).use { - // First compress, then encrypt - GZIPOutputStream(CipherOutputStream(bos, cipher)).use { os -> + res.use { + CipherOutputStream(bos, cipher).use { os -> it.transferTo(os) } } diff --git a/buildSrc/src/main/java/Setup.kt b/buildSrc/src/main/java/Setup.kt index 88570b530..75e623323 100644 --- a/buildSrc/src/main/java/Setup.kt +++ b/buildSrc/src/main/java/Setup.kt @@ -1,30 +1,30 @@ - import com.android.build.gradle.BaseExtension import com.android.build.gradle.internal.dsl.BaseAppModuleExtension import org.apache.tools.ant.filters.FixCrLfFilter import org.gradle.api.Action -import org.gradle.api.DefaultTask import org.gradle.api.JavaVersion import org.gradle.api.Project import org.gradle.api.tasks.StopExecutionException import org.gradle.api.tasks.Sync -import org.gradle.internal.os.OperatingSystem import org.gradle.kotlin.dsl.filter -import org.gradle.kotlin.dsl.named -import java.io.File -import java.io.OutputStream -import java.io.PrintStream -import java.nio.file.Paths +import java.io.* import java.util.* +import java.util.zip.Deflater +import java.util.zip.ZipEntry +import java.util.zip.ZipFile +import java.util.zip.ZipOutputStream -private fun Project.android(configure: Action) = +private fun Project.androidBase(configure: Action) = extensions.configure("android", configure) -private val Project.android: BaseAppModuleExtension get() = - extensions.getByName("android") as BaseAppModuleExtension +private fun Project.android(configure: Action) = + extensions.configure("android", configure) + +private val Project.android: BaseAppModuleExtension + get() = extensions.getByName("android") as BaseAppModuleExtension fun Project.setupCommon() { - android { + androidBase { compileSdkVersion(31) buildToolsVersion = "31.0.0" ndkPath = "${System.getenv("ANDROID_SDK_ROOT")}/ndk/magisk" @@ -69,9 +69,13 @@ private fun Project.setupAppCommon() { } } - lintOptions { + lint { disable += "MissingTranslation" } + + dependenciesInfo { + includeInApk = false + } } } @@ -147,11 +151,9 @@ fun Project.setupApp() { } } - tasks.named("preBuild") { - dependsOn(syncResources) - } - android.applicationVariants.all { + preBuildProvider.get().dependsOn(syncResources) + val keysDir = rootProject.file("tools/keys") val outSrcDir = File(buildDir, "generated/source/keydata/$name") val outSrc = File(outSrcDir, "com/topjohnwu/magisk/signing/KeyData.java") @@ -170,91 +172,67 @@ fun Project.setupApp() { fun Project.setupStub() { setupAppCommon() - // Make sure we have a working manifest while building - val ensureManifest = tasks.register("ensureManifest") { - val manifest = file("src/main/AndroidManifest.xml") - if (!manifest.exists()) { - PrintStream(manifest).use { - it.println("") - } - } - } - - tasks.named("preBuild") { - dependsOn(ensureManifest) - } - android.applicationVariants.all { - val manifest = file("src/main/AndroidManifest.xml") - val outSrcDir = File(buildDir, "generated/source/obfuscate/$name") + val variantCapped = name.capitalize(Locale.ROOT) + val variantLowered = name.toLowerCase(Locale.ROOT) + val manifest = file("src/${variantLowered}/AndroidManifest.xml") + val outSrcDir = File(buildDir, "generated/source/obfuscate/${variantLowered}") val templateDir = file("template") - val resDir = file("res") + val aapt = File(android.sdkDirectory, "build-tools/${android.buildToolsVersion}/aapt2") + val apk = File(buildDir, "intermediates/processed_res/" + + "${variantLowered}/out/resources-${variantLowered}.ap_") + val apkTmp = File("${apk}.tmp") - val androidJar = Paths.get(android.sdkDirectory.path, "platforms", - android.compileSdkVersion, "android.jar") - - val aaptCommand = if (OperatingSystem.current().isWindows) "aapt2.exe" else "aapt2" - val aapt = Paths.get(android.sdkDirectory.path, - "build-tools", android.buildToolsVersion, aaptCommand) - - val dummy = object : OutputStream() { - override fun write(b: Int) {} - override fun write(bytes: ByteArray, off: Int, len: Int) {} - } - - val genSrcTask = tasks.register("generate${name.capitalize(Locale.ROOT)}ObfuscatedSources") { + val genManifestTask = tasks.register("generate${variantCapped}ObfuscatedManifest") { doLast { val xml = genStubManifest(templateDir, outSrcDir) + manifest.parentFile.mkdirs() PrintStream(manifest).use { it.print(xml) } + } + } + mergeResourcesProvider.get().dependsOn(genManifestTask) - val compileTmp = File.createTempFile("tmp", ".zip") - val linkTmp = File.createTempFile("tmp", ".zip") - val optTmp = File.createTempFile("tmp", ".zip") - val stubXml = File.createTempFile("tmp", ".xml") - try { - PrintStream(stubXml).use { - it.println("") - } - - exec { - commandLine(aapt, "compile", - "-o", compileTmp, - "--dir", resDir) - standardOutput = dummy - errorOutput = dummy - } - - exec { - commandLine(aapt, "link", - "-o", linkTmp, - "-I", androidJar, - "--min-sdk-version", android.defaultConfig.minSdk, - "--target-sdk-version", android.defaultConfig.targetSdk, - "--manifest", stubXml, - "--java", outSrcDir, compileTmp) - standardOutput = dummy - errorOutput = dummy - } - - exec { - commandLine(aapt, "optimize", - "-o", optTmp, - "--collapse-resource-names", linkTmp) - standardOutput = dummy - errorOutput = dummy - } - - genEncryptedResources(optTmp, outSrcDir) - } finally { - compileTmp.delete() - linkTmp.delete() - optTmp.delete() - stubXml.delete() + val genSrcTask = tasks.register("generate${variantCapped}ObfuscatedSources") { + dependsOn(":stub:process${variantCapped}Resources") + doLast { + exec { + commandLine(aapt, "optimize", "-o", apkTmp, "--collapse-resource-names", apk) } + + val buffer = ByteArrayOutputStream(apk.length().toInt()) + val newApk = ZipOutputStream(FileOutputStream(apk)) + ZipFile(apkTmp).use { + newApk.use { new -> + new.setLevel(Deflater.BEST_COMPRESSION) + new.putNextEntry(ZipEntry("AndroidManifest.xml")) + it.getInputStream(it.getEntry("AndroidManifest.xml")).transferTo(new) + new.closeEntry() + new.finish() + } + ZipOutputStream(buffer).use { arsc -> + arsc.setLevel(Deflater.BEST_COMPRESSION) + arsc.putNextEntry(ZipEntry("resources.arsc")) + it.getInputStream(it.getEntry("resources.arsc")).transferTo(arsc) + arsc.closeEntry() + arsc.finish() + } + } + apkTmp.delete() + genEncryptedResources(ByteArrayInputStream(buffer.toByteArray()), outSrcDir) } } registerJavaGeneratingTask(genSrcTask, outSrcDir) } + // Override optimizeReleaseResources task + tasks.whenTaskAdded { + val apk = File(buildDir, "intermediates/processed_res/" + + "release/out/resources-release.ap_") + val optRes = File(buildDir, "intermediates/optimized_processed_res/" + + "release/resources-release-optimize.ap_") + if (name == "optimizeReleaseResources") { + doLast { apk.copyTo(optRes, true) } + } + } } diff --git a/stub/.gitignore b/stub/.gitignore index fa72e45ca..96c96e110 100644 --- a/stub/.gitignore +++ b/stub/.gitignore @@ -1,2 +1,3 @@ /build -/src/main/AndroidManifest.xml +/src/release/AndroidManifest.xml +/src/debug/AndroidManifest.xml diff --git a/stub/build.gradle.kts b/stub/build.gradle.kts index 94f9b567f..93723bf46 100644 --- a/stub/build.gradle.kts +++ b/stub/build.gradle.kts @@ -29,11 +29,6 @@ android { proguardFiles("proguard-rules.pro") } } - - dependenciesInfo { - includeInApk = false - includeInBundle = false - } } setupStub() diff --git a/stub/src/main/AndroidManifest.xml b/stub/src/main/AndroidManifest.xml new file mode 100644 index 000000000..7d5e790bd --- /dev/null +++ b/stub/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/stub/src/main/java/com/topjohnwu/magisk/DownloadActivity.java b/stub/src/main/java/com/topjohnwu/magisk/DownloadActivity.java index e2ff4e5e1..6c033d076 100644 --- a/stub/src/main/java/com/topjohnwu/magisk/DownloadActivity.java +++ b/stub/src/main/java/com/topjohnwu/magisk/DownloadActivity.java @@ -3,10 +3,10 @@ package com.topjohnwu.magisk; import static android.R.string.no; import static android.R.string.ok; import static android.R.string.yes; -import static com.topjohnwu.magisk.R2.string.dling; -import static com.topjohnwu.magisk.R2.string.no_internet_msg; -import static com.topjohnwu.magisk.R2.string.relaunch_app; -import static com.topjohnwu.magisk.R2.string.upgrade_msg; +import static com.topjohnwu.magisk.R.string.dling; +import static com.topjohnwu.magisk.R.string.no_internet_msg; +import static com.topjohnwu.magisk.R.string.relaunch_app; +import static com.topjohnwu.magisk.R.string.upgrade_msg; import android.app.Activity; import android.app.AlertDialog; @@ -28,9 +28,6 @@ import org.json.JSONException; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileOutputStream; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.zip.GZIPInputStream; import javax.crypto.Cipher; import javax.crypto.CipherInputStream; @@ -140,10 +137,13 @@ public class DownloadActivity extends Activity { SecretKey key = new SecretKeySpec(Bytes.key(), "AES"); IvParameterSpec iv = new IvParameterSpec(Bytes.iv()); cipher.init(Cipher.DECRYPT_MODE, key, iv); - InputStream is = new CipherInputStream(new ByteArrayInputStream(Bytes.res()), cipher); - try (InputStream gzip = new GZIPInputStream(is); - OutputStream out = new FileOutputStream(apk)) { - APKInstall.transfer(gzip, out); + var is = new CipherInputStream(new ByteArrayInputStream(Bytes.res()), cipher); + var out = new FileOutputStream(apk); + try (is; out) { + byte[] buf = new byte[4096]; + for (int read; (read = is.read(buf)) >= 0;) { + out.write(buf, 0, read); + } } DynAPK.addAssetPath(getResources().getAssets(), apk.getPath()); } catch (Exception ignored) { diff --git a/stub/res/values-ar/strings.xml b/stub/src/main/res/values-ar/strings.xml similarity index 100% rename from stub/res/values-ar/strings.xml rename to stub/src/main/res/values-ar/strings.xml diff --git a/stub/res/values-az/strings.xml b/stub/src/main/res/values-az/strings.xml similarity index 100% rename from stub/res/values-az/strings.xml rename to stub/src/main/res/values-az/strings.xml diff --git a/stub/res/values-be/strings.xml b/stub/src/main/res/values-be/strings.xml similarity index 100% rename from stub/res/values-be/strings.xml rename to stub/src/main/res/values-be/strings.xml diff --git a/stub/res/values-bg/strings.xml b/stub/src/main/res/values-bg/strings.xml similarity index 100% rename from stub/res/values-bg/strings.xml rename to stub/src/main/res/values-bg/strings.xml diff --git a/stub/res/values-ca/strings.xml b/stub/src/main/res/values-ca/strings.xml similarity index 100% rename from stub/res/values-ca/strings.xml rename to stub/src/main/res/values-ca/strings.xml diff --git a/stub/res/values-cs/strings.xml b/stub/src/main/res/values-cs/strings.xml similarity index 100% rename from stub/res/values-cs/strings.xml rename to stub/src/main/res/values-cs/strings.xml diff --git a/stub/res/values-de/strings.xml b/stub/src/main/res/values-de/strings.xml similarity index 100% rename from stub/res/values-de/strings.xml rename to stub/src/main/res/values-de/strings.xml diff --git a/stub/res/values-el/strings.xml b/stub/src/main/res/values-el/strings.xml similarity index 100% rename from stub/res/values-el/strings.xml rename to stub/src/main/res/values-el/strings.xml diff --git a/stub/res/values-es/strings.xml b/stub/src/main/res/values-es/strings.xml similarity index 100% rename from stub/res/values-es/strings.xml rename to stub/src/main/res/values-es/strings.xml diff --git a/stub/res/values-et/strings.xml b/stub/src/main/res/values-et/strings.xml similarity index 100% rename from stub/res/values-et/strings.xml rename to stub/src/main/res/values-et/strings.xml diff --git a/stub/res/values-fa/strings.xml b/stub/src/main/res/values-fa/strings.xml similarity index 100% rename from stub/res/values-fa/strings.xml rename to stub/src/main/res/values-fa/strings.xml diff --git a/stub/res/values-fr/strings.xml b/stub/src/main/res/values-fr/strings.xml similarity index 100% rename from stub/res/values-fr/strings.xml rename to stub/src/main/res/values-fr/strings.xml diff --git a/stub/res/values-hi/strings.xml b/stub/src/main/res/values-hi/strings.xml similarity index 100% rename from stub/res/values-hi/strings.xml rename to stub/src/main/res/values-hi/strings.xml diff --git a/stub/res/values-hr/strings.xml b/stub/src/main/res/values-hr/strings.xml similarity index 100% rename from stub/res/values-hr/strings.xml rename to stub/src/main/res/values-hr/strings.xml diff --git a/stub/res/values-in/strings.xml b/stub/src/main/res/values-in/strings.xml similarity index 100% rename from stub/res/values-in/strings.xml rename to stub/src/main/res/values-in/strings.xml diff --git a/stub/res/values-it/strings.xml b/stub/src/main/res/values-it/strings.xml similarity index 100% rename from stub/res/values-it/strings.xml rename to stub/src/main/res/values-it/strings.xml diff --git a/stub/res/values-iw/strings.xml b/stub/src/main/res/values-iw/strings.xml similarity index 100% rename from stub/res/values-iw/strings.xml rename to stub/src/main/res/values-iw/strings.xml diff --git a/stub/res/values-ja/strings.xml b/stub/src/main/res/values-ja/strings.xml similarity index 100% rename from stub/res/values-ja/strings.xml rename to stub/src/main/res/values-ja/strings.xml diff --git a/stub/res/values-ka/strings.xml b/stub/src/main/res/values-ka/strings.xml similarity index 100% rename from stub/res/values-ka/strings.xml rename to stub/src/main/res/values-ka/strings.xml diff --git a/stub/res/values-ko/strings.xml b/stub/src/main/res/values-ko/strings.xml similarity index 100% rename from stub/res/values-ko/strings.xml rename to stub/src/main/res/values-ko/strings.xml diff --git a/stub/res/values-lt/strings.xml b/stub/src/main/res/values-lt/strings.xml similarity index 100% rename from stub/res/values-lt/strings.xml rename to stub/src/main/res/values-lt/strings.xml diff --git a/stub/res/values-mk/strings.xml b/stub/src/main/res/values-mk/strings.xml similarity index 100% rename from stub/res/values-mk/strings.xml rename to stub/src/main/res/values-mk/strings.xml diff --git a/stub/res/values-nb/strings.xml b/stub/src/main/res/values-nb/strings.xml similarity index 100% rename from stub/res/values-nb/strings.xml rename to stub/src/main/res/values-nb/strings.xml diff --git a/stub/res/values-nl/strings.xml b/stub/src/main/res/values-nl/strings.xml similarity index 100% rename from stub/res/values-nl/strings.xml rename to stub/src/main/res/values-nl/strings.xml diff --git a/stub/res/values-pa/strings.xml b/stub/src/main/res/values-pa/strings.xml similarity index 100% rename from stub/res/values-pa/strings.xml rename to stub/src/main/res/values-pa/strings.xml diff --git a/stub/res/values-pl/strings.xml b/stub/src/main/res/values-pl/strings.xml similarity index 100% rename from stub/res/values-pl/strings.xml rename to stub/src/main/res/values-pl/strings.xml diff --git a/stub/res/values-pt-rBR/strings.xml b/stub/src/main/res/values-pt-rBR/strings.xml similarity index 100% rename from stub/res/values-pt-rBR/strings.xml rename to stub/src/main/res/values-pt-rBR/strings.xml diff --git a/stub/res/values-pt-rPT/strings.xml b/stub/src/main/res/values-pt-rPT/strings.xml similarity index 100% rename from stub/res/values-pt-rPT/strings.xml rename to stub/src/main/res/values-pt-rPT/strings.xml diff --git a/stub/res/values-ro/strings.xml b/stub/src/main/res/values-ro/strings.xml similarity index 100% rename from stub/res/values-ro/strings.xml rename to stub/src/main/res/values-ro/strings.xml diff --git a/stub/res/values-ru/strings.xml b/stub/src/main/res/values-ru/strings.xml similarity index 100% rename from stub/res/values-ru/strings.xml rename to stub/src/main/res/values-ru/strings.xml diff --git a/stub/res/values-sk/strings.xml b/stub/src/main/res/values-sk/strings.xml similarity index 100% rename from stub/res/values-sk/strings.xml rename to stub/src/main/res/values-sk/strings.xml diff --git a/stub/res/values-sq/strings.xml b/stub/src/main/res/values-sq/strings.xml similarity index 100% rename from stub/res/values-sq/strings.xml rename to stub/src/main/res/values-sq/strings.xml diff --git a/stub/res/values-sr/strings.xml b/stub/src/main/res/values-sr/strings.xml similarity index 100% rename from stub/res/values-sr/strings.xml rename to stub/src/main/res/values-sr/strings.xml diff --git a/stub/res/values-sv/strings.xml b/stub/src/main/res/values-sv/strings.xml similarity index 100% rename from stub/res/values-sv/strings.xml rename to stub/src/main/res/values-sv/strings.xml diff --git a/stub/res/values-ta/strings.xml b/stub/src/main/res/values-ta/strings.xml similarity index 100% rename from stub/res/values-ta/strings.xml rename to stub/src/main/res/values-ta/strings.xml diff --git a/stub/res/values-th/strings.xml b/stub/src/main/res/values-th/strings.xml similarity index 100% rename from stub/res/values-th/strings.xml rename to stub/src/main/res/values-th/strings.xml diff --git a/stub/res/values-tr/strings.xml b/stub/src/main/res/values-tr/strings.xml similarity index 100% rename from stub/res/values-tr/strings.xml rename to stub/src/main/res/values-tr/strings.xml diff --git a/stub/res/values-uk/strings.xml b/stub/src/main/res/values-uk/strings.xml similarity index 100% rename from stub/res/values-uk/strings.xml rename to stub/src/main/res/values-uk/strings.xml diff --git a/stub/res/values-vi/strings.xml b/stub/src/main/res/values-vi/strings.xml similarity index 100% rename from stub/res/values-vi/strings.xml rename to stub/src/main/res/values-vi/strings.xml diff --git a/stub/res/values-zh-rCN/strings.xml b/stub/src/main/res/values-zh-rCN/strings.xml similarity index 100% rename from stub/res/values-zh-rCN/strings.xml rename to stub/src/main/res/values-zh-rCN/strings.xml diff --git a/stub/res/values-zh-rTW/strings.xml b/stub/src/main/res/values-zh-rTW/strings.xml similarity index 100% rename from stub/res/values-zh-rTW/strings.xml rename to stub/src/main/res/values-zh-rTW/strings.xml diff --git a/stub/res/values/strings.xml b/stub/src/main/res/values/strings.xml similarity index 100% rename from stub/res/values/strings.xml rename to stub/src/main/res/values/strings.xml