mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-08-14 05:59:28 +00:00
Compare commits
48 Commits
canary-270
...
canary-281
Author | SHA1 | Date | |
---|---|---|---|
![]() |
47cc532d96 | ||
![]() |
218327f92b | ||
![]() |
4eae66a1a7 | ||
![]() |
b09ceeb43c | ||
![]() |
4fb539c110 | ||
![]() |
849b284da5 | ||
![]() |
895b5f6cbf | ||
![]() |
cb3d4ea514 | ||
![]() |
0d89a2a97d | ||
![]() |
3ca5913055 | ||
![]() |
df6b808f49 | ||
![]() |
09c7ac754b | ||
![]() |
805da67c23 | ||
![]() |
3c6889505b | ||
![]() |
c8e9ce7627 | ||
![]() |
837c679a31 | ||
![]() |
06616659b8 | ||
![]() |
a34c04f999 | ||
![]() |
da43ac89a0 | ||
![]() |
830fc758b9 | ||
![]() |
0f3cfef278 | ||
![]() |
b32d7bfafd | ||
![]() |
c0899f2939 | ||
![]() |
082330808f | ||
![]() |
024da05888 | ||
![]() |
377b6d0cc2 | ||
![]() |
c661009b31 | ||
![]() |
613f2d31c5 | ||
![]() |
7dbb973db5 | ||
![]() |
f4502f8be8 | ||
![]() |
455b13b83c | ||
![]() |
8b98709743 | ||
![]() |
1b12f45f39 | ||
![]() |
a5cad532ff | ||
![]() |
070719db50 | ||
![]() |
28cccdf7aa | ||
![]() |
b7e0986a5c | ||
![]() |
da709745dd | ||
![]() |
8b6771d487 | ||
![]() |
e1b847fbc5 | ||
![]() |
7188de1205 | ||
![]() |
44fb7dbcbe | ||
![]() |
8086b5933c | ||
![]() |
7f675f4bf7 | ||
![]() |
5e6b53e0da | ||
![]() |
5b29fefc65 | ||
![]() |
16a168535d | ||
![]() |
33f70f8f6d |
2
.github/actions/setup/action.yml
vendored
2
.github/actions/setup/action.yml
vendored
@@ -6,7 +6,7 @@ inputs:
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Set up JDK 17
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: "temurin"
|
||||
|
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@@ -83,10 +83,10 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
version: [23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34]
|
||||
version: [23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35]
|
||||
type: [""]
|
||||
include:
|
||||
- version: 35
|
||||
- version: "Baklava"
|
||||
type: "google_apis"
|
||||
|
||||
steps:
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -14,6 +14,7 @@ native/out
|
||||
*.iml
|
||||
.gradle
|
||||
.idea
|
||||
.kotlin
|
||||
/local.properties
|
||||
/build
|
||||
/captures
|
||||
|
@@ -20,9 +20,9 @@ Some highlight features:
|
||||
|
||||
Click the icon below to download Magisk apk.
|
||||
|
||||
[](https://github.com/topjohnwu/Magisk/releases/tag/v27.0)
|
||||
[](https://github.com/topjohnwu/Magisk/releases/tag/v27.0)
|
||||
[](https://github.com/topjohnwu/Magisk/releases/tag/canary-27008)
|
||||
[](https://github.com/topjohnwu/Magisk/releases/tag/v28.1)
|
||||
[](https://github.com/topjohnwu/Magisk/releases/tag/v28.1)
|
||||
[](https://github.com/topjohnwu/Magisk/releases/tag/canary-28101)
|
||||
|
||||
## Useful Links
|
||||
|
||||
|
@@ -6,7 +6,7 @@ plugins {
|
||||
id("androidx.navigation.safeargs.kotlin")
|
||||
}
|
||||
|
||||
setupAppCommon()
|
||||
setupMainApk()
|
||||
|
||||
kapt {
|
||||
correctErrorTypes = true
|
||||
@@ -18,27 +18,6 @@ kapt {
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.topjohnwu.magisk"
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "com.topjohnwu.magisk"
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
versionName = Config.version
|
||||
versionCode = Config.versionCode
|
||||
ndk {
|
||||
abiFilters += listOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64", "riscv64")
|
||||
debugSymbolLevel = "FULL"
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = true
|
||||
isShrinkResources = true
|
||||
proguardFiles("proguard-rules.pro")
|
||||
}
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
dataBinding = true
|
||||
}
|
||||
@@ -46,6 +25,13 @@ android {
|
||||
compileOptions {
|
||||
isCoreLibraryDesugaringEnabled = true
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = true
|
||||
isShrinkResources = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
@@ -1,13 +1,18 @@
|
||||
package com.topjohnwu.magisk.dialog
|
||||
|
||||
import android.widget.Toast
|
||||
import androidx.core.os.postDelayed
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.topjohnwu.magisk.core.BuildConfig
|
||||
import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.magisk.core.R
|
||||
import com.topjohnwu.magisk.core.ktx.reboot
|
||||
import com.topjohnwu.magisk.core.ktx.toast
|
||||
import com.topjohnwu.magisk.core.tasks.MagiskInstaller
|
||||
import com.topjohnwu.magisk.events.DialogBuilder
|
||||
import com.topjohnwu.magisk.ui.home.HomeViewModel
|
||||
import com.topjohnwu.magisk.view.MagiskDialog
|
||||
import com.topjohnwu.superuser.internal.UiThreadHandler
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class EnvFixDialog(private val vm: HomeViewModel, private val code: Int) : DialogBuilder {
|
||||
@@ -27,9 +32,15 @@ class EnvFixDialog(private val vm: HomeViewModel, private val code: Int) : Dialo
|
||||
setCancelable(false)
|
||||
}
|
||||
dialog.activity.lifecycleScope.launch {
|
||||
MagiskInstaller.FixEnv {
|
||||
MagiskInstaller.FixEnv().exec { success ->
|
||||
dialog.dismiss()
|
||||
}.exec()
|
||||
context.toast(
|
||||
if (success) R.string.reboot_delay_toast else R.string.setup_fail,
|
||||
Toast.LENGTH_LONG
|
||||
)
|
||||
if (success)
|
||||
UiThreadHandler.handler.postDelayed(5000) { reboot() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,15 +1,17 @@
|
||||
package com.topjohnwu.magisk.dialog
|
||||
|
||||
import android.app.ProgressDialog
|
||||
import android.content.Context
|
||||
import android.widget.Toast
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.topjohnwu.magisk.arch.NavigationActivity
|
||||
import com.topjohnwu.magisk.arch.UIActivity
|
||||
import com.topjohnwu.magisk.core.R
|
||||
import com.topjohnwu.magisk.core.ktx.toast
|
||||
import com.topjohnwu.magisk.core.tasks.MagiskInstaller
|
||||
import com.topjohnwu.magisk.events.DialogBuilder
|
||||
import com.topjohnwu.magisk.ui.flash.FlashFragment
|
||||
import com.topjohnwu.magisk.view.MagiskDialog
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class UninstallDialog : DialogBuilder {
|
||||
|
||||
@@ -19,7 +21,7 @@ class UninstallDialog : DialogBuilder {
|
||||
setMessage(R.string.uninstall_magisk_msg)
|
||||
setButton(MagiskDialog.ButtonType.POSITIVE) {
|
||||
text = R.string.restore_img
|
||||
onClick { restore(dialog.context) }
|
||||
onClick { restore(dialog.activity) }
|
||||
}
|
||||
setButton(MagiskDialog.ButtonType.NEGATIVE) {
|
||||
text = R.string.complete_uninstall
|
||||
@@ -29,18 +31,20 @@ class UninstallDialog : DialogBuilder {
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
private fun restore(context: Context) {
|
||||
val dialog = ProgressDialog(context).apply {
|
||||
setMessage(context.getString(R.string.restore_img_msg))
|
||||
private fun restore(activity: UIActivity<*>) {
|
||||
val dialog = ProgressDialog(activity).apply {
|
||||
setMessage(activity.getString(R.string.restore_img_msg))
|
||||
show()
|
||||
}
|
||||
|
||||
Shell.cmd("restore_imgs").submit { result ->
|
||||
dialog.dismiss()
|
||||
if (result.isSuccess) {
|
||||
context.toast(R.string.restore_done, Toast.LENGTH_SHORT)
|
||||
} else {
|
||||
context.toast(R.string.restore_fail, Toast.LENGTH_LONG)
|
||||
activity.lifecycleScope.launch {
|
||||
MagiskInstaller.Restore().exec { success ->
|
||||
dialog.dismiss()
|
||||
if (success) {
|
||||
activity.toast(R.string.restore_done, Toast.LENGTH_SHORT)
|
||||
} else {
|
||||
activity.toast(R.string.restore_fail, Toast.LENGTH_LONG)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -71,7 +71,7 @@ class FlashFragment : BaseFragment<FragmentFlashMd2Binding>(), MenuProvider {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
defaultOrientation = activity?.requestedOrientation ?: -1
|
||||
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR
|
||||
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LOCKED
|
||||
if (savedInstanceState == null) {
|
||||
viewModel.startFlashing()
|
||||
}
|
||||
|
@@ -8,6 +8,7 @@ import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewTreeObserver
|
||||
import android.widget.Toast
|
||||
import androidx.core.view.MenuProvider
|
||||
import androidx.core.view.isVisible
|
||||
@@ -16,8 +17,6 @@ import com.topjohnwu.magisk.arch.BaseFragment
|
||||
import com.topjohnwu.magisk.arch.viewModel
|
||||
import com.topjohnwu.magisk.core.ktx.toast
|
||||
import com.topjohnwu.magisk.databinding.FragmentActionMd2Binding
|
||||
import com.topjohnwu.magisk.ui.flash.FlashViewModel
|
||||
import timber.log.Timber
|
||||
import com.topjohnwu.magisk.core.R as CoreR
|
||||
|
||||
class ActionFragment : BaseFragment<FragmentActionMd2Binding>(), MenuProvider {
|
||||
@@ -37,39 +36,32 @@ class ActionFragment : BaseFragment<FragmentActionMd2Binding>(), MenuProvider {
|
||||
super.onStart()
|
||||
activity?.setTitle(viewModel.args.name)
|
||||
binding.closeBtn.setOnClickListener {
|
||||
activity?.onBackPressed();
|
||||
activity?.onBackPressed()
|
||||
}
|
||||
|
||||
viewModel.state.observe(this) {
|
||||
activity?.supportActionBar?.setSubtitle(
|
||||
when (it) {
|
||||
ActionViewModel.State.RUNNING -> CoreR.string.running
|
||||
ActionViewModel.State.SUCCESS -> CoreR.string.done
|
||||
ActionViewModel.State.FAILED -> CoreR.string.failure
|
||||
if (it != ActionViewModel.State.RUNNING) {
|
||||
binding.closeBtn.apply {
|
||||
if (!this.isVisible) this.show()
|
||||
if (!this.isFocused) this.requestFocus()
|
||||
}
|
||||
}
|
||||
if (it != ActionViewModel.State.SUCCESS) return@observe
|
||||
view?.viewTreeObserver?.addOnWindowFocusChangeListener(
|
||||
object : ViewTreeObserver.OnWindowFocusChangeListener {
|
||||
override fun onWindowFocusChanged(hasFocus: Boolean) {
|
||||
if (hasFocus) return
|
||||
view?.viewTreeObserver?.removeOnWindowFocusChangeListener(this)
|
||||
view?.context?.apply {
|
||||
toast(
|
||||
getString(CoreR.string.done_action, viewModel.args.name),
|
||||
Toast.LENGTH_SHORT
|
||||
)
|
||||
}
|
||||
viewModel.back()
|
||||
}
|
||||
}
|
||||
)
|
||||
when (it) {
|
||||
ActionViewModel.State.SUCCESS -> {
|
||||
activity?.apply {
|
||||
toast(
|
||||
getString(
|
||||
com.topjohnwu.magisk.core.R.string.done_action,
|
||||
this@ActionFragment.viewModel.args.name
|
||||
), Toast.LENGTH_LONG
|
||||
)
|
||||
onBackPressed()
|
||||
}
|
||||
}
|
||||
|
||||
ActionViewModel.State.FAILED -> {
|
||||
binding.closeBtn.apply {
|
||||
if (!this.isVisible) this.show()
|
||||
if (!this.isFocused) this.requestFocus()
|
||||
}
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +77,7 @@ class ActionFragment : BaseFragment<FragmentActionMd2Binding>(), MenuProvider {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
defaultOrientation = activity?.requestedOrientation ?: -1
|
||||
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR
|
||||
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LOCKED
|
||||
if (savedInstanceState == null) {
|
||||
viewModel.startRunAction()
|
||||
}
|
||||
|
@@ -1,28 +1,26 @@
|
||||
package com.topjohnwu.magisk.ui.module
|
||||
|
||||
import android.view.MenuItem
|
||||
import androidx.databinding.Bindable
|
||||
import androidx.databinding.ObservableArrayList
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.map
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.topjohnwu.magisk.BR
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.arch.BaseViewModel
|
||||
import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.magisk.core.ktx.synchronized
|
||||
import com.topjohnwu.magisk.core.ktx.timeFormatStandard
|
||||
import com.topjohnwu.magisk.core.ktx.toTime
|
||||
import com.topjohnwu.magisk.core.tasks.RunAction
|
||||
import com.topjohnwu.magisk.core.utils.MediaStoreUtils
|
||||
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
|
||||
import com.topjohnwu.magisk.databinding.set
|
||||
import com.topjohnwu.magisk.events.SnackbarEvent
|
||||
import com.topjohnwu.magisk.ui.flash.ConsoleItem
|
||||
import com.topjohnwu.superuser.CallbackList
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import timber.log.Timber
|
||||
import java.io.IOException
|
||||
|
||||
class ActionViewModel : BaseViewModel() {
|
||||
|
||||
@@ -32,7 +30,6 @@ class ActionViewModel : BaseViewModel() {
|
||||
|
||||
private val _state = MutableLiveData(State.RUNNING)
|
||||
val state: LiveData<State> get() = _state
|
||||
val running = state.map { it == State.RUNNING }
|
||||
|
||||
val items = ObservableArrayList<ConsoleItem>()
|
||||
lateinit var args: ActionFragmentArgs
|
||||
@@ -46,10 +43,17 @@ class ActionViewModel : BaseViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
fun startRunAction() {
|
||||
viewModelScope.launch {
|
||||
onResult(RunAction(args.id, outItems, logItems).exec())
|
||||
}
|
||||
fun startRunAction() = viewModelScope.launch {
|
||||
onResult(withContext(Dispatchers.IO) {
|
||||
try {
|
||||
Shell.cmd("run_action \'${args.id}\'")
|
||||
.to(outItems, logItems)
|
||||
.exec().isSuccess
|
||||
} catch (e: IOException) {
|
||||
Timber.e(e)
|
||||
false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun onResult(success: Boolean) {
|
||||
|
@@ -19,6 +19,7 @@ android {
|
||||
buildConfigField("int", "APP_VERSION_CODE", "${Config.versionCode}")
|
||||
buildConfigField("String", "APP_VERSION_NAME", "\"${Config.version}\"")
|
||||
buildConfigField("int", "STUB_VERSION", Config.stubVersion)
|
||||
consumerProguardFile("proguard-rules.pro")
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
|
@@ -22,36 +22,21 @@
|
||||
int mActivityHandlesConfigFlags;
|
||||
}
|
||||
|
||||
# main
|
||||
-keep,allowoptimization public class com.topjohnwu.magisk.signing.SignBoot {
|
||||
public static void main(java.lang.String[]);
|
||||
}
|
||||
|
||||
# Strip Timber verbose and debug logging
|
||||
-assumenosideeffects class timber.log.Timber$Tree {
|
||||
public void v(**);
|
||||
public void d(**);
|
||||
}
|
||||
|
||||
# https://github.com/square/retrofit/issues/3751#issuecomment-1192043644
|
||||
# Keep generic signature of Call, Response (R8 full mode strips signatures from non-kept items).
|
||||
-keep,allowobfuscation,allowshrinking interface retrofit2.Call
|
||||
-keep,allowobfuscation,allowshrinking class retrofit2.Response
|
||||
|
||||
# With R8 full mode generic signatures are stripped for classes that are not
|
||||
# kept. Suspend functions are wrapped in continuations where the type argument
|
||||
# is used.
|
||||
-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation
|
||||
|
||||
|
||||
# Excessive obfuscation
|
||||
-repackageclasses 'a'
|
||||
-flattenpackagehierarchy
|
||||
-allowaccessmodification
|
||||
|
||||
-obfuscationdictionary ../dict.txt
|
||||
-classobfuscationdictionary ../dict.txt
|
||||
-packageobfuscationdictionary ../dict.txt
|
||||
|
||||
-dontwarn org.bouncycastle.jsse.BCSSLParameters
|
||||
-dontwarn org.bouncycastle.jsse.BCSSLSocket
|
||||
-dontwarn org.bouncycastle.jsse.provider.BouncyCastleJsseProvider
|
@@ -191,11 +191,12 @@ object AppMigration {
|
||||
|
||||
// Install and auto launch app
|
||||
val session = APKInstall.startSession(activity, pkg, onFailure) {
|
||||
Config.suManager = pkg
|
||||
Shell.cmd("touch $AppApkPath").exec()
|
||||
launchApp(activity, pkg)
|
||||
}
|
||||
|
||||
Config.suManager = pkg
|
||||
val cmd = "touch $AppApkPath; adb_pm_install $repack $pkg"
|
||||
val cmd = "adb_pm_install $repack $pkg"
|
||||
if (Shell.cmd(cmd).exec().isSuccess) return true
|
||||
|
||||
try {
|
||||
@@ -240,11 +241,12 @@ object AppMigration {
|
||||
}
|
||||
val apk = StubApk.current(activity)
|
||||
val session = APKInstall.startSession(activity, APP_PACKAGE_NAME, onFailure) {
|
||||
Config.suManager = ""
|
||||
Shell.cmd("touch $AppApkPath").exec()
|
||||
launchApp(activity, APP_PACKAGE_NAME)
|
||||
dialog.dismiss()
|
||||
}
|
||||
Config.suManager = ""
|
||||
val cmd = "touch $AppApkPath; adb_pm_install $apk $APP_PACKAGE_NAME"
|
||||
val cmd = "adb_pm_install $apk $APP_PACKAGE_NAME"
|
||||
if (Shell.cmd(cmd).await().isSuccess) return
|
||||
val success = withContext(Dispatchers.IO) {
|
||||
try {
|
||||
|
@@ -6,7 +6,6 @@ import android.system.ErrnoException
|
||||
import android.system.Os
|
||||
import android.system.OsConstants
|
||||
import android.system.OsConstants.O_WRONLY
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.WorkerThread
|
||||
import androidx.core.os.postDelayed
|
||||
import com.topjohnwu.magisk.StubApk
|
||||
@@ -15,13 +14,10 @@ import com.topjohnwu.magisk.core.BuildConfig
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.magisk.core.R
|
||||
import com.topjohnwu.magisk.core.di.ServiceLocator
|
||||
import com.topjohnwu.magisk.core.isRunningAsStub
|
||||
import com.topjohnwu.magisk.core.ktx.copyAll
|
||||
import com.topjohnwu.magisk.core.ktx.copyAndClose
|
||||
import com.topjohnwu.magisk.core.ktx.reboot
|
||||
import com.topjohnwu.magisk.core.ktx.toast
|
||||
import com.topjohnwu.magisk.core.ktx.writeTo
|
||||
import com.topjohnwu.magisk.core.utils.DummyList
|
||||
import com.topjohnwu.magisk.core.utils.MediaStoreUtils
|
||||
@@ -585,6 +581,8 @@ abstract class MagiskInstallImpl protected constructor(
|
||||
|
||||
protected suspend fun fixEnv() = extractFiles() && "fix_env $installDir".sh().isSuccess
|
||||
|
||||
protected fun restore() = findImage() && "restore_imgs $srcBoot".sh().isSuccess
|
||||
|
||||
protected fun uninstall() = "run_uninstaller $AppApkPath".sh().isSuccess
|
||||
|
||||
@WorkerThread
|
||||
@@ -608,11 +606,10 @@ abstract class MagiskInstallImpl protected constructor(
|
||||
}
|
||||
}
|
||||
|
||||
abstract class MagiskInstaller(
|
||||
abstract class ConsoleInstaller(
|
||||
console: MutableList<String>,
|
||||
logs: MutableList<String>
|
||||
) : MagiskInstallImpl(console, logs) {
|
||||
|
||||
override suspend fun exec(): Boolean {
|
||||
val success = super.exec()
|
||||
if (success) {
|
||||
@@ -622,40 +619,51 @@ abstract class MagiskInstaller(
|
||||
}
|
||||
return success
|
||||
}
|
||||
}
|
||||
|
||||
abstract class CallBackInstaller : MagiskInstallImpl(DummyList, DummyList) {
|
||||
suspend fun exec(callback: (Boolean) -> Unit): Boolean {
|
||||
val success = exec()
|
||||
callback(success)
|
||||
return success
|
||||
}
|
||||
}
|
||||
|
||||
class MagiskInstaller {
|
||||
|
||||
class Patch(
|
||||
private val uri: Uri,
|
||||
console: MutableList<String>,
|
||||
logs: MutableList<String>
|
||||
) : MagiskInstaller(console, logs) {
|
||||
) : ConsoleInstaller(console, logs) {
|
||||
override suspend fun operations() = patchFile(uri)
|
||||
}
|
||||
|
||||
class SecondSlot(
|
||||
console: MutableList<String>,
|
||||
logs: MutableList<String>
|
||||
) : MagiskInstaller(console, logs) {
|
||||
) : ConsoleInstaller(console, logs) {
|
||||
override suspend fun operations() = secondSlot()
|
||||
}
|
||||
|
||||
class Direct(
|
||||
console: MutableList<String>,
|
||||
logs: MutableList<String>
|
||||
) : MagiskInstaller(console, logs) {
|
||||
) : ConsoleInstaller(console, logs) {
|
||||
override suspend fun operations() = direct()
|
||||
}
|
||||
|
||||
class Emulator(
|
||||
console: MutableList<String>,
|
||||
logs: MutableList<String>
|
||||
) : MagiskInstaller(console, logs) {
|
||||
) : ConsoleInstaller(console, logs) {
|
||||
override suspend fun operations() = fixEnv()
|
||||
}
|
||||
|
||||
class Uninstall(
|
||||
console: MutableList<String>,
|
||||
logs: MutableList<String>
|
||||
) : MagiskInstallImpl(console, logs) {
|
||||
) : ConsoleInstaller(console, logs) {
|
||||
override suspend fun operations() = uninstall()
|
||||
|
||||
override suspend fun exec(): Boolean {
|
||||
@@ -669,19 +677,11 @@ abstract class MagiskInstaller(
|
||||
}
|
||||
}
|
||||
|
||||
class FixEnv(private val callback: () -> Unit) : MagiskInstallImpl(DummyList, DummyList) {
|
||||
override suspend fun operations() = fixEnv()
|
||||
class Restore : CallBackInstaller() {
|
||||
override suspend fun operations() = restore()
|
||||
}
|
||||
|
||||
override suspend fun exec(): Boolean {
|
||||
val success = super.exec()
|
||||
callback()
|
||||
context.toast(
|
||||
if (success) R.string.reboot_delay_toast else R.string.setup_fail,
|
||||
Toast.LENGTH_LONG
|
||||
)
|
||||
if (success)
|
||||
UiThreadHandler.handler.postDelayed(5000) { reboot() }
|
||||
return success
|
||||
}
|
||||
class FixEnv : CallBackInstaller() {
|
||||
override suspend fun operations() = fixEnv()
|
||||
}
|
||||
}
|
||||
|
@@ -1,42 +0,0 @@
|
||||
package com.topjohnwu.magisk.core.tasks
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.core.net.toFile
|
||||
import com.topjohnwu.magisk.core.AppContext
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.ktx.writeTo
|
||||
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.displayName
|
||||
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.inputStream
|
||||
import com.topjohnwu.magisk.core.utils.unzip
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import java.io.FileNotFoundException
|
||||
import java.io.IOException
|
||||
|
||||
open class RunAction(
|
||||
private val module: String,
|
||||
private val console: MutableList<String>,
|
||||
private val logs: MutableList<String>
|
||||
) {
|
||||
@Throws(IOException::class)
|
||||
private suspend fun run(): Boolean {
|
||||
return Shell.cmd("run_action \'$module\'").to(console, logs).exec().isSuccess
|
||||
}
|
||||
|
||||
open suspend fun exec() = withContext(Dispatchers.IO) {
|
||||
try {
|
||||
if (!run()) {
|
||||
console.add("! Run action failed")
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
Timber.e(e)
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
package com.topjohnwu.magisk.core.utils;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.util.zip.ZipEntry;
|
||||
|
||||
public class Desugar {
|
||||
public static FileTime getLastModifiedTime(ZipEntry entry) {
|
||||
if (Build.VERSION.SDK_INT >= 26) {
|
||||
return entry.getLastModifiedTime();
|
||||
} else {
|
||||
return FileTime.fromMillis(entry.getTime());
|
||||
}
|
||||
}
|
||||
|
||||
public static FileTime getLastAccessTime(ZipEntry entry) {
|
||||
if (Build.VERSION.SDK_INT >= 26) {
|
||||
return entry.getLastAccessTime();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static FileTime getCreationTime(ZipEntry entry) {
|
||||
if (Build.VERSION.SDK_INT >= 26) {
|
||||
return entry.getCreationTime();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@@ -2,154 +2,130 @@
|
||||
|
||||
<!--Sections-->
|
||||
<string name="modules">الإضافات</string>
|
||||
<string name="superuser">المستخدم الخارق</string>
|
||||
<string name="superuser">صلاحية الروت</string>
|
||||
<string name="logs">السجلات</string>
|
||||
<string name="settings">الإعدادات</string>
|
||||
<string name="install">التثبيت</string>
|
||||
<string name="section_home">الرئيسية</string>
|
||||
<string name="section_theme">المظهر</string>
|
||||
<string name="denylist">القائمة السوداء</string>
|
||||
<string name="install">تثبيت</string>
|
||||
<string name="section_home">الأساسي</string>
|
||||
<string name="section_theme">السِمات</string>
|
||||
|
||||
<!--Home-->
|
||||
<string name="no_connection">لا يوجد اتصال متاح</string>
|
||||
<string name="app_changelog">سجل التغييرات</string>
|
||||
<string name="no_connection">لا يوجد إتصال</string>
|
||||
<string name="app_changelog">تفاصيل التحديث</string>
|
||||
<string name="loading">جارٍ التحميل...</string>
|
||||
<string name="update">تحديث</string>
|
||||
<string name="not_available">غير متاح</string>
|
||||
<string name="not_available">غير/متوفر</string>
|
||||
<string name="hide">إخفاء</string>
|
||||
<string name="home_package">الحزمة</string>
|
||||
<string name="home_app_title">التطبيق</string>
|
||||
|
||||
<string name="home_notice_content">قم بتحميل Magisk فقط من صفحة GitHub الرسمية. الملفات من مصادر غير معروفة قد تكون ضارة!</string>
|
||||
<string name="home_support_title">ادعمنا</string>
|
||||
<string name="home_follow_title">تابعنا</string>
|
||||
<string name="home_item_source">المصدر</string>
|
||||
<string name="home_support_content">Magisk مجاني ومفتوح المصدر وسيظل كذلك دائمًا. يمكنك إظهار دعمك لنا من خلال التبرع.</string>
|
||||
<string name="home_installed_version">المثبتة</string>
|
||||
<string name="home_latest_version">الأحدث</string>
|
||||
<string name="invalid_update_channel">قناة التحديث غير صالحة</string>
|
||||
<string name="home_support_title">تبرع لنا</string>
|
||||
<string name="home_item_source">الكود المصدري للتطبيق</string>
|
||||
<string name="home_support_content">مـاجـيسك هي، وستظل دوماً، مجانيةً و مفتوحة المصدر، اظهر اهتمامك لنا لكي نبقيها هكذا بدعم مالي صغير</string>
|
||||
<string name="home_installed_version">تم التثبيت</string>
|
||||
<string name="home_latest_version">آخر إصدار</string>
|
||||
<string name="invalid_update_channel">مصدر التحديث غير صالح</string>
|
||||
<string name="uninstall_magisk_title">إلغاء تثبيت Magisk</string>
|
||||
<string name="uninstall_magisk_msg">ستتم إزالة جميع الوحدات / تعطيلها!\nسيتم إزالة الروت!\nأي تخزين داخلي تم فك تشفيره باستخدام Magisk سيتم إعادة تشفيره!</string>
|
||||
<string name="uninstall_magisk_msg">ستُعطل/ستُحذف جميع الإضافات. سيُحذف الروت، وربما ستشفر بياناتك إذا لم تكن غير مشفرة حالياً.</string>
|
||||
|
||||
<!--Install-->
|
||||
<string name="keep_force_encryption">الحفاظ على التشفير الإجباري</string>
|
||||
<string name="keep_dm_verity">الحفاظ على AVB 2.0/dm-verity</string>
|
||||
<string name="recovery_mode">وضع الاسترداد</string>
|
||||
<string name="keep_force_encryption">فرض التشفير الإجباري</string>
|
||||
<string name="keep_dm_verity">فرض تشفيرات AVB2.0/dm-verity</string>
|
||||
<string name="recovery_mode">وضـع الريكفري</string>
|
||||
<string name="install_options_title">الخيارات</string>
|
||||
<string name="install_method_title">الطريقة</string>
|
||||
<string name="install_next">التالي</string>
|
||||
<string name="install_start">هيا بنا</string>
|
||||
<string name="manager_download_install">اضغط للتنزيل والتثبيت</string>
|
||||
<string name="direct_install">التثبيت المباشر (موصى به)</string>
|
||||
<string name="install_inactive_slot">التثبيت على الشريحة غير النشطة (بعد OTA)</string>
|
||||
<string name="install_inactive_slot_msg">سيتم إجبار جهازك على التمهيد إلى الشريحة غير النشطة الحالية بعد إعادة التشغيل!\nاستخدم هذا الخيار فقط بعد الانتهاء من OTA.\nهل تود المتابعة؟</string>
|
||||
<string name="setup_title">إعداد إضافي</string>
|
||||
<string name="select_patch_file">اختر وقم بعمل باتش ملف</string>
|
||||
<string name="patch_file_msg">اختر صورة خام (*.img) أو ملف ODIN tarfile (*.tar) أو payload.bin (*.bin)</string>
|
||||
<string name="reboot_delay_toast">سيتم إعادة التشغيل في 5 ثوانٍ...</string>
|
||||
<string name="install_start">هيا، بنا</string>
|
||||
<string name="manager_download_install">اضغط للتنزيل و التثبيت</string>
|
||||
<string name="direct_install">تثبيت مباشر (موصى بها)</string>
|
||||
<string name="install_inactive_slot">التثبيت على المنطقة الغير نشطة (بعد OTA)</string>
|
||||
<string name="install_inactive_slot_msg">سيُجبر جهازك للاقلاع على المنطقة الغير النشطة بعد إعادة التشغيل!\n استخدم هذا الخيار فقط بعد الانتهاء من OTA. استمرار؟</string>
|
||||
<string name="setup_title">إعدادات إضافية</string>
|
||||
<string name="select_patch_file">حدد و عدل ملفاً</string>
|
||||
<string name="patch_file_msg">اختر ملف (*.img) أو ملف odin (*.tar)</string>
|
||||
<string name="reboot_delay_toast">إعادة التشغيل بعد ٥ ثواني…</string>
|
||||
<string name="flash_screen_title">التثبيت</string>
|
||||
|
||||
<!--Superuser-->
|
||||
<string name="su_request_title">طلب المستخدم الخارق</string>
|
||||
<string name="touch_filtered_warning">نظرًا لأن تطبيقًا ما يحجب طلب المستخدم الخارق، لا يمكن لـ Magisk التحقق من استجابتك</string>
|
||||
<string name="su_request_title">طلبات صلاحية الروت</string>
|
||||
<string name="deny">رفض</string>
|
||||
<string name="prompt">إشعار</string>
|
||||
<string name="grant">منح</string>
|
||||
<string name="su_warning">يمنح حق الوصول الكامل لجهازك.\nارفض إذا لم تكن متأكدًا!</string>
|
||||
<string name="forever">دائمًا</string>
|
||||
<string name="prompt">طلب</string>
|
||||
<string name="grant">سماح</string>
|
||||
<string name="su_warning">يمنح حق الوصول الكامل إلى جهازك. ارفض إذا كنت غير متأكد!</string>
|
||||
<string name="forever">للأبد</string>
|
||||
<string name="once">مرة واحدة</string>
|
||||
<string name="tenmin">جار0 دقائق</string>
|
||||
<string name="tenmin">10 دقائق</string>
|
||||
<string name="twentymin">20 دقيقة</string>
|
||||
<string name="thirtymin">30 دقيقة</string>
|
||||
<string name="sixtymin">60 دقيقة</string>
|
||||
<string name="su_allow_toast">%جار$s تم منحه حقوق المستخدم الخارق</string>
|
||||
<string name="su_deny_toast">%جار$s تم رفض حقوق المستخدم الخارق</string>
|
||||
<string name="su_snack_grant">تم منح حقوق المستخدم الخارق لـ %جار$s</string>
|
||||
<string name="su_snack_deny">تم رفض حقوق المستخدم الخارق لـ %جار$s</string>
|
||||
<string name="su_snack_notif_on">تم تفعيل الإشعارات لـ %جار$s</string>
|
||||
<string name="su_snack_notif_off">تم تعطيل الإشعارات لـ %جار$s</string>
|
||||
<string name="su_snack_log_on">تم تفعيل السجلات لـ %جار$s</string>
|
||||
<string name="su_snack_log_off">تم تعطيل السجلات لـ %جار$s</string>
|
||||
<string name="su_revoke_title">إلغاء؟</string>
|
||||
<string name="su_revoke_msg">تأكيد لإلغاء حقوق المستخدم الخارق لـ %جار$s</string>
|
||||
<string name="toast">إشعار</string>
|
||||
<string name="none">لا شيء</string>
|
||||
<string name="su_allow_toast">تم منح صلاحيات الروت لـ%1$s</string>
|
||||
<string name="su_deny_toast">تم رفض صلاحيات الروت لـ%1$s </string>
|
||||
<string name="su_snack_grant">تم منح صلاحيات الروت لـ%1$s</string>
|
||||
<string name="su_snack_deny">تم رفض صلاحيات الروت لـ%1$s</string>
|
||||
<string name="su_snack_notif_on">تم تفعيل الإشعارات لـ%1$s</string>
|
||||
<string name="su_snack_notif_off">تم تعطيل الإشعارات لـ%1$s</string>
|
||||
<string name="su_snack_log_on">تم تفعيل السجلات لـ%1$s</string>
|
||||
<string name="su_snack_log_off">تم تعطيل السجلات لـ%1$s</string>
|
||||
<string name="su_revoke_title">منع؟</string>
|
||||
<string name="su_revoke_msg">هل تريد منع صلاحية %1$s?</string>
|
||||
<string name="toast">اشعار</string>
|
||||
<string name="none">بدون</string>
|
||||
|
||||
<string name="superuser_toggle_notification">الإشعارات</string>
|
||||
<string name="superuser_toggle_revoke">إلغاء</string>
|
||||
<string name="superuser_policy_none">لم يطلب أي تطبيق بعد إذن المستخدم الخارق.</string>
|
||||
<string name="superuser_toggle_revoke">منع</string>
|
||||
<string name="superuser_policy_none">لم يسأل آية تطبيق لصلاحيات الروت</string>
|
||||
|
||||
<!--Logs-->
|
||||
<string name="log_data_none">أنت خالٍ من السجلات، جرب استخدام تطبيقات الروت الخاصة بك أكثر</string>
|
||||
<string name="log_data_magisk_none">سجلات Magisk فارغة، هذا غريب</string>
|
||||
<string name="menuSaveLog">حفظ السجل</string>
|
||||
<string name="menuClearLog">مسح السجل الآن</string>
|
||||
<string name="logs_cleared">تم مسح السجل بنجاح</string>
|
||||
<string name="pid">PID: %جار$d</string>
|
||||
<string name="target_uid">UID الهدف: %جار$d</string>
|
||||
<string name="target_pid">PID هدف النطاق المركب: %s</string>
|
||||
<string name="selinux_context">سياق SELinux: %s</string>
|
||||
<string name="supp_group">المجموعة التكميلية: %s</string>
|
||||
<string name="log_data_none">لا يوجد أية سجلات هنا :-:، حاول استعمال تطبيقات روت اكثر</string>
|
||||
<string name="log_data_magisk_none">لا توجد أيةَ سجلات ⊙_⊙</string>
|
||||
<string name="menuSaveLog">حفظ السجلات</string>
|
||||
<string name="menuClearLog">حذف السجلات</string>
|
||||
<string name="logs_cleared">تم الحذف بنجاح</string>
|
||||
<string name="pid">PID: %1$d</string>
|
||||
<string name="target_uid">UID: %1$d</string>
|
||||
|
||||
<!--SafetyNet-->
|
||||
|
||||
<!--MagiskHide-->
|
||||
<string name="show_system_app">عرض تطبيقات النظام</string>
|
||||
<string name="show_os_app">عرض تطبيقات نظام التشغيل</string>
|
||||
<string name="hide_filter_hint">التصفية بالاسم</string>
|
||||
<string name="hide_search">بحث</string>
|
||||
<!-- MagiskHide -->
|
||||
<string name="show_system_app">إظهار برامج النظام</string>
|
||||
<string name="hide_filter_hint">البحث بالإسم</string>
|
||||
<string name="hide_search">ابحث</string>
|
||||
|
||||
<!--Module-->
|
||||
<string name="no_info_provided">(لم يتم تقديم معلومات)</string>
|
||||
<string name="reboot_userspace">إعادة تشغيل ناعمة</string>
|
||||
<string name="reboot_recovery">إعادة التشغيل إلى وضع الاسترداد</string>
|
||||
<string name="reboot_bootloader">إعادة التشغيل إلى محمل الإقلاع</string>
|
||||
<string name="reboot_download">إعادة التشغيل إلى وضع التنزيل</string>
|
||||
<string name="reboot_edl">إعادة التشغيل إلى وضع EDL</string>
|
||||
<string name="reboot_safe_mode">وضع الآمن</string>
|
||||
<string name="module_state_remove">إزالة</string>
|
||||
<string name="module_state_restore">استعادة</string>
|
||||
<string name="module_action_install_external">التثبيت من التخزين</string>
|
||||
<string name="update_available">تحديث متاح</string>
|
||||
<string name="suspend_text_riru">تم تعليق الإضافةة لأن %جار$s مفعّل</string>
|
||||
<string name="suspend_text_zygisk">تم تعليق الإضافةة لأن %جار$s غير مفعّل</string>
|
||||
<string name="zygisk_module_unloaded">لم يتم تحميل إضافة Zygisk بسبب عدم التوافق</string>
|
||||
<string name="module_empty">لم يتم تثبيت أي إضافة</string>
|
||||
<string name="confirm_install">هل تريد تثبيت الإضافة %جار$s؟</string>
|
||||
<string name="confirm_install_title">تأكيد التثبيت</string>
|
||||
<!--Module Fragment-->
|
||||
<string name="no_info_provided">(لم توفر معلومات)</string>
|
||||
<string name="reboot_recovery">إعادة التشغيل إلى Recovery</string>
|
||||
<string name="reboot_bootloader">إعادة التشغيل إلى Bootloader</string>
|
||||
<string name="reboot_download">إعادة التشغيل إلى وضـع Odin</string>
|
||||
<string name="reboot_edl">إعادة التشغيل إلى وضـعية EDL</string>
|
||||
<string name="module_version_author">%1$sبواسطة%2$s</string>
|
||||
<string name="module_state_remove">إزالة </string>
|
||||
<string name="module_state_restore">إسترجاع</string>
|
||||
<string name="module_action_install_external">اختر من الذاكرة الداخلية</string>
|
||||
<string name="update_available">التحديث متوفر</string>
|
||||
<string name="external_rw_permission_denied">امنحني إذن الولوج للذاكرة الداخلية</string>
|
||||
|
||||
<!--Settings-->
|
||||
<string name="settings_dark_mode_title">وضع الثيم</string>
|
||||
<string name="settings_dark_mode_message">اختر الوضع الذي يناسب نمطك!</string>
|
||||
<string name="settings_dark_mode_light">دائمًا فاتح</string>
|
||||
<string name="settings_dark_mode_system">تابع النظام</string>
|
||||
<string name="settings_dark_mode_dark">دائمًا داكن</string>
|
||||
<string name="settings_download_path_title">مسار التنزيل</string>
|
||||
<string name="settings_download_path_message">سيتم حفظ الملفات في %جار$s</string>
|
||||
<string name="settings_hide_app_title">إخفاء تطبيق Magisk</string>
|
||||
<string name="settings_hide_app_summary">تثبيت تطبيق وكيل بمعرف حزمة عشوائي واسم تطبيق مخصص</string>
|
||||
<string name="settings_restore_app_title">استعادة تطبيق Magisk</string>
|
||||
<string name="settings_restore_app_summary">إظهار التطبيق واستعادة APK الأصلي</string>
|
||||
<!--Settings -->
|
||||
<string name="settings_dark_mode_title">وضـعية الِسمات</string>
|
||||
<string name="settings_dark_mode_message">حدد الوضـع الذي يناسب ذوقك</string>
|
||||
<string name="settings_dark_mode_light">الوضـع المضيء</string>
|
||||
<string name="settings_dark_mode_system">اتبّع النظام</string>
|
||||
<string name="settings_dark_mode_dark">وضـع الظلام</string>
|
||||
<string name="settings_download_path_title">مسار التحميل</string>
|
||||
<string name="settings_download_path_message">ستحمل الملفات إلى %1$s</string>
|
||||
<string name="language">اللغة</string>
|
||||
<string name="system_default">(افتراضي النظام)</string>
|
||||
<string name="system_default">(الأفتراضي)</string>
|
||||
<string name="settings_check_update_title">تحقق من التحديثات</string>
|
||||
<string name="settings_check_update_summary">التحقق دوريًا من التحديثات في الخلفية</string>
|
||||
<string name="settings_update_channel_title">قناة التحديث</string>
|
||||
<string name="settings_check_update_summary">التحقق من التحديثات في الخلفية بشكل دوري</string>
|
||||
<string name="settings_update_channel_title">مصدر التحديثات</string>
|
||||
<string name="settings_update_stable">مستقر</string>
|
||||
<string name="settings_update_beta">بيتا</string>
|
||||
<string name="settings_update_beta">تجريبي</string>
|
||||
<string name="settings_update_custom">مخصص</string>
|
||||
<string name="settings_update_custom_msg">أدخل عنوان URL لقناة مخصصة</string>
|
||||
<string name="settings_zygisk_summary">تشغيل أجزاء من Magisk في خدمة zygote</string>
|
||||
<string name="settings_denylist_title">تفعيل القائمة السوداء</string>
|
||||
<string name="settings_denylist_summary">سيتم إرجاع جميع تعديلات Magisk للعمليات الموجودة في القائمة السوداء</string>
|
||||
<string name="settings_denylist_config_title">تكوين القائمة السوداء</string>
|
||||
<string name="settings_denylist_config_summary">اختر العمليات التي سيتم تضمينها في القائمة السوداء</string>
|
||||
<string name="settings_hosts_title">مضيفين بدون نظام</string>
|
||||
<string name="settings_hosts_summary">دعم المضيفين بدون نظام لتطبيقات حظر الإعلانات</string>
|
||||
<string name="settings_hosts_toast">تم إضافة إضافة المضيفين بدون نظام</string>
|
||||
<string name="settings_app_name_hint">اسم جديد</string>
|
||||
<string name="settings_app_name_helper">سيتم إعادة تغليف التطبيق بهذا الاسم</string>
|
||||
<string name="settings_app_name_error">تنسيق غير صالح</string>
|
||||
<string name="settings_update_custom_msg">أدخل الرابط لمصدرك المخصص</string>
|
||||
<string name="settings_hosts_title">موانع الاعلانات</string>
|
||||
<string name="settings_hosts_summary">حجب الاعلانات دون تعديل النظام</string>
|
||||
<string name="settings_hosts_toast">تم تمكين خاصية حجب الاعلانات</string>
|
||||
<string name="settings_app_name_hint">الإسم الجديد</string>
|
||||
<string name="settings_app_name_helper">التطبيق الجديد سوف يملك هذا الإسم</string>
|
||||
<string name="settings_app_name_error">الصيغة غير مقبولة</string>
|
||||
<string name="settings_su_app_adb">التطبيقات و ADB</string>
|
||||
<string name="settings_su_app">التطبيقات فقط</string>
|
||||
<string name="settings_su_adb">ADB فقط</string>
|
||||
@@ -160,86 +136,55 @@
|
||||
<string name="settings_su_request_30">30 ثانية</string>
|
||||
<string name="settings_su_request_45">45 ثانية</string>
|
||||
<string name="settings_su_request_60">60 ثانية</string>
|
||||
<string name="superuser_access">وصول المستخدم الخارق</string>
|
||||
<string name="auto_response">استجابة تلقائية</string>
|
||||
<string name="request_timeout">انتهاء مهلة الطلب</string>
|
||||
<string name="superuser_notification">إشعار المستخدم الخارق</string>
|
||||
<string name="settings_su_reauth_title">إعادة التوثيق بعد الترقية</string>
|
||||
<string name="settings_su_reauth_summary">طلب أذونات المستخدم الخارق مرة أخرى بعد ترقية التطبيقات</string>
|
||||
<string name="settings_su_tapjack_title">حماية من اختراق النقرات</string>
|
||||
<string name="settings_su_tapjack_summary">لن يستجيب مربع حوار طلب المستخدم الخارق لأي إدخال أثناء تغطيته بواسطة أي نافذة أو تراكب آخر</string>
|
||||
<string name="settings_su_auth_title">توثيق المستخدم</string>
|
||||
<string name="settings_su_auth_summary">طلب توثيق المستخدم أثناء طلبات المستخدم الخارق</string>
|
||||
<string name="settings_su_auth_insecure">لا توجد طريقة توثيق مهيأة على الجهاز</string>
|
||||
<string name="settings_customization">التخصيص</string>
|
||||
<string name="setting_add_shortcut_summary">إضافة اختصار جميل إلى الشاشة الرئيسية في حالة كان الاسم والأيقونة صعب التعرف عليهما بعد إخفاء التطبيق</string>
|
||||
<string name="settings_doh_title">DNS عبر HTTPS</string>
|
||||
<string name="settings_doh_description">الحل لمشكلة تسميم DNS في بعض الدول</string>
|
||||
<string name="settings_random_name_title">تغيير الاسم عشوائيًا</string>
|
||||
<string name="settings_random_name_description">تغيير اسم ملف الخرج عشوائيًا لصور وملفات tar المصححة لمنع الاكتشاف</string>
|
||||
<string name="superuser_access">صلاحيات الروت</string>
|
||||
<string name="auto_response">الفعل التلقائي</string>
|
||||
<string name="request_timeout">المهلة قبل الفعل التلقائي</string>
|
||||
<string name="superuser_notification">إشعارات طلبات الروت</string>
|
||||
<string name="settings_su_reauth_title">إعادة المصادقة بعد الترقية</string>
|
||||
<string name="settings_su_reauth_summary">أعد مصادقة صلاحيات الروت بعد إجراء ترقيات للتطبيق</string>
|
||||
<string name="settings_customization">تخصيص</string>
|
||||
|
||||
<string name="multiuser_mode">وضع المستخدمين المتعددين</string>
|
||||
<string name="multiuser_mode">نمط مستخدمين متعددين</string>
|
||||
<string name="settings_owner_only">مالك الجهاز فقط</string>
|
||||
<string name="settings_owner_manage">يديرها مالك الجهاز</string>
|
||||
<string name="settings_user_independent">مستقل عن المستخدم</string>
|
||||
<string name="owner_only_summary">فقط المالك له وصول روت</string>
|
||||
<string name="owner_manage_summary">فقط المالك يمكنه إدارة وصول الروت وتلقي طلبات الإذن</string>
|
||||
<string name="user_independent_summary">كل مستخدم لديه قواعد الروت الخاصة به</string>
|
||||
<string name="settings_owner_manage">المالك هو من يحدد</string>
|
||||
<string name="settings_user_independent">مستقل </string>
|
||||
<string name="owner_only_summary">للمالك فقط له صلاحيات الروت</string>
|
||||
<string name="owner_manage_summary">فقط المالك من يرفض و يمنح صلاحيات الروت</string>
|
||||
<string name="user_independent_summary">كل مستخدم له قواعد روت خاصة به</string>
|
||||
|
||||
<string name="mount_namespace_mode">وضع مساحة التثبيت</string>
|
||||
<string name="settings_ns_global">مساحة أسماء عامة</string>
|
||||
<string name="settings_ns_requester">وراثة مساحة الأسماء</string>
|
||||
<string name="settings_ns_isolate">مساحة أسماء معزولة</string>
|
||||
<string name="global_summary">جميع جلسات الروت تستخدم مساحة التثبيت العامة</string>
|
||||
<string name="requester_summary">جلسات الروت سترث مساحة الأسماء من طالب الروت</string>
|
||||
<string name="isolate_summary">كل جلسة روت سيكون لها مساحة أسماء معزولة خاصة بها</string>
|
||||
<string name="mount_namespace_mode">نمط Mount Namespace</string>
|
||||
<string name="settings_ns_global">نمط Namespace العام</string>
|
||||
<string name="settings_ns_requester">نمط NameSpace المتوارث</string>
|
||||
<string name="settings_ns_isolate">نمط NameSpace المعزول</string>
|
||||
<string name="global_summary">جميع الجلسات الروت تستخدم NameSpace العام</string>
|
||||
<string name="requester_summary">جميع الجلسات الروت تستخدم NameSpace المتوارث</string>
|
||||
<string name="isolate_summary">جميع الجلسات الروت تستخدم NameSpace المعزول</string>
|
||||
|
||||
<!--Notifications-->
|
||||
<string name="update_channel">تحديثات Magisk</string>
|
||||
<string name="progress_channel">إشعارات التقدم</string>
|
||||
<string name="updated_channel">اكتمل التحديث</string>
|
||||
<string name="download_complete">اكتمل التنزيل</string>
|
||||
<string name="download_file_error">خطأ في تنزيل الملف</string>
|
||||
<string name="magisk_update_title">تحديث Magisk متاح!</string>
|
||||
<string name="updated_title">تم تحديث Magisk</string>
|
||||
<string name="updated_text">اضغط لفتح التطبيق</string>
|
||||
<string name="download_file_error">فشل تنزيل الملف</string>
|
||||
<string name="magisk_update_title">تحديث مـاجـيسك متوفر!</string>
|
||||
|
||||
<!--Toasts, Dialogs-->
|
||||
<string name="yes">نعم</string>
|
||||
<string name="no">لا</string>
|
||||
<string name="download">تنزيل</string>
|
||||
<string name="reboot">إعادة التشغيل</string>
|
||||
<string name="release_notes">ملاحظات الإصدار</string>
|
||||
<string name="flashing">جارٍ التثبيت...</string>
|
||||
<string name="release_notes">معلومات الأصدار الجديد</string>
|
||||
<string name="flashing">يتم الحرق...</string>
|
||||
<string name="done">تم!</string>
|
||||
<string name="failure">فشل!</string>
|
||||
<string name="hide_app_title">جارٍ إخفاء تطبيق Magisk...</string>
|
||||
<string name="open_link_failed_toast">لم يتم العثور على تطبيق لفتح الرابط</string>
|
||||
<string name="complete_uninstall">إلغاء التثبيت الكامل</string>
|
||||
<string name="open_link_failed_toast">لم يُعثر على تطبيق لفتح الرابط …</string>
|
||||
<string name="complete_uninstall">إلغاء التثبيت بالكامل</string>
|
||||
<string name="restore_img">استعادة الصور</string>
|
||||
<string name="restore_img_msg">جارٍ الاستعادة...</string>
|
||||
<string name="restore_done">اكتملت الاستعادة!</string>
|
||||
<string name="restore_fail">لا يوجد نسخة احتياطية أصلية!</string>
|
||||
<string name="setup_fail">فشل الإعداد</string>
|
||||
<string name="env_fix_title">يتطلب إعداد إضافي</string>
|
||||
<string name="env_fix_msg">يحتاج جهازك إلى إعداد إضافي ليعمل Magisk بشكل صحيح. هل تريد المتابعة وإعادة التشغيل؟</string>
|
||||
<string name="env_full_fix_msg">يحتاج جهازك إلى إعادة تثبيت Magisk ليعمل بشكل صحيح. يرجى إعادة تثبيت Magisk من داخل التطبيق، لا يمكن لوضع الاسترداد الحصول على معلومات الجهاز الصحيحة.</string>
|
||||
<string name="setup_msg">جارٍ تشغيل إعداد البيئة...</string>
|
||||
<string name="unsupport_magisk_title">إصدار Magisk غير مدعوم</string>
|
||||
<string name="unsupport_magisk_msg">هذا الإصدار من التطبيق لا يدعم إصدارات Magisk الأقل من %جار$s.\n\nسيعمل التطبيق كما لو أن Magisk غير مثبت، يرجى ترقية Magisk في أقرب وقت ممكن.</string>
|
||||
<string name="unsupport_general_title">حالة غير طبيعية</string>
|
||||
<string name="unsupport_system_app_msg">تشغيل هذا التطبيق كتطبيق نظام غير مدعوم. يرجى إعادة التطبيق إلى تطبيق مستخدم.</string>
|
||||
<string name="unsupport_other_su_msg">تم اكتشاف "su" ثنائي ليس من Magisk. يرجى إزالة أي حل روت منافس و/أو إعادة تثبيت Magisk.</string>
|
||||
<string name="unsupport_external_storage_msg">تم تثبيت Magisk في التخزين الخارجي. يرجى نقل التطبيق إلى التخزين الداخلي.</string>
|
||||
<string name="unsupport_nonroot_stub_msg">لا يمكن للتطبيق المخفي Magisk الاستمرار في العمل لأن الروت قد فقد. يرجى استعادة APK الأصلي.</string>
|
||||
<string name="unsupport_nonroot_stub_title">@string/settings_restore_app_title</string>
|
||||
<string name="external_rw_permission_denied">امنح إذن التخزين لتمكين هذه الوظيفة</string>
|
||||
<string name="post_notifications_denied">امنح إذن الإشعارات لتمكين هذه الوظيفة</string>
|
||||
<string name="install_unknown_denied">اسمح بتثبيت "التطبيقات غير المعروفة" لتمكين هذه الوظيفة</string>
|
||||
<string name="add_shortcut_title">إضافة اختصار إلى الشاشة الرئيسية</string>
|
||||
<string name="add_shortcut_msg">بعد إخفاء هذا التطبيق، قد يصبح من الصعب التعرف على اسمه ورمزه. هل تريد إضافة اختصار جميل إلى الشاشة الرئيسية؟</string>
|
||||
<string name="app_not_found">لم يتم العثور على تطبيق لمعالجة هذا الإجراء</string>
|
||||
<string name="reboot_apply_change">إعادة التشغيل لتطبيق التغييرات</string>
|
||||
<string name="restore_app_confirmation">سيؤدي هذا إلى استعادة التطبيق المخفي إلى التطبيق الأصلي. هل تريد حقًا القيام بذلك؟</string>
|
||||
<string name="restore_img_msg">جار الأستعادة…</string>
|
||||
<string name="restore_done">تم الأستعادة</string>
|
||||
<string name="restore_fail">النسخة الاحتياطية الأصلية غير موجودة!</string>
|
||||
<string name="setup_fail">فشل التضبيط</string>
|
||||
<string name="env_fix_title"> الإعداد الأضافي مطلوب</string>
|
||||
<string name="setup_msg">جار تضبيت البيئة</string>
|
||||
<string name="unsupport_magisk_title">إصدار مـاجـيسك غير مدعوم</string>
|
||||
|
||||
</resources>
|
||||
|
@@ -10,10 +10,9 @@
|
||||
<string name="section_theme">עיצוב</string>
|
||||
<string name="denylist">רשימת דחייה</string>
|
||||
|
||||
|
||||
<!--Home-->
|
||||
<string name="no_connection">אין חיבור זמין</string>
|
||||
<string name="app_changelog">רשימת שינויים</string>
|
||||
<string name="app_changelog">יומן שינויים</string>
|
||||
<string name="loading">טוען…</string>
|
||||
<string name="update">עדכון</string>
|
||||
<string name="not_available">ל/ז</string>
|
||||
@@ -45,16 +44,16 @@
|
||||
<string name="install_inactive_slot_msg">ההתקן שלך ייאלץ אתחול לחריץ הלא פעיל הנוכחי שלך לאחר הפעלה מחדש!\nיש להשתמש באפשרות זו רק לאחר ביצוע OTA בלבד.\nלהמשיך?</string>
|
||||
<string name="setup_title">התקנה נוספת</string>
|
||||
<string name="select_patch_file">בחירה והתקנת קובץ</string>
|
||||
<string name="patch_file_msg">בחירת תמונה גולמית (*.img) או ODIN קובץ tar (*.tar)</string>
|
||||
<string name="patch_file_msg">בחירת תמונה גולמית (*.img) או ODIN tarfile (*.tar) או payload.bin (*.bin)</string>
|
||||
<string name="reboot_delay_toast">מאתחל בעוד 5 שניות…</string>
|
||||
<string name="flash_screen_title">התקנה</string>
|
||||
|
||||
<!--Superuser-->
|
||||
<string name="su_request_title">בקשות משתמש על</string>
|
||||
<string name="touch_filtered_warning">מכיוון שיישום מסתיר בקשה של משתמש על, Magisk לא יכול לאמת את תגובתך</string>
|
||||
<string name="deny">דחה</string>
|
||||
<string name="deny">דחייה</string>
|
||||
<string name="prompt">מיידי</string>
|
||||
<string name="grant">הענק</string>
|
||||
<string name="grant">הענקה</string>
|
||||
<string name="su_warning">מעניק גישה מלאה להתקן שלך.\nיש לדחות באי וודאות!</string>
|
||||
<string name="forever">לצמיתות</string>
|
||||
<string name="once">פעם אחת</string>
|
||||
@@ -62,24 +61,24 @@
|
||||
<string name="twentymin">20 דקות</string>
|
||||
<string name="thirtymin">חצי שעה</string>
|
||||
<string name="sixtymin">שעה</string>
|
||||
<string name="su_allow_toast">%1$s הוענקו הרשאות משתמש עבור</string>
|
||||
<string name="su_deny_toast">%1$s נשללו הרשאות משתמש עבור</string>
|
||||
<string name="su_allow_toast">%1$s קיבל הרשאות משתמש על</string>
|
||||
<string name="su_deny_toast">%1$s נשללו הרשאות משתמש על</string>
|
||||
<string name="su_snack_grant">הרשאות משתמש על עבור %1$s הוענקו</string>
|
||||
<string name="su_snack_deny">הרשאות משתמש על עבור %1$s נשללו</string>
|
||||
<string name="su_snack_notif_on">התראות עבור %1$s פועלות</string>
|
||||
<string name="su_snack_notif_off">התראות עבור %1$s כבויות</string>
|
||||
<string name="su_snack_notif_on">התראות של %1$s מופעלות</string>
|
||||
<string name="su_snack_notif_off">התראות של %1$s מושבתות</string>
|
||||
<string name="su_snack_log_on">יומני רישום עבור %1$s פועלות</string>
|
||||
<string name="su_snack_log_off">יומני רישום עבור %1$s כבויות</string>
|
||||
<string name="su_snack_log_off">יומני רישום עבור %1$s מושבתות</string>
|
||||
<string name="su_revoke_title">להסיר?</string>
|
||||
<string name="su_revoke_msg">נא לאשר שלילת הרשאות עבור %1$s?</string>
|
||||
<string name="toast">הרמת כוסית</string>
|
||||
<string name="none">ללא</string>
|
||||
<string name="superuser_toggle_notification">התראות</string>
|
||||
<string name="superuser_toggle_revoke">הסרה</string>
|
||||
<string name="superuser_policy_none">לא נתבקשו הרשאות משתמש על על ידי שום יישום</string>
|
||||
<string name="superuser_policy_none">טרם נתבקשו הרשאות משתמש על על ידי יישומים</string>
|
||||
|
||||
<!--Logs-->
|
||||
<string name="log_data_none">הינך ללא יומן רישום, יש לנסות להשתמש ביישומים מותאמים יותר למשתמש העל שלך</string>
|
||||
<string name="log_data_none">הינך ללא יומן, יש לנסות להשתמש יותר ביישומי השורש שלך</string>
|
||||
<string name="log_data_magisk_none">יומני רישום Magisk ריקים, זה מוזר</string>
|
||||
<string name="menuSaveLog">שמירת יומן רישום</string>
|
||||
<string name="menuClearLog">ניקוי יומן רישום כעת</string>
|
||||
@@ -92,7 +91,7 @@
|
||||
|
||||
<!--SafetyNet-->
|
||||
|
||||
<!-- MagiskHide -->
|
||||
<!--MagiskHide-->
|
||||
<string name="show_system_app">הצגת יישומי מערכת</string>
|
||||
<string name="show_os_app">הצגת יישומי מערכת הפעלה</string>
|
||||
<string name="hide_filter_hint">סינון לפי שם</string>
|
||||
@@ -100,14 +99,16 @@
|
||||
|
||||
<!--Module-->
|
||||
<string name="no_info_provided">(לא סופק מידע)</string>
|
||||
<string name="reboot_userspace">אתחול מהיר</string>
|
||||
<string name="reboot_userspace">אתחול רך</string>
|
||||
<string name="reboot_recovery">אתחול למצב שחזור</string>
|
||||
<string name="reboot_bootloader">אתחול מצב מנהל האתחול</string>
|
||||
<string name="reboot_download">אתחול מצב הורדה</string>
|
||||
<string name="reboot_bootloader">אתחול לטוען האתחול</string>
|
||||
<string name="reboot_download">אתחול למצב הורדה</string>
|
||||
<string name="reboot_edl">אתחול למצב EDL</string>
|
||||
<string name="reboot_safe_mode">מצב בטוח</string>
|
||||
<string name="module_version_author">%1$s מאת %2$s</string>
|
||||
<string name="module_state_remove">הסרה</string>
|
||||
<string name="module_state_restore">שיחזור</string>
|
||||
<string name="module_action">פעולה</string>
|
||||
<string name="module_state_restore">שחזור</string>
|
||||
<string name="module_action_install_external">התקנה מהאחסון</string>
|
||||
<string name="update_available">עדכונים זמינים</string>
|
||||
<string name="suspend_text_riru">מודול מושעה כי %1$s מופעל</string>
|
||||
@@ -117,7 +118,7 @@
|
||||
<string name="confirm_install">להתקין מודול %1$s?</string>
|
||||
<string name="confirm_install_title">אישור התקנה</string>
|
||||
|
||||
<!--Settings -->
|
||||
<!--Settings-->
|
||||
<string name="settings_dark_mode_title">מצב עיצוב</string>
|
||||
<string name="settings_dark_mode_message">נא לבחור מצב המתאים ביותר לסגנון שלך!</string>
|
||||
<string name="settings_dark_mode_light">תמיד בהיר</string>
|
||||
@@ -128,11 +129,11 @@
|
||||
<string name="settings_hide_app_title">הסתרת היישום Magisk</string>
|
||||
<string name="settings_hide_app_summary">התקנת יישום מתווך עם מזהה חבילה אקראי ותווית שם מותאמת אישית</string>
|
||||
<string name="settings_restore_app_title">שיחזור היישום Magisk</string>
|
||||
<string name="settings_restore_app_summary">יש לבטל את הסתרת היישום ולשחזור אותו ל-APK המקורי</string>
|
||||
<string name="settings_restore_app_summary">ביטול הסתרת היישום ושחזור אל ה-APK המקורי</string>
|
||||
<string name="language">שפה</string>
|
||||
<string name="system_default">(ברירת מחדל מערכת)</string>
|
||||
<string name="settings_check_update_title">בדיקת עדכונים</string>
|
||||
<string name="settings_check_update_summary">בדוק מעת לעת ברקע אם יש עדכונים</string>
|
||||
<string name="settings_check_update_summary">בדיקה מעת לעת ברקע אם יש עדכונים</string>
|
||||
<string name="settings_update_channel_title">ערוץ עדכון</string>
|
||||
<string name="settings_update_stable">יציב</string>
|
||||
<string name="settings_update_beta">בטא</string>
|
||||
@@ -161,12 +162,12 @@
|
||||
<string name="settings_su_request_60">60 שניות</string>
|
||||
<string name="superuser_access">גישת משתמש על</string>
|
||||
<string name="auto_response">תגובה אוטומטית</string>
|
||||
<string name="request_timeout">בקש פסק זמן</string>
|
||||
<string name="request_timeout">בקשת פסק זמן</string>
|
||||
<string name="superuser_notification">התראות משתמש על</string>
|
||||
<string name="settings_su_reauth_title">אימות מחדש לאחר שדרוג</string>
|
||||
<string name="settings_su_reauth_summary">אימות מחדש הרשאות של משתמש על לאחר שדרוג יישום</string>
|
||||
<string name="settings_su_tapjack_title">הפעלת הגנת Tapjacking</string>
|
||||
<string name="settings_su_tapjack_summary">תיבת הדו שיח של משתמש העל לא תגיב לקלט כשהיא מוסתרת על ידי חלון או כיסוי אחר</string>
|
||||
<string name="settings_su_tapjack_title">הגנת Tapjacking</string>
|
||||
<string name="settings_su_tapjack_summary">תיבת הדו שיח של משתמש העל לא תגיב לקלט כשהיא מוסתרת על ידי חלון או שכבת על אחרת</string>
|
||||
<string name="settings_su_auth_title">אימות משתמש</string>
|
||||
<string name="settings_su_auth_summary">בקשת אימות משתמש במהלך בקשות משתמש על</string>
|
||||
<string name="settings_su_auth_insecure">לא מוגדרת שיטת אימות בהתקן</string>
|
||||
@@ -174,6 +175,8 @@
|
||||
<string name="setting_add_shortcut_summary">הוספת קיצור דרך יפה במסך הבית למקרה שקשה לזהות את השם ואת הסמל לאחר הסתרת היישום</string>
|
||||
<string name="settings_doh_title">DNS על HTTPS</string>
|
||||
<string name="settings_doh_description">עקיפת DNS מורעל במדינות מסוימות</string>
|
||||
<string name="settings_random_name_title">שם פלט אקראי</string>
|
||||
<string name="settings_random_name_description">שם אקראי לקובץ הפלט של תמונות מתוקנות וקבצי tar כדי למנוע זיהוי</string>
|
||||
<string name="multiuser_mode">מצב מרובה משתמשים</string>
|
||||
<string name="settings_owner_only">בעל ההתקן בלבד</string>
|
||||
<string name="settings_owner_manage">אחראי ניהול ההתקן</string>
|
||||
@@ -205,10 +208,13 @@
|
||||
<string name="repo_install_title">מתקין %1$s %2$s(%3$d)</string>
|
||||
<string name="download">הורדה</string>
|
||||
<string name="reboot">הפעלה מחדש</string>
|
||||
<string name="close">סגירה</string>
|
||||
<string name="release_notes">הערות שחרור</string>
|
||||
<string name="flashing">צורב…</string>
|
||||
<string name="running">רץ…</string>
|
||||
<string name="done">בוצע!</string>
|
||||
<string name="failure">נכשל</string>
|
||||
<string name="done_action">בוצעה ריצת פעולה של %1$s</string>
|
||||
<string name="failure">נכשל!</string>
|
||||
<string name="hide_app_title">מסתיר את יישום Magisk…</string>
|
||||
<string name="open_link_failed_toast">לא נמצאו יישומים לפתיחת קישור זה</string>
|
||||
<string name="complete_uninstall">הסרה מלאה</string>
|
||||
@@ -237,4 +243,5 @@
|
||||
<string name="app_not_found">לא נמצא יישום לטיפול בפעולה זו</string>
|
||||
<string name="reboot_apply_change">ייש להפעיל מחדש כדי להחיל שינויים</string>
|
||||
<string name="restore_app_confirmation">פעולה זו תשחזר את היישום המוסתר חזרה ליישום המקורי. האם בוודאות ברצונך לעשות את זה?</string>
|
||||
|
||||
</resources>
|
||||
|
@@ -87,6 +87,9 @@
|
||||
<string name="logs_cleared">Логи успешно очищены</string>
|
||||
<string name="pid">PID: %1$d</string>
|
||||
<string name="target_uid">Целевой UID: %1$d</string>
|
||||
<string name="target_pid">Целевой PID пространства имён: %s</string>
|
||||
<string name="selinux_context">Контекст SELinux: %s</string>
|
||||
<string name="supp_group">Дополнительная группа: %s</string>
|
||||
|
||||
<!--SafetyNet-->
|
||||
|
||||
@@ -164,11 +167,16 @@
|
||||
<string name="settings_su_reauth_title">Повторная аутентификация</string>
|
||||
<string name="settings_su_reauth_summary">Повторный запрос прав суперпользователя после обновления приложений</string>
|
||||
<string name="settings_su_tapjack_title">Защита от перехвата нажатий</string>
|
||||
<string name="settings_su_auth_title">Аутентификация пользователя</string>
|
||||
<string name="settings_su_auth_summary">Требовать аутентификацию пользователя при запросах Superuser</string>
|
||||
<string name="settings_su_auth_insecure">На устройстве не настроен метод аутентификации</string>
|
||||
<string name="settings_su_tapjack_summary">Окно запроса прав суперпользователя будет неактивно пока активированы наложения экрана</string>
|
||||
<string name="settings_customization">Персонализация</string>
|
||||
<string name="setting_add_shortcut_summary">Добавить ярлык на рабочий стол для удобного восприятия приложения после его скрытия</string>
|
||||
<string name="settings_doh_title">DNS поверх HTTPS</string>
|
||||
<string name="settings_doh_description">Активировать DoH (используйте при проблемах с подключением к сети)</string>
|
||||
<string name="settings_random_name_title">Случайное имя образа</string>
|
||||
<string name="settings_random_name_description">Генерировать случайные имена для патченных образов и tar-файлов для предотвращения обнаружения</string>
|
||||
|
||||
<string name="multiuser_mode">Многопользовательский режим</string>
|
||||
<string name="settings_owner_only">Только администратор</string>
|
||||
|
@@ -130,8 +130,8 @@
|
||||
<string name="settings_update_custom">Власний</string>
|
||||
<string name="settings_update_custom_msg">Вставте власний URL</string>
|
||||
<string name="settings_zygisk_summary">Запускати частини Magisk в сервісі zygote</string>
|
||||
<string name="settings_denylist_title">Enforce DenyList</string>
|
||||
<string name="settings_denylist_summary">Processes on the denylist will have all Magisk modifications reverted</string>
|
||||
<string name="settings_denylist_title">Увімкнути DenyList</string>
|
||||
<string name="settings_denylist_summary">Всі зміни, внесені Magisk, будуть приховані від процесів, позначених у DenyList</string>
|
||||
<string name="settings_denylist_config_title">Налаштувати DenyList</string>
|
||||
<string name="settings_denylist_config_summary">Вибрати процеси, які будуть додані до denylist</string>
|
||||
<string name="settings_hosts_title">Позасистемні хости</string>
|
||||
@@ -156,7 +156,7 @@
|
||||
<string name="superuser_notification">Сповіщення суперкористувача</string>
|
||||
<string name="settings_su_reauth_title">Повторна автентифікація</string>
|
||||
<string name="settings_su_reauth_summary">Перевидача прав суперкористувача після оновлення застосунку</string>
|
||||
<string name="settings_su_tapjack_title">Увімкнути захист від Tapjack</string>
|
||||
<string name="settings_su_tapjack_title">Увімкнути захист від підміни натискань</string>
|
||||
<string name="settings_su_tapjack_summary">Діалогове вікно суперкористувача не буде отримувати ввід від користувача, коли вікно перекрито іншим застосунком чи вікном</string>
|
||||
<string name="settings_customization">Оформлення</string>
|
||||
<string name="setting_add_shortcut_summary">Додати ярлик на домашній екран для зручного сприйняття застосунку після його приховування</string>
|
||||
|
@@ -109,6 +109,7 @@
|
||||
<string name="reboot_safe_mode">安全模式</string>
|
||||
<string name="module_version_author">%1$s,作者 %2$s</string>
|
||||
<string name="module_state_remove">移除</string>
|
||||
<string name="module_action">操作</string>
|
||||
<string name="module_state_restore">还原</string>
|
||||
<string name="module_action_install_external">从本地安装</string>
|
||||
<string name="update_available">可更新</string>
|
||||
@@ -211,9 +212,12 @@
|
||||
<string name="repo_install_title">安装 %1$s %2$s(%3$d)</string>
|
||||
<string name="download">下载</string>
|
||||
<string name="reboot">重启</string>
|
||||
<string name="close">关闭</string>
|
||||
<string name="release_notes">发布说明</string>
|
||||
<string name="flashing">正在刷入</string>
|
||||
<string name="running">运行中……</string>
|
||||
<string name="done">完成!</string>
|
||||
<string name="done_action">%1$s 操作运行完成</string>
|
||||
<string name="failure">失败</string>
|
||||
<string name="hide_app_title">正在隐藏 Magisk 应用</string>
|
||||
<string name="open_link_failed_toast">找不到能打开此链接的应用</string>
|
||||
|
@@ -15,7 +15,7 @@ android {
|
||||
val canary = !Config.version.contains(".")
|
||||
|
||||
val url = if (canary) null
|
||||
else "https://cdn.jsdelivr.net/gh/topjohnwu/magisk-files@${Config.version}/app-release.apk"
|
||||
else "https://github.com/topjohnwu/Magisk/releases/download/v${Config.version}/Magisk-v${Config.version}.apk"
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "com.topjohnwu.magisk"
|
||||
@@ -27,9 +27,9 @@ android {
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
proguardFiles("proguard-rules.pro")
|
||||
isMinifyEnabled = true
|
||||
isShrinkResources = false
|
||||
proguardFiles("proguard-rules.pro")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
setupStub()
|
||||
setupStubApk()
|
||||
|
||||
dependencies {
|
||||
implementation(project(":app:shared"))
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
|
||||
|
||||
plugins {
|
||||
`kotlin-dsl`
|
||||
@@ -18,9 +18,9 @@ gradlePlugin {
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType<KotlinCompile>().configureEach {
|
||||
kotlinOptions {
|
||||
languageVersion = "2.0"
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
languageVersion = KotlinVersion.KOTLIN_2_0
|
||||
}
|
||||
}
|
||||
|
||||
|
78
buildSrc/src/main/java/DesugarClassVisitorFactory.kt
Normal file
78
buildSrc/src/main/java/DesugarClassVisitorFactory.kt
Normal file
@@ -0,0 +1,78 @@
|
||||
import com.android.build.api.instrumentation.AsmClassVisitorFactory
|
||||
import com.android.build.api.instrumentation.ClassContext
|
||||
import com.android.build.api.instrumentation.ClassData
|
||||
import com.android.build.api.instrumentation.InstrumentationParameters
|
||||
import org.objectweb.asm.ClassVisitor
|
||||
import org.objectweb.asm.MethodVisitor
|
||||
import org.objectweb.asm.Opcodes
|
||||
import org.objectweb.asm.Opcodes.ASM9
|
||||
|
||||
private const val ZIP_ENTRY_CLASS_NAME = "java.util.zip.ZipEntry"
|
||||
private const val DESUGAR_CLASS_NAME = "com.topjohnwu.magisk.core.utils.Desugar"
|
||||
private const val ZIP_ENTRY_GET_TIME_DESC = "()Ljava/nio/file/attribute/FileTime;"
|
||||
private const val DESUGAR_GET_TIME_DESC =
|
||||
"(Ljava/util/zip/ZipEntry;)Ljava/nio/file/attribute/FileTime;"
|
||||
|
||||
private fun ClassData.isTypeOf(name: String) = className == name || superClasses.contains(name)
|
||||
|
||||
abstract class DesugarClassVisitorFactory : AsmClassVisitorFactory<InstrumentationParameters.None> {
|
||||
override fun createClassVisitor(
|
||||
classContext: ClassContext,
|
||||
nextClassVisitor: ClassVisitor
|
||||
): ClassVisitor {
|
||||
return DesugarClassVisitor(classContext, nextClassVisitor)
|
||||
}
|
||||
|
||||
override fun isInstrumentable(classData: ClassData) = classData.className != DESUGAR_CLASS_NAME
|
||||
|
||||
class DesugarClassVisitor(private val classContext: ClassContext, cv: ClassVisitor) :
|
||||
ClassVisitor(ASM9, cv) {
|
||||
override fun visitMethod(
|
||||
access: Int,
|
||||
name: String?,
|
||||
descriptor: String?,
|
||||
signature: String?,
|
||||
exceptions: Array<out String>?
|
||||
): MethodVisitor {
|
||||
return DesugarMethodVisitor(
|
||||
super.visitMethod(access, name, descriptor, signature, exceptions)
|
||||
)
|
||||
}
|
||||
|
||||
inner class DesugarMethodVisitor(mv: MethodVisitor?) :
|
||||
MethodVisitor(ASM9, mv) {
|
||||
override fun visitMethodInsn(
|
||||
opcode: Int,
|
||||
owner: String,
|
||||
name: String,
|
||||
descriptor: String,
|
||||
isInterface: Boolean
|
||||
) {
|
||||
if (!process(owner, name, descriptor)) {
|
||||
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface)
|
||||
}
|
||||
}
|
||||
|
||||
private fun process(owner: String, name: String, descriptor: String): Boolean {
|
||||
val classData = classContext.loadClassData(owner.replace("/", ".")) ?: return false
|
||||
if (!classData.isTypeOf(ZIP_ENTRY_CLASS_NAME))
|
||||
return false
|
||||
if (descriptor != ZIP_ENTRY_GET_TIME_DESC)
|
||||
return false
|
||||
return when (name) {
|
||||
"getLastModifiedTime", "getLastAccessTime", "getCreationTime" -> {
|
||||
mv.visitMethodInsn(
|
||||
Opcodes.INVOKESTATIC,
|
||||
DESUGAR_CLASS_NAME.replace('.', '/'),
|
||||
name,
|
||||
DESUGAR_GET_TIME_DESC,
|
||||
false
|
||||
)
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,6 +1,8 @@
|
||||
import com.android.build.api.artifact.ArtifactTransformationRequest
|
||||
import com.android.build.api.artifact.SingleArtifact
|
||||
import com.android.build.api.dsl.ApkSigningConfig
|
||||
import com.android.build.api.instrumentation.FramesComputationMode.COMPUTE_FRAMES_FOR_INSTRUMENTED_METHODS
|
||||
import com.android.build.api.instrumentation.InstrumentationScope
|
||||
import com.android.build.api.variant.ApplicationAndroidComponentsExtension
|
||||
import com.android.build.gradle.BaseExtension
|
||||
import com.android.build.gradle.LibraryExtension
|
||||
@@ -15,6 +17,7 @@ import org.gradle.api.Action
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.JavaVersion
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.Copy
|
||||
@@ -114,9 +117,9 @@ fun Project.setupCommon() {
|
||||
}
|
||||
|
||||
const val BUSYBOX_DOWNLOAD_URL =
|
||||
"https://github.com/topjohnwu/magisk-files/releases/download/files/busybox-1.36.1.0.zip"
|
||||
"https://github.com/topjohnwu/magisk-files/releases/download/files/busybox-1.36.1.1.zip"
|
||||
const val BUSYBOX_ZIP_CHECKSUM =
|
||||
"ea4f3019b0087dcb68130b32ab59dc2db0ee0af11d8396124a94c4231c5ea441"
|
||||
"b4d0551feabaf314e53c79316c980e8f66432e9fb91a69dbbf10a93564b40951"
|
||||
|
||||
fun Project.setupCoreLib() {
|
||||
setupCommon()
|
||||
@@ -348,7 +351,34 @@ fun Project.setupAppCommon() {
|
||||
}
|
||||
}
|
||||
|
||||
fun Project.setupStub() {
|
||||
fun Project.setupMainApk() {
|
||||
setupAppCommon()
|
||||
|
||||
android {
|
||||
namespace = "com.topjohnwu.magisk"
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "com.topjohnwu.magisk"
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
versionName = Config.version
|
||||
versionCode = Config.versionCode
|
||||
ndk {
|
||||
abiFilters += listOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64", "riscv64")
|
||||
debugSymbolLevel = "FULL"
|
||||
}
|
||||
}
|
||||
|
||||
androidComponents.onVariants { variant ->
|
||||
variant.instrumentation.apply {
|
||||
setAsmFramesComputationMode(COMPUTE_FRAMES_FOR_INSTRUMENTED_METHODS)
|
||||
transformClassesWith(
|
||||
DesugarClassVisitorFactory::class.java, InstrumentationScope.ALL) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Project.setupStubApk() {
|
||||
setupAppCommon()
|
||||
|
||||
androidComponents.onVariants { variant ->
|
||||
|
@@ -1,5 +1,37 @@
|
||||
# Magisk Changelog
|
||||
|
||||
### v28.1
|
||||
|
||||
- [App] Fix stub APK download link
|
||||
- [App] Fix support for Android lower than 8.0
|
||||
- [General] Fix support for MTK Samsung devices
|
||||
- [MagiskInit] Fix a regression for 2SI devices
|
||||
- [MagiskPolicy] Fix a regression causing `overlay.d` replaced files to be not accessible
|
||||
|
||||
### v28.0
|
||||
|
||||
- [General] Support 16k page size
|
||||
- [General] Add basic support for RISC-V (not built in releases)
|
||||
- [General] Use a minimal libc to build static executables (`magiskinit` and `magiskboot`) for smaller sizes
|
||||
- [Core] Remove unnecessary mirror for magic mount
|
||||
- [Core] Update boot image detection logic to support more devices
|
||||
- [MagiskInit] Rewrite 2SI logic for injecting `magiskinit` as `init`
|
||||
- [MagiskInit] Update preinit partition detection
|
||||
- [Zygisk] Update internal JNI hooking implementation
|
||||
- [MagiskPolicy] Preserve sepolicy config flag after patching
|
||||
- [MagiskPolicy] Optimize patching rules to reduce the amount of new rules being injected
|
||||
- [DenyList] Support enforcing denylist when Zygisk is disabled
|
||||
- [Resetprop] Improve implementation to workaround several property modification detections
|
||||
- [Resetprop] Update to properly work with property overlays
|
||||
- [App] Major internal code refactoring
|
||||
- [App] Support patching Samsung firmware with images larger than 8GiB
|
||||
- [App] Use user-initiated job instead of foreground services on Android 14
|
||||
- [App] Support Android 13+ built-in per-app language preferences
|
||||
- [App] Add `action.sh` support to allow modules to define an action triggered from UI
|
||||
- [MagiskBoot] Support spliting kernel images without decompression
|
||||
- [MagiskBoot] Properly support vendor boot images
|
||||
- [MagiskBoot] Disable Samsung PROCA from kernel image
|
||||
|
||||
### v27.0
|
||||
|
||||
- [Zygisk] Introduce new code injection mechanism
|
||||
|
25
docs/releases/28000.md
Normal file
25
docs/releases/28000.md
Normal file
@@ -0,0 +1,25 @@
|
||||
## 2024.10.10 Magisk v28.0
|
||||
|
||||
- [General] Support 16k page size
|
||||
- [General] Add basic support for RISC-V (not built in releases)
|
||||
- [General] Use a minimal libc to build static executables (`magiskinit` and `magiskboot`) for smaller sizes
|
||||
- [Core] Remove unnecessary mirror for magic mount
|
||||
- [Core] Update boot image detection logic to support more devices
|
||||
- [MagiskInit] Rewrite 2SI logic for injecting `magiskinit` as `init`
|
||||
- [MagiskInit] Update preinit partition detection
|
||||
- [Zygisk] Update internal JNI hooking implementation
|
||||
- [MagiskPolicy] Preserve sepolicy config flag after patching
|
||||
- [MagiskPolicy] Optimize patching rules to reduce the amount of new rules being injected
|
||||
- [DenyList] Support enforcing denylist when Zygisk is disabled
|
||||
- [Resetprop] Improve implementation to workaround several property modification detections
|
||||
- [Resetprop] Update to properly work with property overlays
|
||||
- [App] Major internal code refactoring
|
||||
- [App] Support patching Samsung firmware with images larger than 8GiB
|
||||
- [App] Use user-initiated job instead of foreground services on Android 14
|
||||
- [App] Support Android 13+ built-in per-app language preferences
|
||||
- [App] Add `action.sh` support to allow modules to define an action triggered from UI
|
||||
- [MagiskBoot] Support spliting kernel images without decompression
|
||||
- [MagiskBoot] Properly support vendor boot images
|
||||
- [MagiskBoot] Disable Samsung PROCA from kernel image
|
||||
|
||||
### Full Changelog: [here](https://topjohnwu.github.io/Magisk/changes.html)
|
33
docs/releases/28100.md
Normal file
33
docs/releases/28100.md
Normal file
@@ -0,0 +1,33 @@
|
||||
## 2024.12.6 Magisk v28.1
|
||||
|
||||
- [App] Fix stub APK download link
|
||||
- [App] Fix support for Android lower than 8.0
|
||||
- [General] Fix support for MTK Samsung devices
|
||||
- [MagiskInit] Fix a regression for 2SI devices
|
||||
- [MagiskPolicy] Fix a regression causing `overlay.d` replaced files to be not accessible
|
||||
|
||||
## Magisk v28.0 Changes
|
||||
|
||||
- [General] Support 16k page size
|
||||
- [General] Add basic support for RISC-V (not built in releases)
|
||||
- [General] Use a minimal libc to build static executables (`magiskinit` and `magiskboot`) for smaller sizes
|
||||
- [Core] Remove unnecessary mirror for magic mount
|
||||
- [Core] Update boot image detection logic to support more devices
|
||||
- [MagiskInit] Rewrite 2SI logic for injecting `magiskinit` as `init`
|
||||
- [MagiskInit] Update preinit partition detection
|
||||
- [Zygisk] Update internal JNI hooking implementation
|
||||
- [MagiskPolicy] Preserve sepolicy config flag after patching
|
||||
- [MagiskPolicy] Optimize patching rules to reduce the amount of new rules being injected
|
||||
- [DenyList] Support enforcing denylist when Zygisk is disabled
|
||||
- [Resetprop] Improve implementation to workaround several property modification detections
|
||||
- [Resetprop] Update to properly work with property overlays
|
||||
- [App] Major internal code refactoring
|
||||
- [App] Support patching Samsung firmware with images larger than 8GiB
|
||||
- [App] Use user-initiated job instead of foreground services on Android 14
|
||||
- [App] Support Android 13+ built-in per-app language preferences
|
||||
- [App] Add `action.sh` support to allow modules to define an action triggered from UI
|
||||
- [MagiskBoot] Support spliting kernel images without decompression
|
||||
- [MagiskBoot] Properly support vendor boot images
|
||||
- [MagiskBoot] Disable Samsung PROCA from kernel image
|
||||
|
||||
### Full Changelog: [here](https://topjohnwu.github.io/Magisk/changes.html)
|
@@ -1,5 +1,7 @@
|
||||
# Release Notes
|
||||
|
||||
- [v28.1](28100.md)
|
||||
- [v28.0](28000.md)
|
||||
- [v27.0](27000.md)
|
||||
- [v26.4](26400.md)
|
||||
- [v26.3](26300.md)
|
||||
|
@@ -30,5 +30,5 @@ android.nonFinalResIds=false
|
||||
|
||||
# Magisk
|
||||
magisk.stubVersion=40
|
||||
magisk.versionCode=27008
|
||||
magisk.versionCode=28101
|
||||
magisk.ondkVersion=r27.4
|
||||
|
@@ -1,9 +1,9 @@
|
||||
[versions]
|
||||
kotlin = "2.0.20"
|
||||
android = "8.6.0"
|
||||
ksp = "2.0.20-1.0.25"
|
||||
kotlin = "2.0.21"
|
||||
android = "8.7.3"
|
||||
ksp = "2.0.21-1.0.28"
|
||||
rikka = "1.3.0"
|
||||
navigation = "2.8.0"
|
||||
navigation = "2.8.4"
|
||||
libsu = "6.0.0"
|
||||
moshi = "1.15.1"
|
||||
okhttp = "4.12.0"
|
||||
@@ -11,7 +11,7 @@ retrofit = "2.11.0"
|
||||
room = "2.6.1"
|
||||
|
||||
[libraries]
|
||||
bcpkix = { module = "org.bouncycastle:bcpkix-jdk18on", version = "1.78.1" }
|
||||
bcpkix = { module = "org.bouncycastle:bcpkix-jdk18on", version = "1.79" }
|
||||
commons-compress = { module = "org.apache.commons:commons-compress", version = "1.27.1" }
|
||||
retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
|
||||
retrofit-moshi = { module = "com.squareup.retrofit2:converter-moshi", version.ref = "retrofit" }
|
||||
@@ -26,25 +26,25 @@ timber = { module = "com.jakewharton.timber:timber", version = "5.0.1" }
|
||||
jgit = { module = "org.eclipse.jgit:org.eclipse.jgit", version = "6.10.0.202406032230-r" }
|
||||
|
||||
# AndroidX
|
||||
activity = { module = "androidx.activity:activity", version = "1.9.2" }
|
||||
activity = { module = "androidx.activity:activity", version = "1.9.3" }
|
||||
appcompat = { module = "androidx.appcompat:appcompat", version = "1.7.0" }
|
||||
core-ktx = { module = "androidx.core:core-ktx", version = "1.13.1" }
|
||||
core-ktx = { module = "androidx.core:core-ktx", version = "1.15.0" }
|
||||
core-splashscreen = { module = "androidx.core:core-splashscreen", version = "1.0.1" }
|
||||
constraintlayout = { module = "androidx.constraintlayout:constraintlayout", version = "2.1.4" }
|
||||
fragment-ktx = { module = "androidx.fragment:fragment-ktx", version = "1.8.3" }
|
||||
constraintlayout = { module = "androidx.constraintlayout:constraintlayout", version = "2.2.0" }
|
||||
fragment-ktx = { module = "androidx.fragment:fragment-ktx", version = "1.8.5" }
|
||||
navigation-fragment-ktx = { module = "androidx.navigation:navigation-fragment-ktx", version.ref = "navigation" }
|
||||
navigation-ui-ktx = { module = "androidx.navigation:navigation-ui-ktx", version.ref = "navigation" }
|
||||
profileinstaller = { module = "androidx.profileinstaller:profileinstaller", version = "1.3.1" }
|
||||
profileinstaller = { module = "androidx.profileinstaller:profileinstaller", version = "1.4.1" }
|
||||
recyclerview = { module = "androidx.recyclerview:recyclerview", version = "1.3.2" }
|
||||
room-ktx = { module = "androidx.room:room-ktx", version.ref = "room" }
|
||||
room-runtime = { module = "androidx.room:room-runtime", version.ref = "room" }
|
||||
room-compiler = { module = "androidx.room:room-compiler", version.ref = "room" }
|
||||
swiperefreshlayout = { module = "androidx.swiperefreshlayout:swiperefreshlayout", version = "1.1.0" }
|
||||
transition = { module = "androidx.transition:transition", version = "1.5.1" }
|
||||
collection-ktx = { module = "androidx.collection:collection-ktx", version = "1.4.3" }
|
||||
lifecycle-process = { module = "androidx.lifecycle:lifecycle-process", version = "2.8.5" }
|
||||
collection-ktx = { module = "androidx.collection:collection-ktx", version = "1.4.5" }
|
||||
lifecycle-process = { module = "androidx.lifecycle:lifecycle-process", version = "2.8.7" }
|
||||
material = { module = "com.google.android.material:material", version = "1.12.0" }
|
||||
jdk-libs = { module = "com.android.tools:desugar_jdk_libs_nio", version = "2.1.2" }
|
||||
jdk-libs = { module = "com.android.tools:desugar_jdk_libs_nio", version = "2.1.3" }
|
||||
|
||||
# topjohnwu
|
||||
indeterminate-checkbox = { module = "com.github.topjohnwu:indeterminate-checkbox", version = "1.0.7" }
|
||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
72
native/src/Cargo.lock
generated
72
native/src/Cargo.lock
generated
@@ -2,6 +2,12 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
|
||||
|
||||
[[package]]
|
||||
name = "argh"
|
||||
version = "0.1.12"
|
||||
@@ -111,6 +117,32 @@ version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69371e34337c4c984bbe322360c2547210bf632eb2814bbe78a6e87a2935bd2b"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e24c1b4099818523236a8ca881d2b45db98dadfb4625cf6608c12069fcbbde1"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7"
|
||||
|
||||
[[package]]
|
||||
name = "codespan-reporting"
|
||||
version = "0.11.1"
|
||||
@@ -182,16 +214,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cxx"
|
||||
version = "1.0.124"
|
||||
version = "1.0.133"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cxxbridge-cmd",
|
||||
"cxxbridge-flags",
|
||||
"cxxbridge-macro",
|
||||
"foldhash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxx-gen"
|
||||
version = "0.7.124"
|
||||
version = "0.7.133"
|
||||
dependencies = [
|
||||
"codespan-reporting",
|
||||
"proc-macro2",
|
||||
@@ -199,16 +233,28 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxxbridge-cmd"
|
||||
version = "1.0.133"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"codespan-reporting",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxxbridge-flags"
|
||||
version = "1.0.124"
|
||||
version = "1.0.133"
|
||||
|
||||
[[package]]
|
||||
name = "cxxbridge-macro"
|
||||
version = "1.0.124"
|
||||
version = "1.0.133"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn",
|
||||
]
|
||||
|
||||
@@ -305,6 +351,12 @@ version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3ea1ec5f8307826a5b71094dd91fc04d4ae75d5709b20ad351c7fb4815c86ec"
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.15"
|
||||
@@ -709,6 +761,12 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248"
|
||||
|
||||
[[package]]
|
||||
name = "sec1"
|
||||
version = "0.8.0-rc.0"
|
||||
@@ -803,6 +861,12 @@ dependencies = [
|
||||
"der",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.6.1"
|
||||
|
@@ -366,7 +366,7 @@ static const char *vendor_ramdisk_type(int type) {
|
||||
}
|
||||
|
||||
#define assert_off() \
|
||||
if ((base_addr + off) > (map.buf() + map.sz())) { \
|
||||
if ((base_addr + off) > (map.buf() + map_end)) { \
|
||||
fprintf(stderr, "Corrupted boot image!\n"); \
|
||||
return false; \
|
||||
}
|
||||
@@ -395,6 +395,7 @@ bool boot_img::parse_image(const uint8_t *p, format_t type) {
|
||||
|
||||
hdr->print();
|
||||
|
||||
size_t map_end = align_to(map.sz(), getpagesize());
|
||||
size_t off = hdr->hdr_space();
|
||||
get_block(kernel);
|
||||
get_block(ramdisk);
|
||||
@@ -408,7 +409,7 @@ bool boot_img::parse_image(const uint8_t *p, format_t type) {
|
||||
|
||||
payload = byte_view(base_addr, off);
|
||||
auto tail_addr = base_addr + off;
|
||||
tail = byte_view(tail_addr, map.buf() + map.sz() - tail_addr);
|
||||
tail = byte_view(tail_addr, map.buf() + map_end - tail_addr);
|
||||
|
||||
if (auto size = hdr->kernel_size()) {
|
||||
if (int dtb_off = find_dtb_offset(kernel, size); dtb_off > 0) {
|
||||
|
@@ -49,6 +49,7 @@ pub mod ffi {
|
||||
}
|
||||
|
||||
#[namespace = "rust"]
|
||||
#[allow(unused_unsafe)]
|
||||
extern "Rust" {
|
||||
unsafe fn extract_boot_from_payload(
|
||||
partition: *const c_char,
|
||||
|
@@ -8,10 +8,6 @@ using namespace std;
|
||||
|
||||
#ifdef USE_CRT0
|
||||
__BEGIN_DECLS
|
||||
int tfp_vsscanf(const char *s, const char *fmt, va_list args);
|
||||
int vsscanf(const char *s, const char *fmt, va_list args) {
|
||||
return tfp_vsscanf(s, fmt, args);
|
||||
}
|
||||
int musl_vfprintf(FILE *stream, const char *format, va_list arg);
|
||||
int vfprintf(FILE *stream, const char *format, va_list arg) {
|
||||
return musl_vfprintf(stream, format, arg);
|
||||
|
@@ -148,8 +148,8 @@ static bool check_safe_mode() {
|
||||
* Boot Stage Handlers *
|
||||
***********************/
|
||||
|
||||
bool MagiskD::post_fs_data() const {
|
||||
as_rust().setup_logfile();
|
||||
bool MagiskD::post_fs_data() const noexcept {
|
||||
setup_logfile();
|
||||
|
||||
LOGI("** post-fs-data mode running\n");
|
||||
|
||||
@@ -194,8 +194,8 @@ bool MagiskD::post_fs_data() const {
|
||||
return safe_mode;
|
||||
}
|
||||
|
||||
void MagiskD::late_start() const {
|
||||
as_rust().setup_logfile();
|
||||
void MagiskD::late_start() const noexcept {
|
||||
setup_logfile();
|
||||
|
||||
LOGI("** late_start service mode running\n");
|
||||
|
||||
@@ -203,8 +203,8 @@ void MagiskD::late_start() const {
|
||||
exec_module_scripts("service");
|
||||
}
|
||||
|
||||
void MagiskD::boot_complete() const {
|
||||
as_rust().setup_logfile();
|
||||
void MagiskD::boot_complete() const noexcept {
|
||||
setup_logfile();
|
||||
|
||||
LOGI("** boot-complete triggered\n");
|
||||
|
||||
|
@@ -128,20 +128,8 @@ static void poll_ctrl_handler(pollfd *pfd) {
|
||||
}
|
||||
}
|
||||
|
||||
const MagiskD &MagiskD::get() {
|
||||
return *reinterpret_cast<const MagiskD*>(&rust::get_magiskd());
|
||||
}
|
||||
|
||||
const rust::MagiskD *MagiskD::operator->() const {
|
||||
return reinterpret_cast<const rust::MagiskD*>(this);
|
||||
}
|
||||
|
||||
const rust::MagiskD &MagiskD::as_rust() const {
|
||||
return *operator->();
|
||||
}
|
||||
|
||||
void MagiskD::reboot() const {
|
||||
if (as_rust().is_recovery())
|
||||
void MagiskD::reboot() const noexcept {
|
||||
if (is_recovery())
|
||||
exec_command_sync("/system/bin/reboot", "recovery");
|
||||
else
|
||||
exec_command_sync("/system/bin/reboot");
|
||||
@@ -171,7 +159,7 @@ static void handle_request_async(int client, int code, const sock_cred &cred) {
|
||||
write_int(client, 0);
|
||||
close(client);
|
||||
if (do_reboot) {
|
||||
MagiskD::get().reboot();
|
||||
MagiskD().reboot();
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -196,7 +184,7 @@ static void handle_request_sync(int client, int code) {
|
||||
write_int(client, MAGISK_VER_CODE);
|
||||
break;
|
||||
case +RequestCode::START_DAEMON:
|
||||
MagiskD::get()->setup_logfile();
|
||||
MagiskD().setup_logfile();
|
||||
break;
|
||||
case +RequestCode::STOP_DAEMON: {
|
||||
// Unmount all overlays
|
||||
@@ -298,7 +286,7 @@ static void handle_request(pollfd *pfd) {
|
||||
exec_task([=, fd = client.release()] { handle_request_async(fd, code, cred); });
|
||||
} else {
|
||||
exec_task([=, fd = client.release()] {
|
||||
MagiskD::get()->boot_stage_handler(fd, code);
|
||||
MagiskD().boot_stage_handler(fd, code);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -372,6 +360,11 @@ static void daemon_entry() {
|
||||
}
|
||||
}
|
||||
LOGI("* Device API level: %d\n", SDK_INT);
|
||||
|
||||
// Samsung workaround #7887
|
||||
if (access("/system_ext/app/mediatek-res/mediatek-res.apk", F_OK) == 0) {
|
||||
set_prop("ro.vendor.mtk_model", "0");
|
||||
}
|
||||
|
||||
restore_tmpcon();
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::io::BufReader;
|
||||
use std::sync::{Mutex, OnceLock};
|
||||
use std::{io, mem};
|
||||
|
||||
use base::libc::{O_CLOEXEC, O_RDONLY};
|
||||
use base::{
|
||||
@@ -10,7 +10,7 @@ use base::{
|
||||
};
|
||||
|
||||
use crate::consts::MAIN_CONFIG;
|
||||
use crate::ffi::{get_magisk_tmp, CxxMagiskD, RequestCode};
|
||||
use crate::ffi::{get_magisk_tmp, RequestCode};
|
||||
use crate::get_prop;
|
||||
use crate::logging::magisk_logging;
|
||||
|
||||
@@ -64,7 +64,7 @@ impl MagiskD {
|
||||
match code {
|
||||
RequestCode::POST_FS_DATA => {
|
||||
if check_data() && !state.contains(BootState::PostFsDataDone) {
|
||||
if self.as_cxx().post_fs_data() {
|
||||
if self.post_fs_data() {
|
||||
state.set(BootState::SafeMode);
|
||||
}
|
||||
state.set(BootState::PostFsDataDone);
|
||||
@@ -75,7 +75,7 @@ impl MagiskD {
|
||||
unsafe { libc::close(client) };
|
||||
if state.contains(BootState::PostFsDataDone) && !state.contains(BootState::SafeMode)
|
||||
{
|
||||
self.as_cxx().late_start();
|
||||
self.late_start();
|
||||
state.set(BootState::LateStartDone);
|
||||
}
|
||||
}
|
||||
@@ -83,7 +83,7 @@ impl MagiskD {
|
||||
unsafe { libc::close(client) };
|
||||
if state.contains(BootState::PostFsDataDone) {
|
||||
state.set(BootState::BootComplete);
|
||||
self.as_cxx().boot_complete()
|
||||
self.boot_complete()
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
@@ -91,11 +91,6 @@ impl MagiskD {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn as_cxx(&self) -> &CxxMagiskD {
|
||||
unsafe { mem::transmute(self) }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn daemon_entry() {
|
||||
|
@@ -108,7 +108,7 @@ db_settings::db_settings() {
|
||||
data[SU_MULTIUSER_MODE] = MULTIUSER_MODE_OWNER_ONLY;
|
||||
data[SU_MNT_NS] = NAMESPACE_MODE_REQUESTER;
|
||||
data[DENYLIST_CONFIG] = false;
|
||||
data[ZYGISK_CONFIG] = MagiskD::get()->is_emulator();
|
||||
data[ZYGISK_CONFIG] = MagiskD().is_emulator();
|
||||
data[BOOTLOOP_COUNT] = 0;
|
||||
}
|
||||
|
||||
|
@@ -2,29 +2,6 @@
|
||||
|
||||
#include <base.hpp>
|
||||
|
||||
namespace rust {
|
||||
struct MagiskD;
|
||||
}
|
||||
|
||||
struct MagiskD {
|
||||
// Make sure only references can exist
|
||||
~MagiskD() = delete;
|
||||
|
||||
// Binding to Rust
|
||||
static const MagiskD &get();
|
||||
|
||||
// C++ implementation
|
||||
void reboot() const;
|
||||
bool post_fs_data() const;
|
||||
void late_start() const;
|
||||
void boot_complete() const;
|
||||
|
||||
const rust::MagiskD *operator->() const;
|
||||
|
||||
private:
|
||||
const rust::MagiskD &as_rust() const;
|
||||
};
|
||||
|
||||
const char *get_magisk_tmp();
|
||||
|
||||
// Rust bindings
|
||||
|
@@ -74,12 +74,6 @@ pub mod ffi {
|
||||
fn resolve_preinit_dir(base_dir: Utf8CStrRef) -> String;
|
||||
|
||||
fn switch_mnt_ns(pid: i32) -> i32;
|
||||
|
||||
#[cxx_name = "MagiskD"]
|
||||
type CxxMagiskD;
|
||||
fn post_fs_data(self: &CxxMagiskD) -> bool;
|
||||
fn late_start(self: &CxxMagiskD);
|
||||
fn boot_complete(self: &CxxMagiskD);
|
||||
}
|
||||
|
||||
extern "Rust" {
|
||||
@@ -99,18 +93,28 @@ pub mod ffi {
|
||||
unsafe fn persist_get_props(prop_cb: Pin<&mut PropCb>);
|
||||
unsafe fn persist_delete_prop(name: Utf8CStrRef) -> bool;
|
||||
unsafe fn persist_set_prop(name: Utf8CStrRef, value: Utf8CStrRef) -> bool;
|
||||
|
||||
#[namespace = "rust"]
|
||||
fn daemon_entry();
|
||||
}
|
||||
|
||||
#[namespace = "rust"]
|
||||
// FFI for MagiskD
|
||||
extern "Rust" {
|
||||
fn daemon_entry();
|
||||
|
||||
type MagiskD;
|
||||
fn get_magiskd() -> &'static MagiskD;
|
||||
fn setup_logfile(self: &MagiskD);
|
||||
fn is_emulator(self: &MagiskD) -> bool;
|
||||
fn is_recovery(self: &MagiskD) -> bool;
|
||||
fn boot_stage_handler(self: &MagiskD, client: i32, code: i32);
|
||||
|
||||
#[cxx_name = "MagiskD"]
|
||||
fn get_magiskd() -> &'static MagiskD;
|
||||
}
|
||||
unsafe extern "C++" {
|
||||
#[allow(dead_code)]
|
||||
fn reboot(self: &MagiskD);
|
||||
fn post_fs_data(self: &MagiskD) -> bool;
|
||||
fn late_start(self: &MagiskD);
|
||||
fn boot_complete(self: &MagiskD);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -177,26 +177,23 @@ void tmpfs_node::mount() {
|
||||
class magisk_node : public node_entry {
|
||||
public:
|
||||
explicit magisk_node(const char *name) : node_entry(name, DT_REG, this) {}
|
||||
explicit magisk_node(const char *name, const char *target)
|
||||
: node_entry(name, DT_LNK, this), target(target) {}
|
||||
|
||||
void mount() override {
|
||||
const string src = get_magisk_tmp() + "/"s + name();
|
||||
if (access(src.data(), F_OK))
|
||||
return;
|
||||
|
||||
const string dir_name = isa<tmpfs_node>(parent()) ? parent()->worker_path() : parent()->node_path();
|
||||
if (name() == "magisk") {
|
||||
for (int i = 0; applet_names[i]; ++i) {
|
||||
string dest = dir_name + "/" + applet_names[i];
|
||||
VLOGD("create", "./magisk", dest.data());
|
||||
xsymlink("./magisk", dest.data());
|
||||
}
|
||||
if (target) {
|
||||
string dest = isa<tmpfs_node>(parent()) ? worker_path() : node_path();
|
||||
VLOGD("create", target, dest.data());
|
||||
xsymlink(target, dest.data());
|
||||
} else {
|
||||
string dest = dir_name + "/supolicy";
|
||||
VLOGD("create", "./magiskpolicy", dest.data());
|
||||
xsymlink("./magiskpolicy", dest.data());
|
||||
string src = get_magisk_tmp() + "/"s + name();
|
||||
if (access(src.data(), F_OK) == 0)
|
||||
create_and_mount("magisk", src, true);
|
||||
}
|
||||
create_and_mount("magisk", src, true);
|
||||
}
|
||||
|
||||
private:
|
||||
const char *target = nullptr;
|
||||
};
|
||||
|
||||
class zygisk_node : public node_entry {
|
||||
@@ -231,10 +228,10 @@ static void inject_magisk_bins(root_node *system) {
|
||||
bin->insert(new magisk_node("magisk"));
|
||||
bin->insert(new magisk_node("magiskpolicy"));
|
||||
|
||||
// Also delete all applets to make sure no modules can override it
|
||||
// Also insert all applets to make sure no one can override it
|
||||
for (int i = 0; applet_names[i]; ++i)
|
||||
delete bin->extract(applet_names[i]);
|
||||
delete bin->extract("supolicy");
|
||||
bin->insert(new magisk_node(applet_names[i], "./magisk"));
|
||||
bin->insert(new magisk_node("supolicy", "./magiskpolicy"));
|
||||
}
|
||||
|
||||
static void inject_zygisk_libs(root_node *system) {
|
||||
|
2
native/src/external/crt0
vendored
2
native/src/external/crt0
vendored
Submodule native/src/external/crt0 updated: 1602918648...795cab5ab6
2
native/src/external/cxx-rs
vendored
2
native/src/external/cxx-rs
vendored
Submodule native/src/external/cxx-rs updated: 7535230afb...08cb634704
@@ -11,8 +11,6 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
vector<string> mount_list;
|
||||
|
||||
template<char... cs> using chars = integer_sequence<char, cs...>;
|
||||
|
||||
// If quoted, parsing ends when we find char in [breaks]
|
||||
@@ -148,6 +146,12 @@ void BootConfig::set(const kv_pairs &kv) {
|
||||
strscpy(fstab_suffix, value.data(), sizeof(fstab_suffix));
|
||||
} else if (key == "qemu") {
|
||||
emulator = true;
|
||||
} else if (key == "androidboot.partition_map") {
|
||||
// androidboot.partition_map allows mapping a partition name to a raw block device.
|
||||
// For example, "androidboot.partition_map=vdb,metadata;vdc,userdata" maps
|
||||
// "vdb" to "metadata", and "vdc" to "userdata".
|
||||
// https://android.googlesource.com/platform/system/core/+/refs/heads/android13-release/init/devices.cpp#191
|
||||
partition_map = parse_partition_map(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -165,41 +169,29 @@ void BootConfig::print() {
|
||||
}
|
||||
|
||||
#define read_dt(name, key) \
|
||||
ssprintf(file_name, sizeof(file_name), "%s/" name, config->dt_dir); \
|
||||
ssprintf(file_name, sizeof(file_name), "%s/" name, dt_dir); \
|
||||
if (access(file_name, R_OK) == 0) { \
|
||||
string data = full_read(file_name); \
|
||||
if (!data.empty()) { \
|
||||
data.pop_back(); \
|
||||
strscpy(config->key, data.data(), sizeof(config->key)); \
|
||||
strscpy(key, data.data(), sizeof(key)); \
|
||||
} \
|
||||
}
|
||||
|
||||
void load_kernel_info(BootConfig *config) {
|
||||
// Get kernel data using procfs and sysfs
|
||||
xmkdir("/proc", 0755);
|
||||
xmount("proc", "/proc", "proc", 0, nullptr);
|
||||
xmkdir("/sys", 0755);
|
||||
xmount("sysfs", "/sys", "sysfs", 0, nullptr);
|
||||
void BootConfig::init() {
|
||||
set(parse_cmdline(full_read("/proc/cmdline")));
|
||||
set(parse_bootconfig(full_read("/proc/bootconfig")));
|
||||
|
||||
mount_list.emplace_back("/proc");
|
||||
mount_list.emplace_back("/sys");
|
||||
|
||||
// Log to kernel
|
||||
rust::setup_klog();
|
||||
|
||||
config->set(parse_cmdline(full_read("/proc/cmdline")));
|
||||
config->set(parse_bootconfig(full_read("/proc/bootconfig")));
|
||||
|
||||
parse_prop_file("/.backup/.magisk", [=](auto key, auto value) -> bool {
|
||||
parse_prop_file("/.backup/.magisk", [&](auto key, auto value) -> bool {
|
||||
if (key == "RECOVERYMODE" && value == "true") {
|
||||
config->skip_initramfs = config->emulator || !check_key_combo();
|
||||
skip_initramfs = emulator || !check_key_combo();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (config->dt_dir[0] == '\0')
|
||||
strscpy(config->dt_dir, DEFAULT_DT_DIR, sizeof(config->dt_dir));
|
||||
if (dt_dir[0] == '\0')
|
||||
strscpy(dt_dir, DEFAULT_DT_DIR, sizeof(dt_dir));
|
||||
|
||||
char file_name[128];
|
||||
read_dt("fstab_suffix", fstab_suffix)
|
||||
@@ -207,26 +199,7 @@ void load_kernel_info(BootConfig *config) {
|
||||
read_dt("hardware.platform", hardware_plat)
|
||||
|
||||
LOGD("Device config:\n");
|
||||
config->print();
|
||||
}
|
||||
|
||||
// `androidboot.partition_map` allows associating a partition name for a raw block device
|
||||
// through a comma separated and semicolon deliminated list. For example,
|
||||
// `androidboot.partition_map=vdb,metadata;vdc,userdata` maps `vdb` to `metadata` and `vdc` to
|
||||
// `userdata`.
|
||||
// https://android.googlesource.com/platform/system/core/+/refs/heads/android13-release/init/devices.cpp#191
|
||||
|
||||
kv_pairs load_partition_map() {
|
||||
const string_view kPartitionMapKey = "androidboot.partition_map";
|
||||
for (const auto &[key, value] : parse_cmdline(full_read("/proc/cmdline"))) {
|
||||
if (key == kPartitionMapKey)
|
||||
return parse_partition_map(value);
|
||||
}
|
||||
for (const auto &[key, value] : parse_bootconfig(full_read("/proc/bootconfig"))) {
|
||||
if (key == kPartitionMapKey)
|
||||
return parse_partition_map(value);
|
||||
}
|
||||
return {};
|
||||
print();
|
||||
}
|
||||
|
||||
bool check_two_stage() {
|
||||
@@ -236,12 +209,15 @@ bool check_two_stage() {
|
||||
return true;
|
||||
if (access("/system/bin/init", F_OK) == 0)
|
||||
return true;
|
||||
// Use the apex folder to determine whether 2SI (Android 10+)
|
||||
if (access("/apex", F_OK) == 0)
|
||||
return true;
|
||||
// If we still have no indication, parse the original init and see what's up
|
||||
mmap_data init(backup_init());
|
||||
return init.contains("selinux_setup");
|
||||
}
|
||||
|
||||
void unxz_init(const char *init_xz, const char *init) {
|
||||
static void unxz_init(const char *init_xz, const char *init) {
|
||||
LOGD("unxz %s -> %s\n", init_xz, init);
|
||||
int fd = xopen(init, O_WRONLY | O_CREAT, 0777);
|
||||
fd_stream ch(fd);
|
||||
|
@@ -13,9 +13,9 @@ using namespace std;
|
||||
|
||||
#ifdef USE_CRT0
|
||||
__BEGIN_DECLS
|
||||
int tfp_vfprintf(FILE *stream, const char *format, va_list arg);
|
||||
int tiny_vfprintf(FILE *stream, const char *format, va_list arg);
|
||||
int vfprintf(FILE *stream, const char *format, va_list arg) {
|
||||
return tfp_vfprintf(stream, format, arg);
|
||||
return tiny_vfprintf(stream, format, arg);
|
||||
}
|
||||
__END_DECLS
|
||||
#endif
|
||||
@@ -60,16 +60,67 @@ void restore_ramdisk_init() {
|
||||
}
|
||||
}
|
||||
|
||||
class RecoveryInit : public BaseInit {
|
||||
public:
|
||||
using BaseInit::BaseInit;
|
||||
void start() override {
|
||||
LOGD("Ramdisk is recovery, abort\n");
|
||||
restore_ramdisk_init();
|
||||
rm_rf("/.backup");
|
||||
exec_init();
|
||||
MagiskInit::MagiskInit(char **argv) : argv(argv), config{} {
|
||||
// Get kernel data using procfs and sysfs
|
||||
if (access("/proc/cmdline", F_OK) != 0) {
|
||||
xmkdir("/proc", 0755);
|
||||
xmount("proc", "/proc", "proc", 0, nullptr);
|
||||
mount_list.emplace_back("/proc");
|
||||
}
|
||||
};
|
||||
if (access("/sys/block", F_OK) != 0) {
|
||||
xmkdir("/sys", 0755);
|
||||
xmount("sysfs", "/sys", "sysfs", 0, nullptr);
|
||||
mount_list.emplace_back("/sys");
|
||||
}
|
||||
|
||||
// Log to kernel
|
||||
rust::setup_klog();
|
||||
|
||||
// Load kernel configs
|
||||
config.init();
|
||||
}
|
||||
|
||||
static void recovery() {
|
||||
LOGI("Ramdisk is recovery, abort\n");
|
||||
restore_ramdisk_init();
|
||||
rm_rf("/.backup");
|
||||
}
|
||||
|
||||
void MagiskInit::legacy_system_as_root() {
|
||||
LOGI("Legacy SAR Init\n");
|
||||
prepare_data();
|
||||
bool is_two_stage = mount_system_root();
|
||||
if (is_two_stage)
|
||||
redirect_second_stage();
|
||||
else
|
||||
patch_ro_root();
|
||||
}
|
||||
|
||||
void MagiskInit::rootfs() {
|
||||
LOGI("RootFS Init\n");
|
||||
prepare_data();
|
||||
LOGD("Restoring /init\n");
|
||||
rename(backup_init(), "/init");
|
||||
patch_rw_root();
|
||||
}
|
||||
|
||||
void MagiskInit::start() {
|
||||
if (argv[1] != nullptr && argv[1] == "selinux_setup"sv)
|
||||
second_stage();
|
||||
else if (config.skip_initramfs)
|
||||
legacy_system_as_root();
|
||||
else if (config.force_normal_boot)
|
||||
first_stage();
|
||||
else if (access("/sbin/recovery", F_OK) == 0 || access("/system/bin/recovery", F_OK) == 0)
|
||||
recovery();
|
||||
else if (check_two_stage())
|
||||
first_stage();
|
||||
else
|
||||
rootfs();
|
||||
|
||||
// Finally execute the original init
|
||||
exec_init();
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
umask(0);
|
||||
@@ -81,31 +132,6 @@ int main(int argc, char *argv[]) {
|
||||
if (getpid() != 1)
|
||||
return 1;
|
||||
|
||||
BaseInit *init;
|
||||
BootConfig config{};
|
||||
|
||||
if (argc > 1 && argv[1] == "selinux_setup"sv) {
|
||||
rust::setup_klog();
|
||||
init = new SecondStageInit(argv);
|
||||
} else {
|
||||
// This will also mount /sys and /proc
|
||||
load_kernel_info(&config);
|
||||
bool recovery = access("/sbin/recovery", F_OK) == 0 ||
|
||||
access("/system/bin/recovery", F_OK) == 0;
|
||||
|
||||
if (config.force_normal_boot)
|
||||
init = new FirstStageInit(argv, &config);
|
||||
else if (!recovery && check_two_stage())
|
||||
init = new FirstStageInit(argv, &config);
|
||||
else if (config.skip_initramfs)
|
||||
init = new LegacySARInit(argv, &config);
|
||||
else if (recovery)
|
||||
init = new RecoveryInit(argv, &config);
|
||||
else
|
||||
init = new RootFSInit(argv, &config);
|
||||
}
|
||||
|
||||
// Run the main routine
|
||||
init->start();
|
||||
exit(1);
|
||||
MagiskInit init(argv);
|
||||
init.start();
|
||||
}
|
||||
|
@@ -15,7 +15,10 @@ struct BootConfig {
|
||||
char fstab_suffix[32];
|
||||
char hardware[32];
|
||||
char hardware_plat[32];
|
||||
kv_pairs partition_map;
|
||||
|
||||
void init();
|
||||
private:
|
||||
void set(const kv_pairs &);
|
||||
void print();
|
||||
};
|
||||
@@ -24,120 +27,45 @@ struct BootConfig {
|
||||
#define INIT_PATH "/system/bin/init"
|
||||
#define REDIR_PATH "/data/magiskinit"
|
||||
|
||||
extern std::vector<std::string> mount_list;
|
||||
|
||||
int magisk_proxy_main(int argc, char *argv[]);
|
||||
bool unxz(out_stream &strm, rust::Slice<const uint8_t> bytes);
|
||||
void load_kernel_info(BootConfig *config);
|
||||
kv_pairs load_partition_map();
|
||||
bool check_two_stage();
|
||||
const char *backup_init();
|
||||
void restore_ramdisk_init();
|
||||
|
||||
/***************
|
||||
* Base classes
|
||||
***************/
|
||||
|
||||
class BaseInit {
|
||||
protected:
|
||||
BootConfig *config = nullptr;
|
||||
char **argv = nullptr;
|
||||
|
||||
[[noreturn]] void exec_init();
|
||||
void prepare_data();
|
||||
public:
|
||||
BaseInit(char *argv[], BootConfig *config = nullptr) : config(config), argv(argv) {}
|
||||
virtual ~BaseInit() = default;
|
||||
virtual void start() = 0;
|
||||
};
|
||||
|
||||
class MagiskInit : public BaseInit {
|
||||
class MagiskInit {
|
||||
private:
|
||||
std::string preinit_dev;
|
||||
std::vector<std::string> mount_list;
|
||||
char **argv;
|
||||
BootConfig config;
|
||||
|
||||
void parse_config_file();
|
||||
void patch_sepolicy(const char *in, const char *out);
|
||||
bool hijack_sepolicy();
|
||||
// Setup mounts and environment
|
||||
void setup_tmp(const char *path);
|
||||
protected:
|
||||
void collect_devices();
|
||||
void mount_preinit_dir();
|
||||
void prepare_data();
|
||||
dev_t find_block(const char *partname);
|
||||
bool mount_system_root();
|
||||
|
||||
// Setup and patch root directory
|
||||
void parse_config_file();
|
||||
void patch_rw_root();
|
||||
void patch_ro_root();
|
||||
|
||||
// Two stage init
|
||||
void redirect_second_stage();
|
||||
void first_stage();
|
||||
void second_stage();
|
||||
|
||||
// SELinux
|
||||
void patch_sepolicy(const char *in, const char *out);
|
||||
bool hijack_sepolicy();
|
||||
|
||||
[[noreturn]] void exec_init();
|
||||
void legacy_system_as_root();
|
||||
void rootfs();
|
||||
public:
|
||||
using BaseInit::BaseInit;
|
||||
};
|
||||
|
||||
/***************
|
||||
* 2 Stage Init
|
||||
***************/
|
||||
|
||||
class FirstStageInit : public BaseInit {
|
||||
private:
|
||||
void prepare();
|
||||
public:
|
||||
FirstStageInit(char *argv[], BootConfig *config) : BaseInit(argv, config) {
|
||||
LOGD("%s\n", __FUNCTION__);
|
||||
};
|
||||
void start() override {
|
||||
prepare();
|
||||
exec_init();
|
||||
}
|
||||
};
|
||||
|
||||
class SecondStageInit : public MagiskInit {
|
||||
private:
|
||||
bool prepare();
|
||||
public:
|
||||
SecondStageInit(char *argv[]) : MagiskInit(argv) {
|
||||
LOGD("%s\n", __FUNCTION__);
|
||||
};
|
||||
|
||||
void start() override {
|
||||
bool is_rootfs = prepare();
|
||||
if (is_rootfs)
|
||||
patch_rw_root();
|
||||
else
|
||||
patch_ro_root();
|
||||
exec_init();
|
||||
}
|
||||
};
|
||||
|
||||
/*************
|
||||
* Legacy SAR
|
||||
*************/
|
||||
|
||||
class LegacySARInit : public MagiskInit {
|
||||
private:
|
||||
bool mount_system_root();
|
||||
void first_stage_prep();
|
||||
public:
|
||||
LegacySARInit(char *argv[], BootConfig *config) : MagiskInit(argv, config) {
|
||||
LOGD("%s\n", __FUNCTION__);
|
||||
};
|
||||
void start() override {
|
||||
prepare_data();
|
||||
bool is_two_stage = mount_system_root();
|
||||
if (is_two_stage)
|
||||
first_stage_prep();
|
||||
else
|
||||
patch_ro_root();
|
||||
exec_init();
|
||||
}
|
||||
};
|
||||
|
||||
/************
|
||||
* Initramfs
|
||||
************/
|
||||
|
||||
class RootFSInit : public MagiskInit {
|
||||
private:
|
||||
void prepare();
|
||||
public:
|
||||
RootFSInit(char *argv[], BootConfig *config) : MagiskInit(argv, config) {
|
||||
LOGD("%s\n", __FUNCTION__);
|
||||
}
|
||||
void start() override {
|
||||
prepare();
|
||||
patch_rw_root();
|
||||
exec_init();
|
||||
}
|
||||
explicit MagiskInit(char *argv[]);
|
||||
void start();
|
||||
};
|
||||
|
@@ -45,7 +45,7 @@ static void parse_device(devinfo *dev, const char *uevent) {
|
||||
});
|
||||
}
|
||||
|
||||
static void collect_devices(const auto &partition_map) {
|
||||
void MagiskInit::collect_devices() {
|
||||
char path[PATH_MAX];
|
||||
devinfo dev{};
|
||||
if (auto dir = xopen_dir("/sys/dev/block"); dir) {
|
||||
@@ -59,9 +59,9 @@ static void collect_devices(const auto &partition_map) {
|
||||
auto name = rtrim(full_read(path));
|
||||
strscpy(dev.dmname, name.data(), sizeof(dev.dmname));
|
||||
}
|
||||
if (auto it = std::ranges::find_if(partition_map, [&](const auto &i) {
|
||||
if (auto it = std::ranges::find_if(config.partition_map, [&](const auto &i) {
|
||||
return i.first == dev.devname;
|
||||
}); dev.partname[0] == '\0' && it != partition_map.end()) {
|
||||
}); dev.partname[0] == '\0' && it != config.partition_map.end()) {
|
||||
// use androidboot.partition_map as partname fallback.
|
||||
strscpy(dev.partname, it->second.data(), sizeof(dev.partname));
|
||||
}
|
||||
@@ -72,52 +72,45 @@ static void collect_devices(const auto &partition_map) {
|
||||
}
|
||||
}
|
||||
|
||||
static struct {
|
||||
char partname[32];
|
||||
char block_dev[64];
|
||||
} blk_info;
|
||||
|
||||
static dev_t setup_block() {
|
||||
static const auto partition_map = load_partition_map();
|
||||
dev_t MagiskInit::find_block(const char *partname) {
|
||||
if (dev_list.empty())
|
||||
collect_devices(partition_map);
|
||||
collect_devices();
|
||||
|
||||
for (int tries = 0; tries < 3; ++tries) {
|
||||
for (auto &dev : dev_list) {
|
||||
if (strcasecmp(dev.partname, blk_info.partname) == 0)
|
||||
LOGD("Setup %s: [%s] (%d, %d)\n", dev.partname, dev.devname, dev.major, dev.minor);
|
||||
else if (strcasecmp(dev.dmname, blk_info.partname) == 0)
|
||||
LOGD("Setup %s: [%s] (%d, %d)\n", dev.dmname, dev.devname, dev.major, dev.minor);
|
||||
else if (strcasecmp(dev.devname, blk_info.partname) == 0)
|
||||
LOGD("Setup %s: [%s] (%d, %d)\n", dev.devname, dev.devname, dev.major, dev.minor);
|
||||
else if (std::string_view(dev.devpath).ends_with("/"s + blk_info.partname))
|
||||
LOGD("Setup %s: [%s] (%d, %d)\n", dev.devpath, dev.devname, dev.major, dev.minor);
|
||||
const char *name;
|
||||
if (strcasecmp(dev.partname, partname) == 0)
|
||||
name = dev.partname;
|
||||
else if (strcasecmp(dev.dmname, partname) == 0)
|
||||
name = dev.dmname;
|
||||
else if (strcasecmp(dev.devname, partname) == 0)
|
||||
name = dev.devname;
|
||||
else if (std::string_view(dev.devpath).ends_with("/"s + partname))
|
||||
name = dev.devpath;
|
||||
else
|
||||
continue;
|
||||
|
||||
dev_t rdev = makedev(dev.major, dev.minor);
|
||||
xmknod(blk_info.block_dev, S_IFBLK | 0600, rdev);
|
||||
return rdev;
|
||||
LOGD("Found %s: [%s] (%d, %d)\n", name, dev.devname, dev.major, dev.minor);
|
||||
return makedev(dev.major, dev.minor);
|
||||
}
|
||||
// Wait 10ms and try again
|
||||
usleep(10000);
|
||||
dev_list.clear();
|
||||
collect_devices(partition_map);
|
||||
collect_devices();
|
||||
}
|
||||
|
||||
// The requested partname does not exist
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mount_preinit_dir(string preinit_dev) {
|
||||
void MagiskInit::mount_preinit_dir() {
|
||||
if (preinit_dev.empty()) return;
|
||||
strcpy(blk_info.partname, preinit_dev.data());
|
||||
strcpy(blk_info.block_dev, PREINITDEV);
|
||||
auto dev = setup_block();
|
||||
auto dev = find_block(preinit_dev.data());
|
||||
if (dev == 0) {
|
||||
LOGE("Cannot find preinit %s, abort!\n", preinit_dev.data());
|
||||
return;
|
||||
}
|
||||
xmknod(PREINITDEV, S_IFBLK | 0600, dev);
|
||||
xmkdir(MIRRDIR, 0);
|
||||
bool mounted = false;
|
||||
// First, find if it is already mounted
|
||||
@@ -150,40 +143,40 @@ static void mount_preinit_dir(string preinit_dev) {
|
||||
}
|
||||
}
|
||||
|
||||
bool LegacySARInit::mount_system_root() {
|
||||
bool MagiskInit::mount_system_root() {
|
||||
LOGD("Mounting system_root\n");
|
||||
|
||||
// there's no /dev in stub cpio
|
||||
xmkdir("/dev", 0777);
|
||||
|
||||
strcpy(blk_info.block_dev, "/dev/root");
|
||||
|
||||
dev_t dev;
|
||||
do {
|
||||
// Try legacy SAR dm-verity
|
||||
strcpy(blk_info.partname, "vroot");
|
||||
auto dev = setup_block();
|
||||
dev = find_block("vroot");
|
||||
if (dev > 0)
|
||||
goto mount_root;
|
||||
|
||||
// Try NVIDIA naming scheme
|
||||
strcpy(blk_info.partname, "APP");
|
||||
dev = setup_block();
|
||||
dev = find_block("APP");
|
||||
if (dev > 0)
|
||||
goto mount_root;
|
||||
|
||||
sprintf(blk_info.partname, "system%s", config->slot);
|
||||
dev = setup_block();
|
||||
// Try normal partname
|
||||
char sys_part[32];
|
||||
sprintf(sys_part, "system%s", config.slot);
|
||||
dev = find_block(sys_part);
|
||||
if (dev > 0)
|
||||
goto mount_root;
|
||||
|
||||
// Poll forever if rootwait was given in cmdline
|
||||
} while (config->rootwait);
|
||||
} while (config.rootwait);
|
||||
|
||||
// We don't really know what to do at this point...
|
||||
LOGE("Cannot find root partition, abort\n");
|
||||
exit(1);
|
||||
|
||||
mount_root:
|
||||
xmknod("/dev/root", S_IFBLK | 0600, dev);
|
||||
xmkdir("/system_root", 0755);
|
||||
|
||||
if (xmount("/dev/root", "/system_root", "ext4", MS_RDONLY, nullptr)) {
|
||||
@@ -205,20 +198,19 @@ mount_root:
|
||||
|
||||
// For API 28 AVD, it uses legacy SAR setup that requires
|
||||
// special hacks in magiskinit to work properly.
|
||||
if (!is_two_stage && config->emulator) {
|
||||
if (!is_two_stage && config.emulator) {
|
||||
avd_hack = true;
|
||||
// These values are hardcoded for API 28 AVD
|
||||
auto vendor_dev = find_block("vendor");
|
||||
xmkdir("/dev/block", 0755);
|
||||
strcpy(blk_info.block_dev, "/dev/block/vde1");
|
||||
strcpy(blk_info.partname, "vendor");
|
||||
setup_block();
|
||||
xmount(blk_info.block_dev, "/vendor", "ext4", MS_RDONLY, nullptr);
|
||||
xmknod("/dev/block/vde1", S_IFBLK | 0600, vendor_dev);
|
||||
xmount("/dev/block/vde1", "/vendor", "ext4", MS_RDONLY, nullptr);
|
||||
}
|
||||
|
||||
return is_two_stage;
|
||||
}
|
||||
|
||||
void BaseInit::exec_init() {
|
||||
void MagiskInit::exec_init() {
|
||||
// Unmount in reverse order
|
||||
for (auto &p : reversed(mount_list)) {
|
||||
if (xumount2(p.data(), MNT_DETACH) == 0)
|
||||
@@ -228,12 +220,12 @@ void BaseInit::exec_init() {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void BaseInit::prepare_data() {
|
||||
void MagiskInit::prepare_data() {
|
||||
LOGD("Setup data tmp\n");
|
||||
xmkdir("/data", 0755);
|
||||
xmount("magisk", "/data", "tmpfs", 0, "mode=755");
|
||||
|
||||
cp_afc("/init", "/data/magiskinit");
|
||||
cp_afc("/init", REDIR_PATH);
|
||||
cp_afc("/.backup", "/data/.backup");
|
||||
cp_afc("/overlay.d", "/data/overlay.d");
|
||||
}
|
||||
@@ -246,7 +238,7 @@ void MagiskInit::setup_tmp(const char *path) {
|
||||
xmkdir(DEVICEDIR, 0711);
|
||||
xmkdir(WORKERDIR, 0);
|
||||
|
||||
mount_preinit_dir(preinit_dev);
|
||||
mount_preinit_dir();
|
||||
|
||||
cp_afc(".backup/.magisk", MAIN_CONFIG);
|
||||
rm_rf(".backup");
|
||||
@@ -261,7 +253,7 @@ void MagiskInit::setup_tmp(const char *path) {
|
||||
chdir(path);
|
||||
|
||||
// Prepare worker
|
||||
xmount(WORKERDIR, WORKERDIR, nullptr, MS_BIND, nullptr);
|
||||
xmount("magisk", WORKERDIR, "tmpfs", 0, "mode=755");
|
||||
|
||||
// Use isolated devpts if kernel support
|
||||
if (access("/dev/pts/ptmx", F_OK) == 0) {
|
||||
|
@@ -347,12 +347,6 @@ void MagiskInit::patch_ro_root() {
|
||||
chdir("/");
|
||||
}
|
||||
|
||||
void RootFSInit::prepare() {
|
||||
prepare_data();
|
||||
LOGD("Restoring /init\n");
|
||||
rename(backup_init(), "/init");
|
||||
}
|
||||
|
||||
#define PRE_TMPSRC "/magisk"
|
||||
#define PRE_TMPDIR PRE_TMPSRC "/tmp"
|
||||
|
||||
|
@@ -64,7 +64,7 @@ bool MagiskInit::hijack_sepolicy() {
|
||||
// This only happens on Android 8.0 - 9.0
|
||||
|
||||
char buf[4096];
|
||||
ssprintf(buf, sizeof(buf), "%s/fstab/compatible", config->dt_dir);
|
||||
ssprintf(buf, sizeof(buf), "%s/fstab/compatible", config.dt_dir);
|
||||
dt_compat = full_read(buf);
|
||||
if (dt_compat.empty()) {
|
||||
// Device does not do early mount and uses monolithic policy
|
||||
@@ -106,7 +106,7 @@ bool MagiskInit::hijack_sepolicy() {
|
||||
int fd = xopen(MOCK_COMPAT, O_WRONLY);
|
||||
|
||||
char buf[4096];
|
||||
ssprintf(buf, sizeof(buf), "%s/fstab/compatible", config->dt_dir);
|
||||
ssprintf(buf, sizeof(buf), "%s/fstab/compatible", config.dt_dir);
|
||||
xumount2(buf, MNT_DETACH);
|
||||
|
||||
hijack();
|
||||
|
@@ -8,12 +8,13 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
void FirstStageInit::prepare() {
|
||||
void MagiskInit::first_stage() {
|
||||
LOGI("First Stage Init\n");
|
||||
prepare_data();
|
||||
|
||||
if (struct stat st{}; fstatat(-1, "/sdcard", &st, AT_SYMLINK_NOFOLLOW) != 0 &&
|
||||
fstatat(-1, "/first_stage_ramdisk/sdcard", &st, AT_SYMLINK_NOFOLLOW) != 0) {
|
||||
if (config->force_normal_boot) {
|
||||
if (config.force_normal_boot) {
|
||||
xmkdirs("/first_stage_ramdisk/storage/self", 0755);
|
||||
xsymlink("/system/system/bin/init", "/first_stage_ramdisk/storage/self/primary");
|
||||
LOGD("Symlink /first_stage_ramdisk/storage/self/primary -> /system/system/bin/init\n");
|
||||
@@ -29,8 +30,8 @@ void FirstStageInit::prepare() {
|
||||
LOGD("Bind mount /sdcard -> /sdcard\n");
|
||||
} else {
|
||||
// rootfs before 3.12
|
||||
xmount("/data/magiskinit", "/sdcard", nullptr, MS_BIND, nullptr);
|
||||
LOGD("Bind mount /sdcard -> /data/magiskinit\n");
|
||||
xmount(REDIR_PATH, "/sdcard", nullptr, MS_BIND, nullptr);
|
||||
LOGD("Bind mount " REDIR_PATH " -> /sdcard\n");
|
||||
}
|
||||
restore_ramdisk_init();
|
||||
} else {
|
||||
@@ -44,7 +45,7 @@ void FirstStageInit::prepare() {
|
||||
}
|
||||
}
|
||||
|
||||
void LegacySARInit::first_stage_prep() {
|
||||
void MagiskInit::redirect_second_stage() {
|
||||
// Patch init binary
|
||||
int src = xopen("/init", O_RDONLY);
|
||||
int dest = xopen("/data/init", O_CREAT | O_WRONLY, 0);
|
||||
@@ -61,7 +62,8 @@ void LegacySARInit::first_stage_prep() {
|
||||
xmount("/data/init", "/init", nullptr, MS_BIND, nullptr);
|
||||
}
|
||||
|
||||
bool SecondStageInit::prepare() {
|
||||
void MagiskInit::second_stage() {
|
||||
LOGI("Second Stage Init\n");
|
||||
umount2("/init", MNT_DETACH);
|
||||
umount2(INIT_PATH, MNT_DETACH); // just in case
|
||||
unlink("/data/init");
|
||||
@@ -76,7 +78,8 @@ bool SecondStageInit::prepare() {
|
||||
// We are still on rootfs, so make sure we will execute the init of the 2nd stage
|
||||
unlink("/init");
|
||||
xsymlink(INIT_PATH, "/init");
|
||||
return true;
|
||||
patch_rw_root();
|
||||
} else {
|
||||
patch_ro_root();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@@ -101,9 +101,8 @@ impl SepolicyMagisk for sepolicy {
|
||||
"system_app", "priv_app", "untrusted_app", "untrusted_app_all"],
|
||||
[proc], ["unix_stream_socket"], ["connectto", "getopt"]);
|
||||
|
||||
// Let selected domains access tmpfs files
|
||||
// For tmpfs overlay on 2SI, Zygisk on lower Android versions and AVD scripts
|
||||
allow(["init", "zygote", "shell"], ["tmpfs"], ["file"], all);
|
||||
// For tmpfs overlay on 2SI. We allow all domains to access tmpfs files.
|
||||
allow(["domain"], ["tmpfs"], ["file"], all);
|
||||
|
||||
// Allow magiskinit daemon to handle mock selinuxfs
|
||||
allow(["kernel"], ["tmpfs"], ["fifo_file"], ["write"]);
|
||||
|
@@ -271,6 +271,10 @@ bool sepol_impl::add_rule(const char *s, const char *t, const char *c, const cha
|
||||
#define ioctl_func(x) (x & 0xFF)
|
||||
|
||||
void sepol_impl::add_xperm_rule(type_datum_t *src, type_datum_t *tgt, class_datum_t *cls, const Xperm &p, int effect) {
|
||||
if (db->policyvers < POLICYDB_VERSION_XPERMS_IOCTL) {
|
||||
LOGW("policy version %u does not support ioctl extended permissions rules\n", db->policyvers);
|
||||
return;
|
||||
}
|
||||
if (src == nullptr) {
|
||||
for_each_attr(db->p_types.table, [&](type_datum_t *type) {
|
||||
add_xperm_rule(type, tgt, cls, p, effect);
|
||||
|
@@ -2,10 +2,14 @@
|
||||
# Magisk app internal scripts
|
||||
##################################
|
||||
|
||||
# $1 = delay
|
||||
# $2 = command
|
||||
run_delay() {
|
||||
(sleep $1; $2)&
|
||||
}
|
||||
|
||||
# $1 = version string
|
||||
# $2 = version code
|
||||
env_check() {
|
||||
for file in busybox magiskboot magiskinit util_functions.sh boot_patch.sh; do
|
||||
[ -f "$MAGISKBIN/$file" ] || return 1
|
||||
@@ -21,6 +25,8 @@ env_check() {
|
||||
return 0
|
||||
}
|
||||
|
||||
# $1 = dir to copy
|
||||
# $2 = destination (optional)
|
||||
cp_readlink() {
|
||||
if [ -z $2 ]; then
|
||||
cd $1
|
||||
@@ -39,6 +45,7 @@ cp_readlink() {
|
||||
cd /
|
||||
}
|
||||
|
||||
# $1 = install dir
|
||||
fix_env() {
|
||||
# Cleanup and make dirs
|
||||
rm -rf $MAGISKBIN/*
|
||||
@@ -49,6 +56,8 @@ fix_env() {
|
||||
chown -R 0:0 $MAGISKBIN
|
||||
}
|
||||
|
||||
# $1 = install dir
|
||||
# $2 = boot partition
|
||||
direct_install() {
|
||||
echo "- Flashing new boot image"
|
||||
flash_image $1/new-boot.img $2
|
||||
@@ -70,6 +79,7 @@ direct_install() {
|
||||
return 0
|
||||
}
|
||||
|
||||
# $1 = uninstaller zip
|
||||
run_uninstaller() {
|
||||
rm -rf /dev/tmp
|
||||
mkdir -p /dev/tmp/install
|
||||
@@ -77,24 +87,16 @@ run_uninstaller() {
|
||||
INSTALLER=/dev/tmp/install sh /dev/tmp/install/assets/uninstaller.sh dummy 1 "$1"
|
||||
}
|
||||
|
||||
# $1 = boot partition
|
||||
restore_imgs() {
|
||||
local SHA1=$(grep_prop SHA1 $MAGISKTMP/.magisk/config)
|
||||
local BACKUPDIR=/data/magisk_backup_$SHA1
|
||||
[ -d $BACKUPDIR ] || return 1
|
||||
|
||||
get_flags
|
||||
find_boot_image
|
||||
|
||||
for name in dtb dtbo; do
|
||||
[ -f $BACKUPDIR/${name}.img.gz ] || continue
|
||||
local IMAGE=$(find_block $name$SLOT)
|
||||
[ -z $IMAGE ] && continue
|
||||
flash_image $BACKUPDIR/${name}.img.gz $IMAGE
|
||||
done
|
||||
[ -f $BACKUPDIR/boot.img.gz ] || return 1
|
||||
flash_image $BACKUPDIR/boot.img.gz $BOOTIMAGE
|
||||
flash_image $BACKUPDIR/boot.img.gz $1
|
||||
}
|
||||
|
||||
# $1 = path to bootctl executable
|
||||
post_ota() {
|
||||
cd /data/adb
|
||||
cp -f $1 bootctl
|
||||
@@ -131,6 +133,8 @@ EOF
|
||||
cd /
|
||||
}
|
||||
|
||||
# $1 = APK
|
||||
# $2 = package name
|
||||
adb_pm_install() {
|
||||
local tmp=/data/local/tmp/temp.apk
|
||||
cp -f "$1" $tmp
|
||||
|
@@ -37,7 +37,7 @@ if [ -z "$FIRST_STAGE" ]; then
|
||||
export ASH_STANDALONE=1
|
||||
if [ $(./busybox id -u) -ne 0 ]; then
|
||||
# Re-exec script with root
|
||||
exec /system/xbin/su 0 ./busybox sh $0
|
||||
exec /system/xbin/su 0 /data/local/tmp/busybox sh $0
|
||||
else
|
||||
# Re-exec script with busybox
|
||||
exec ./busybox sh $0
|
||||
@@ -66,7 +66,7 @@ fi
|
||||
|
||||
# Stop zygote (and previous setup if exists)
|
||||
magisk --stop 2>/dev/null
|
||||
stop
|
||||
stop zygote
|
||||
if [ -d /debug_ramdisk ]; then
|
||||
umount -l /debug_ramdisk 2>/dev/null
|
||||
fi
|
||||
@@ -141,16 +141,17 @@ ln -s ./magisk $MAGISKTMP/resetprop
|
||||
ln -s ./magiskpolicy $MAGISKTMP/supolicy
|
||||
|
||||
mkdir -p $MAGISKTMP/.magisk/device
|
||||
mkdir -p $MAGISKTMP/.magisk/worker
|
||||
mount -t tmpfs -o 'mode=0755' magisk $MAGISKTMP/.magisk/worker
|
||||
mount --make-private $MAGISKTMP/.magisk/worker
|
||||
touch $MAGISKTMP/.magisk/config
|
||||
|
||||
export MAGISKTMP
|
||||
MAKEDEV=1 $MAGISKTMP/magisk --preinit-device 2>&1
|
||||
|
||||
RULESCMD=""
|
||||
for r in $MAGISKTMP/.magisk/preinit/*/sepolicy.rule; do
|
||||
[ -f "$r" ] || continue
|
||||
RULESCMD="$RULESCMD --apply $r"
|
||||
done
|
||||
rule="$MAGISKTMP/.magisk/preinit/sepolicy.rule"
|
||||
[ -f "$rule" ] && RULESCMD="--apply $rule"
|
||||
|
||||
# SELinux stuffs
|
||||
if [ -d /sys/fs/selinux ]; then
|
||||
@@ -165,5 +166,8 @@ fi
|
||||
|
||||
# Boot up
|
||||
$MAGISKTMP/magisk --post-fs-data
|
||||
start
|
||||
start zygote
|
||||
$MAGISKTMP/magisk --service
|
||||
# Make sure reset nb prop after zygote starts
|
||||
sleep 2
|
||||
$MAGISKTMP/magisk --boot-complete
|
||||
|
@@ -8,7 +8,7 @@ lsposed_url='https://github.com/LSPosed/LSPosed/releases/download/v1.9.2/LSPosed
|
||||
emu_pid=
|
||||
|
||||
atd_min_api=30
|
||||
atd_max_api=34
|
||||
atd_max_api=35
|
||||
lsposed_min_api=27
|
||||
lsposed_max_api=34
|
||||
huge_ram_min_api=26
|
||||
@@ -25,6 +25,7 @@ cleanup() {
|
||||
}
|
||||
|
||||
wait_for_bootanim() {
|
||||
set -e
|
||||
adb wait-for-device
|
||||
while true; do
|
||||
local result="$(adb exec-out getprop init.svc.bootanim)"
|
||||
@@ -38,6 +39,7 @@ wait_for_bootanim() {
|
||||
}
|
||||
|
||||
wait_for_boot() {
|
||||
set -e
|
||||
adb wait-for-device
|
||||
while true; do
|
||||
local result="$(adb exec-out getprop sys.boot_completed)"
|
||||
@@ -79,8 +81,15 @@ test_emu() {
|
||||
|
||||
test_setup $variant
|
||||
|
||||
# Install LSPosed
|
||||
local lsposed
|
||||
if [ $api -ge $lsposed_min_api -a $api -le $lsposed_max_api ]; then
|
||||
lsposed=true
|
||||
else
|
||||
lsposed=false
|
||||
fi
|
||||
|
||||
# Install LSPosed
|
||||
if $lsposed; then
|
||||
adb push out/lsposed.zip /data/local/tmp/lsposed.zip
|
||||
echo 'PATH=$PATH:/debug_ramdisk magisk --install-module /data/local/tmp/lsposed.zip' | adb shell /system/xbin/su
|
||||
fi
|
||||
@@ -91,7 +100,7 @@ test_emu() {
|
||||
test_app
|
||||
|
||||
# Try to launch LSPosed
|
||||
if [ $api -ge $lsposed_min_api -a $api -le $atd_max_api ]; then
|
||||
if $lsposed; then
|
||||
adb shell rm -f /data/local/tmp/window_dump.xml
|
||||
adb shell am start -c org.lsposed.manager.LAUNCH_MANAGER com.android.shell/.BugreportWarningActivity
|
||||
while adb shell '[ ! -f /data/local/tmp/window_dump.xml ]'; do
|
||||
@@ -113,6 +122,7 @@ run_test() {
|
||||
TiramisuPrivacySandbox) api=33 ;;
|
||||
UpsideDownCakePrivacySandbox) api=34 ;;
|
||||
VanillaIceCream) api=35 ;;
|
||||
Baklava) api=36 ;;
|
||||
*)
|
||||
print_error "! Unknown system image version '$ver'"
|
||||
exit 1
|
||||
@@ -211,11 +221,11 @@ curl -L $lsposed_url -o out/lsposed.zip
|
||||
if [ -n "$1" ]; then
|
||||
run_test $1 $2
|
||||
else
|
||||
for api in $(seq 23 34); do
|
||||
for api in $(seq 23 35); do
|
||||
run_test $api
|
||||
done
|
||||
# Android 15 Beta
|
||||
run_test 35 google_apis
|
||||
# Android 16 Beta
|
||||
run_test Baklava google_apis
|
||||
# Run 16k page tests
|
||||
run_test 35 google_apis_ps16k
|
||||
fi
|
||||
|
Reference in New Issue
Block a user