From cc79a96fa31c3c7b9d05177726465a0f126880dc Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Tue, 3 May 2022 01:25:26 -0700 Subject: [PATCH] Update libsu --- app/build.gradle.kts | 4 +- .../magisk/core/utils/IRootUtils.aidl | 1 + .../topjohnwu/magisk/arch/BaseMainActivity.kt | 2 +- .../java/com/topjohnwu/magisk/core/App.kt | 7 +-- .../java/com/topjohnwu/magisk/core/Info.kt | 4 +- .../magisk/core/model/module/LocalModule.kt | 18 +++--- .../magisk/core/tasks/MagiskInstaller.kt | 61 +++++++++---------- .../topjohnwu/magisk/core/utils/RootUtils.kt | 9 ++- .../topjohnwu/magisk/core/utils/ShellInit.kt | 1 + .../topjohnwu/magisk/core/utils/ZipUtils.kt | 12 ++-- .../magisk/ui/flash/FlashViewModel.kt | 3 +- .../topjohnwu/magisk/ui/home/HomeFragment.kt | 4 +- .../magisk/ui/install/InstallViewModel.kt | 3 +- 13 files changed, 63 insertions(+), 66 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index c0e4b4c8d..0a544d161 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -86,10 +86,10 @@ dependencies { implementation("${bindingAdapter}:${vBAdapt}") implementation("${bindingAdapter}-recyclerview:${vBAdapt}") - val vLibsu = "4.0.3" + val vLibsu = "5.0.0" implementation("com.github.topjohnwu.libsu:core:${vLibsu}") - implementation("com.github.topjohnwu.libsu:io:${vLibsu}") implementation("com.github.topjohnwu.libsu:service:${vLibsu}") + implementation("com.github.topjohnwu.libsu:nio:${vLibsu}") val vRetrofit = "2.9.0" implementation("com.squareup.retrofit2:retrofit:${vRetrofit}") diff --git a/app/src/main/aidl/com/topjohnwu/magisk/core/utils/IRootUtils.aidl b/app/src/main/aidl/com/topjohnwu/magisk/core/utils/IRootUtils.aidl index 3f32dd5d3..981d82d69 100644 --- a/app/src/main/aidl/com/topjohnwu/magisk/core/utils/IRootUtils.aidl +++ b/app/src/main/aidl/com/topjohnwu/magisk/core/utils/IRootUtils.aidl @@ -5,4 +5,5 @@ package com.topjohnwu.magisk.core.utils; interface IRootUtils { android.app.ActivityManager.RunningAppProcessInfo getAppProcess(int pid); + IBinder getFileSystem(); } diff --git a/app/src/main/java/com/topjohnwu/magisk/arch/BaseMainActivity.kt b/app/src/main/java/com/topjohnwu/magisk/arch/BaseMainActivity.kt index 25894c78f..10e5e3814 100644 --- a/app/src/main/java/com/topjohnwu/magisk/arch/BaseMainActivity.kt +++ b/app/src/main/java/com/topjohnwu/magisk/arch/BaseMainActivity.kt @@ -46,7 +46,7 @@ abstract class BaseMainActivity : NavigationActivity< } if (doPreload) { - Shell.getShell(null) { + Shell.getShell(Shell.EXECUTOR) { if (isRunningAsStub && !it.isRoot) { showInvalidStateMessage() return@getShell diff --git a/app/src/main/java/com/topjohnwu/magisk/core/App.kt b/app/src/main/java/com/topjohnwu/magisk/core/App.kt index 1f0325ee3..4b2ef3c92 100644 --- a/app/src/main/java/com/topjohnwu/magisk/core/App.kt +++ b/app/src/main/java/com/topjohnwu/magisk/core/App.kt @@ -8,7 +8,6 @@ import android.content.res.Configuration import android.os.Bundle import com.topjohnwu.magisk.StubApk import com.topjohnwu.magisk.core.utils.* -import com.topjohnwu.magisk.di.AppContext import com.topjohnwu.magisk.di.ServiceLocator import com.topjohnwu.magisk.ui.surequest.SuRequestActivity import com.topjohnwu.superuser.Shell @@ -54,13 +53,11 @@ open class App() : Application() { super.attachBaseContext(base) ServiceLocator.context = base app.registerActivityLifecycleCallbacks(ActivityTracker) - } - override fun onCreate() { - super.onCreate() Shell.setDefaultBuilder(Shell.Builder.create() .setFlags(Shell.FLAG_MOUNT_MASTER) .setInitializers(ShellInit::class.java) + .setContext(base) .setTimeout(2)) Shell.EXECUTOR = DispatcherExecutor(Dispatchers.IO) RootUtils.bindTask = RootService.bindOrTask( @@ -72,7 +69,7 @@ open class App() : Application() { Shell.getShell(null) {} refreshLocale() - AppContext.resources.patch() + resources.patch() } override fun onConfigurationChanged(newConfig: Configuration) { diff --git a/app/src/main/java/com/topjohnwu/magisk/core/Info.kt b/app/src/main/java/com/topjohnwu/magisk/core/Info.kt index 5e1b18a97..aa1b73dbe 100644 --- a/app/src/main/java/com/topjohnwu/magisk/core/Info.kt +++ b/app/src/main/java/com/topjohnwu/magisk/core/Info.kt @@ -8,7 +8,6 @@ import com.topjohnwu.magisk.core.utils.net.NetworkObserver import com.topjohnwu.magisk.data.repository.NetworkService import com.topjohnwu.magisk.di.AppContext import com.topjohnwu.magisk.ktx.getProperty -import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.ShellUtils.fastCmd import com.topjohnwu.superuser.internal.UiThreadHandler @@ -36,6 +35,7 @@ object Info { @JvmField var vbmeta = false var crypto = "" var noDataExec = false + var isRooted = false @JvmField var hasGMS = true val isSamsung = Build.MANUFACTURER.equals("samsung", ignoreCase = true) @@ -62,7 +62,7 @@ object Info { ) { val versionCode = when { code < Const.Version.MIN_VERCODE -> -1 - else -> if (Shell.rootAccess()) code else -1 + else -> if (isRooted) code else -1 } val isUnsupported = code > 0 && code < Const.Version.MIN_VERCODE val isActive = versionCode >= 0 diff --git a/app/src/main/java/com/topjohnwu/magisk/core/model/module/LocalModule.kt b/app/src/main/java/com/topjohnwu/magisk/core/model/module/LocalModule.kt index fbc799fc1..64a5725a2 100644 --- a/app/src/main/java/com/topjohnwu/magisk/core/model/module/LocalModule.kt +++ b/app/src/main/java/com/topjohnwu/magisk/core/model/module/LocalModule.kt @@ -2,9 +2,9 @@ package com.topjohnwu.magisk.core.model.module import com.squareup.moshi.JsonDataException import com.topjohnwu.magisk.core.Const +import com.topjohnwu.magisk.core.utils.RootUtils import com.topjohnwu.magisk.di.ServiceLocator import com.topjohnwu.superuser.Shell -import com.topjohnwu.superuser.io.SuFile import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import timber.log.Timber @@ -26,13 +26,13 @@ data class LocalModule( var outdated = false private var updateUrl: String = "" - private val removeFile = SuFile(path, "remove") - private val disableFile = SuFile(path, "disable") - private val updateFile = SuFile(path, "update") - private val ruleFile = SuFile(path, "sepolicy.rule") - private val riruFolder = SuFile(path, "riru") - private val zygiskFolder = SuFile(path, "zygisk") - private val unloaded = SuFile(zygiskFolder, "unloaded") + private val removeFile = RootUtils.fs.getFile(path, "remove") + private val disableFile = RootUtils.fs.getFile(path, "disable") + private val updateFile = RootUtils.fs.getFile(path, "update") + private val ruleFile = RootUtils.fs.getFile(path, "sepolicy.rule") + private val riruFolder = RootUtils.fs.getFile(path, "riru") + private val zygiskFolder = RootUtils.fs.getFile(path, "zygisk") + private val unloaded = RootUtils.fs.getFile(zygiskFolder, "unloaded") val updated: Boolean get() = updateFile.exists() val isRiru: Boolean get() = (id == "riru-core") || riruFolder.exists() @@ -139,7 +139,7 @@ data class LocalModule( private val PERSIST get() = "${Const.MAGISKTMP}/mirror/persist/magisk" suspend fun installed() = withContext(Dispatchers.IO) { - SuFile(Const.MAGISK_PATH) + RootUtils.fs.getFile(Const.MAGISK_PATH) .listFiles() .orEmpty() .filter { !it.isFile } diff --git a/app/src/main/java/com/topjohnwu/magisk/core/tasks/MagiskInstaller.kt b/app/src/main/java/com/topjohnwu/magisk/core/tasks/MagiskInstaller.kt index 08287289a..00361f436 100644 --- a/app/src/main/java/com/topjohnwu/magisk/core/tasks/MagiskInstaller.kt +++ b/app/src/main/java/com/topjohnwu/magisk/core/tasks/MagiskInstaller.kt @@ -12,6 +12,7 @@ import com.topjohnwu.magisk.core.* import com.topjohnwu.magisk.core.utils.MediaStoreUtils import com.topjohnwu.magisk.core.utils.MediaStoreUtils.inputStream import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream +import com.topjohnwu.magisk.core.utils.RootUtils import com.topjohnwu.magisk.di.ServiceLocator import com.topjohnwu.magisk.ktx.reboot import com.topjohnwu.magisk.ktx.withStreams @@ -22,9 +23,8 @@ import com.topjohnwu.superuser.Shell 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 com.topjohnwu.superuser.nio.ExtendedFile +import com.topjohnwu.superuser.nio.FileSystemManager import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import net.jpountz.lz4.LZ4FrameInputStream @@ -45,21 +45,24 @@ abstract class MagiskInstallImpl protected constructor( private val logs: MutableList = NOPList.getInstance() ) { - protected var installDir = File("xxx") - private lateinit var srcBoot: File + protected lateinit var installDir: ExtendedFile + private lateinit var srcBoot: ExtendedFile private val shell = Shell.getShell() private val service get() = ServiceLocator.networkService protected val context get() = ServiceLocator.deContext private val useRootDir = shell.isRoot && Info.noDataExec + private val rootFS get() = RootUtils.fs + private val localFS get() = FileSystemManager.getLocal() + private fun findImage(): Boolean { val bootPath = "find_boot_image; echo \"\$BOOTIMAGE\"".fsh() if (bootPath.isEmpty()) { console.add("! Unable to detect target image") return false } - srcBoot = SuFile(bootPath) + srcBoot = rootFS.getFile(bootPath) console.add("- Target image: $bootPath") return true } @@ -77,7 +80,7 @@ abstract class MagiskInstallImpl protected constructor( console.add("! Unable to detect target image") return false } - srcBoot = SuFile(bootPath) + srcBoot = rootFS.getFile(bootPath) console.add("- Target image: $bootPath") return true } @@ -86,7 +89,7 @@ abstract class MagiskInstallImpl protected constructor( console.add("- Device platform: ${Const.CPU_ABI}") console.add("- Installing: ${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})") - installDir = File(context.filesDir.parent, "install") + installDir = localFS.getFile(context.filesDir.parent, "install") installDir.deleteRecursively() installDir.mkdirs() @@ -146,7 +149,7 @@ abstract class MagiskInstallImpl protected constructor( if (useRootDir) { // Move everything to tmpfs to workaround Samsung bullshit - SuFile(Const.TMPDIR).also { + rootFS.getFile(Const.TMPDIR).also { arrayOf( "rm -rf $it", "mkdir -p $it", @@ -160,14 +163,6 @@ abstract class MagiskInstallImpl protected constructor( return true } - // Optimization for SuFile I/O streams to skip an internal trial and error - private fun installDirFile(name: String): File { - return if (useRootDir) - SuFile(installDir, name) - else - File(installDir, name) - } - private fun InputStream.cleanPump(out: OutputStream) = withStreams(this, out) { src, _ -> src.copyTo(out) } @@ -198,8 +193,8 @@ abstract class MagiskInstallImpl protected constructor( val name = entry.name.replace(".lz4", "") console.add("-- Extracting: $name") - val extract = installDirFile(name) - decompressedStream().cleanPump(SuFileOutputStream.open(extract)) + val extract = installDir.getChildFile(name) + decompressedStream().cleanPump(extract.newOutputStream()) } else if (entry.name.contains("vbmeta.img")) { val rawData = decompressedStream().readBytes() // Valid vbmeta.img should be at least 256 bytes @@ -219,8 +214,8 @@ abstract class MagiskInstallImpl protected constructor( } } } - val boot = installDirFile("boot.img") - val recovery = installDirFile("recovery.img") + val boot = installDir.getChildFile("boot.img") + val recovery = installDir.getChildFile("recovery.img") if (Config.recovery && recovery.exists() && boot.exists()) { // Install to recovery srcBoot = recovery @@ -234,7 +229,7 @@ abstract class MagiskInstallImpl protected constructor( "./magiskboot cleanup", "rm -f new-boot.img", "cd /").sh() - SuFileInputStream.open(boot).use { + boot.newInputStream().use { tarOut.putNextEntry(newTarEntry("boot.img", boot.length())) it.copyTo(tarOut) } @@ -280,9 +275,9 @@ abstract class MagiskInstallImpl protected constructor( processTar(src, outFile!!.uri.outputStream()) } else { // raw image - srcBoot = installDirFile("boot.img") + srcBoot = installDir.getChildFile("boot.img") console.add("- Copying image to cache") - src.cleanPump(SuFileOutputStream.open(srcBoot)) + src.cleanPump(srcBoot.newOutputStream()) outFile = MediaStoreUtils.getFile("$filename.img", true) outFile!!.uri.outputStream() } @@ -302,12 +297,12 @@ abstract class MagiskInstallImpl protected constructor( // Output file try { - val newBoot = installDirFile("new-boot.img") + val newBoot = installDir.getChildFile("new-boot.img") if (outStream is TarOutputStream) { val name = if (srcBoot.path.contains("recovery")) "recovery.img" else "boot.img" outStream.putNextEntry(newTarEntry(name, newBoot.length())) } - SuFileInputStream.open(newBoot).cleanPump(outStream) + newBoot.newInputStream().cleanPump(outStream) newBoot.delete() console.add("") @@ -331,9 +326,9 @@ abstract class MagiskInstallImpl protected constructor( private fun patchBoot(): Boolean { var isSigned = false - if (srcBoot.let { it !is SuFile || !it.isCharacter }) { + if (!srcBoot.isCharacter) { try { - SuFileInputStream.open(srcBoot).use { + srcBoot.newInputStream().use { if (SignBoot.verifySignature(it, null)) { isSigned = true console.add("- Boot image is signed with AVB 1.0") @@ -346,7 +341,7 @@ abstract class MagiskInstallImpl protected constructor( } } - val newBoot = installDirFile("new-boot.img") + val newBoot = installDir.getChildFile("new-boot.img") if (!useRootDir) { // Create output files before hand newBoot.createNewFile() @@ -370,7 +365,7 @@ abstract class MagiskInstallImpl protected constructor( console.add("- Signing boot image with verity keys") val signed = File.createTempFile("signed", ".img", context.cacheDir) try { - val src = SuFileInputStream.open(newBoot).buffered() + val src = newBoot.newInputStream().buffered() val out = signed.outputStream().buffered() withStreams(src, out) { _, _ -> SignBoot.doSignature(null, null, src, out, "/boot") @@ -410,11 +405,11 @@ abstract class MagiskInstallImpl protected constructor( private fun String.fsh() = ShellUtils.fastCmd(shell, this) private fun Array.fsh() = ShellUtils.fastCmd(shell, *this) - protected fun doPatchFile(patchFile: Uri) = extractFiles() && handleFile(patchFile) + protected fun patchFile(file: Uri) = extractFiles() && handleFile(file) protected fun direct() = findImage() && extractFiles() && patchBoot() && flashBoot() - protected suspend fun secondSlot() = + protected fun secondSlot() = findSecondary() && extractFiles() && patchBoot() && flashBoot() && postOTA() protected fun fixEnv() = extractFiles() && "fix_env $installDir".sh().isSuccess @@ -463,7 +458,7 @@ abstract class MagiskInstaller( console: MutableList, logs: MutableList ) : MagiskInstaller(console, logs) { - override suspend fun operations() = doPatchFile(uri) + override suspend fun operations() = patchFile(uri) } class SecondSlot( diff --git a/app/src/main/java/com/topjohnwu/magisk/core/utils/RootUtils.kt b/app/src/main/java/com/topjohnwu/magisk/core/utils/RootUtils.kt index 1357e2db2..4c272cd17 100644 --- a/app/src/main/java/com/topjohnwu/magisk/core/utils/RootUtils.kt +++ b/app/src/main/java/com/topjohnwu/magisk/core/utils/RootUtils.kt @@ -9,6 +9,7 @@ import androidx.core.content.getSystemService import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.ShellUtils import com.topjohnwu.superuser.ipc.RootService +import com.topjohnwu.superuser.nio.FileSystemManager import timber.log.Timber import java.io.File import java.util.concurrent.locks.AbstractQueuedSynchronizer @@ -33,6 +34,7 @@ class RootUtils(stub: Any?) : RootService() { override fun onBind(intent: Intent): IBinder { return object : IRootUtils.Stub() { override fun getAppProcess(pid: Int) = safe(null) { getAppProcessImpl(pid) } + override fun getFileSystem(): IBinder = FileSystemManager.getService() } } @@ -68,7 +70,10 @@ class RootUtils(stub: Any?) : RootService() { override fun onServiceConnected(name: ComponentName, service: IBinder) { Timber.d("onServiceConnected") - obj = IRootUtils.Stub.asInterface(service) + IRootUtils.Stub.asInterface(service).let { + obj = it + fs = FileSystemManager.getRemote(it.fileSystem) + } releaseShared(1) } @@ -101,6 +106,8 @@ class RootUtils(stub: Any?) : RootService() { companion object { var bindTask: Shell.Task? = null + var fs = FileSystemManager.getLocal() + private set var obj: IRootUtils? = null get() { Connection.await() diff --git a/app/src/main/java/com/topjohnwu/magisk/core/utils/ShellInit.kt b/app/src/main/java/com/topjohnwu/magisk/core/utils/ShellInit.kt index a40c18b3e..c309dc5fb 100644 --- a/app/src/main/java/com/topjohnwu/magisk/core/utils/ShellInit.kt +++ b/app/src/main/java/com/topjohnwu/magisk/core/utils/ShellInit.kt @@ -19,6 +19,7 @@ import java.util.jar.JarFile class ShellInit : Shell.Initializer() { override fun onInit(context: Context, shell: Shell): Boolean { if (shell.isRoot) { + Info.isRooted = true RootUtils.bindTask?.let { shell.execTask(it) } RootUtils.bindTask = null } diff --git a/app/src/main/java/com/topjohnwu/magisk/core/utils/ZipUtils.kt b/app/src/main/java/com/topjohnwu/magisk/core/utils/ZipUtils.kt index 758efe27b..2eee01a97 100644 --- a/app/src/main/java/com/topjohnwu/magisk/core/utils/ZipUtils.kt +++ b/app/src/main/java/com/topjohnwu/magisk/core/utils/ZipUtils.kt @@ -1,7 +1,5 @@ package com.topjohnwu.magisk.core.utils -import com.topjohnwu.superuser.io.SuFile -import com.topjohnwu.superuser.io.SuFileOutputStream import java.io.File import java.io.IOException import java.io.InputStream @@ -31,12 +29,12 @@ fun InputStream.unzip(folder: File, path: String, junkPath: Boolean) { else entry.name - var dest = File(folder, name) - if (!dest.parentFile!!.exists() && !dest.parentFile!!.mkdirs()) { - dest = SuFile(folder, name) - dest.parentFile!!.mkdirs() + val dest = File(folder, name) + dest.parentFile!!.let { + if (!it.exists()) + it.mkdirs() } - SuFileOutputStream.open(dest).use { out -> zin.copyTo(out) } + dest.outputStream().use { out -> zin.copyTo(out) } } } catch (e: IllegalArgumentException) { throw IOException(e) diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashViewModel.kt index ef8f6bbb6..cfbd5d041 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashViewModel.kt @@ -21,14 +21,13 @@ import com.topjohnwu.magisk.databinding.set import com.topjohnwu.magisk.events.SnackbarEvent import com.topjohnwu.magisk.ktx.* import com.topjohnwu.superuser.CallbackList -import com.topjohnwu.superuser.Shell import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch class FlashViewModel : BaseViewModel() { @get:Bindable - var showReboot = Shell.rootAccess() + var showReboot = Info.isRooted set(value) = set(value, field, { field = it }, BR.showReboot) private val _subtitle = MutableLiveData(R.string.flashing) diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeFragment.kt b/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeFragment.kt index 21e8ff130..6974576b3 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeFragment.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeFragment.kt @@ -6,11 +6,11 @@ import android.widget.ImageView import android.widget.TextView import com.topjohnwu.magisk.R import com.topjohnwu.magisk.arch.BaseFragment +import com.topjohnwu.magisk.core.Info import com.topjohnwu.magisk.core.download.DownloadService import com.topjohnwu.magisk.databinding.FragmentHomeMd2Binding import com.topjohnwu.magisk.di.viewModel import com.topjohnwu.magisk.events.RebootEvent -import com.topjohnwu.superuser.Shell class HomeFragment : BaseFragment() { @@ -56,7 +56,7 @@ class HomeFragment : BaseFragment() { override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { inflater.inflate(R.menu.menu_home_md2, menu) - if (!Shell.rootAccess()) + if (!Info.isRooted) menu.removeItem(R.id.action_reboot) } diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/install/InstallViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/install/InstallViewModel.kt index ca5c0689c..7be546ac2 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/install/InstallViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/install/InstallViewModel.kt @@ -18,7 +18,6 @@ import com.topjohnwu.magisk.di.ServiceLocator import com.topjohnwu.magisk.events.MagiskInstallFileEvent import com.topjohnwu.magisk.events.dialog.SecondSlotWarningDialog import com.topjohnwu.magisk.ui.flash.FlashFragment -import com.topjohnwu.superuser.Shell import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import timber.log.Timber @@ -29,7 +28,7 @@ class InstallViewModel( svc: NetworkService ) : BaseViewModel() { - val isRooted = Shell.rootAccess() + val isRooted get() = Info.isRooted val hideVbmeta = Info.vbmeta || Info.isSamsung || Info.isAB val skipOptions = Info.isEmulator || (Info.isSAR && !Info.isFDE && hideVbmeta && Info.ramdisk) val noSecondSlot = !isRooted || !Info.isAB || Info.isEmulator