mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-11-23 18:15:30 +00:00
Avoiding using shell I/O
This commit is contained in:
parent
6fb20b3ee5
commit
bec5edca84
@ -10,8 +10,9 @@ import androidx.multidex.MultiDex
|
||||
import androidx.work.WorkManager
|
||||
import com.topjohnwu.magisk.BuildConfig
|
||||
import com.topjohnwu.magisk.DynAPK
|
||||
import com.topjohnwu.magisk.core.utils.AppShellInit
|
||||
import com.topjohnwu.magisk.core.utils.BusyBoxInit
|
||||
import com.topjohnwu.magisk.core.utils.IODispatcherExecutor
|
||||
import com.topjohnwu.magisk.core.utils.RootInit
|
||||
import com.topjohnwu.magisk.core.utils.updateConfig
|
||||
import com.topjohnwu.magisk.di.koinModules
|
||||
import com.topjohnwu.magisk.ktx.unwrap
|
||||
@ -32,7 +33,7 @@ open class App() : Application() {
|
||||
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
|
||||
Shell.setDefaultBuilder(Shell.Builder.create()
|
||||
.setFlags(Shell.FLAG_MOUNT_MASTER)
|
||||
.setInitializers(RootInit::class.java)
|
||||
.setInitializers(BusyBoxInit::class.java, AppShellInit::class.java)
|
||||
.setTimeout(2))
|
||||
Shell.EXECUTOR = IODispatcherExecutor()
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.topjohnwu.magisk.core
|
||||
|
||||
import android.os.Build
|
||||
import androidx.databinding.ObservableBoolean
|
||||
import com.topjohnwu.magisk.DynAPK
|
||||
import com.topjohnwu.magisk.core.model.UpdateInfo
|
||||
@ -34,9 +35,10 @@ object Info {
|
||||
@JvmStatic val isFDE get() = crypto == "block"
|
||||
@JvmField var ramdisk = false
|
||||
@JvmField var hasGMS = true
|
||||
@JvmField var isPixel = false
|
||||
@JvmField val isPixel = Build.BRAND == "google"
|
||||
@JvmField val isEmulator = getProperty("ro.kernel.qemu", "0") == "1"
|
||||
var crypto = ""
|
||||
var noDataExec = false
|
||||
|
||||
val isConnected by lazy {
|
||||
ObservableBoolean(false).also { field ->
|
||||
|
@ -8,9 +8,9 @@ import androidx.core.os.postDelayed
|
||||
import com.topjohnwu.magisk.BuildConfig
|
||||
import com.topjohnwu.magisk.DynAPK
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.isRunningAsStub
|
||||
import com.topjohnwu.magisk.core.*
|
||||
import com.topjohnwu.magisk.core.utils.BusyBoxInit
|
||||
import com.topjohnwu.magisk.core.utils.LightShellInit
|
||||
import com.topjohnwu.magisk.core.utils.MediaStoreUtils
|
||||
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.inputStream
|
||||
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
|
||||
@ -27,8 +27,6 @@ import com.topjohnwu.superuser.ShellUtils
|
||||
import com.topjohnwu.superuser.internal.NOPList
|
||||
import com.topjohnwu.superuser.internal.UiThreadHandler
|
||||
import com.topjohnwu.superuser.io.SuFile
|
||||
import com.topjohnwu.superuser.io.SuFileInputStream
|
||||
import com.topjohnwu.superuser.io.SuFileOutputStream
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import net.jpountz.lz4.LZ4FrameInputStream
|
||||
@ -53,7 +51,9 @@ abstract class MagiskInstallImpl protected constructor(
|
||||
protected lateinit var installDir: File
|
||||
private lateinit var srcBoot: File
|
||||
|
||||
private var tarOut: TarOutputStream? = null
|
||||
private lateinit var shell: Shell
|
||||
private var closeShell = false
|
||||
|
||||
private val service: NetworkService by inject()
|
||||
protected val context: Context by inject(Protected)
|
||||
|
||||
@ -68,7 +68,7 @@ abstract class MagiskInstallImpl protected constructor(
|
||||
return true
|
||||
}
|
||||
|
||||
private fun findSecondaryImage(): Boolean {
|
||||
private fun findSecondary(): Boolean {
|
||||
val slot = "echo \$SLOT".fsh()
|
||||
val target = if (slot == "_a") "_b" else "_a"
|
||||
console.add("- Target slot: $target")
|
||||
@ -86,26 +86,13 @@ abstract class MagiskInstallImpl protected constructor(
|
||||
return true
|
||||
}
|
||||
|
||||
private fun installDirFile(name: String): File {
|
||||
return if (installDir is SuFile)
|
||||
SuFile(installDir, name)
|
||||
else
|
||||
File(installDir, name)
|
||||
}
|
||||
|
||||
private fun extractFiles(): Boolean {
|
||||
console.add("- Device platform: ${Const.CPU_ABI}")
|
||||
console.add("- Installing: ${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})")
|
||||
|
||||
val binDir = File(context.filesDir.parent, "install")
|
||||
binDir.deleteRecursively()
|
||||
binDir.mkdirs()
|
||||
|
||||
installDir = if (Shell.rootAccess()) {
|
||||
SuFile("${Const.TMPDIR}/install")
|
||||
} else {
|
||||
binDir
|
||||
}
|
||||
installDir = File(context.filesDir.parent, "install")
|
||||
installDir.deleteRecursively()
|
||||
installDir.mkdirs()
|
||||
|
||||
try {
|
||||
// Extract binaries
|
||||
@ -116,7 +103,7 @@ abstract class MagiskInstallImpl protected constructor(
|
||||
}.forEach {
|
||||
val n = it.name.substring(it.name.lastIndexOf('/') + 1)
|
||||
val name = n.substring(3, n.length - 3)
|
||||
val dest = File(binDir, name)
|
||||
val dest = File(installDir, name)
|
||||
zf.getInputStream(it).writeTo(dest)
|
||||
}
|
||||
} else {
|
||||
@ -125,21 +112,21 @@ abstract class MagiskInstallImpl protected constructor(
|
||||
} ?: emptyArray()
|
||||
for (lib in libs) {
|
||||
val name = lib.name.substring(3, lib.name.length - 3)
|
||||
val bin = File(binDir, name)
|
||||
val bin = File(installDir, name)
|
||||
symlink(lib.path, bin.path)
|
||||
}
|
||||
}
|
||||
|
||||
// Extract scripts
|
||||
for (script in listOf("util_functions.sh", "boot_patch.sh", "addon.d.sh")) {
|
||||
val dest = File(binDir, script)
|
||||
val dest = File(installDir, script)
|
||||
context.assets.open(script).writeTo(dest)
|
||||
}
|
||||
// Extract chromeos tools
|
||||
File(binDir, "chromeos").mkdir()
|
||||
File(installDir, "chromeos").mkdir()
|
||||
for (file in listOf("futility", "kernel_data_key.vbprivk", "kernel.keyblock")) {
|
||||
val name = "chromeos/$file"
|
||||
val dest = File(binDir, name)
|
||||
val dest = File(installDir, name)
|
||||
context.assets.open(name).writeTo(dest)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
@ -148,19 +135,10 @@ abstract class MagiskInstallImpl protected constructor(
|
||||
return false
|
||||
}
|
||||
|
||||
if (installDir !== binDir) {
|
||||
arrayOf(
|
||||
"rm -rf $installDir",
|
||||
"mkdir -p $installDir",
|
||||
"cp_readlink $binDir $installDir",
|
||||
"rm -rf $binDir"
|
||||
).sh()
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun newEntry(name: String, size: Long): TarEntry {
|
||||
private fun newTarEntry(name: String, size: Long): TarEntry {
|
||||
console.add("-- Writing: $name")
|
||||
return TarEntry(TarHeader.createHeader(name, size, 0, false, 420 /* 0644 */))
|
||||
}
|
||||
@ -172,8 +150,13 @@ abstract class MagiskInstallImpl protected constructor(
|
||||
TarInputStream(input).use { tarIn ->
|
||||
lateinit var entry: TarEntry
|
||||
|
||||
fun decompressedStream() =
|
||||
if (entry.name.endsWith(".lz4")) LZ4FrameInputStream(tarIn) else tarIn
|
||||
fun decompressedStream(): InputStream {
|
||||
val src = if (entry.name.endsWith(".lz4")) LZ4FrameInputStream(tarIn) else tarIn
|
||||
return object : FilterInputStream(src) {
|
||||
override fun available() = 0 /* Workaround bug in LZ4FrameInputStream */
|
||||
override fun close() { /* Never close src stream */ }
|
||||
}
|
||||
}
|
||||
|
||||
while (tarIn.nextEntry?.let { entry = it } != null) {
|
||||
if (entry.name.contains("boot.img") ||
|
||||
@ -181,15 +164,10 @@ abstract class MagiskInstallImpl protected constructor(
|
||||
val name = entry.name.replace(".lz4", "")
|
||||
console.add("-- Extracting: $name")
|
||||
|
||||
val extract = installDirFile(name)
|
||||
SuFileOutputStream(extract).use { decompressedStream().copyTo(it) }
|
||||
val extract = File(installDir, name)
|
||||
decompressedStream().writeTo(extract)
|
||||
} else if (entry.name.contains("vbmeta.img")) {
|
||||
// DO NOT USE readBytes() DUE TO BUG IN LZ4FrameInputStream
|
||||
val rawData = decompressedStream().run {
|
||||
val buffer = ByteArrayOutputStream()
|
||||
copyTo(buffer)
|
||||
buffer.toByteArray()
|
||||
}
|
||||
val rawData = decompressedStream().readBytes()
|
||||
// Valid vbmeta.img should be at least 256 bytes
|
||||
if (rawData.size < 256)
|
||||
continue
|
||||
@ -198,7 +176,7 @@ abstract class MagiskInstallImpl protected constructor(
|
||||
// AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED
|
||||
console.add("-- Patching: vbmeta.img")
|
||||
ByteBuffer.wrap(rawData).putInt(120, 3)
|
||||
tarOut.putNextEntry(newEntry("vbmeta.img", rawData.size.toLong()))
|
||||
tarOut.putNextEntry(newTarEntry("vbmeta.img", rawData.size.toLong()))
|
||||
tarOut.write(rawData)
|
||||
} else {
|
||||
console.add("-- Copying: ${entry.name}")
|
||||
@ -207,19 +185,21 @@ abstract class MagiskInstallImpl protected constructor(
|
||||
}
|
||||
}
|
||||
}
|
||||
val boot = installDirFile("boot.img")
|
||||
val recovery = installDirFile("recovery.img")
|
||||
val boot = File(installDir, "boot.img")
|
||||
val recovery = File(installDir, "recovery.img")
|
||||
if (Config.recovery && recovery.exists() && boot.exists()) {
|
||||
// Install Magisk to recovery
|
||||
// Install to recovery
|
||||
srcBoot = recovery
|
||||
// Repack boot image to prevent restore
|
||||
// Repack boot image to prevent auto restore
|
||||
arrayOf(
|
||||
"cd $installDir",
|
||||
"./magiskboot unpack boot.img",
|
||||
"./magiskboot repack boot.img",
|
||||
"./magiskboot cleanup",
|
||||
"mv new-boot.img boot.img").sh()
|
||||
SuFileInputStream(boot).use {
|
||||
tarOut.putNextEntry(newEntry("boot.img", boot.length()))
|
||||
"mv new-boot.img boot.img",
|
||||
"cd /").sh()
|
||||
boot.inputStream().use {
|
||||
tarOut.putNextEntry(newTarEntry("boot.img", boot.length()))
|
||||
it.copyTo(tarOut)
|
||||
}
|
||||
boot.delete()
|
||||
@ -263,9 +243,9 @@ abstract class MagiskInstallImpl protected constructor(
|
||||
handleTar(src, outFile!!.uri.outputStream())
|
||||
} else {
|
||||
// Raw image
|
||||
srcBoot = installDirFile("boot.img")
|
||||
srcBoot = File(installDir, "boot.img")
|
||||
console.add("- Copying image to cache")
|
||||
SuFileOutputStream(srcBoot).use { src.copyTo(it) }
|
||||
src.writeTo(srcBoot)
|
||||
outFile = MediaStoreUtils.getFile("$filename.img", true)
|
||||
outFile!!.uri.outputStream()
|
||||
}
|
||||
@ -285,12 +265,12 @@ abstract class MagiskInstallImpl protected constructor(
|
||||
|
||||
// Output file
|
||||
try {
|
||||
val patched = installDirFile("new-boot.img")
|
||||
val patched = File(installDir, "new-boot.img")
|
||||
if (outStream is TarOutputStream) {
|
||||
val name = if (srcBoot.path.contains("recovery")) "recovery.img" else "boot.img"
|
||||
outStream.putNextEntry(newEntry(name, patched.length()))
|
||||
outStream.putNextEntry(newTarEntry(name, patched.length()))
|
||||
}
|
||||
withStreams(SuFileInputStream(patched), outStream) { src, out -> src.copyTo(out) }
|
||||
withStreams(patched.inputStream(), outStream) { src, out -> src.copyTo(out) }
|
||||
patched.delete()
|
||||
|
||||
console.add("")
|
||||
@ -306,22 +286,56 @@ abstract class MagiskInstallImpl protected constructor(
|
||||
}
|
||||
|
||||
// Fix up binaries
|
||||
if (installDir is SuFile) {
|
||||
"fix_env $installDir".sh()
|
||||
} else {
|
||||
"cp_readlink $installDir".sh()
|
||||
}
|
||||
srcBoot.delete()
|
||||
"cp_readlink $installDir".sh()
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun rootInputStream(file: File): InputStream {
|
||||
return if (file is SuFile)
|
||||
object : BufferedInputStream(null) {
|
||||
private val tmp =
|
||||
File.createTempFile(file.name, null, context.cacheDir).also {
|
||||
// Copy to tmp file and read from there
|
||||
"cat $file > $it".sh()
|
||||
`in` = it.inputStream()
|
||||
}
|
||||
override fun close() {
|
||||
super.close()
|
||||
tmp.delete()
|
||||
}
|
||||
}
|
||||
else
|
||||
file.inputStream().buffered()
|
||||
}
|
||||
|
||||
private fun patchBoot(): Boolean {
|
||||
"cd $installDir".sh()
|
||||
val inRootDir = shell.isRoot && Info.noDataExec
|
||||
|
||||
val newBootImg: File
|
||||
if (inRootDir) {
|
||||
// Migrate everything to tmpfs to workaround Samsung bullshit
|
||||
SuFile("${Const.TMPDIR}/install").also {
|
||||
arrayOf(
|
||||
"rm -rf $it",
|
||||
"mkdir -p $it",
|
||||
"cp_readlink $installDir $it",
|
||||
"rm -rf $installDir"
|
||||
).sh()
|
||||
installDir = it
|
||||
}
|
||||
newBootImg = SuFile(installDir, "new-boot.img")
|
||||
} else {
|
||||
newBootImg = File(installDir, "new-boot.img")
|
||||
// Create the output file before hand
|
||||
newBootImg.createNewFile()
|
||||
}
|
||||
|
||||
var isSigned = false
|
||||
if (srcBoot.let { it !is SuFile || !it.isCharacter }) {
|
||||
try {
|
||||
SuFileInputStream(srcBoot).use {
|
||||
rootInputStream(srcBoot).use {
|
||||
if (SignBoot.verifySignature(it, null)) {
|
||||
isSigned = true
|
||||
console.add("- Boot image is signed with AVB 1.0")
|
||||
@ -333,90 +347,99 @@ abstract class MagiskInstallImpl protected constructor(
|
||||
}
|
||||
}
|
||||
|
||||
val FLAGS =
|
||||
val flags =
|
||||
"KEEPFORCEENCRYPT=${Config.keepEnc} " +
|
||||
"KEEPVERITY=${Config.keepVerity} " +
|
||||
"RECOVERYMODE=${Config.recovery}"
|
||||
|
||||
if (!"$FLAGS sh boot_patch.sh $srcBoot".sh().isSuccess)
|
||||
if (!"cd $installDir; $flags sh boot_patch.sh $srcBoot".sh().isSuccess)
|
||||
return false
|
||||
|
||||
val job = Shell.sh("./magiskboot cleanup", "cd /")
|
||||
val job = shell.newJob().add("./magiskboot cleanup", "cd /")
|
||||
|
||||
val patched = installDirFile("new-boot.img")
|
||||
if (isSigned) {
|
||||
console.add("- Signing boot image with verity keys")
|
||||
val signed = installDirFile("signed.img")
|
||||
val signed = File.createTempFile("signed", ".img", context.cacheDir)
|
||||
try {
|
||||
withStreams(SuFileInputStream(patched), SuFileOutputStream(signed)) {
|
||||
input, out -> SignBoot.doSignature(null, null, input, out, "/boot")
|
||||
withStreams(rootInputStream(newBootImg), signed.outputStream().buffered()) {
|
||||
src, out -> SignBoot.doSignature(null, null, src, out, "/boot")
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
console.add("! Unable to sign image")
|
||||
Timber.e(e)
|
||||
return false
|
||||
}
|
||||
|
||||
job.add("mv -f $signed $patched")
|
||||
if (inRootDir) {
|
||||
job.add("cp -f $signed $newBootImg", "rm -f $signed")
|
||||
} else {
|
||||
signed.copyTo(newBootImg, overwrite = true)
|
||||
signed.delete()
|
||||
}
|
||||
}
|
||||
job.exec()
|
||||
return true
|
||||
}
|
||||
|
||||
private fun flashBoot(): Boolean {
|
||||
if (!"direct_install $installDir $srcBoot".sh().isSuccess)
|
||||
return false
|
||||
arrayOf("run_migrations", "copy_sepolicy_rules").sh()
|
||||
return true
|
||||
}
|
||||
private fun flashBoot() = "direct_install $installDir $srcBoot".sh().isSuccess
|
||||
|
||||
private suspend fun postOTA(): Boolean {
|
||||
val bootctl = SuFile("/data/adb/bootctl")
|
||||
try {
|
||||
withStreams(service.fetchBootctl().byteStream(), SuFileOutputStream(bootctl)) {
|
||||
it, out -> it.copyTo(out)
|
||||
}
|
||||
val bootctl = File.createTempFile("bootctl", null, context.cacheDir)
|
||||
service.fetchBootctl().byteStream().writeTo(bootctl)
|
||||
"post_ota $bootctl".sh()
|
||||
} catch (e: IOException) {
|
||||
console.add("! Unable to download bootctl")
|
||||
Timber.e(e)
|
||||
return false
|
||||
}
|
||||
|
||||
"post_ota ${bootctl.parent}".sh()
|
||||
|
||||
console.add("***************************************")
|
||||
console.add(" Next reboot will boot to second slot!")
|
||||
console.add("***************************************")
|
||||
return true
|
||||
}
|
||||
|
||||
protected fun uninstall(): Boolean {
|
||||
val apk = if (isRunningAsStub) {
|
||||
DynAPK.current(context).path
|
||||
} else {
|
||||
context.packageCodePath
|
||||
private fun setupShell(forceNonRoot: Boolean = false): Boolean {
|
||||
shell = Shell.getShell()
|
||||
if (forceNonRoot && shell.isRoot) {
|
||||
shell = Shell.Builder.create()
|
||||
.setFlags(Shell.FLAG_NON_ROOT_SHELL)
|
||||
.setInitializers(BusyBoxInit::class.java, LightShellInit::class.java)
|
||||
.build()
|
||||
closeShell = true
|
||||
}
|
||||
return "run_uninstaller $apk".sh().isSuccess
|
||||
return true
|
||||
}
|
||||
|
||||
private fun String.sh() = Shell.sh(this).to(console, logs).exec()
|
||||
private fun Array<String>.sh() = Shell.sh(*this).to(console, logs).exec()
|
||||
private fun String.fsh() = ShellUtils.fastCmd(this)
|
||||
private fun Array<String>.fsh() = ShellUtils.fastCmd(*this)
|
||||
private fun String.sh() = shell.newJob().add(this).to(console, logs).exec()
|
||||
private fun Array<String>.sh() = shell.newJob().add(*this).to(console, logs).exec()
|
||||
private fun String.fsh() = ShellUtils.fastCmd(shell, this)
|
||||
private fun Array<String>.fsh() = ShellUtils.fastCmd(shell, *this)
|
||||
|
||||
protected fun doPatchFile(patchFile: Uri) = extractFiles() && handleFile(patchFile)
|
||||
protected fun doPatchFile(patchFile: Uri) =
|
||||
setupShell(true) && extractFiles() && handleFile(patchFile)
|
||||
|
||||
protected fun direct() = findImage() && extractFiles() && patchBoot() && flashBoot()
|
||||
protected fun direct() =
|
||||
setupShell() && findImage() && extractFiles() && patchBoot() && flashBoot()
|
||||
|
||||
protected suspend fun secondSlot() =
|
||||
findSecondaryImage() && extractFiles() && patchBoot() && flashBoot() && postOTA()
|
||||
setupShell() && findSecondary() && extractFiles() && patchBoot() && flashBoot() && postOTA()
|
||||
|
||||
protected fun fixEnv() = extractFiles() && "fix_env $installDir".sh().isSuccess
|
||||
protected fun fixEnv() =
|
||||
setupShell() && extractFiles() && "fix_env $installDir".sh().isSuccess
|
||||
|
||||
protected fun uninstall() =
|
||||
setupShell() && "run_uninstaller ${AssetHack.apk}".sh().isSuccess
|
||||
|
||||
@WorkerThread
|
||||
protected abstract suspend fun operations(): Boolean
|
||||
|
||||
open suspend fun exec() = withContext(Dispatchers.IO) { operations() }
|
||||
open suspend fun exec() = withContext(Dispatchers.IO) {
|
||||
val result = operations()
|
||||
if (closeShell)
|
||||
shell.close()
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
abstract class MagiskInstaller(
|
||||
|
@ -14,20 +14,19 @@ import com.topjohnwu.superuser.ShellUtils
|
||||
import java.io.File
|
||||
import java.util.jar.JarFile
|
||||
|
||||
class RootInit : Shell.Initializer() {
|
||||
|
||||
override fun onInit(context: Context, shell: Shell): Boolean {
|
||||
abstract class BaseShellInit : Shell.Initializer() {
|
||||
final override fun onInit(context: Context, shell: Shell): Boolean {
|
||||
return init(context.wrap(), shell)
|
||||
}
|
||||
|
||||
private fun init(context: Context, shell: Shell): Boolean {
|
||||
abstract fun init(context: Context, shell: Shell): Boolean
|
||||
}
|
||||
|
||||
fun fastCmd(cmd: String) = ShellUtils.fastCmd(shell, cmd)
|
||||
fun getVar(name: String) = fastCmd("echo \$$name")
|
||||
fun getBool(name: String) = getVar(name).toBoolean()
|
||||
|
||||
class BusyBoxInit : BaseShellInit() {
|
||||
|
||||
override fun init(context: Context, shell: Shell): Boolean {
|
||||
shell.newJob().apply {
|
||||
add("export SDK_INT=${Build.VERSION.SDK_INT}")
|
||||
add("export ASH_STANDALONE=1")
|
||||
|
||||
val localBB: File
|
||||
@ -41,27 +40,58 @@ class RootInit : Shell.Initializer() {
|
||||
localBB = File(Const.NATIVE_LIB_DIR, "libbusybox.so")
|
||||
}
|
||||
|
||||
if (!shell.isRoot) {
|
||||
// Directly execute the file
|
||||
add("exec $localBB sh")
|
||||
} else {
|
||||
// Copy it out of /data to workaround Samsung BS
|
||||
if (shell.isRoot) {
|
||||
add("export MAGISKTMP=\$(magisk --path)/.magisk")
|
||||
// Test if we can properly execute stuff in /data
|
||||
Info.noDataExec = !shell.newJob().add("$localBB true").exec().isSuccess
|
||||
}
|
||||
|
||||
if (Info.noDataExec) {
|
||||
// Copy it out of /data to workaround Samsung bullshit
|
||||
add(
|
||||
"export MAGISKTMP=\$(magisk --path)/.magisk",
|
||||
"if [ -x \$MAGISKTMP/busybox/busybox ]; then",
|
||||
" cp -af $localBB \$MAGISKTMP/busybox/busybox",
|
||||
" exec \$MAGISKTMP/busybox/busybox sh",
|
||||
"else",
|
||||
" exec $localBB sh",
|
||||
" cp -af $localBB /dev/.busybox",
|
||||
" exec /dev/.busybox sh",
|
||||
"fi"
|
||||
)
|
||||
} else {
|
||||
// Directly execute the file
|
||||
add("exec $localBB sh")
|
||||
}
|
||||
}.exec()
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
class LightShellInit : BaseShellInit() {
|
||||
|
||||
override fun init(context: Context, shell: Shell): Boolean {
|
||||
shell.newJob().apply {
|
||||
add("export SDK_INT=${Build.VERSION.SDK_INT}")
|
||||
add(context.rawResource(R.raw.manager))
|
||||
}.exec()
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
class AppShellInit : BaseShellInit() {
|
||||
|
||||
override fun init(context: Context, shell: Shell): Boolean {
|
||||
|
||||
fun fastCmd(cmd: String) = ShellUtils.fastCmd(shell, cmd)
|
||||
fun getVar(name: String) = fastCmd("echo \$$name")
|
||||
fun getBool(name: String) = getVar(name).toBoolean()
|
||||
|
||||
shell.newJob().apply {
|
||||
add("export SDK_INT=${Build.VERSION.SDK_INT}")
|
||||
add(context.rawResource(R.raw.manager))
|
||||
if (shell.isRoot) {
|
||||
add(context.assets.open("util_functions.sh"))
|
||||
}
|
||||
add("mm_init")
|
||||
add("app_init")
|
||||
}.exec()
|
||||
|
||||
Const.MAGISKTMP = getVar("MAGISKTMP")
|
||||
@ -69,7 +99,6 @@ class RootInit : Shell.Initializer() {
|
||||
Info.ramdisk = getBool("RAMDISKEXIST")
|
||||
Info.isAB = getBool("ISAB")
|
||||
Info.crypto = getVar("CRYPTOTYPE")
|
||||
Info.isPixel = fastCmd("getprop ro.product.brand") == "google"
|
||||
|
||||
// Default presets
|
||||
Config.recovery = getBool("RECOVERYMODE")
|
@ -36,7 +36,7 @@ fix_env() {
|
||||
rm -rf $MAGISKBIN/*
|
||||
mkdir -p $MAGISKBIN 2>/dev/null
|
||||
chmod 700 $NVBASE
|
||||
cp -af $1/. $MAGISKBIN
|
||||
cp_readlink $1 $MAGISKBIN
|
||||
rm -rf $1
|
||||
chown -R 0:0 $MAGISKBIN
|
||||
}
|
||||
@ -57,6 +57,8 @@ direct_install() {
|
||||
|
||||
rm -f $1/new-boot.img
|
||||
fix_env $1
|
||||
run_migrations
|
||||
copy_sepolicy_rules
|
||||
|
||||
return 0
|
||||
}
|
||||
@ -87,15 +89,17 @@ restore_imgs() {
|
||||
}
|
||||
|
||||
post_ota() {
|
||||
cd $1
|
||||
cd /data/adb
|
||||
cp -f $1 bootctl
|
||||
rm -f $1
|
||||
chmod 755 bootctl
|
||||
./bootctl hal-info || return
|
||||
[ $(./bootctl get-current-slot) -eq 0 ] && SLOT_NUM=1 || SLOT_NUM=0
|
||||
./bootctl set-active-boot-slot $SLOT_NUM
|
||||
cat << EOF > post-fs-data.d/post_ota.sh
|
||||
${1}/bootctl mark-boot-successful
|
||||
rm -f ${1}/bootctl
|
||||
rm -f ${1}/post-fs-data.d/post_ota.sh
|
||||
/data/adb/bootctl mark-boot-successful
|
||||
rm -f /data/adb/bootctl
|
||||
rm -f /data/adb/post-fs-data.d/post_ota.sh
|
||||
EOF
|
||||
chmod 755 post-fs-data.d/post_ota.sh
|
||||
cd /
|
||||
@ -196,8 +200,7 @@ grep_prop() { return; }
|
||||
# Initialize
|
||||
#############
|
||||
|
||||
mm_init() {
|
||||
export BOOTMODE=true
|
||||
app_init() {
|
||||
mount_partitions
|
||||
get_flags
|
||||
run_migrations
|
||||
@ -207,3 +210,5 @@ mm_init() {
|
||||
# Make sure RECOVERYMODE has value
|
||||
[ -z $RECOVERYMODE ] && RECOVERYMODE=false
|
||||
}
|
||||
|
||||
export BOOTMODE=true
|
||||
|
@ -28,6 +28,6 @@ kapt.incremental.apt=true
|
||||
|
||||
# Magisk
|
||||
magisk.stubVersion=17
|
||||
magisk.versionCode=21405
|
||||
magisk.versionCode=21406
|
||||
magisk.ndkVersion=21d
|
||||
magisk.fullNdkVersion=21.3.6528147
|
||||
|
Loading…
Reference in New Issue
Block a user