Compare commits

..

48 Commits

Author SHA1 Message Date
topjohnwu
47cc532d96 Release new canary build 2024-12-06 18:19:06 -08:00
topjohnwu
218327f92b Release Magisk v28.1 2024-12-06 17:45:41 -08:00
topjohnwu
4eae66a1a7 Add v28.1 release notes 2024-12-06 17:38:43 -08:00
vvb2060
b09ceeb43c scripts: sync avd_magisk.sh with mgiskinit 2024-12-06 02:21:17 -08:00
vvb2060
4fb539c110 core: use a new tmpfs as worker 2024-12-06 02:19:43 -08:00
vvb2060
849b284da5 core: insert symlink magisk_node 2024-12-06 02:19:32 -08:00
topjohnwu
895b5f6cbf Release new canary build 2024-12-04 01:28:31 -08:00
SonyaMedved
cb3d4ea514 strings.xml
The strings have been translated into Ukrainian.
2024-12-04 01:26:39 -08:00
topjohnwu
0d89a2a97d Update AGP 2024-12-04 01:25:44 -08:00
nedokaka
3ca5913055 Update Russian Translation 2024-12-03 19:52:53 -08:00
topjohnwu
df6b808f49 Cleanup DesugarClassVisitorFactory 2024-12-03 19:52:39 -08:00
topjohnwu
09c7ac754b Simplify MagiskD Rust/C++ FFI 2024-12-03 15:51:17 -08:00
topjohnwu
805da67c23 Update cxx-rs 2024-12-03 14:16:14 -08:00
topjohnwu
3c6889505b Stop using polymorphism in magiskinit 2024-12-03 02:18:22 -08:00
topjohnwu
c8e9ce7627 Cleanup mount code in magiskinit 2024-12-03 02:18:22 -08:00
topjohnwu
837c679a31 Update avd_test API versions 2024-12-03 02:18:22 -08:00
LoveSy
06616659b8 Only desugar ZipEntry's methods 2024-12-02 19:55:28 -08:00
topjohnwu
a34c04f999 Release new canary build 2024-12-01 14:59:57 -08:00
topjohnwu
da43ac89a0 Allow all domains to access tmpfs files
Fix #8457
2024-11-30 23:21:33 -08:00
vvb2060
830fc758b9 init: Use apex dir to determine whether 2SI 2024-11-30 23:03:29 -08:00
vvb2060
0f3cfef278 Revert "init: support 2SI devices with skip_initramfs"
This reverts commit b38fd1ca5f.
2024-11-30 23:03:29 -08:00
topjohnwu
b32d7bfafd Update gradle version 2024-11-21 21:05:35 -08:00
topjohnwu
c0899f2939 Update dependencies 2024-11-19 20:29:15 -08:00
topjohnwu
082330808f Fix building APK 2024-11-19 20:25:10 -08:00
topjohnwu
024da05888 Move several stuff into buildSrc 2024-11-09 20:08:12 -08:00
LoveSy
377b6d0cc2 avoid desugar the Desugar class 2024-11-09 19:41:06 -08:00
Georgi Boiko
c661009b31 docs(ci): update setup action to state correct jdk version 2024-11-04 11:12:01 -08:00
vvb2060
613f2d31c5 app: auto close action fragment only when focus lost 2024-11-04 11:11:41 -08:00
vvb2060
7dbb973db5 daemon: some samsung devices using incorrect mediatek-res path 2024-11-04 11:09:53 -08:00
topjohnwu
f4502f8be8 Add our own API desugaring
Some checks failed
Magisk Build / Build Magisk artifacts (push) Has been cancelled
Magisk Build / Test building on ${{ matrix.os }} (ubuntu-latest) (push) Has been cancelled
Magisk Build / Test building on ${{ matrix.os }} (windows-latest) (push) Has been cancelled
Magisk Build / Test API ${{ matrix.version }} (x86_64) (, 23) (push) Has been cancelled
Magisk Build / Test API ${{ matrix.version }} (x86_64) (, 24) (push) Has been cancelled
Magisk Build / Test API ${{ matrix.version }} (x86_64) (, 25) (push) Has been cancelled
Magisk Build / Test API ${{ matrix.version }} (x86_64) (, 26) (push) Has been cancelled
Magisk Build / Test API ${{ matrix.version }} (x86_64) (, 27) (push) Has been cancelled
Magisk Build / Test API ${{ matrix.version }} (x86_64) (, 28) (push) Has been cancelled
Magisk Build / Test API ${{ matrix.version }} (x86_64) (, 29) (push) Has been cancelled
Magisk Build / Test API ${{ matrix.version }} (x86_64) (, 30) (push) Has been cancelled
Magisk Build / Test API ${{ matrix.version }} (x86_64) (, 31) (push) Has been cancelled
Magisk Build / Test API ${{ matrix.version }} (x86_64) (, 32) (push) Has been cancelled
Magisk Build / Test API ${{ matrix.version }} (x86_64) (, 33) (push) Has been cancelled
Magisk Build / Test API ${{ matrix.version }} (x86_64) (, 34) (push) Has been cancelled
Magisk Build / Test API ${{ matrix.version }} (x86_64) (google_apis, 35) (push) Has been cancelled
Magisk Build / Test API ${{ matrix.version }} (x86) (23) (push) Has been cancelled
Magisk Build / Test API ${{ matrix.version }} (x86) (24) (push) Has been cancelled
Magisk Build / Test API ${{ matrix.version }} (x86) (25) (push) Has been cancelled
Magisk Build / Test API ${{ matrix.version }} (x86) (26) (push) Has been cancelled
Magisk Build / Test API ${{ matrix.version }} (x86) (27) (push) Has been cancelled
Magisk Build / Test API ${{ matrix.version }} (x86) (28) (push) Has been cancelled
Magisk Build / Test API ${{ matrix.version }} (x86) (29) (push) Has been cancelled
Magisk Build / Test API ${{ matrix.version }} (x86) (30) (push) Has been cancelled
Magisk Build / Test ${{ matrix.device }} (aosp-main, aosp_cf_x86_64_phone) (push) Has been cancelled
Magisk Build / Test ${{ matrix.device }} (aosp-main-throttled, aosp_cf_x86_64_phone_pgagnostic) (push) Has been cancelled
Fix #8452
2024-10-29 12:13:22 -07:00
topjohnwu
455b13b83c Fix download URL in stub.apk 2024-10-17 19:42:10 -07:00
topjohnwu
8b98709743 Update dependencies 2024-10-17 13:17:46 -07:00
tzagim
1b12f45f39 Update Hebrew Translation 2024-10-15 15:23:21 -07:00
vvb2060
a5cad532ff ui: fix lock screen orientation 2024-10-12 01:16:24 -07:00
topjohnwu
070719db50 Release new canary build 2024-10-10 02:10:50 -07:00
topjohnwu
28cccdf7aa Release Magisk v28.0 2024-10-10 01:47:00 -07:00
topjohnwu
b7e0986a5c Add v28.0 changelog 2024-10-10 01:40:14 -07:00
topjohnwu
da709745dd Revert #8245 2024-10-09 15:40:23 -07:00
topjohnwu
8b6771d487 Update dependencies 2024-10-08 01:40:09 -07:00
topjohnwu
e1b847fbc5 Find boot image with MagiskInstaller
Fix #8211
2024-10-07 16:52:35 -07:00
topjohnwu
7188de1205 Support unaligned boot image file
Fix #7733
2024-10-06 03:01:08 -07:00
topjohnwu
44fb7dbcbe Update Busybox
Fix #8403
2024-10-06 01:47:13 -07:00
topjohnwu
8086b5933c Update crt0
Fix #8424
2024-10-02 16:37:07 -07:00
topjohnwu
7f675f4bf7 Update dependencies 2024-09-27 14:38:32 -07:00
vvb2060
5e6b53e0da AppMigration: put suManager after installation 2024-09-25 12:34:21 -07:00
残页
5b29fefc65 Replace LOGE with LOGW so the process don't abort
Co-authored-by: 南宫雪珊 <vvb2060@gmail.com>
2024-09-25 11:59:58 -07:00
残页
16a168535d Check sepolicy database version in add_xperm_rule
Fix #8344
2024-09-25 11:59:58 -07:00
Wang Han
33f70f8f6d Update zh-rCN strings 2024-09-17 15:01:10 -07:00
57 changed files with 879 additions and 771 deletions

View File

@@ -6,7 +6,7 @@ inputs:
runs: runs:
using: "composite" using: "composite"
steps: steps:
- name: Set up JDK 17 - name: Set up JDK 21
uses: actions/setup-java@v4 uses: actions/setup-java@v4
with: with:
distribution: "temurin" distribution: "temurin"

View File

@@ -83,10 +83,10 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: 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: [""] type: [""]
include: include:
- version: 35 - version: "Baklava"
type: "google_apis" type: "google_apis"
steps: steps:

1
.gitignore vendored
View File

@@ -14,6 +14,7 @@ native/out
*.iml *.iml
.gradle .gradle
.idea .idea
.kotlin
/local.properties /local.properties
/build /build
/captures /captures

View File

@@ -20,9 +20,9 @@ Some highlight features:
Click the icon below to download Magisk apk. Click the icon below to download Magisk apk.
[![](https://img.shields.io/badge/Magisk-v27.0-blue)](https://github.com/topjohnwu/Magisk/releases/tag/v27.0) [![](https://img.shields.io/badge/Magisk-v28.1-blue)](https://github.com/topjohnwu/Magisk/releases/tag/v28.1)
[![](https://img.shields.io/badge/Magisk%20Beta-v27.0-blue)](https://github.com/topjohnwu/Magisk/releases/tag/v27.0) [![](https://img.shields.io/badge/Magisk%20Beta-v28.1-blue)](https://github.com/topjohnwu/Magisk/releases/tag/v28.1)
[![](https://img.shields.io/badge/Magisk-Canary-red)](https://github.com/topjohnwu/Magisk/releases/tag/canary-27008) [![](https://img.shields.io/badge/Magisk-Canary-red)](https://github.com/topjohnwu/Magisk/releases/tag/canary-28101)
## Useful Links ## Useful Links

View File

@@ -6,7 +6,7 @@ plugins {
id("androidx.navigation.safeargs.kotlin") id("androidx.navigation.safeargs.kotlin")
} }
setupAppCommon() setupMainApk()
kapt { kapt {
correctErrorTypes = true correctErrorTypes = true
@@ -18,27 +18,6 @@ kapt {
} }
android { 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 { buildFeatures {
dataBinding = true dataBinding = true
} }
@@ -46,6 +25,13 @@ android {
compileOptions { compileOptions {
isCoreLibraryDesugaringEnabled = true isCoreLibraryDesugaringEnabled = true
} }
buildTypes {
release {
isMinifyEnabled = true
isShrinkResources = true
}
}
} }
dependencies { dependencies {

View File

@@ -1,13 +1,18 @@
package com.topjohnwu.magisk.dialog package com.topjohnwu.magisk.dialog
import android.widget.Toast
import androidx.core.os.postDelayed
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.topjohnwu.magisk.core.BuildConfig import com.topjohnwu.magisk.core.BuildConfig
import com.topjohnwu.magisk.core.Info import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.R 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.core.tasks.MagiskInstaller
import com.topjohnwu.magisk.events.DialogBuilder import com.topjohnwu.magisk.events.DialogBuilder
import com.topjohnwu.magisk.ui.home.HomeViewModel import com.topjohnwu.magisk.ui.home.HomeViewModel
import com.topjohnwu.magisk.view.MagiskDialog import com.topjohnwu.magisk.view.MagiskDialog
import com.topjohnwu.superuser.internal.UiThreadHandler
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
class EnvFixDialog(private val vm: HomeViewModel, private val code: Int) : DialogBuilder { 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) setCancelable(false)
} }
dialog.activity.lifecycleScope.launch { dialog.activity.lifecycleScope.launch {
MagiskInstaller.FixEnv { MagiskInstaller.FixEnv().exec { success ->
dialog.dismiss() 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() }
}
} }
} }
} }

View File

@@ -1,15 +1,17 @@
package com.topjohnwu.magisk.dialog package com.topjohnwu.magisk.dialog
import android.app.ProgressDialog import android.app.ProgressDialog
import android.content.Context
import android.widget.Toast import android.widget.Toast
import androidx.lifecycle.lifecycleScope
import com.topjohnwu.magisk.arch.NavigationActivity import com.topjohnwu.magisk.arch.NavigationActivity
import com.topjohnwu.magisk.arch.UIActivity
import com.topjohnwu.magisk.core.R import com.topjohnwu.magisk.core.R
import com.topjohnwu.magisk.core.ktx.toast import com.topjohnwu.magisk.core.ktx.toast
import com.topjohnwu.magisk.core.tasks.MagiskInstaller
import com.topjohnwu.magisk.events.DialogBuilder import com.topjohnwu.magisk.events.DialogBuilder
import com.topjohnwu.magisk.ui.flash.FlashFragment import com.topjohnwu.magisk.ui.flash.FlashFragment
import com.topjohnwu.magisk.view.MagiskDialog import com.topjohnwu.magisk.view.MagiskDialog
import com.topjohnwu.superuser.Shell import kotlinx.coroutines.launch
class UninstallDialog : DialogBuilder { class UninstallDialog : DialogBuilder {
@@ -19,7 +21,7 @@ class UninstallDialog : DialogBuilder {
setMessage(R.string.uninstall_magisk_msg) setMessage(R.string.uninstall_magisk_msg)
setButton(MagiskDialog.ButtonType.POSITIVE) { setButton(MagiskDialog.ButtonType.POSITIVE) {
text = R.string.restore_img text = R.string.restore_img
onClick { restore(dialog.context) } onClick { restore(dialog.activity) }
} }
setButton(MagiskDialog.ButtonType.NEGATIVE) { setButton(MagiskDialog.ButtonType.NEGATIVE) {
text = R.string.complete_uninstall text = R.string.complete_uninstall
@@ -29,18 +31,20 @@ class UninstallDialog : DialogBuilder {
} }
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
private fun restore(context: Context) { private fun restore(activity: UIActivity<*>) {
val dialog = ProgressDialog(context).apply { val dialog = ProgressDialog(activity).apply {
setMessage(context.getString(R.string.restore_img_msg)) setMessage(activity.getString(R.string.restore_img_msg))
show() show()
} }
Shell.cmd("restore_imgs").submit { result -> activity.lifecycleScope.launch {
dialog.dismiss() MagiskInstaller.Restore().exec { success ->
if (result.isSuccess) { dialog.dismiss()
context.toast(R.string.restore_done, Toast.LENGTH_SHORT) if (success) {
} else { activity.toast(R.string.restore_done, Toast.LENGTH_SHORT)
context.toast(R.string.restore_fail, Toast.LENGTH_LONG) } else {
activity.toast(R.string.restore_fail, Toast.LENGTH_LONG)
}
} }
} }
} }

View File

@@ -71,7 +71,7 @@ class FlashFragment : BaseFragment<FragmentFlashMd2Binding>(), MenuProvider {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
defaultOrientation = activity?.requestedOrientation ?: -1 defaultOrientation = activity?.requestedOrientation ?: -1
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LOCKED
if (savedInstanceState == null) { if (savedInstanceState == null) {
viewModel.startFlashing() viewModel.startFlashing()
} }

View File

@@ -8,6 +8,7 @@ import android.view.Menu
import android.view.MenuInflater import android.view.MenuInflater
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.view.ViewTreeObserver
import android.widget.Toast import android.widget.Toast
import androidx.core.view.MenuProvider import androidx.core.view.MenuProvider
import androidx.core.view.isVisible 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.arch.viewModel
import com.topjohnwu.magisk.core.ktx.toast import com.topjohnwu.magisk.core.ktx.toast
import com.topjohnwu.magisk.databinding.FragmentActionMd2Binding 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 import com.topjohnwu.magisk.core.R as CoreR
class ActionFragment : BaseFragment<FragmentActionMd2Binding>(), MenuProvider { class ActionFragment : BaseFragment<FragmentActionMd2Binding>(), MenuProvider {
@@ -37,39 +36,32 @@ class ActionFragment : BaseFragment<FragmentActionMd2Binding>(), MenuProvider {
super.onStart() super.onStart()
activity?.setTitle(viewModel.args.name) activity?.setTitle(viewModel.args.name)
binding.closeBtn.setOnClickListener { binding.closeBtn.setOnClickListener {
activity?.onBackPressed(); activity?.onBackPressed()
} }
viewModel.state.observe(this) { viewModel.state.observe(this) {
activity?.supportActionBar?.setSubtitle( if (it != ActionViewModel.State.RUNNING) {
when (it) { binding.closeBtn.apply {
ActionViewModel.State.RUNNING -> CoreR.string.running if (!this.isVisible) this.show()
ActionViewModel.State.SUCCESS -> CoreR.string.done if (!this.isFocused) this.requestFocus()
ActionViewModel.State.FAILED -> CoreR.string.failure }
}
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) super.onViewCreated(view, savedInstanceState)
defaultOrientation = activity?.requestedOrientation ?: -1 defaultOrientation = activity?.requestedOrientation ?: -1
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LOCKED
if (savedInstanceState == null) { if (savedInstanceState == null) {
viewModel.startRunAction() viewModel.startRunAction()
} }

View File

@@ -1,28 +1,26 @@
package com.topjohnwu.magisk.ui.module package com.topjohnwu.magisk.ui.module
import android.view.MenuItem import android.view.MenuItem
import androidx.databinding.Bindable
import androidx.databinding.ObservableArrayList import androidx.databinding.ObservableArrayList
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.map
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseViewModel 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.synchronized
import com.topjohnwu.magisk.core.ktx.timeFormatStandard import com.topjohnwu.magisk.core.ktx.timeFormatStandard
import com.topjohnwu.magisk.core.ktx.toTime 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
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
import com.topjohnwu.magisk.databinding.set
import com.topjohnwu.magisk.events.SnackbarEvent import com.topjohnwu.magisk.events.SnackbarEvent
import com.topjohnwu.magisk.ui.flash.ConsoleItem import com.topjohnwu.magisk.ui.flash.ConsoleItem
import com.topjohnwu.superuser.CallbackList import com.topjohnwu.superuser.CallbackList
import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import timber.log.Timber
import java.io.IOException
class ActionViewModel : BaseViewModel() { class ActionViewModel : BaseViewModel() {
@@ -32,7 +30,6 @@ class ActionViewModel : BaseViewModel() {
private val _state = MutableLiveData(State.RUNNING) private val _state = MutableLiveData(State.RUNNING)
val state: LiveData<State> get() = _state val state: LiveData<State> get() = _state
val running = state.map { it == State.RUNNING }
val items = ObservableArrayList<ConsoleItem>() val items = ObservableArrayList<ConsoleItem>()
lateinit var args: ActionFragmentArgs lateinit var args: ActionFragmentArgs
@@ -46,10 +43,17 @@ class ActionViewModel : BaseViewModel() {
} }
} }
fun startRunAction() { fun startRunAction() = viewModelScope.launch {
viewModelScope.launch { onResult(withContext(Dispatchers.IO) {
onResult(RunAction(args.id, outItems, logItems).exec()) try {
} Shell.cmd("run_action \'${args.id}\'")
.to(outItems, logItems)
.exec().isSuccess
} catch (e: IOException) {
Timber.e(e)
false
}
})
} }
private fun onResult(success: Boolean) { private fun onResult(success: Boolean) {

View File

@@ -19,6 +19,7 @@ android {
buildConfigField("int", "APP_VERSION_CODE", "${Config.versionCode}") buildConfigField("int", "APP_VERSION_CODE", "${Config.versionCode}")
buildConfigField("String", "APP_VERSION_NAME", "\"${Config.version}\"") buildConfigField("String", "APP_VERSION_NAME", "\"${Config.version}\"")
buildConfigField("int", "STUB_VERSION", Config.stubVersion) buildConfigField("int", "STUB_VERSION", Config.stubVersion)
consumerProguardFile("proguard-rules.pro")
} }
buildFeatures { buildFeatures {

View File

@@ -22,36 +22,21 @@
int mActivityHandlesConfigFlags; 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 # Strip Timber verbose and debug logging
-assumenosideeffects class timber.log.Timber$Tree { -assumenosideeffects class timber.log.Timber$Tree {
public void v(**); public void v(**);
public void d(**); 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 # With R8 full mode generic signatures are stripped for classes that are not
# kept. Suspend functions are wrapped in continuations where the type argument # kept. Suspend functions are wrapped in continuations where the type argument
# is used. # is used.
-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation -keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation
# Excessive obfuscation # Excessive obfuscation
-repackageclasses 'a' -flattenpackagehierarchy
-allowaccessmodification -allowaccessmodification
-obfuscationdictionary ../dict.txt
-classobfuscationdictionary ../dict.txt
-packageobfuscationdictionary ../dict.txt
-dontwarn org.bouncycastle.jsse.BCSSLParameters -dontwarn org.bouncycastle.jsse.BCSSLParameters
-dontwarn org.bouncycastle.jsse.BCSSLSocket -dontwarn org.bouncycastle.jsse.BCSSLSocket
-dontwarn org.bouncycastle.jsse.provider.BouncyCastleJsseProvider -dontwarn org.bouncycastle.jsse.provider.BouncyCastleJsseProvider

View File

@@ -191,11 +191,12 @@ object AppMigration {
// Install and auto launch app // Install and auto launch app
val session = APKInstall.startSession(activity, pkg, onFailure) { val session = APKInstall.startSession(activity, pkg, onFailure) {
Config.suManager = pkg
Shell.cmd("touch $AppApkPath").exec()
launchApp(activity, pkg) launchApp(activity, pkg)
} }
Config.suManager = pkg val cmd = "adb_pm_install $repack $pkg"
val cmd = "touch $AppApkPath; adb_pm_install $repack $pkg"
if (Shell.cmd(cmd).exec().isSuccess) return true if (Shell.cmd(cmd).exec().isSuccess) return true
try { try {
@@ -240,11 +241,12 @@ object AppMigration {
} }
val apk = StubApk.current(activity) val apk = StubApk.current(activity)
val session = APKInstall.startSession(activity, APP_PACKAGE_NAME, onFailure) { val session = APKInstall.startSession(activity, APP_PACKAGE_NAME, onFailure) {
Config.suManager = ""
Shell.cmd("touch $AppApkPath").exec()
launchApp(activity, APP_PACKAGE_NAME) launchApp(activity, APP_PACKAGE_NAME)
dialog.dismiss() dialog.dismiss()
} }
Config.suManager = "" val cmd = "adb_pm_install $apk $APP_PACKAGE_NAME"
val cmd = "touch $AppApkPath; adb_pm_install $apk $APP_PACKAGE_NAME"
if (Shell.cmd(cmd).await().isSuccess) return if (Shell.cmd(cmd).await().isSuccess) return
val success = withContext(Dispatchers.IO) { val success = withContext(Dispatchers.IO) {
try { try {

View File

@@ -6,7 +6,6 @@ import android.system.ErrnoException
import android.system.Os import android.system.Os
import android.system.OsConstants import android.system.OsConstants
import android.system.OsConstants.O_WRONLY import android.system.OsConstants.O_WRONLY
import android.widget.Toast
import androidx.annotation.WorkerThread import androidx.annotation.WorkerThread
import androidx.core.os.postDelayed import androidx.core.os.postDelayed
import com.topjohnwu.magisk.StubApk 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.Config
import com.topjohnwu.magisk.core.Const import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.Info import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.R
import com.topjohnwu.magisk.core.di.ServiceLocator import com.topjohnwu.magisk.core.di.ServiceLocator
import com.topjohnwu.magisk.core.isRunningAsStub import com.topjohnwu.magisk.core.isRunningAsStub
import com.topjohnwu.magisk.core.ktx.copyAll import com.topjohnwu.magisk.core.ktx.copyAll
import com.topjohnwu.magisk.core.ktx.copyAndClose 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.ktx.writeTo
import com.topjohnwu.magisk.core.utils.DummyList import com.topjohnwu.magisk.core.utils.DummyList
import com.topjohnwu.magisk.core.utils.MediaStoreUtils 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 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 protected fun uninstall() = "run_uninstaller $AppApkPath".sh().isSuccess
@WorkerThread @WorkerThread
@@ -608,11 +606,10 @@ abstract class MagiskInstallImpl protected constructor(
} }
} }
abstract class MagiskInstaller( abstract class ConsoleInstaller(
console: MutableList<String>, console: MutableList<String>,
logs: MutableList<String> logs: MutableList<String>
) : MagiskInstallImpl(console, logs) { ) : MagiskInstallImpl(console, logs) {
override suspend fun exec(): Boolean { override suspend fun exec(): Boolean {
val success = super.exec() val success = super.exec()
if (success) { if (success) {
@@ -622,40 +619,51 @@ abstract class MagiskInstaller(
} }
return success 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( class Patch(
private val uri: Uri, private val uri: Uri,
console: MutableList<String>, console: MutableList<String>,
logs: MutableList<String> logs: MutableList<String>
) : MagiskInstaller(console, logs) { ) : ConsoleInstaller(console, logs) {
override suspend fun operations() = patchFile(uri) override suspend fun operations() = patchFile(uri)
} }
class SecondSlot( class SecondSlot(
console: MutableList<String>, console: MutableList<String>,
logs: MutableList<String> logs: MutableList<String>
) : MagiskInstaller(console, logs) { ) : ConsoleInstaller(console, logs) {
override suspend fun operations() = secondSlot() override suspend fun operations() = secondSlot()
} }
class Direct( class Direct(
console: MutableList<String>, console: MutableList<String>,
logs: MutableList<String> logs: MutableList<String>
) : MagiskInstaller(console, logs) { ) : ConsoleInstaller(console, logs) {
override suspend fun operations() = direct() override suspend fun operations() = direct()
} }
class Emulator( class Emulator(
console: MutableList<String>, console: MutableList<String>,
logs: MutableList<String> logs: MutableList<String>
) : MagiskInstaller(console, logs) { ) : ConsoleInstaller(console, logs) {
override suspend fun operations() = fixEnv() override suspend fun operations() = fixEnv()
} }
class Uninstall( class Uninstall(
console: MutableList<String>, console: MutableList<String>,
logs: MutableList<String> logs: MutableList<String>
) : MagiskInstallImpl(console, logs) { ) : ConsoleInstaller(console, logs) {
override suspend fun operations() = uninstall() override suspend fun operations() = uninstall()
override suspend fun exec(): Boolean { override suspend fun exec(): Boolean {
@@ -669,19 +677,11 @@ abstract class MagiskInstaller(
} }
} }
class FixEnv(private val callback: () -> Unit) : MagiskInstallImpl(DummyList, DummyList) { class Restore : CallBackInstaller() {
override suspend fun operations() = fixEnv() override suspend fun operations() = restore()
}
override suspend fun exec(): Boolean { class FixEnv : CallBackInstaller() {
val success = super.exec() override suspend fun operations() = fixEnv()
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
}
} }
} }

View File

@@ -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
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -2,154 +2,130 @@
<!--Sections--> <!--Sections-->
<string name="modules">الإضافات</string> <string name="modules">الإضافات</string>
<string name="superuser">المستخدم الخارق</string> <string name="superuser">صلاحية الروت</string>
<string name="logs">السجلات</string> <string name="logs">السجلات</string>
<string name="settings">الإعدادات</string> <string name="settings">الإعدادات</string>
<string name="install">التثبيت</string> <string name="install">تثبيت</string>
<string name="section_home">الرئيسية</string> <string name="section_home">الأساسي</string>
<string name="section_theme">المظهر</string> <string name="section_theme">السِمات</string>
<string name="denylist">القائمة السوداء</string>
<!--Home--> <!--Home-->
<string name="no_connection">لا يوجد اتصال متاح</string> <string name="no_connection">لا يوجد إتصال</string>
<string name="app_changelog">سجل التغييرات</string> <string name="app_changelog">تفاصيل التحديث</string>
<string name="loading">جارٍ التحميل...</string> <string name="loading">جارٍ التحميل...</string>
<string name="update">تحديث</string> <string name="update">تحديث</string>
<string name="not_available">غير متاح</string> <string name="not_available">غير/متوفر</string>
<string name="hide">إخفاء</string> <string name="hide">إخفاء</string>
<string name="home_package">الحزمة</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_support_title">ادعمنا</string> <string name="home_item_source">الكود المصدري للتطبيق</string>
<string name="home_follow_title">تابعنا</string> <string name="home_support_content">مـاجـيسك هي، وستظل دوماً، مجانيةً و مفتوحة المصدر، اظهر اهتمامك لنا لكي نبقيها هكذا بدعم مالي صغير</string>
<string name="home_item_source">المصدر</string> <string name="home_installed_version">تم التثبيت</string>
<string name="home_support_content">Magisk مجاني ومفتوح المصدر وسيظل كذلك دائمًا. يمكنك إظهار دعمك لنا من خلال التبرع.</string> <string name="home_latest_version">آخر إصدار</string>
<string name="home_installed_version">المثبتة</string> <string name="invalid_update_channel">مصدر التحديث غير صالح</string>
<string name="home_latest_version">الأحدث</string>
<string name="invalid_update_channel">قناة التحديث غير صالحة</string>
<string name="uninstall_magisk_title">إلغاء تثبيت Magisk</string> <string name="uninstall_magisk_title">إلغاء تثبيت Magisk</string>
<string name="uninstall_magisk_msg">ستتم إزالة جميع الوحدات / تعطيلها!\nسيتم إزالة الروت!\nأي تخزين داخلي تم فك تشفيره باستخدام Magisk سيتم إعادة تشفيره!</string> <string name="uninstall_magisk_msg">ستُعطل/ستُحذف جميع الإضافات. سيُحذف الروت، وربما ستشفر بياناتك إذا لم تكن غير مشفرة حالياً.</string>
<!--Install--> <!--Install-->
<string name="keep_force_encryption">الحفاظ على التشفير الإجباري</string> <string name="keep_force_encryption">فرض التشفير الإجباري</string>
<string name="keep_dm_verity">الحفاظ على AVB 2.0/dm-verity</string> <string name="keep_dm_verity">فرض تشفيرات AVB2.0/dm-verity</string>
<string name="recovery_mode">وضع الاسترداد</string> <string name="recovery_mode">وضـع الريكفري</string>
<string name="install_options_title">الخيارات</string> <string name="install_options_title">الخيارات</string>
<string name="install_method_title">الطريقة</string> <string name="install_method_title">الطريقة</string>
<string name="install_next">التالي</string> <string name="install_next">التالي</string>
<string name="install_start">هيا بنا</string> <string name="install_start">هيا، بنا</string>
<string name="manager_download_install">اضغط للتنزيل والتثبيت</string> <string name="manager_download_install">اضغط للتنزيل و التثبيت</string>
<string name="direct_install">التثبيت المباشر (موصى به)</string> <string name="direct_install">تثبيت مباشر (موصى بها)</string>
<string name="install_inactive_slot">التثبيت على الشريحة غير النشطة (بعد OTA)</string> <string name="install_inactive_slot">التثبيت على المنطقة الغير نشطة (بعد OTA)</string>
<string name="install_inactive_slot_msg">سيتم إجبار جهازك على التمهيد إلى الشريحة غير النشطة الحالية بعد إعادة التشغيل!\nاستخدم هذا الخيار فقط بعد الانتهاء من OTA.\nهل تود المتابعة؟</string> <string name="install_inactive_slot_msg">سيُجبر جهازك للاقلاع على المنطقة الغير النشطة بعد إعادة التشغيل!\n استخدم هذا الخيار فقط بعد الانتهاء من OTA. استمرار؟</string>
<string name="setup_title">إعداد إضافي</string> <string name="setup_title">إعدادات إضافية</string>
<string name="select_patch_file">اختر وقم بعمل باتش ملف</string> <string name="select_patch_file">حدد و عدل ملفاً</string>
<string name="patch_file_msg">اختر صورة خام (*.img) أو ملف ODIN tarfile (*.tar) أو payload.bin (*.bin)</string> <string name="patch_file_msg">اختر ملف (*.img) أو ملف odin (*.tar)</string>
<string name="reboot_delay_toast">سيتم إعادة التشغيل في 5 ثوانٍ...</string> <string name="reboot_delay_toast">إعادة التشغيل بعد ٥ ثواني…</string>
<string name="flash_screen_title">التثبيت</string> <string name="flash_screen_title">التثبيت</string>
<!--Superuser--> <!--Superuser-->
<string name="su_request_title">طلب المستخدم الخارق</string> <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="prompt">طلب</string>
<string name="grant">منح</string> <string name="grant">سماح</string>
<string name="su_warning">يمنح حق الوصول الكامل لجهازك.\nارفض إذا لم تكن متأكدًا!</string> <string name="su_warning">يمنح حق الوصول الكامل إلى جهازك. ارفض إذا كنت غير متأكد!</string>
<string name="forever">دائمًا</string> <string name="forever">للأبد</string>
<string name="once">مرة واحدة</string> <string name="once">مرة واحدة</string>
<string name="tenmin">جار0 دقائق</string> <string name="tenmin">10 دقائق</string>
<string name="twentymin">20 دقيقة</string> <string name="twentymin">20 دقيقة</string>
<string name="thirtymin">30 دقيقة</string> <string name="thirtymin">30 دقيقة</string>
<string name="sixtymin">60 دقيقة</string> <string name="sixtymin">60 دقيقة</string>
<string name="su_allow_toast">%جار$s تم منحه حقوق المستخدم الخارق</string> <string name="su_allow_toast">تم منح صلاحيات الروت لـ%1$s</string>
<string name="su_deny_toast">%جار$s تم رفض حقوق المستخدم الخارق</string> <string name="su_deny_toast">تم رفض صلاحيات الروت لـ%1$s </string>
<string name="su_snack_grant">تم منح حقوق المستخدم الخارق لـ %جار$s</string> <string name="su_snack_grant">تم منح صلاحيات الروت لـ%1$s</string>
<string name="su_snack_deny">تم رفض حقوق المستخدم الخارق لـ %جار$s</string> <string name="su_snack_deny">تم رفض صلاحيات الروت لـ%1$s</string>
<string name="su_snack_notif_on">تم تفعيل الإشعارات لـ %جار$s</string> <string name="su_snack_notif_on">تم تفعيل الإشعارات لـ%1$s</string>
<string name="su_snack_notif_off">تم تعطيل الإشعارات لـ %جار$s</string> <string name="su_snack_notif_off">تم تعطيل الإشعارات لـ%1$s</string>
<string name="su_snack_log_on">تم تفعيل السجلات لـ %جار$s</string> <string name="su_snack_log_on">تم تفعيل السجلات لـ%1$s</string>
<string name="su_snack_log_off">تم تعطيل السجلات لـ %جار$s</string> <string name="su_snack_log_off">تم تعطيل السجلات لـ%1$s</string>
<string name="su_revoke_title">إلغاء؟</string> <string name="su_revoke_title">منع؟</string>
<string name="su_revoke_msg">تأكيد لإلغاء حقوق المستخدم الخارق لـ %جار$s</string> <string name="su_revoke_msg">هل تريد منع صلاحية %1$s?</string>
<string name="toast">إشعار</string> <string name="toast">اشعار</string>
<string name="none">لا شيء</string> <string name="none">بدون</string>
<string name="superuser_toggle_notification">الإشعارات</string> <string name="superuser_toggle_notification">الإشعارات</string>
<string name="superuser_toggle_revoke">إلغاء</string> <string name="superuser_toggle_revoke">منع</string>
<string name="superuser_policy_none">لم يطلب أي تطبيق بعد إذن المستخدم الخارق.</string> <string name="superuser_policy_none">لم يسأل آية تطبيق لصلاحيات الروت</string>
<!--Logs--> <!--Logs-->
<string name="log_data_none">أنت خالٍ من السجلات، جرب استخدام تطبيقات الروت الخاصة بك أكثر</string> <string name="log_data_none">لا يوجد أية سجلات هنا :-:، حاول استعمال تطبيقات روت اكثر</string>
<string name="log_data_magisk_none">سجلات Magisk فارغة، هذا غريب</string> <string name="log_data_magisk_none">لا توجد أيةَ سجلات ⊙_⊙</string>
<string name="menuSaveLog">حفظ السجل</string> <string name="menuSaveLog">حفظ السجلات</string>
<string name="menuClearLog">مسح السجل الآن</string> <string name="menuClearLog">حذف السجلات</string>
<string name="logs_cleared">تم مسح السجل بنجاح</string> <string name="logs_cleared">تم الحذف بنجاح</string>
<string name="pid">PID: %جار$d</string> <string name="pid">PID: %1$d</string>
<string name="target_uid">UID الهدف: %جار$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--> <!--SafetyNet-->
<!--MagiskHide--> <!-- MagiskHide -->
<string name="show_system_app">عرض تطبيقات النظام</string> <string name="show_system_app">إظهار برامج النظام</string>
<string name="show_os_app">عرض تطبيقات نظام التشغيل</string> <string name="hide_filter_hint">البحث بالإسم</string>
<string name="hide_filter_hint">التصفية بالاسم</string> <string name="hide_search">ابحث</string>
<string name="hide_search">بحث</string>
<!--Module--> <!--Module Fragment-->
<string name="no_info_provided">(لم يتم تقديم معلومات)</string> <string name="no_info_provided">(لم توفر معلومات)</string>
<string name="reboot_userspace">إعادة تشغيل ناعمة</string> <string name="reboot_recovery">إعادة التشغيل إلى Recovery</string>
<string name="reboot_recovery">إعادة التشغيل إلى وضع الاسترداد</string> <string name="reboot_bootloader">إعادة التشغيل إلى Bootloader</string>
<string name="reboot_bootloader">إعادة التشغيل إلى محمل الإقلاع</string> <string name="reboot_download">إعادة التشغيل إلى وضـع Odin</string>
<string name="reboot_download">إعادة التشغيل إلى وضع التنزيل</string> <string name="reboot_edl">إعادة التشغيل إلى وضـعية EDL</string>
<string name="reboot_edl">إعادة التشغيل إلى وضع EDL</string> <string name="module_version_author">%1$sبواسطة%2$s</string>
<string name="reboot_safe_mode">وضع الآمن</string> <string name="module_state_remove">إزالة </string>
<string name="module_state_remove">إزالة</string> <string name="module_state_restore">إسترجاع</string>
<string name="module_state_restore">استعادة</string> <string name="module_action_install_external">اختر من الذاكرة الداخلية</string>
<string name="module_action_install_external">التثبيت من التخزين</string> <string name="update_available">التحديث متوفر</string>
<string name="update_available">تحديث متاح</string> <string name="external_rw_permission_denied">امنحني إذن الولوج للذاكرة الداخلية</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>
<!--Settings--> <!--Settings -->
<string name="settings_dark_mode_title">وضع الثيم</string> <string name="settings_dark_mode_title">وضـعية الِسمات</string>
<string name="settings_dark_mode_message">اختر الوضع الذي يناسب نمطك!</string> <string name="settings_dark_mode_message">حدد الوضـع الذي يناسب ذوقك</string>
<string name="settings_dark_mode_light">دائمًا فاتح</string> <string name="settings_dark_mode_light">الوضـع المضيء</string>
<string name="settings_dark_mode_system">تابع النظام</string> <string name="settings_dark_mode_system">اتبّع النظام</string>
<string name="settings_dark_mode_dark">دائمًا داكن</string> <string name="settings_dark_mode_dark">وضـع الظلام</string>
<string name="settings_download_path_title">مسار التنزيل</string> <string name="settings_download_path_title">مسار التحميل</string>
<string name="settings_download_path_message">سيتم حفظ الملفات في %جار$s</string> <string name="settings_download_path_message">ستحمل الملفات إلى %1$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>
<string name="language">اللغة</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_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_channel_title">مصدر التحديثات</string>
<string name="settings_update_stable">مستقر</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">مخصص</string>
<string name="settings_update_custom_msg">أدخل عنوان URL لقناة مخصصة</string> <string name="settings_update_custom_msg">أدخل الرابط لمصدرك المخصص</string>
<string name="settings_zygisk_summary">تشغيل أجزاء من Magisk في خدمة zygote</string> <string name="settings_hosts_title">موانع الاعلانات</string>
<string name="settings_denylist_title">تفعيل القائمة السوداء</string> <string name="settings_hosts_summary">حجب الاعلانات دون تعديل النظام</string>
<string name="settings_denylist_summary">سيتم إرجاع جميع تعديلات Magisk للعمليات الموجودة في القائمة السوداء</string> <string name="settings_hosts_toast">تم تمكين خاصية حجب الاعلانات</string>
<string name="settings_denylist_config_title">تكوين القائمة السوداء</string> <string name="settings_app_name_hint">الإسم الجديد</string>
<string name="settings_denylist_config_summary">اختر العمليات التي سيتم تضمينها في القائمة السوداء</string> <string name="settings_app_name_helper">التطبيق الجديد سوف يملك هذا الإسم</string>
<string name="settings_hosts_title">مضيفين بدون نظام</string> <string name="settings_app_name_error">الصيغة غير مقبولة</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_adb">التطبيقات و ADB</string>
<string name="settings_su_app">التطبيقات فقط</string> <string name="settings_su_app">التطبيقات فقط</string>
<string name="settings_su_adb">ADB فقط</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_30">30 ثانية</string>
<string name="settings_su_request_45">45 ثانية</string> <string name="settings_su_request_45">45 ثانية</string>
<string name="settings_su_request_60">60 ثانية</string> <string name="settings_su_request_60">60 ثانية</string>
<string name="superuser_access">وصول المستخدم الخارق</string> <string name="superuser_access">صلاحيات الروت</string>
<string name="auto_response">استجابة تلقائية</string> <string name="auto_response">الفعل التلقائي</string>
<string name="request_timeout">انتهاء مهلة الطلب</string> <string name="request_timeout">المهلة قبل الفعل التلقائي</string>
<string name="superuser_notification">إشعار المستخدم الخارق</string> <string name="superuser_notification">إشعارات طلبات الروت</string>
<string name="settings_su_reauth_title">إعادة التوثيق بعد الترقية</string> <string name="settings_su_reauth_title">إعادة المصادقة بعد الترقية</string>
<string name="settings_su_reauth_summary">طلب أذونات المستخدم الخارق مرة أخرى بعد ترقية التطبيقات</string> <string name="settings_su_reauth_summary">أعد مصادقة صلاحيات الروت بعد إجراء ترقيات للتطبيق</string>
<string name="settings_su_tapjack_title">حماية من اختراق النقرات</string> <string name="settings_customization">تخصيص</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="multiuser_mode">وضع المستخدمين المتعددين</string> <string name="multiuser_mode">نمط مستخدمين متعددين</string>
<string name="settings_owner_only">مالك الجهاز فقط</string> <string name="settings_owner_only">مالك الجهاز فقط</string>
<string name="settings_owner_manage">يديرها مالك الجهاز</string> <string name="settings_owner_manage">المالك هو من يحدد</string>
<string name="settings_user_independent">مستقل عن المستخدم</string> <string name="settings_user_independent">مستقل </string>
<string name="owner_only_summary">فقط المالك له وصول روت</string> <string name="owner_only_summary">للمالك فقط له صلاحيات الروت</string>
<string name="owner_manage_summary">فقط المالك يمكنه إدارة وصول الروت وتلقي طلبات الإذن</string> <string name="owner_manage_summary">فقط المالك من يرفض و يمنح صلاحيات الروت</string>
<string name="user_independent_summary">كل مستخدم لديه قواعد الروت الخاصة به</string> <string name="user_independent_summary">كل مستخدم له قواعد روت خاصة به</string>
<string name="mount_namespace_mode">وضع مساحة التثبيت</string> <string name="mount_namespace_mode">نمط Mount Namespace</string>
<string name="settings_ns_global">مساحة أسماء عامة</string> <string name="settings_ns_global">نمط Namespace العام</string>
<string name="settings_ns_requester">وراثة مساحة الأسماء</string> <string name="settings_ns_requester">نمط NameSpace المتوارث</string>
<string name="settings_ns_isolate">مساحة أسماء معزولة</string> <string name="settings_ns_isolate">نمط NameSpace المعزول</string>
<string name="global_summary">جميع جلسات الروت تستخدم مساحة التثبيت العامة</string> <string name="global_summary">جميع الجلسات الروت تستخدم NameSpace العام</string>
<string name="requester_summary">جلسات الروت سترث مساحة الأسماء من طالب الروت</string> <string name="requester_summary">جميع الجلسات الروت تستخدم NameSpace المتوارث</string>
<string name="isolate_summary">كل جلسة روت سيكون لها مساحة أسماء معزولة خاصة بها</string> <string name="isolate_summary">جميع الجلسات الروت تستخدم NameSpace المعزول</string>
<!--Notifications--> <!--Notifications-->
<string name="update_channel">تحديثات Magisk</string> <string name="update_channel">تحديثات Magisk</string>
<string name="progress_channel">إشعارات التقدم</string> <string name="progress_channel">إشعارات التقدم</string>
<string name="updated_channel">اكتمل التحديث</string>
<string name="download_complete">اكتمل التنزيل</string> <string name="download_complete">اكتمل التنزيل</string>
<string name="download_file_error">خطأ في تنزيل الملف</string> <string name="download_file_error">فشل تنزيل الملف</string>
<string name="magisk_update_title">تحديث Magisk متاح!</string> <string name="magisk_update_title">تحديث مـاجـيسك متوفر!</string>
<string name="updated_title">تم تحديث Magisk</string>
<string name="updated_text">اضغط لفتح التطبيق</string>
<!--Toasts, Dialogs--> <!--Toasts, Dialogs-->
<string name="yes">نعم</string> <string name="yes">نعم</string>
<string name="no">لا</string> <string name="no">لا</string>
<string name="download">تنزيل</string> <string name="download">تنزيل</string>
<string name="reboot">إعادة التشغيل</string> <string name="reboot">إعادة التشغيل</string>
<string name="release_notes">ملاحظات الإصدار</string> <string name="release_notes">معلومات الأصدار الجديد</string>
<string name="flashing">جارٍ التثبيت...</string> <string name="flashing">يتم الحرق...</string>
<string name="done">تم!</string> <string name="done">تم!</string>
<string name="failure">فشل!</string> <string name="failure">فشل!</string>
<string name="hide_app_title">جارٍ إخفاء تطبيق Magisk...</string> <string name="open_link_failed_toast">لم يُعثر على تطبيق لفتح الرابط …</string>
<string name="open_link_failed_toast">لم يتم العثور على تطبيق لفتح الرابط</string> <string name="complete_uninstall">إلغاء التثبيت بالكامل</string>
<string name="complete_uninstall">إلغاء التثبيت الكامل</string>
<string name="restore_img">استعادة الصور</string> <string name="restore_img">استعادة الصور</string>
<string name="restore_img_msg">جارٍ الاستعادة...</string> <string name="restore_img_msg">جار الأستعادة</string>
<string name="restore_done">اكتملت الاستعادة!</string> <string name="restore_done">تم الأستعادة</string>
<string name="restore_fail">لا يوجد نسخة احتياطية أصلية!</string> <string name="restore_fail">النسخة الاحتياطية الأصلية غير موجودة!</string>
<string name="setup_fail">فشل الإعداد</string> <string name="setup_fail">فشل التضبيط</string>
<string name="env_fix_title">يتطلب إعداد إضافي</string> <string name="env_fix_title"> الإعداد الأضافي مطلوب</string>
<string name="env_fix_msg">يحتاج جهازك إلى إعداد إضافي ليعمل Magisk بشكل صحيح. هل تريد المتابعة وإعادة التشغيل؟</string> <string name="setup_msg">جار تضبيت البيئة</string>
<string name="env_full_fix_msg">يحتاج جهازك إلى إعادة تثبيت Magisk ليعمل بشكل صحيح. يرجى إعادة تثبيت Magisk من داخل التطبيق، لا يمكن لوضع الاسترداد الحصول على معلومات الجهاز الصحيحة.</string> <string name="unsupport_magisk_title">إصدار مـاجـيسك غير مدعوم</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>
</resources> </resources>

View File

@@ -10,10 +10,9 @@
<string name="section_theme">עיצוב</string> <string name="section_theme">עיצוב</string>
<string name="denylist">רשימת דחייה</string> <string name="denylist">רשימת דחייה</string>
<!--Home--> <!--Home-->
<string name="no_connection">אין חיבור זמין</string> <string name="no_connection">אין חיבור זמין</string>
<string name="app_changelog">רשימת שינויים</string> <string name="app_changelog">יומן שינויים</string>
<string name="loading">טוען…</string> <string name="loading">טוען…</string>
<string name="update">עדכון</string> <string name="update">עדכון</string>
<string name="not_available">ל/ז</string> <string name="not_available">ל/ז</string>
@@ -45,16 +44,16 @@
<string name="install_inactive_slot_msg">ההתקן שלך ייאלץ אתחול לחריץ הלא פעיל הנוכחי שלך לאחר הפעלה מחדש!\nיש להשתמש באפשרות זו רק לאחר ביצוע OTA בלבד.\nלהמשיך?</string> <string name="install_inactive_slot_msg">ההתקן שלך ייאלץ אתחול לחריץ הלא פעיל הנוכחי שלך לאחר הפעלה מחדש!\nיש להשתמש באפשרות זו רק לאחר ביצוע OTA בלבד.\nלהמשיך?</string>
<string name="setup_title">התקנה נוספת</string> <string name="setup_title">התקנה נוספת</string>
<string name="select_patch_file">בחירה והתקנת קובץ</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="reboot_delay_toast">מאתחל בעוד 5 שניות…</string>
<string name="flash_screen_title">התקנה</string> <string name="flash_screen_title">התקנה</string>
<!--Superuser--> <!--Superuser-->
<string name="su_request_title">בקשות משתמש על</string> <string name="su_request_title">בקשות משתמש על</string>
<string name="touch_filtered_warning">מכיוון שיישום מסתיר בקשה של משתמש על, Magisk לא יכול לאמת את תגובתך</string> <string name="touch_filtered_warning">מכיוון שיישום מסתיר בקשה של משתמש על, Magisk לא יכול לאמת את תגובתך</string>
<string name="deny">דחה</string> <string name="deny">דחייה</string>
<string name="prompt">מיידי</string> <string name="prompt">מיידי</string>
<string name="grant">הענק</string> <string name="grant">הענקה</string>
<string name="su_warning">מעניק גישה מלאה להתקן שלך.\nיש לדחות באי וודאות!</string> <string name="su_warning">מעניק גישה מלאה להתקן שלך.\nיש לדחות באי וודאות!</string>
<string name="forever">לצמיתות</string> <string name="forever">לצמיתות</string>
<string name="once">פעם אחת</string> <string name="once">פעם אחת</string>
@@ -62,24 +61,24 @@
<string name="twentymin">20 דקות</string> <string name="twentymin">20 דקות</string>
<string name="thirtymin">חצי שעה</string> <string name="thirtymin">חצי שעה</string>
<string name="sixtymin">שעה</string> <string name="sixtymin">שעה</string>
<string name="su_allow_toast">%1$s הוענקו הרשאות משתמש עבור</string> <string name="su_allow_toast">%1$s קיבל הרשאות משתמש על</string>
<string name="su_deny_toast">%1$s נשללו הרשאות משתמש עבור</string> <string name="su_deny_toast">%1$s נשללו הרשאות משתמש על</string>
<string name="su_snack_grant">הרשאות משתמש על עבור %1$s הוענקו</string> <string name="su_snack_grant">הרשאות משתמש על עבור %1$s הוענקו</string>
<string name="su_snack_deny">הרשאות משתמש על עבור %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_on">התראות של %1$s מופעלות</string>
<string name="su_snack_notif_off">התראות עבור %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_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_title">להסיר?</string>
<string name="su_revoke_msg">נא לאשר שלילת הרשאות עבור %1$s?</string> <string name="su_revoke_msg">נא לאשר שלילת הרשאות עבור %1$s?</string>
<string name="toast">הרמת כוסית</string> <string name="toast">הרמת כוסית</string>
<string name="none">ללא</string> <string name="none">ללא</string>
<string name="superuser_toggle_notification">התראות</string> <string name="superuser_toggle_notification">התראות</string>
<string name="superuser_toggle_revoke">הסרה</string> <string name="superuser_toggle_revoke">הסרה</string>
<string name="superuser_policy_none">לא נתבקשו הרשאות משתמש על על ידי שום יישום</string> <string name="superuser_policy_none">טרם נתבקשו הרשאות משתמש על על ידי יישומים</string>
<!--Logs--> <!--Logs-->
<string name="log_data_none">הינך ללא יומן רישום, יש לנסות להשתמש ביישומים מותאמים יותר למשתמש העל שלך</string> <string name="log_data_none">הינך ללא יומן, יש לנסות להשתמש יותר ביישומי השורש שלך</string>
<string name="log_data_magisk_none">יומני רישום Magisk ריקים, זה מוזר</string> <string name="log_data_magisk_none">יומני רישום Magisk ריקים, זה מוזר</string>
<string name="menuSaveLog">שמירת יומן רישום</string> <string name="menuSaveLog">שמירת יומן רישום</string>
<string name="menuClearLog">ניקוי יומן רישום כעת</string> <string name="menuClearLog">ניקוי יומן רישום כעת</string>
@@ -92,7 +91,7 @@
<!--SafetyNet--> <!--SafetyNet-->
<!-- MagiskHide --> <!--MagiskHide-->
<string name="show_system_app">הצגת יישומי מערכת</string> <string name="show_system_app">הצגת יישומי מערכת</string>
<string name="show_os_app">הצגת יישומי מערכת הפעלה</string> <string name="show_os_app">הצגת יישומי מערכת הפעלה</string>
<string name="hide_filter_hint">סינון לפי שם</string> <string name="hide_filter_hint">סינון לפי שם</string>
@@ -100,14 +99,16 @@
<!--Module--> <!--Module-->
<string name="no_info_provided">(לא סופק מידע)</string> <string name="no_info_provided">(לא סופק מידע)</string>
<string name="reboot_userspace">אתחול מהיר</string> <string name="reboot_userspace">אתחול רך</string>
<string name="reboot_recovery">אתחול למצב שחזור</string> <string name="reboot_recovery">אתחול למצב שחזור</string>
<string name="reboot_bootloader">אתחול מצב מנהל האתחול</string> <string name="reboot_bootloader">אתחול לטוען האתחול</string>
<string name="reboot_download">אתחול מצב הורדה</string> <string name="reboot_download">אתחול למצב הורדה</string>
<string name="reboot_edl">אתחול למצב EDL</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_version_author">%1$s מאת %2$s</string>
<string name="module_state_remove">הסרה</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="module_action_install_external">התקנה מהאחסון</string>
<string name="update_available">עדכונים זמינים</string> <string name="update_available">עדכונים זמינים</string>
<string name="suspend_text_riru">מודול מושעה כי %1$s מופעל</string> <string name="suspend_text_riru">מודול מושעה כי %1$s מופעל</string>
@@ -117,7 +118,7 @@
<string name="confirm_install">להתקין מודול %1$s?</string> <string name="confirm_install">להתקין מודול %1$s?</string>
<string name="confirm_install_title">אישור התקנה</string> <string name="confirm_install_title">אישור התקנה</string>
<!--Settings --> <!--Settings-->
<string name="settings_dark_mode_title">מצב עיצוב</string> <string name="settings_dark_mode_title">מצב עיצוב</string>
<string name="settings_dark_mode_message">נא לבחור מצב המתאים ביותר לסגנון שלך!</string> <string name="settings_dark_mode_message">נא לבחור מצב המתאים ביותר לסגנון שלך!</string>
<string name="settings_dark_mode_light">תמיד בהיר</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_title">הסתרת היישום Magisk</string>
<string name="settings_hide_app_summary">התקנת יישום מתווך עם מזהה חבילה אקראי ותווית שם מותאמת אישית</string> <string name="settings_hide_app_summary">התקנת יישום מתווך עם מזהה חבילה אקראי ותווית שם מותאמת אישית</string>
<string name="settings_restore_app_title">שיחזור היישום Magisk</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="language">שפה</string>
<string name="system_default">(ברירת מחדל מערכת)</string> <string name="system_default">(ברירת מחדל מערכת)</string>
<string name="settings_check_update_title">בדיקת עדכונים</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_channel_title">ערוץ עדכון</string>
<string name="settings_update_stable">יציב</string> <string name="settings_update_stable">יציב</string>
<string name="settings_update_beta">בטא</string> <string name="settings_update_beta">בטא</string>
@@ -161,12 +162,12 @@
<string name="settings_su_request_60">60 שניות</string> <string name="settings_su_request_60">60 שניות</string>
<string name="superuser_access">גישת משתמש על</string> <string name="superuser_access">גישת משתמש על</string>
<string name="auto_response">תגובה אוטומטית</string> <string name="auto_response">תגובה אוטומטית</string>
<string name="request_timeout">בקש פסק זמן</string> <string name="request_timeout">בקשת פסק זמן</string>
<string name="superuser_notification">התראות משתמש על</string> <string name="superuser_notification">התראות משתמש על</string>
<string name="settings_su_reauth_title">אימות מחדש לאחר שדרוג</string> <string name="settings_su_reauth_title">אימות מחדש לאחר שדרוג</string>
<string name="settings_su_reauth_summary">אימות מחדש הרשאות של משתמש על לאחר שדרוג יישום</string> <string name="settings_su_reauth_summary">אימות מחדש הרשאות של משתמש על לאחר שדרוג יישום</string>
<string name="settings_su_tapjack_title">הפעלת הגנת Tapjacking</string> <string name="settings_su_tapjack_title">הגנת Tapjacking</string>
<string name="settings_su_tapjack_summary">תיבת הדו שיח של משתמש העל לא תגיב לקלט כשהיא מוסתרת על ידי חלון או כיסוי אחר</string> <string name="settings_su_tapjack_summary">תיבת הדו שיח של משתמש העל לא תגיב לקלט כשהיא מוסתרת על ידי חלון או שכבת על אחרת</string>
<string name="settings_su_auth_title">אימות משתמש</string> <string name="settings_su_auth_title">אימות משתמש</string>
<string name="settings_su_auth_summary">בקשת אימות משתמש במהלך בקשות משתמש על</string> <string name="settings_su_auth_summary">בקשת אימות משתמש במהלך בקשות משתמש על</string>
<string name="settings_su_auth_insecure">לא מוגדרת שיטת אימות בהתקן</string> <string name="settings_su_auth_insecure">לא מוגדרת שיטת אימות בהתקן</string>
@@ -174,6 +175,8 @@
<string name="setting_add_shortcut_summary">הוספת קיצור דרך יפה במסך הבית למקרה שקשה לזהות את השם ואת הסמל לאחר הסתרת היישום</string> <string name="setting_add_shortcut_summary">הוספת קיצור דרך יפה במסך הבית למקרה שקשה לזהות את השם ואת הסמל לאחר הסתרת היישום</string>
<string name="settings_doh_title">DNS על HTTPS</string> <string name="settings_doh_title">DNS על HTTPS</string>
<string name="settings_doh_description">עקיפת DNS מורעל במדינות מסוימות</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="multiuser_mode">מצב מרובה משתמשים</string>
<string name="settings_owner_only">בעל ההתקן בלבד</string> <string name="settings_owner_only">בעל ההתקן בלבד</string>
<string name="settings_owner_manage">אחראי ניהול ההתקן</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="repo_install_title">מתקין %1$s %2$s(%3$d)</string>
<string name="download">הורדה</string> <string name="download">הורדה</string>
<string name="reboot">הפעלה מחדש</string> <string name="reboot">הפעלה מחדש</string>
<string name="close">סגירה</string>
<string name="release_notes">הערות שחרור</string> <string name="release_notes">הערות שחרור</string>
<string name="flashing">צורב…</string> <string name="flashing">צורב…</string>
<string name="running">רץ…</string>
<string name="done">בוצע!</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="hide_app_title">מסתיר את יישום Magisk…</string>
<string name="open_link_failed_toast">לא נמצאו יישומים לפתיחת קישור זה</string> <string name="open_link_failed_toast">לא נמצאו יישומים לפתיחת קישור זה</string>
<string name="complete_uninstall">הסרה מלאה</string> <string name="complete_uninstall">הסרה מלאה</string>
@@ -237,4 +243,5 @@
<string name="app_not_found">לא נמצא יישום לטיפול בפעולה זו</string> <string name="app_not_found">לא נמצא יישום לטיפול בפעולה זו</string>
<string name="reboot_apply_change">ייש להפעיל מחדש כדי להחיל שינויים</string> <string name="reboot_apply_change">ייש להפעיל מחדש כדי להחיל שינויים</string>
<string name="restore_app_confirmation">פעולה זו תשחזר את היישום המוסתר חזרה ליישום המקורי. האם בוודאות ברצונך לעשות את זה?</string> <string name="restore_app_confirmation">פעולה זו תשחזר את היישום המוסתר חזרה ליישום המקורי. האם בוודאות ברצונך לעשות את זה?</string>
</resources> </resources>

View File

@@ -87,6 +87,9 @@
<string name="logs_cleared">Логи успешно очищены</string> <string name="logs_cleared">Логи успешно очищены</string>
<string name="pid">PID: %1$d</string> <string name="pid">PID: %1$d</string>
<string name="target_uid">Целевой UID: %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--> <!--SafetyNet-->
@@ -164,11 +167,16 @@
<string name="settings_su_reauth_title">Повторная аутентификация</string> <string name="settings_su_reauth_title">Повторная аутентификация</string>
<string name="settings_su_reauth_summary">Повторный запрос прав суперпользователя после обновления приложений</string> <string name="settings_su_reauth_summary">Повторный запрос прав суперпользователя после обновления приложений</string>
<string name="settings_su_tapjack_title">Защита от перехвата нажатий</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_su_tapjack_summary">Окно запроса прав суперпользователя будет неактивно пока активированы наложения экрана</string>
<string name="settings_customization">Персонализация</string> <string name="settings_customization">Персонализация</string>
<string name="setting_add_shortcut_summary">Добавить ярлык на рабочий стол для удобного восприятия приложения после его скрытия</string> <string name="setting_add_shortcut_summary">Добавить ярлык на рабочий стол для удобного восприятия приложения после его скрытия</string>
<string name="settings_doh_title">DNS поверх HTTPS</string> <string name="settings_doh_title">DNS поверх HTTPS</string>
<string name="settings_doh_description">Активировать DoH (используйте при проблемах с подключением к сети)</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="multiuser_mode">Многопользовательский режим</string>
<string name="settings_owner_only">Только администратор</string> <string name="settings_owner_only">Только администратор</string>

View File

@@ -130,8 +130,8 @@
<string name="settings_update_custom">Власний</string> <string name="settings_update_custom">Власний</string>
<string name="settings_update_custom_msg">Вставте власний URL</string> <string name="settings_update_custom_msg">Вставте власний URL</string>
<string name="settings_zygisk_summary">Запускати частини Magisk в сервісі zygote</string> <string name="settings_zygisk_summary">Запускати частини Magisk в сервісі zygote</string>
<string name="settings_denylist_title">Enforce DenyList</string> <string name="settings_denylist_title">Увімкнути DenyList</string>
<string name="settings_denylist_summary">Processes on the denylist will have all Magisk modifications reverted</string> <string name="settings_denylist_summary">Всі зміни, внесені Magisk, будуть приховані від процесів, позначених у DenyList</string>
<string name="settings_denylist_config_title">Налаштувати DenyList</string> <string name="settings_denylist_config_title">Налаштувати DenyList</string>
<string name="settings_denylist_config_summary">Вибрати процеси, які будуть додані до denylist</string> <string name="settings_denylist_config_summary">Вибрати процеси, які будуть додані до denylist</string>
<string name="settings_hosts_title">Позасистемні хости</string> <string name="settings_hosts_title">Позасистемні хости</string>
@@ -156,7 +156,7 @@
<string name="superuser_notification">Сповіщення суперкористувача</string> <string name="superuser_notification">Сповіщення суперкористувача</string>
<string name="settings_su_reauth_title">Повторна автентифікація</string> <string name="settings_su_reauth_title">Повторна автентифікація</string>
<string name="settings_su_reauth_summary">Перевидача прав суперкористувача після оновлення застосунку</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_su_tapjack_summary">Діалогове вікно суперкористувача не буде отримувати ввід від користувача, коли вікно перекрито іншим застосунком чи вікном</string>
<string name="settings_customization">Оформлення</string> <string name="settings_customization">Оформлення</string>
<string name="setting_add_shortcut_summary">Додати ярлик на домашній екран для зручного сприйняття застосунку після його приховування</string> <string name="setting_add_shortcut_summary">Додати ярлик на домашній екран для зручного сприйняття застосунку після його приховування</string>

View File

@@ -109,6 +109,7 @@
<string name="reboot_safe_mode">安全模式</string> <string name="reboot_safe_mode">安全模式</string>
<string name="module_version_author">%1$s作者 %2$s</string> <string name="module_version_author">%1$s作者 %2$s</string>
<string name="module_state_remove">移除</string> <string name="module_state_remove">移除</string>
<string name="module_action">操作</string>
<string name="module_state_restore">还原</string> <string name="module_state_restore">还原</string>
<string name="module_action_install_external">从本地安装</string> <string name="module_action_install_external">从本地安装</string>
<string name="update_available">可更新</string> <string name="update_available">可更新</string>
@@ -211,9 +212,12 @@
<string name="repo_install_title">安装 %1$s %2$s(%3$d)</string> <string name="repo_install_title">安装 %1$s %2$s(%3$d)</string>
<string name="download">下载</string> <string name="download">下载</string>
<string name="reboot">重启</string> <string name="reboot">重启</string>
<string name="close">关闭</string>
<string name="release_notes">发布说明</string> <string name="release_notes">发布说明</string>
<string name="flashing">正在刷入</string> <string name="flashing">正在刷入</string>
<string name="running">运行中……</string>
<string name="done">完成!</string> <string name="done">完成!</string>
<string name="done_action">%1$s 操作运行完成</string>
<string name="failure">失败</string> <string name="failure">失败</string>
<string name="hide_app_title">正在隐藏 Magisk 应用</string> <string name="hide_app_title">正在隐藏 Magisk 应用</string>
<string name="open_link_failed_toast">找不到能打开此链接的应用</string> <string name="open_link_failed_toast">找不到能打开此链接的应用</string>

View File

@@ -15,7 +15,7 @@ android {
val canary = !Config.version.contains(".") val canary = !Config.version.contains(".")
val url = if (canary) null 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 { defaultConfig {
applicationId = "com.topjohnwu.magisk" applicationId = "com.topjohnwu.magisk"
@@ -27,9 +27,9 @@ android {
buildTypes { buildTypes {
release { release {
proguardFiles("proguard-rules.pro")
isMinifyEnabled = true isMinifyEnabled = true
isShrinkResources = false isShrinkResources = false
proguardFiles("proguard-rules.pro")
} }
} }
@@ -38,7 +38,7 @@ android {
} }
} }
setupStub() setupStubApk()
dependencies { dependencies {
implementation(project(":app:shared")) implementation(project(":app:shared"))

View File

@@ -1,4 +1,4 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
plugins { plugins {
`kotlin-dsl` `kotlin-dsl`
@@ -18,9 +18,9 @@ gradlePlugin {
} }
} }
tasks.withType<KotlinCompile>().configureEach { kotlin {
kotlinOptions { compilerOptions {
languageVersion = "2.0" languageVersion = KotlinVersion.KOTLIN_2_0
} }
} }

View 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
}
}
}
}
}

View File

@@ -1,6 +1,8 @@
import com.android.build.api.artifact.ArtifactTransformationRequest import com.android.build.api.artifact.ArtifactTransformationRequest
import com.android.build.api.artifact.SingleArtifact import com.android.build.api.artifact.SingleArtifact
import com.android.build.api.dsl.ApkSigningConfig 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.api.variant.ApplicationAndroidComponentsExtension
import com.android.build.gradle.BaseExtension import com.android.build.gradle.BaseExtension
import com.android.build.gradle.LibraryExtension import com.android.build.gradle.LibraryExtension
@@ -15,6 +17,7 @@ import org.gradle.api.Action
import org.gradle.api.DefaultTask import org.gradle.api.DefaultTask
import org.gradle.api.JavaVersion import org.gradle.api.JavaVersion
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.DirectoryProperty
import org.gradle.api.provider.Property import org.gradle.api.provider.Property
import org.gradle.api.tasks.Copy import org.gradle.api.tasks.Copy
@@ -114,9 +117,9 @@ fun Project.setupCommon() {
} }
const val BUSYBOX_DOWNLOAD_URL = 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 = const val BUSYBOX_ZIP_CHECKSUM =
"ea4f3019b0087dcb68130b32ab59dc2db0ee0af11d8396124a94c4231c5ea441" "b4d0551feabaf314e53c79316c980e8f66432e9fb91a69dbbf10a93564b40951"
fun Project.setupCoreLib() { fun Project.setupCoreLib() {
setupCommon() 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() setupAppCommon()
androidComponents.onVariants { variant -> androidComponents.onVariants { variant ->

View File

@@ -1,5 +1,37 @@
# Magisk Changelog # 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 ### v27.0
- [Zygisk] Introduce new code injection mechanism - [Zygisk] Introduce new code injection mechanism

25
docs/releases/28000.md Normal file
View 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
View 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)

View File

@@ -1,5 +1,7 @@
# Release Notes # Release Notes
- [v28.1](28100.md)
- [v28.0](28000.md)
- [v27.0](27000.md) - [v27.0](27000.md)
- [v26.4](26400.md) - [v26.4](26400.md)
- [v26.3](26300.md) - [v26.3](26300.md)

View File

@@ -30,5 +30,5 @@ android.nonFinalResIds=false
# Magisk # Magisk
magisk.stubVersion=40 magisk.stubVersion=40
magisk.versionCode=27008 magisk.versionCode=28101
magisk.ondkVersion=r27.4 magisk.ondkVersion=r27.4

View File

@@ -1,9 +1,9 @@
[versions] [versions]
kotlin = "2.0.20" kotlin = "2.0.21"
android = "8.6.0" android = "8.7.3"
ksp = "2.0.20-1.0.25" ksp = "2.0.21-1.0.28"
rikka = "1.3.0" rikka = "1.3.0"
navigation = "2.8.0" navigation = "2.8.4"
libsu = "6.0.0" libsu = "6.0.0"
moshi = "1.15.1" moshi = "1.15.1"
okhttp = "4.12.0" okhttp = "4.12.0"
@@ -11,7 +11,7 @@ retrofit = "2.11.0"
room = "2.6.1" room = "2.6.1"
[libraries] [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" } commons-compress = { module = "org.apache.commons:commons-compress", version = "1.27.1" }
retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" } retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
retrofit-moshi = { module = "com.squareup.retrofit2:converter-moshi", 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" } jgit = { module = "org.eclipse.jgit:org.eclipse.jgit", version = "6.10.0.202406032230-r" }
# AndroidX # 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" } 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" } core-splashscreen = { module = "androidx.core:core-splashscreen", version = "1.0.1" }
constraintlayout = { module = "androidx.constraintlayout:constraintlayout", version = "2.1.4" } constraintlayout = { module = "androidx.constraintlayout:constraintlayout", version = "2.2.0" }
fragment-ktx = { module = "androidx.fragment:fragment-ktx", version = "1.8.3" } fragment-ktx = { module = "androidx.fragment:fragment-ktx", version = "1.8.5" }
navigation-fragment-ktx = { module = "androidx.navigation:navigation-fragment-ktx", version.ref = "navigation" } navigation-fragment-ktx = { module = "androidx.navigation:navigation-fragment-ktx", version.ref = "navigation" }
navigation-ui-ktx = { module = "androidx.navigation:navigation-ui-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" } recyclerview = { module = "androidx.recyclerview:recyclerview", version = "1.3.2" }
room-ktx = { module = "androidx.room:room-ktx", version.ref = "room" } room-ktx = { module = "androidx.room:room-ktx", version.ref = "room" }
room-runtime = { module = "androidx.room:room-runtime", version.ref = "room" } room-runtime = { module = "androidx.room:room-runtime", version.ref = "room" }
room-compiler = { module = "androidx.room:room-compiler", version.ref = "room" } room-compiler = { module = "androidx.room:room-compiler", version.ref = "room" }
swiperefreshlayout = { module = "androidx.swiperefreshlayout:swiperefreshlayout", version = "1.1.0" } swiperefreshlayout = { module = "androidx.swiperefreshlayout:swiperefreshlayout", version = "1.1.0" }
transition = { module = "androidx.transition:transition", version = "1.5.1" } transition = { module = "androidx.transition:transition", version = "1.5.1" }
collection-ktx = { module = "androidx.collection:collection-ktx", version = "1.4.3" } collection-ktx = { module = "androidx.collection:collection-ktx", version = "1.4.5" }
lifecycle-process = { module = "androidx.lifecycle:lifecycle-process", version = "2.8.5" } lifecycle-process = { module = "androidx.lifecycle:lifecycle-process", version = "2.8.7" }
material = { module = "com.google.android.material:material", version = "1.12.0" } 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 # topjohnwu
indeterminate-checkbox = { module = "com.github.topjohnwu:indeterminate-checkbox", version = "1.0.7" } indeterminate-checkbox = { module = "com.github.topjohnwu:indeterminate-checkbox", version = "1.0.7" }

View File

@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists 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 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME

72
native/src/Cargo.lock generated
View File

@@ -2,6 +2,12 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 3
[[package]]
name = "anstyle"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
[[package]] [[package]]
name = "argh" name = "argh"
version = "0.1.12" version = "0.1.12"
@@ -111,6 +117,32 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 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]] [[package]]
name = "codespan-reporting" name = "codespan-reporting"
version = "0.11.1" version = "0.11.1"
@@ -182,16 +214,18 @@ dependencies = [
[[package]] [[package]]
name = "cxx" name = "cxx"
version = "1.0.124" version = "1.0.133"
dependencies = [ dependencies = [
"cc", "cc",
"cxxbridge-cmd",
"cxxbridge-flags", "cxxbridge-flags",
"cxxbridge-macro", "cxxbridge-macro",
"foldhash",
] ]
[[package]] [[package]]
name = "cxx-gen" name = "cxx-gen"
version = "0.7.124" version = "0.7.133"
dependencies = [ dependencies = [
"codespan-reporting", "codespan-reporting",
"proc-macro2", "proc-macro2",
@@ -199,16 +233,28 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "cxxbridge-cmd"
version = "1.0.133"
dependencies = [
"clap",
"codespan-reporting",
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "cxxbridge-flags" name = "cxxbridge-flags"
version = "1.0.124" version = "1.0.133"
[[package]] [[package]]
name = "cxxbridge-macro" name = "cxxbridge-macro"
version = "1.0.124" version = "1.0.133"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"rustversion",
"syn", "syn",
] ]
@@ -305,6 +351,12 @@ version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3ea1ec5f8307826a5b71094dd91fc04d4ae75d5709b20ad351c7fb4815c86ec" checksum = "b3ea1ec5f8307826a5b71094dd91fc04d4ae75d5709b20ad351c7fb4815c86ec"
[[package]]
name = "foldhash"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2"
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.15" version = "0.2.15"
@@ -709,6 +761,12 @@ dependencies = [
"zeroize", "zeroize",
] ]
[[package]]
name = "rustversion"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248"
[[package]] [[package]]
name = "sec1" name = "sec1"
version = "0.8.0-rc.0" version = "0.8.0-rc.0"
@@ -803,6 +861,12 @@ dependencies = [
"der", "der",
] ]
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]] [[package]]
name = "subtle" name = "subtle"
version = "2.6.1" version = "2.6.1"

View File

@@ -366,7 +366,7 @@ static const char *vendor_ramdisk_type(int type) {
} }
#define assert_off() \ #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"); \ fprintf(stderr, "Corrupted boot image!\n"); \
return false; \ return false; \
} }
@@ -395,6 +395,7 @@ bool boot_img::parse_image(const uint8_t *p, format_t type) {
hdr->print(); hdr->print();
size_t map_end = align_to(map.sz(), getpagesize());
size_t off = hdr->hdr_space(); size_t off = hdr->hdr_space();
get_block(kernel); get_block(kernel);
get_block(ramdisk); 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); payload = byte_view(base_addr, off);
auto tail_addr = 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 (auto size = hdr->kernel_size()) {
if (int dtb_off = find_dtb_offset(kernel, size); dtb_off > 0) { if (int dtb_off = find_dtb_offset(kernel, size); dtb_off > 0) {

View File

@@ -49,6 +49,7 @@ pub mod ffi {
} }
#[namespace = "rust"] #[namespace = "rust"]
#[allow(unused_unsafe)]
extern "Rust" { extern "Rust" {
unsafe fn extract_boot_from_payload( unsafe fn extract_boot_from_payload(
partition: *const c_char, partition: *const c_char,

View File

@@ -8,10 +8,6 @@ using namespace std;
#ifdef USE_CRT0 #ifdef USE_CRT0
__BEGIN_DECLS __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 musl_vfprintf(FILE *stream, const char *format, va_list arg);
int 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); return musl_vfprintf(stream, format, arg);

View File

@@ -148,8 +148,8 @@ static bool check_safe_mode() {
* Boot Stage Handlers * * Boot Stage Handlers *
***********************/ ***********************/
bool MagiskD::post_fs_data() const { bool MagiskD::post_fs_data() const noexcept {
as_rust().setup_logfile(); setup_logfile();
LOGI("** post-fs-data mode running\n"); LOGI("** post-fs-data mode running\n");
@@ -194,8 +194,8 @@ bool MagiskD::post_fs_data() const {
return safe_mode; return safe_mode;
} }
void MagiskD::late_start() const { void MagiskD::late_start() const noexcept {
as_rust().setup_logfile(); setup_logfile();
LOGI("** late_start service mode running\n"); LOGI("** late_start service mode running\n");
@@ -203,8 +203,8 @@ void MagiskD::late_start() const {
exec_module_scripts("service"); exec_module_scripts("service");
} }
void MagiskD::boot_complete() const { void MagiskD::boot_complete() const noexcept {
as_rust().setup_logfile(); setup_logfile();
LOGI("** boot-complete triggered\n"); LOGI("** boot-complete triggered\n");

View File

@@ -128,20 +128,8 @@ static void poll_ctrl_handler(pollfd *pfd) {
} }
} }
const MagiskD &MagiskD::get() { void MagiskD::reboot() const noexcept {
return *reinterpret_cast<const MagiskD*>(&rust::get_magiskd()); if (is_recovery())
}
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())
exec_command_sync("/system/bin/reboot", "recovery"); exec_command_sync("/system/bin/reboot", "recovery");
else else
exec_command_sync("/system/bin/reboot"); 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); write_int(client, 0);
close(client); close(client);
if (do_reboot) { if (do_reboot) {
MagiskD::get().reboot(); MagiskD().reboot();
} }
break; break;
} }
@@ -196,7 +184,7 @@ static void handle_request_sync(int client, int code) {
write_int(client, MAGISK_VER_CODE); write_int(client, MAGISK_VER_CODE);
break; break;
case +RequestCode::START_DAEMON: case +RequestCode::START_DAEMON:
MagiskD::get()->setup_logfile(); MagiskD().setup_logfile();
break; break;
case +RequestCode::STOP_DAEMON: { case +RequestCode::STOP_DAEMON: {
// Unmount all overlays // Unmount all overlays
@@ -298,7 +286,7 @@ static void handle_request(pollfd *pfd) {
exec_task([=, fd = client.release()] { handle_request_async(fd, code, cred); }); exec_task([=, fd = client.release()] { handle_request_async(fd, code, cred); });
} else { } else {
exec_task([=, fd = client.release()] { 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); 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(); restore_tmpcon();

View File

@@ -1,7 +1,7 @@
use std::fs::File; use std::fs::File;
use std::io;
use std::io::BufReader; use std::io::BufReader;
use std::sync::{Mutex, OnceLock}; use std::sync::{Mutex, OnceLock};
use std::{io, mem};
use base::libc::{O_CLOEXEC, O_RDONLY}; use base::libc::{O_CLOEXEC, O_RDONLY};
use base::{ use base::{
@@ -10,7 +10,7 @@ use base::{
}; };
use crate::consts::MAIN_CONFIG; 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::get_prop;
use crate::logging::magisk_logging; use crate::logging::magisk_logging;
@@ -64,7 +64,7 @@ impl MagiskD {
match code { match code {
RequestCode::POST_FS_DATA => { RequestCode::POST_FS_DATA => {
if check_data() && !state.contains(BootState::PostFsDataDone) { 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::SafeMode);
} }
state.set(BootState::PostFsDataDone); state.set(BootState::PostFsDataDone);
@@ -75,7 +75,7 @@ impl MagiskD {
unsafe { libc::close(client) }; unsafe { libc::close(client) };
if state.contains(BootState::PostFsDataDone) && !state.contains(BootState::SafeMode) if state.contains(BootState::PostFsDataDone) && !state.contains(BootState::SafeMode)
{ {
self.as_cxx().late_start(); self.late_start();
state.set(BootState::LateStartDone); state.set(BootState::LateStartDone);
} }
} }
@@ -83,7 +83,7 @@ impl MagiskD {
unsafe { libc::close(client) }; unsafe { libc::close(client) };
if state.contains(BootState::PostFsDataDone) { if state.contains(BootState::PostFsDataDone) {
state.set(BootState::BootComplete); 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() { pub fn daemon_entry() {

View File

@@ -108,7 +108,7 @@ db_settings::db_settings() {
data[SU_MULTIUSER_MODE] = MULTIUSER_MODE_OWNER_ONLY; data[SU_MULTIUSER_MODE] = MULTIUSER_MODE_OWNER_ONLY;
data[SU_MNT_NS] = NAMESPACE_MODE_REQUESTER; data[SU_MNT_NS] = NAMESPACE_MODE_REQUESTER;
data[DENYLIST_CONFIG] = false; data[DENYLIST_CONFIG] = false;
data[ZYGISK_CONFIG] = MagiskD::get()->is_emulator(); data[ZYGISK_CONFIG] = MagiskD().is_emulator();
data[BOOTLOOP_COUNT] = 0; data[BOOTLOOP_COUNT] = 0;
} }

View File

@@ -2,29 +2,6 @@
#include <base.hpp> #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(); const char *get_magisk_tmp();
// Rust bindings // Rust bindings

View File

@@ -74,12 +74,6 @@ pub mod ffi {
fn resolve_preinit_dir(base_dir: Utf8CStrRef) -> String; fn resolve_preinit_dir(base_dir: Utf8CStrRef) -> String;
fn switch_mnt_ns(pid: i32) -> i32; 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" { extern "Rust" {
@@ -99,18 +93,28 @@ pub mod ffi {
unsafe fn persist_get_props(prop_cb: Pin<&mut PropCb>); unsafe fn persist_get_props(prop_cb: Pin<&mut PropCb>);
unsafe fn persist_delete_prop(name: Utf8CStrRef) -> bool; unsafe fn persist_delete_prop(name: Utf8CStrRef) -> bool;
unsafe fn persist_set_prop(name: Utf8CStrRef, value: Utf8CStrRef) -> bool; unsafe fn persist_set_prop(name: Utf8CStrRef, value: Utf8CStrRef) -> bool;
#[namespace = "rust"]
fn daemon_entry();
} }
#[namespace = "rust"] // FFI for MagiskD
extern "Rust" { extern "Rust" {
fn daemon_entry();
type MagiskD; type MagiskD;
fn get_magiskd() -> &'static MagiskD;
fn setup_logfile(self: &MagiskD); fn setup_logfile(self: &MagiskD);
fn is_emulator(self: &MagiskD) -> bool; fn is_emulator(self: &MagiskD) -> bool;
fn is_recovery(self: &MagiskD) -> bool; fn is_recovery(self: &MagiskD) -> bool;
fn boot_stage_handler(self: &MagiskD, client: i32, code: i32); 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);
} }
} }

View File

@@ -177,26 +177,23 @@ void tmpfs_node::mount() {
class magisk_node : public node_entry { class magisk_node : public node_entry {
public: public:
explicit magisk_node(const char *name) : node_entry(name, DT_REG, this) {} 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 { void mount() override {
const string src = get_magisk_tmp() + "/"s + name(); if (target) {
if (access(src.data(), F_OK)) string dest = isa<tmpfs_node>(parent()) ? worker_path() : node_path();
return; VLOGD("create", target, dest.data());
xsymlink(target, dest.data());
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());
}
} else { } else {
string dest = dir_name + "/supolicy"; string src = get_magisk_tmp() + "/"s + name();
VLOGD("create", "./magiskpolicy", dest.data()); if (access(src.data(), F_OK) == 0)
xsymlink("./magiskpolicy", dest.data()); create_and_mount("magisk", src, true);
} }
create_and_mount("magisk", src, true);
} }
private:
const char *target = nullptr;
}; };
class zygisk_node : public node_entry { 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("magisk"));
bin->insert(new magisk_node("magiskpolicy")); 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) for (int i = 0; applet_names[i]; ++i)
delete bin->extract(applet_names[i]); bin->insert(new magisk_node(applet_names[i], "./magisk"));
delete bin->extract("supolicy"); bin->insert(new magisk_node("supolicy", "./magiskpolicy"));
} }
static void inject_zygisk_libs(root_node *system) { static void inject_zygisk_libs(root_node *system) {

View File

@@ -11,8 +11,6 @@
using namespace std; using namespace std;
vector<string> mount_list;
template<char... cs> using chars = integer_sequence<char, cs...>; template<char... cs> using chars = integer_sequence<char, cs...>;
// If quoted, parsing ends when we find char in [breaks] // 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)); strscpy(fstab_suffix, value.data(), sizeof(fstab_suffix));
} else if (key == "qemu") { } else if (key == "qemu") {
emulator = true; 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) \ #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) { \ if (access(file_name, R_OK) == 0) { \
string data = full_read(file_name); \ string data = full_read(file_name); \
if (!data.empty()) { \ if (!data.empty()) { \
data.pop_back(); \ data.pop_back(); \
strscpy(config->key, data.data(), sizeof(config->key)); \ strscpy(key, data.data(), sizeof(key)); \
} \ } \
} }
void load_kernel_info(BootConfig *config) { void BootConfig::init() {
// Get kernel data using procfs and sysfs set(parse_cmdline(full_read("/proc/cmdline")));
xmkdir("/proc", 0755); set(parse_bootconfig(full_read("/proc/bootconfig")));
xmount("proc", "/proc", "proc", 0, nullptr);
xmkdir("/sys", 0755);
xmount("sysfs", "/sys", "sysfs", 0, nullptr);
mount_list.emplace_back("/proc"); parse_prop_file("/.backup/.magisk", [&](auto key, auto value) -> bool {
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 {
if (key == "RECOVERYMODE" && value == "true") { if (key == "RECOVERYMODE" && value == "true") {
config->skip_initramfs = config->emulator || !check_key_combo(); skip_initramfs = emulator || !check_key_combo();
return false; return false;
} }
return true; return true;
}); });
if (config->dt_dir[0] == '\0') if (dt_dir[0] == '\0')
strscpy(config->dt_dir, DEFAULT_DT_DIR, sizeof(config->dt_dir)); strscpy(dt_dir, DEFAULT_DT_DIR, sizeof(dt_dir));
char file_name[128]; char file_name[128];
read_dt("fstab_suffix", fstab_suffix) read_dt("fstab_suffix", fstab_suffix)
@@ -207,26 +199,7 @@ void load_kernel_info(BootConfig *config) {
read_dt("hardware.platform", hardware_plat) read_dt("hardware.platform", hardware_plat)
LOGD("Device config:\n"); LOGD("Device config:\n");
config->print(); 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 {};
} }
bool check_two_stage() { bool check_two_stage() {
@@ -236,12 +209,15 @@ bool check_two_stage() {
return true; return true;
if (access("/system/bin/init", F_OK) == 0) if (access("/system/bin/init", F_OK) == 0)
return true; 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 // If we still have no indication, parse the original init and see what's up
mmap_data init(backup_init()); mmap_data init(backup_init());
return init.contains("selinux_setup"); 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); LOGD("unxz %s -> %s\n", init_xz, init);
int fd = xopen(init, O_WRONLY | O_CREAT, 0777); int fd = xopen(init, O_WRONLY | O_CREAT, 0777);
fd_stream ch(fd); fd_stream ch(fd);

View File

@@ -13,9 +13,9 @@ using namespace std;
#ifdef USE_CRT0 #ifdef USE_CRT0
__BEGIN_DECLS __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) { int vfprintf(FILE *stream, const char *format, va_list arg) {
return tfp_vfprintf(stream, format, arg); return tiny_vfprintf(stream, format, arg);
} }
__END_DECLS __END_DECLS
#endif #endif
@@ -60,16 +60,67 @@ void restore_ramdisk_init() {
} }
} }
class RecoveryInit : public BaseInit { MagiskInit::MagiskInit(char **argv) : argv(argv), config{} {
public: // Get kernel data using procfs and sysfs
using BaseInit::BaseInit; if (access("/proc/cmdline", F_OK) != 0) {
void start() override { xmkdir("/proc", 0755);
LOGD("Ramdisk is recovery, abort\n"); xmount("proc", "/proc", "proc", 0, nullptr);
restore_ramdisk_init(); mount_list.emplace_back("/proc");
rm_rf("/.backup");
exec_init();
} }
}; 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[]) { int main(int argc, char *argv[]) {
umask(0); umask(0);
@@ -81,31 +132,6 @@ int main(int argc, char *argv[]) {
if (getpid() != 1) if (getpid() != 1)
return 1; return 1;
BaseInit *init; MagiskInit init(argv);
BootConfig config{}; init.start();
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);
} }

View File

@@ -15,7 +15,10 @@ struct BootConfig {
char fstab_suffix[32]; char fstab_suffix[32];
char hardware[32]; char hardware[32];
char hardware_plat[32]; char hardware_plat[32];
kv_pairs partition_map;
void init();
private:
void set(const kv_pairs &); void set(const kv_pairs &);
void print(); void print();
}; };
@@ -24,120 +27,45 @@ struct BootConfig {
#define INIT_PATH "/system/bin/init" #define INIT_PATH "/system/bin/init"
#define REDIR_PATH "/data/magiskinit" #define REDIR_PATH "/data/magiskinit"
extern std::vector<std::string> mount_list;
int magisk_proxy_main(int argc, char *argv[]); int magisk_proxy_main(int argc, char *argv[]);
bool unxz(out_stream &strm, rust::Slice<const uint8_t> bytes); 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(); bool check_two_stage();
const char *backup_init(); const char *backup_init();
void restore_ramdisk_init(); void restore_ramdisk_init();
/*************** class MagiskInit {
* 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 {
private: private:
std::string preinit_dev; std::string preinit_dev;
std::vector<std::string> mount_list;
char **argv;
BootConfig config;
void parse_config_file(); // Setup mounts and environment
void patch_sepolicy(const char *in, const char *out);
bool hijack_sepolicy();
void setup_tmp(const char *path); 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_rw_root();
void patch_ro_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: public:
using BaseInit::BaseInit; explicit MagiskInit(char *argv[]);
}; void start();
/***************
* 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();
}
}; };

View File

@@ -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]; char path[PATH_MAX];
devinfo dev{}; devinfo dev{};
if (auto dir = xopen_dir("/sys/dev/block"); dir) { 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)); auto name = rtrim(full_read(path));
strscpy(dev.dmname, name.data(), sizeof(dev.dmname)); 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; 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. // use androidboot.partition_map as partname fallback.
strscpy(dev.partname, it->second.data(), sizeof(dev.partname)); strscpy(dev.partname, it->second.data(), sizeof(dev.partname));
} }
@@ -72,52 +72,45 @@ static void collect_devices(const auto &partition_map) {
} }
} }
static struct { dev_t MagiskInit::find_block(const char *partname) {
char partname[32];
char block_dev[64];
} blk_info;
static dev_t setup_block() {
static const auto partition_map = load_partition_map();
if (dev_list.empty()) if (dev_list.empty())
collect_devices(partition_map); collect_devices();
for (int tries = 0; tries < 3; ++tries) { for (int tries = 0; tries < 3; ++tries) {
for (auto &dev : dev_list) { for (auto &dev : dev_list) {
if (strcasecmp(dev.partname, blk_info.partname) == 0) const char *name;
LOGD("Setup %s: [%s] (%d, %d)\n", dev.partname, dev.devname, dev.major, dev.minor); if (strcasecmp(dev.partname, partname) == 0)
else if (strcasecmp(dev.dmname, blk_info.partname) == 0) name = dev.partname;
LOGD("Setup %s: [%s] (%d, %d)\n", dev.dmname, dev.devname, dev.major, dev.minor); else if (strcasecmp(dev.dmname, partname) == 0)
else if (strcasecmp(dev.devname, blk_info.partname) == 0) name = dev.dmname;
LOGD("Setup %s: [%s] (%d, %d)\n", dev.devname, dev.devname, dev.major, dev.minor); else if (strcasecmp(dev.devname, partname) == 0)
else if (std::string_view(dev.devpath).ends_with("/"s + blk_info.partname)) name = dev.devname;
LOGD("Setup %s: [%s] (%d, %d)\n", dev.devpath, dev.devname, dev.major, dev.minor); else if (std::string_view(dev.devpath).ends_with("/"s + partname))
name = dev.devpath;
else else
continue; continue;
dev_t rdev = makedev(dev.major, dev.minor); LOGD("Found %s: [%s] (%d, %d)\n", name, dev.devname, dev.major, dev.minor);
xmknod(blk_info.block_dev, S_IFBLK | 0600, rdev); return makedev(dev.major, dev.minor);
return rdev;
} }
// Wait 10ms and try again // Wait 10ms and try again
usleep(10000); usleep(10000);
dev_list.clear(); dev_list.clear();
collect_devices(partition_map); collect_devices();
} }
// The requested partname does not exist // The requested partname does not exist
return 0; return 0;
} }
static void mount_preinit_dir(string preinit_dev) { void MagiskInit::mount_preinit_dir() {
if (preinit_dev.empty()) return; if (preinit_dev.empty()) return;
strcpy(blk_info.partname, preinit_dev.data()); auto dev = find_block(preinit_dev.data());
strcpy(blk_info.block_dev, PREINITDEV);
auto dev = setup_block();
if (dev == 0) { if (dev == 0) {
LOGE("Cannot find preinit %s, abort!\n", preinit_dev.data()); LOGE("Cannot find preinit %s, abort!\n", preinit_dev.data());
return; return;
} }
xmknod(PREINITDEV, S_IFBLK | 0600, dev);
xmkdir(MIRRDIR, 0); xmkdir(MIRRDIR, 0);
bool mounted = false; bool mounted = false;
// First, find if it is already mounted // 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"); LOGD("Mounting system_root\n");
// there's no /dev in stub cpio // there's no /dev in stub cpio
xmkdir("/dev", 0777); xmkdir("/dev", 0777);
strcpy(blk_info.block_dev, "/dev/root"); dev_t dev;
do { do {
// Try legacy SAR dm-verity // Try legacy SAR dm-verity
strcpy(blk_info.partname, "vroot"); dev = find_block("vroot");
auto dev = setup_block();
if (dev > 0) if (dev > 0)
goto mount_root; goto mount_root;
// Try NVIDIA naming scheme // Try NVIDIA naming scheme
strcpy(blk_info.partname, "APP"); dev = find_block("APP");
dev = setup_block();
if (dev > 0) if (dev > 0)
goto mount_root; goto mount_root;
sprintf(blk_info.partname, "system%s", config->slot); // Try normal partname
dev = setup_block(); char sys_part[32];
sprintf(sys_part, "system%s", config.slot);
dev = find_block(sys_part);
if (dev > 0) if (dev > 0)
goto mount_root; goto mount_root;
// Poll forever if rootwait was given in cmdline // 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... // We don't really know what to do at this point...
LOGE("Cannot find root partition, abort\n"); LOGE("Cannot find root partition, abort\n");
exit(1); exit(1);
mount_root: mount_root:
xmknod("/dev/root", S_IFBLK | 0600, dev);
xmkdir("/system_root", 0755); xmkdir("/system_root", 0755);
if (xmount("/dev/root", "/system_root", "ext4", MS_RDONLY, nullptr)) { 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 // For API 28 AVD, it uses legacy SAR setup that requires
// special hacks in magiskinit to work properly. // special hacks in magiskinit to work properly.
if (!is_two_stage && config->emulator) { if (!is_two_stage && config.emulator) {
avd_hack = true; avd_hack = true;
// These values are hardcoded for API 28 AVD // These values are hardcoded for API 28 AVD
auto vendor_dev = find_block("vendor");
xmkdir("/dev/block", 0755); xmkdir("/dev/block", 0755);
strcpy(blk_info.block_dev, "/dev/block/vde1"); xmknod("/dev/block/vde1", S_IFBLK | 0600, vendor_dev);
strcpy(blk_info.partname, "vendor"); xmount("/dev/block/vde1", "/vendor", "ext4", MS_RDONLY, nullptr);
setup_block();
xmount(blk_info.block_dev, "/vendor", "ext4", MS_RDONLY, nullptr);
} }
return is_two_stage; return is_two_stage;
} }
void BaseInit::exec_init() { void MagiskInit::exec_init() {
// Unmount in reverse order // Unmount in reverse order
for (auto &p : reversed(mount_list)) { for (auto &p : reversed(mount_list)) {
if (xumount2(p.data(), MNT_DETACH) == 0) if (xumount2(p.data(), MNT_DETACH) == 0)
@@ -228,12 +220,12 @@ void BaseInit::exec_init() {
exit(1); exit(1);
} }
void BaseInit::prepare_data() { void MagiskInit::prepare_data() {
LOGD("Setup data tmp\n"); LOGD("Setup data tmp\n");
xmkdir("/data", 0755); xmkdir("/data", 0755);
xmount("magisk", "/data", "tmpfs", 0, "mode=755"); xmount("magisk", "/data", "tmpfs", 0, "mode=755");
cp_afc("/init", "/data/magiskinit"); cp_afc("/init", REDIR_PATH);
cp_afc("/.backup", "/data/.backup"); cp_afc("/.backup", "/data/.backup");
cp_afc("/overlay.d", "/data/overlay.d"); cp_afc("/overlay.d", "/data/overlay.d");
} }
@@ -246,7 +238,7 @@ void MagiskInit::setup_tmp(const char *path) {
xmkdir(DEVICEDIR, 0711); xmkdir(DEVICEDIR, 0711);
xmkdir(WORKERDIR, 0); xmkdir(WORKERDIR, 0);
mount_preinit_dir(preinit_dev); mount_preinit_dir();
cp_afc(".backup/.magisk", MAIN_CONFIG); cp_afc(".backup/.magisk", MAIN_CONFIG);
rm_rf(".backup"); rm_rf(".backup");
@@ -261,7 +253,7 @@ void MagiskInit::setup_tmp(const char *path) {
chdir(path); chdir(path);
// Prepare worker // Prepare worker
xmount(WORKERDIR, WORKERDIR, nullptr, MS_BIND, nullptr); xmount("magisk", WORKERDIR, "tmpfs", 0, "mode=755");
// Use isolated devpts if kernel support // Use isolated devpts if kernel support
if (access("/dev/pts/ptmx", F_OK) == 0) { if (access("/dev/pts/ptmx", F_OK) == 0) {

View File

@@ -347,12 +347,6 @@ void MagiskInit::patch_ro_root() {
chdir("/"); chdir("/");
} }
void RootFSInit::prepare() {
prepare_data();
LOGD("Restoring /init\n");
rename(backup_init(), "/init");
}
#define PRE_TMPSRC "/magisk" #define PRE_TMPSRC "/magisk"
#define PRE_TMPDIR PRE_TMPSRC "/tmp" #define PRE_TMPDIR PRE_TMPSRC "/tmp"

View File

@@ -64,7 +64,7 @@ bool MagiskInit::hijack_sepolicy() {
// This only happens on Android 8.0 - 9.0 // This only happens on Android 8.0 - 9.0
char buf[4096]; 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); dt_compat = full_read(buf);
if (dt_compat.empty()) { if (dt_compat.empty()) {
// Device does not do early mount and uses monolithic policy // 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); int fd = xopen(MOCK_COMPAT, O_WRONLY);
char buf[4096]; 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); xumount2(buf, MNT_DETACH);
hijack(); hijack();

View File

@@ -8,12 +8,13 @@
using namespace std; using namespace std;
void FirstStageInit::prepare() { void MagiskInit::first_stage() {
LOGI("First Stage Init\n");
prepare_data(); prepare_data();
if (struct stat st{}; fstatat(-1, "/sdcard", &st, AT_SYMLINK_NOFOLLOW) != 0 && if (struct stat st{}; fstatat(-1, "/sdcard", &st, AT_SYMLINK_NOFOLLOW) != 0 &&
fstatat(-1, "/first_stage_ramdisk/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); xmkdirs("/first_stage_ramdisk/storage/self", 0755);
xsymlink("/system/system/bin/init", "/first_stage_ramdisk/storage/self/primary"); xsymlink("/system/system/bin/init", "/first_stage_ramdisk/storage/self/primary");
LOGD("Symlink /first_stage_ramdisk/storage/self/primary -> /system/system/bin/init\n"); 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"); LOGD("Bind mount /sdcard -> /sdcard\n");
} else { } else {
// rootfs before 3.12 // rootfs before 3.12
xmount("/data/magiskinit", "/sdcard", nullptr, MS_BIND, nullptr); xmount(REDIR_PATH, "/sdcard", nullptr, MS_BIND, nullptr);
LOGD("Bind mount /sdcard -> /data/magiskinit\n"); LOGD("Bind mount " REDIR_PATH " -> /sdcard\n");
} }
restore_ramdisk_init(); restore_ramdisk_init();
} else { } else {
@@ -44,7 +45,7 @@ void FirstStageInit::prepare() {
} }
} }
void LegacySARInit::first_stage_prep() { void MagiskInit::redirect_second_stage() {
// Patch init binary // Patch init binary
int src = xopen("/init", O_RDONLY); int src = xopen("/init", O_RDONLY);
int dest = xopen("/data/init", O_CREAT | O_WRONLY, 0); 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); 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", MNT_DETACH);
umount2(INIT_PATH, MNT_DETACH); // just in case umount2(INIT_PATH, MNT_DETACH); // just in case
unlink("/data/init"); 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 // We are still on rootfs, so make sure we will execute the init of the 2nd stage
unlink("/init"); unlink("/init");
xsymlink(INIT_PATH, "/init"); xsymlink(INIT_PATH, "/init");
return true; patch_rw_root();
} else {
patch_ro_root();
} }
return false;
} }

View File

@@ -101,9 +101,8 @@ impl SepolicyMagisk for sepolicy {
"system_app", "priv_app", "untrusted_app", "untrusted_app_all"], "system_app", "priv_app", "untrusted_app", "untrusted_app_all"],
[proc], ["unix_stream_socket"], ["connectto", "getopt"]); [proc], ["unix_stream_socket"], ["connectto", "getopt"]);
// Let selected domains access tmpfs files // For tmpfs overlay on 2SI. We allow all domains to access tmpfs files.
// For tmpfs overlay on 2SI, Zygisk on lower Android versions and AVD scripts allow(["domain"], ["tmpfs"], ["file"], all);
allow(["init", "zygote", "shell"], ["tmpfs"], ["file"], all);
// Allow magiskinit daemon to handle mock selinuxfs // Allow magiskinit daemon to handle mock selinuxfs
allow(["kernel"], ["tmpfs"], ["fifo_file"], ["write"]); allow(["kernel"], ["tmpfs"], ["fifo_file"], ["write"]);

View File

@@ -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) #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) { 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) { if (src == nullptr) {
for_each_attr(db->p_types.table, [&](type_datum_t *type) { for_each_attr(db->p_types.table, [&](type_datum_t *type) {
add_xperm_rule(type, tgt, cls, p, effect); add_xperm_rule(type, tgt, cls, p, effect);

View File

@@ -2,10 +2,14 @@
# Magisk app internal scripts # Magisk app internal scripts
################################## ##################################
# $1 = delay
# $2 = command
run_delay() { run_delay() {
(sleep $1; $2)& (sleep $1; $2)&
} }
# $1 = version string
# $2 = version code
env_check() { env_check() {
for file in busybox magiskboot magiskinit util_functions.sh boot_patch.sh; do for file in busybox magiskboot magiskinit util_functions.sh boot_patch.sh; do
[ -f "$MAGISKBIN/$file" ] || return 1 [ -f "$MAGISKBIN/$file" ] || return 1
@@ -21,6 +25,8 @@ env_check() {
return 0 return 0
} }
# $1 = dir to copy
# $2 = destination (optional)
cp_readlink() { cp_readlink() {
if [ -z $2 ]; then if [ -z $2 ]; then
cd $1 cd $1
@@ -39,6 +45,7 @@ cp_readlink() {
cd / cd /
} }
# $1 = install dir
fix_env() { fix_env() {
# Cleanup and make dirs # Cleanup and make dirs
rm -rf $MAGISKBIN/* rm -rf $MAGISKBIN/*
@@ -49,6 +56,8 @@ fix_env() {
chown -R 0:0 $MAGISKBIN chown -R 0:0 $MAGISKBIN
} }
# $1 = install dir
# $2 = boot partition
direct_install() { direct_install() {
echo "- Flashing new boot image" echo "- Flashing new boot image"
flash_image $1/new-boot.img $2 flash_image $1/new-boot.img $2
@@ -70,6 +79,7 @@ direct_install() {
return 0 return 0
} }
# $1 = uninstaller zip
run_uninstaller() { run_uninstaller() {
rm -rf /dev/tmp rm -rf /dev/tmp
mkdir -p /dev/tmp/install 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" INSTALLER=/dev/tmp/install sh /dev/tmp/install/assets/uninstaller.sh dummy 1 "$1"
} }
# $1 = boot partition
restore_imgs() { restore_imgs() {
local SHA1=$(grep_prop SHA1 $MAGISKTMP/.magisk/config) local SHA1=$(grep_prop SHA1 $MAGISKTMP/.magisk/config)
local BACKUPDIR=/data/magisk_backup_$SHA1 local BACKUPDIR=/data/magisk_backup_$SHA1
[ -d $BACKUPDIR ] || return 1 [ -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 [ -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() { post_ota() {
cd /data/adb cd /data/adb
cp -f $1 bootctl cp -f $1 bootctl
@@ -131,6 +133,8 @@ EOF
cd / cd /
} }
# $1 = APK
# $2 = package name
adb_pm_install() { adb_pm_install() {
local tmp=/data/local/tmp/temp.apk local tmp=/data/local/tmp/temp.apk
cp -f "$1" $tmp cp -f "$1" $tmp

View File

@@ -37,7 +37,7 @@ if [ -z "$FIRST_STAGE" ]; then
export ASH_STANDALONE=1 export ASH_STANDALONE=1
if [ $(./busybox id -u) -ne 0 ]; then if [ $(./busybox id -u) -ne 0 ]; then
# Re-exec script with root # 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 else
# Re-exec script with busybox # Re-exec script with busybox
exec ./busybox sh $0 exec ./busybox sh $0
@@ -66,7 +66,7 @@ fi
# Stop zygote (and previous setup if exists) # Stop zygote (and previous setup if exists)
magisk --stop 2>/dev/null magisk --stop 2>/dev/null
stop stop zygote
if [ -d /debug_ramdisk ]; then if [ -d /debug_ramdisk ]; then
umount -l /debug_ramdisk 2>/dev/null umount -l /debug_ramdisk 2>/dev/null
fi fi
@@ -141,16 +141,17 @@ ln -s ./magisk $MAGISKTMP/resetprop
ln -s ./magiskpolicy $MAGISKTMP/supolicy ln -s ./magiskpolicy $MAGISKTMP/supolicy
mkdir -p $MAGISKTMP/.magisk/device 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 touch $MAGISKTMP/.magisk/config
export MAGISKTMP export MAGISKTMP
MAKEDEV=1 $MAGISKTMP/magisk --preinit-device 2>&1 MAKEDEV=1 $MAGISKTMP/magisk --preinit-device 2>&1
RULESCMD="" RULESCMD=""
for r in $MAGISKTMP/.magisk/preinit/*/sepolicy.rule; do rule="$MAGISKTMP/.magisk/preinit/sepolicy.rule"
[ -f "$r" ] || continue [ -f "$rule" ] && RULESCMD="--apply $rule"
RULESCMD="$RULESCMD --apply $r"
done
# SELinux stuffs # SELinux stuffs
if [ -d /sys/fs/selinux ]; then if [ -d /sys/fs/selinux ]; then
@@ -165,5 +166,8 @@ fi
# Boot up # Boot up
$MAGISKTMP/magisk --post-fs-data $MAGISKTMP/magisk --post-fs-data
start start zygote
$MAGISKTMP/magisk --service $MAGISKTMP/magisk --service
# Make sure reset nb prop after zygote starts
sleep 2
$MAGISKTMP/magisk --boot-complete

View File

@@ -8,7 +8,7 @@ lsposed_url='https://github.com/LSPosed/LSPosed/releases/download/v1.9.2/LSPosed
emu_pid= emu_pid=
atd_min_api=30 atd_min_api=30
atd_max_api=34 atd_max_api=35
lsposed_min_api=27 lsposed_min_api=27
lsposed_max_api=34 lsposed_max_api=34
huge_ram_min_api=26 huge_ram_min_api=26
@@ -25,6 +25,7 @@ cleanup() {
} }
wait_for_bootanim() { wait_for_bootanim() {
set -e
adb wait-for-device adb wait-for-device
while true; do while true; do
local result="$(adb exec-out getprop init.svc.bootanim)" local result="$(adb exec-out getprop init.svc.bootanim)"
@@ -38,6 +39,7 @@ wait_for_bootanim() {
} }
wait_for_boot() { wait_for_boot() {
set -e
adb wait-for-device adb wait-for-device
while true; do while true; do
local result="$(adb exec-out getprop sys.boot_completed)" local result="$(adb exec-out getprop sys.boot_completed)"
@@ -79,8 +81,15 @@ test_emu() {
test_setup $variant test_setup $variant
# Install LSPosed local lsposed
if [ $api -ge $lsposed_min_api -a $api -le $lsposed_max_api ]; then 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 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 echo 'PATH=$PATH:/debug_ramdisk magisk --install-module /data/local/tmp/lsposed.zip' | adb shell /system/xbin/su
fi fi
@@ -91,7 +100,7 @@ test_emu() {
test_app test_app
# Try to launch LSPosed # 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 rm -f /data/local/tmp/window_dump.xml
adb shell am start -c org.lsposed.manager.LAUNCH_MANAGER com.android.shell/.BugreportWarningActivity 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 while adb shell '[ ! -f /data/local/tmp/window_dump.xml ]'; do
@@ -113,6 +122,7 @@ run_test() {
TiramisuPrivacySandbox) api=33 ;; TiramisuPrivacySandbox) api=33 ;;
UpsideDownCakePrivacySandbox) api=34 ;; UpsideDownCakePrivacySandbox) api=34 ;;
VanillaIceCream) api=35 ;; VanillaIceCream) api=35 ;;
Baklava) api=36 ;;
*) *)
print_error "! Unknown system image version '$ver'" print_error "! Unknown system image version '$ver'"
exit 1 exit 1
@@ -211,11 +221,11 @@ curl -L $lsposed_url -o out/lsposed.zip
if [ -n "$1" ]; then if [ -n "$1" ]; then
run_test $1 $2 run_test $1 $2
else else
for api in $(seq 23 34); do for api in $(seq 23 35); do
run_test $api run_test $api
done done
# Android 15 Beta # Android 16 Beta
run_test 35 google_apis run_test Baklava google_apis
# Run 16k page tests # Run 16k page tests
run_test 35 google_apis_ps16k run_test 35 google_apis_ps16k
fi fi