Update libsu

This commit is contained in:
topjohnwu 2022-05-03 01:25:26 -07:00
parent ff340ce3d8
commit cc79a96fa3
13 changed files with 63 additions and 66 deletions

View File

@ -86,10 +86,10 @@ dependencies {
implementation("${bindingAdapter}:${vBAdapt}") implementation("${bindingAdapter}:${vBAdapt}")
implementation("${bindingAdapter}-recyclerview:${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:core:${vLibsu}")
implementation("com.github.topjohnwu.libsu:io:${vLibsu}")
implementation("com.github.topjohnwu.libsu:service:${vLibsu}") implementation("com.github.topjohnwu.libsu:service:${vLibsu}")
implementation("com.github.topjohnwu.libsu:nio:${vLibsu}")
val vRetrofit = "2.9.0" val vRetrofit = "2.9.0"
implementation("com.squareup.retrofit2:retrofit:${vRetrofit}") implementation("com.squareup.retrofit2:retrofit:${vRetrofit}")

View File

@ -5,4 +5,5 @@ package com.topjohnwu.magisk.core.utils;
interface IRootUtils { interface IRootUtils {
android.app.ActivityManager.RunningAppProcessInfo getAppProcess(int pid); android.app.ActivityManager.RunningAppProcessInfo getAppProcess(int pid);
IBinder getFileSystem();
} }

View File

@ -46,7 +46,7 @@ abstract class BaseMainActivity<Binding : ViewDataBinding> : NavigationActivity<
} }
if (doPreload) { if (doPreload) {
Shell.getShell(null) { Shell.getShell(Shell.EXECUTOR) {
if (isRunningAsStub && !it.isRoot) { if (isRunningAsStub && !it.isRoot) {
showInvalidStateMessage() showInvalidStateMessage()
return@getShell return@getShell

View File

@ -8,7 +8,6 @@ import android.content.res.Configuration
import android.os.Bundle import android.os.Bundle
import com.topjohnwu.magisk.StubApk import com.topjohnwu.magisk.StubApk
import com.topjohnwu.magisk.core.utils.* import com.topjohnwu.magisk.core.utils.*
import com.topjohnwu.magisk.di.AppContext
import com.topjohnwu.magisk.di.ServiceLocator import com.topjohnwu.magisk.di.ServiceLocator
import com.topjohnwu.magisk.ui.surequest.SuRequestActivity import com.topjohnwu.magisk.ui.surequest.SuRequestActivity
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
@ -54,13 +53,11 @@ open class App() : Application() {
super.attachBaseContext(base) super.attachBaseContext(base)
ServiceLocator.context = base ServiceLocator.context = base
app.registerActivityLifecycleCallbacks(ActivityTracker) app.registerActivityLifecycleCallbacks(ActivityTracker)
}
override fun onCreate() {
super.onCreate()
Shell.setDefaultBuilder(Shell.Builder.create() Shell.setDefaultBuilder(Shell.Builder.create()
.setFlags(Shell.FLAG_MOUNT_MASTER) .setFlags(Shell.FLAG_MOUNT_MASTER)
.setInitializers(ShellInit::class.java) .setInitializers(ShellInit::class.java)
.setContext(base)
.setTimeout(2)) .setTimeout(2))
Shell.EXECUTOR = DispatcherExecutor(Dispatchers.IO) Shell.EXECUTOR = DispatcherExecutor(Dispatchers.IO)
RootUtils.bindTask = RootService.bindOrTask( RootUtils.bindTask = RootService.bindOrTask(
@ -72,7 +69,7 @@ open class App() : Application() {
Shell.getShell(null) {} Shell.getShell(null) {}
refreshLocale() refreshLocale()
AppContext.resources.patch() resources.patch()
} }
override fun onConfigurationChanged(newConfig: Configuration) { override fun onConfigurationChanged(newConfig: Configuration) {

View File

@ -8,7 +8,6 @@ import com.topjohnwu.magisk.core.utils.net.NetworkObserver
import com.topjohnwu.magisk.data.repository.NetworkService import com.topjohnwu.magisk.data.repository.NetworkService
import com.topjohnwu.magisk.di.AppContext import com.topjohnwu.magisk.di.AppContext
import com.topjohnwu.magisk.ktx.getProperty import com.topjohnwu.magisk.ktx.getProperty
import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.ShellUtils.fastCmd import com.topjohnwu.superuser.ShellUtils.fastCmd
import com.topjohnwu.superuser.internal.UiThreadHandler import com.topjohnwu.superuser.internal.UiThreadHandler
@ -36,6 +35,7 @@ object Info {
@JvmField var vbmeta = false @JvmField var vbmeta = false
var crypto = "" var crypto = ""
var noDataExec = false var noDataExec = false
var isRooted = false
@JvmField var hasGMS = true @JvmField var hasGMS = true
val isSamsung = Build.MANUFACTURER.equals("samsung", ignoreCase = true) val isSamsung = Build.MANUFACTURER.equals("samsung", ignoreCase = true)
@ -62,7 +62,7 @@ object Info {
) { ) {
val versionCode = when { val versionCode = when {
code < Const.Version.MIN_VERCODE -> -1 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 isUnsupported = code > 0 && code < Const.Version.MIN_VERCODE
val isActive = versionCode >= 0 val isActive = versionCode >= 0

View File

@ -2,9 +2,9 @@ package com.topjohnwu.magisk.core.model.module
import com.squareup.moshi.JsonDataException import com.squareup.moshi.JsonDataException
import com.topjohnwu.magisk.core.Const import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.utils.RootUtils
import com.topjohnwu.magisk.di.ServiceLocator import com.topjohnwu.magisk.di.ServiceLocator
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.io.SuFile
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import timber.log.Timber import timber.log.Timber
@ -26,13 +26,13 @@ data class LocalModule(
var outdated = false var outdated = false
private var updateUrl: String = "" private var updateUrl: String = ""
private val removeFile = SuFile(path, "remove") private val removeFile = RootUtils.fs.getFile(path, "remove")
private val disableFile = SuFile(path, "disable") private val disableFile = RootUtils.fs.getFile(path, "disable")
private val updateFile = SuFile(path, "update") private val updateFile = RootUtils.fs.getFile(path, "update")
private val ruleFile = SuFile(path, "sepolicy.rule") private val ruleFile = RootUtils.fs.getFile(path, "sepolicy.rule")
private val riruFolder = SuFile(path, "riru") private val riruFolder = RootUtils.fs.getFile(path, "riru")
private val zygiskFolder = SuFile(path, "zygisk") private val zygiskFolder = RootUtils.fs.getFile(path, "zygisk")
private val unloaded = SuFile(zygiskFolder, "unloaded") private val unloaded = RootUtils.fs.getFile(zygiskFolder, "unloaded")
val updated: Boolean get() = updateFile.exists() val updated: Boolean get() = updateFile.exists()
val isRiru: Boolean get() = (id == "riru-core") || riruFolder.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" private val PERSIST get() = "${Const.MAGISKTMP}/mirror/persist/magisk"
suspend fun installed() = withContext(Dispatchers.IO) { suspend fun installed() = withContext(Dispatchers.IO) {
SuFile(Const.MAGISK_PATH) RootUtils.fs.getFile(Const.MAGISK_PATH)
.listFiles() .listFiles()
.orEmpty() .orEmpty()
.filter { !it.isFile } .filter { !it.isFile }

View File

@ -12,6 +12,7 @@ import com.topjohnwu.magisk.core.*
import com.topjohnwu.magisk.core.utils.MediaStoreUtils import com.topjohnwu.magisk.core.utils.MediaStoreUtils
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.inputStream import com.topjohnwu.magisk.core.utils.MediaStoreUtils.inputStream
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream 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.di.ServiceLocator
import com.topjohnwu.magisk.ktx.reboot import com.topjohnwu.magisk.ktx.reboot
import com.topjohnwu.magisk.ktx.withStreams import com.topjohnwu.magisk.ktx.withStreams
@ -22,9 +23,8 @@ import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.ShellUtils import com.topjohnwu.superuser.ShellUtils
import com.topjohnwu.superuser.internal.NOPList import com.topjohnwu.superuser.internal.NOPList
import com.topjohnwu.superuser.internal.UiThreadHandler import com.topjohnwu.superuser.internal.UiThreadHandler
import com.topjohnwu.superuser.io.SuFile import com.topjohnwu.superuser.nio.ExtendedFile
import com.topjohnwu.superuser.io.SuFileInputStream import com.topjohnwu.superuser.nio.FileSystemManager
import com.topjohnwu.superuser.io.SuFileOutputStream
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import net.jpountz.lz4.LZ4FrameInputStream import net.jpountz.lz4.LZ4FrameInputStream
@ -45,21 +45,24 @@ abstract class MagiskInstallImpl protected constructor(
private val logs: MutableList<String> = NOPList.getInstance() private val logs: MutableList<String> = NOPList.getInstance()
) { ) {
protected var installDir = File("xxx") protected lateinit var installDir: ExtendedFile
private lateinit var srcBoot: File private lateinit var srcBoot: ExtendedFile
private val shell = Shell.getShell() private val shell = Shell.getShell()
private val service get() = ServiceLocator.networkService private val service get() = ServiceLocator.networkService
protected val context get() = ServiceLocator.deContext protected val context get() = ServiceLocator.deContext
private val useRootDir = shell.isRoot && Info.noDataExec private val useRootDir = shell.isRoot && Info.noDataExec
private val rootFS get() = RootUtils.fs
private val localFS get() = FileSystemManager.getLocal()
private fun findImage(): Boolean { private fun findImage(): Boolean {
val bootPath = "find_boot_image; echo \"\$BOOTIMAGE\"".fsh() val bootPath = "find_boot_image; echo \"\$BOOTIMAGE\"".fsh()
if (bootPath.isEmpty()) { if (bootPath.isEmpty()) {
console.add("! Unable to detect target image") console.add("! Unable to detect target image")
return false return false
} }
srcBoot = SuFile(bootPath) srcBoot = rootFS.getFile(bootPath)
console.add("- Target image: $bootPath") console.add("- Target image: $bootPath")
return true return true
} }
@ -77,7 +80,7 @@ abstract class MagiskInstallImpl protected constructor(
console.add("! Unable to detect target image") console.add("! Unable to detect target image")
return false return false
} }
srcBoot = SuFile(bootPath) srcBoot = rootFS.getFile(bootPath)
console.add("- Target image: $bootPath") console.add("- Target image: $bootPath")
return true return true
} }
@ -86,7 +89,7 @@ abstract class MagiskInstallImpl protected constructor(
console.add("- Device platform: ${Const.CPU_ABI}") console.add("- Device platform: ${Const.CPU_ABI}")
console.add("- Installing: ${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})") 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.deleteRecursively()
installDir.mkdirs() installDir.mkdirs()
@ -146,7 +149,7 @@ abstract class MagiskInstallImpl protected constructor(
if (useRootDir) { if (useRootDir) {
// Move everything to tmpfs to workaround Samsung bullshit // Move everything to tmpfs to workaround Samsung bullshit
SuFile(Const.TMPDIR).also { rootFS.getFile(Const.TMPDIR).also {
arrayOf( arrayOf(
"rm -rf $it", "rm -rf $it",
"mkdir -p $it", "mkdir -p $it",
@ -160,14 +163,6 @@ abstract class MagiskInstallImpl protected constructor(
return true 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, _ -> private fun InputStream.cleanPump(out: OutputStream) = withStreams(this, out) { src, _ ->
src.copyTo(out) src.copyTo(out)
} }
@ -198,8 +193,8 @@ abstract class MagiskInstallImpl protected constructor(
val name = entry.name.replace(".lz4", "") val name = entry.name.replace(".lz4", "")
console.add("-- Extracting: $name") console.add("-- Extracting: $name")
val extract = installDirFile(name) val extract = installDir.getChildFile(name)
decompressedStream().cleanPump(SuFileOutputStream.open(extract)) decompressedStream().cleanPump(extract.newOutputStream())
} else if (entry.name.contains("vbmeta.img")) { } else if (entry.name.contains("vbmeta.img")) {
val rawData = decompressedStream().readBytes() val rawData = decompressedStream().readBytes()
// Valid vbmeta.img should be at least 256 bytes // Valid vbmeta.img should be at least 256 bytes
@ -219,8 +214,8 @@ abstract class MagiskInstallImpl protected constructor(
} }
} }
} }
val boot = installDirFile("boot.img") val boot = installDir.getChildFile("boot.img")
val recovery = installDirFile("recovery.img") val recovery = installDir.getChildFile("recovery.img")
if (Config.recovery && recovery.exists() && boot.exists()) { if (Config.recovery && recovery.exists() && boot.exists()) {
// Install to recovery // Install to recovery
srcBoot = recovery srcBoot = recovery
@ -234,7 +229,7 @@ abstract class MagiskInstallImpl protected constructor(
"./magiskboot cleanup", "./magiskboot cleanup",
"rm -f new-boot.img", "rm -f new-boot.img",
"cd /").sh() "cd /").sh()
SuFileInputStream.open(boot).use { boot.newInputStream().use {
tarOut.putNextEntry(newTarEntry("boot.img", boot.length())) tarOut.putNextEntry(newTarEntry("boot.img", boot.length()))
it.copyTo(tarOut) it.copyTo(tarOut)
} }
@ -280,9 +275,9 @@ abstract class MagiskInstallImpl protected constructor(
processTar(src, outFile!!.uri.outputStream()) processTar(src, outFile!!.uri.outputStream())
} else { } else {
// raw image // raw image
srcBoot = installDirFile("boot.img") srcBoot = installDir.getChildFile("boot.img")
console.add("- Copying image to cache") console.add("- Copying image to cache")
src.cleanPump(SuFileOutputStream.open(srcBoot)) src.cleanPump(srcBoot.newOutputStream())
outFile = MediaStoreUtils.getFile("$filename.img", true) outFile = MediaStoreUtils.getFile("$filename.img", true)
outFile!!.uri.outputStream() outFile!!.uri.outputStream()
} }
@ -302,12 +297,12 @@ abstract class MagiskInstallImpl protected constructor(
// Output file // Output file
try { try {
val newBoot = installDirFile("new-boot.img") val newBoot = installDir.getChildFile("new-boot.img")
if (outStream is TarOutputStream) { if (outStream is TarOutputStream) {
val name = if (srcBoot.path.contains("recovery")) "recovery.img" else "boot.img" val name = if (srcBoot.path.contains("recovery")) "recovery.img" else "boot.img"
outStream.putNextEntry(newTarEntry(name, newBoot.length())) outStream.putNextEntry(newTarEntry(name, newBoot.length()))
} }
SuFileInputStream.open(newBoot).cleanPump(outStream) newBoot.newInputStream().cleanPump(outStream)
newBoot.delete() newBoot.delete()
console.add("") console.add("")
@ -331,9 +326,9 @@ abstract class MagiskInstallImpl protected constructor(
private fun patchBoot(): Boolean { private fun patchBoot(): Boolean {
var isSigned = false var isSigned = false
if (srcBoot.let { it !is SuFile || !it.isCharacter }) { if (!srcBoot.isCharacter) {
try { try {
SuFileInputStream.open(srcBoot).use { srcBoot.newInputStream().use {
if (SignBoot.verifySignature(it, null)) { if (SignBoot.verifySignature(it, null)) {
isSigned = true isSigned = true
console.add("- Boot image is signed with AVB 1.0") 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) { if (!useRootDir) {
// Create output files before hand // Create output files before hand
newBoot.createNewFile() newBoot.createNewFile()
@ -370,7 +365,7 @@ abstract class MagiskInstallImpl protected constructor(
console.add("- Signing boot image with verity keys") console.add("- Signing boot image with verity keys")
val signed = File.createTempFile("signed", ".img", context.cacheDir) val signed = File.createTempFile("signed", ".img", context.cacheDir)
try { try {
val src = SuFileInputStream.open(newBoot).buffered() val src = newBoot.newInputStream().buffered()
val out = signed.outputStream().buffered() val out = signed.outputStream().buffered()
withStreams(src, out) { _, _ -> withStreams(src, out) { _, _ ->
SignBoot.doSignature(null, null, src, out, "/boot") 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 String.fsh() = ShellUtils.fastCmd(shell, this)
private fun Array<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 patchFile(file: Uri) = extractFiles() && handleFile(file)
protected fun direct() = findImage() && extractFiles() && patchBoot() && flashBoot() protected fun direct() = findImage() && extractFiles() && patchBoot() && flashBoot()
protected suspend fun secondSlot() = protected fun secondSlot() =
findSecondary() && extractFiles() && patchBoot() && flashBoot() && postOTA() findSecondary() && extractFiles() && patchBoot() && flashBoot() && postOTA()
protected fun fixEnv() = extractFiles() && "fix_env $installDir".sh().isSuccess protected fun fixEnv() = extractFiles() && "fix_env $installDir".sh().isSuccess
@ -463,7 +458,7 @@ abstract class MagiskInstaller(
console: MutableList<String>, console: MutableList<String>,
logs: MutableList<String> logs: MutableList<String>
) : MagiskInstaller(console, logs) { ) : MagiskInstaller(console, logs) {
override suspend fun operations() = doPatchFile(uri) override suspend fun operations() = patchFile(uri)
} }
class SecondSlot( class SecondSlot(

View File

@ -9,6 +9,7 @@ import androidx.core.content.getSystemService
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.ShellUtils import com.topjohnwu.superuser.ShellUtils
import com.topjohnwu.superuser.ipc.RootService import com.topjohnwu.superuser.ipc.RootService
import com.topjohnwu.superuser.nio.FileSystemManager
import timber.log.Timber import timber.log.Timber
import java.io.File import java.io.File
import java.util.concurrent.locks.AbstractQueuedSynchronizer import java.util.concurrent.locks.AbstractQueuedSynchronizer
@ -33,6 +34,7 @@ class RootUtils(stub: Any?) : RootService() {
override fun onBind(intent: Intent): IBinder { override fun onBind(intent: Intent): IBinder {
return object : IRootUtils.Stub() { return object : IRootUtils.Stub() {
override fun getAppProcess(pid: Int) = safe(null) { getAppProcessImpl(pid) } 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) { override fun onServiceConnected(name: ComponentName, service: IBinder) {
Timber.d("onServiceConnected") Timber.d("onServiceConnected")
obj = IRootUtils.Stub.asInterface(service) IRootUtils.Stub.asInterface(service).let {
obj = it
fs = FileSystemManager.getRemote(it.fileSystem)
}
releaseShared(1) releaseShared(1)
} }
@ -101,6 +106,8 @@ class RootUtils(stub: Any?) : RootService() {
companion object { companion object {
var bindTask: Shell.Task? = null var bindTask: Shell.Task? = null
var fs = FileSystemManager.getLocal()
private set
var obj: IRootUtils? = null var obj: IRootUtils? = null
get() { get() {
Connection.await() Connection.await()

View File

@ -19,6 +19,7 @@ import java.util.jar.JarFile
class ShellInit : Shell.Initializer() { class ShellInit : Shell.Initializer() {
override fun onInit(context: Context, shell: Shell): Boolean { override fun onInit(context: Context, shell: Shell): Boolean {
if (shell.isRoot) { if (shell.isRoot) {
Info.isRooted = true
RootUtils.bindTask?.let { shell.execTask(it) } RootUtils.bindTask?.let { shell.execTask(it) }
RootUtils.bindTask = null RootUtils.bindTask = null
} }

View File

@ -1,7 +1,5 @@
package com.topjohnwu.magisk.core.utils 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.File
import java.io.IOException import java.io.IOException
import java.io.InputStream import java.io.InputStream
@ -31,12 +29,12 @@ fun InputStream.unzip(folder: File, path: String, junkPath: Boolean) {
else else
entry.name entry.name
var dest = File(folder, name) val dest = File(folder, name)
if (!dest.parentFile!!.exists() && !dest.parentFile!!.mkdirs()) { dest.parentFile!!.let {
dest = SuFile(folder, name) if (!it.exists())
dest.parentFile!!.mkdirs() it.mkdirs()
} }
SuFileOutputStream.open(dest).use { out -> zin.copyTo(out) } dest.outputStream().use { out -> zin.copyTo(out) }
} }
} catch (e: IllegalArgumentException) { } catch (e: IllegalArgumentException) {
throw IOException(e) throw IOException(e)

View File

@ -21,14 +21,13 @@ import com.topjohnwu.magisk.databinding.set
import com.topjohnwu.magisk.events.SnackbarEvent import com.topjohnwu.magisk.events.SnackbarEvent
import com.topjohnwu.magisk.ktx.* import com.topjohnwu.magisk.ktx.*
import com.topjohnwu.superuser.CallbackList import com.topjohnwu.superuser.CallbackList
import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
class FlashViewModel : BaseViewModel() { class FlashViewModel : BaseViewModel() {
@get:Bindable @get:Bindable
var showReboot = Shell.rootAccess() var showReboot = Info.isRooted
set(value) = set(value, field, { field = it }, BR.showReboot) set(value) = set(value, field, { field = it }, BR.showReboot)
private val _subtitle = MutableLiveData(R.string.flashing) private val _subtitle = MutableLiveData(R.string.flashing)

View File

@ -6,11 +6,11 @@ import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseFragment import com.topjohnwu.magisk.arch.BaseFragment
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.download.DownloadService import com.topjohnwu.magisk.core.download.DownloadService
import com.topjohnwu.magisk.databinding.FragmentHomeMd2Binding import com.topjohnwu.magisk.databinding.FragmentHomeMd2Binding
import com.topjohnwu.magisk.di.viewModel import com.topjohnwu.magisk.di.viewModel
import com.topjohnwu.magisk.events.RebootEvent import com.topjohnwu.magisk.events.RebootEvent
import com.topjohnwu.superuser.Shell
class HomeFragment : BaseFragment<FragmentHomeMd2Binding>() { class HomeFragment : BaseFragment<FragmentHomeMd2Binding>() {
@ -56,7 +56,7 @@ class HomeFragment : BaseFragment<FragmentHomeMd2Binding>() {
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.menu_home_md2, menu) inflater.inflate(R.menu.menu_home_md2, menu)
if (!Shell.rootAccess()) if (!Info.isRooted)
menu.removeItem(R.id.action_reboot) menu.removeItem(R.id.action_reboot)
} }

View File

@ -18,7 +18,6 @@ import com.topjohnwu.magisk.di.ServiceLocator
import com.topjohnwu.magisk.events.MagiskInstallFileEvent import com.topjohnwu.magisk.events.MagiskInstallFileEvent
import com.topjohnwu.magisk.events.dialog.SecondSlotWarningDialog import com.topjohnwu.magisk.events.dialog.SecondSlotWarningDialog
import com.topjohnwu.magisk.ui.flash.FlashFragment import com.topjohnwu.magisk.ui.flash.FlashFragment
import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber import timber.log.Timber
@ -29,7 +28,7 @@ class InstallViewModel(
svc: NetworkService svc: NetworkService
) : BaseViewModel() { ) : BaseViewModel() {
val isRooted = Shell.rootAccess() val isRooted get() = Info.isRooted
val hideVbmeta = Info.vbmeta || Info.isSamsung || Info.isAB val hideVbmeta = Info.vbmeta || Info.isSamsung || Info.isAB
val skipOptions = Info.isEmulator || (Info.isSAR && !Info.isFDE && hideVbmeta && Info.ramdisk) val skipOptions = Info.isEmulator || (Info.isSAR && !Info.isFDE && hideVbmeta && Info.ramdisk)
val noSecondSlot = !isRooted || !Info.isAB || Info.isEmulator val noSecondSlot = !isRooted || !Info.isAB || Info.isEmulator