mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-08-14 16:07:26 +00:00
Compare commits
17 Commits
canary-280
...
canary-281
Author | SHA1 | Date | |
---|---|---|---|
![]() |
47cc532d96 | ||
![]() |
218327f92b | ||
![]() |
4eae66a1a7 | ||
![]() |
b09ceeb43c | ||
![]() |
4fb539c110 | ||
![]() |
849b284da5 | ||
![]() |
895b5f6cbf | ||
![]() |
cb3d4ea514 | ||
![]() |
0d89a2a97d | ||
![]() |
3ca5913055 | ||
![]() |
df6b808f49 | ||
![]() |
09c7ac754b | ||
![]() |
805da67c23 | ||
![]() |
3c6889505b | ||
![]() |
c8e9ce7627 | ||
![]() |
837c679a31 | ||
![]() |
06616659b8 |
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@@ -83,10 +83,10 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
version: [23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34]
|
||||
version: [23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35]
|
||||
type: [""]
|
||||
include:
|
||||
- version: 35
|
||||
- version: "Baklava"
|
||||
type: "google_apis"
|
||||
|
||||
steps:
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -14,6 +14,7 @@ native/out
|
||||
*.iml
|
||||
.gradle
|
||||
.idea
|
||||
.kotlin
|
||||
/local.properties
|
||||
/build
|
||||
/captures
|
||||
|
@@ -20,9 +20,9 @@ Some highlight features:
|
||||
|
||||
Click the icon below to download Magisk apk.
|
||||
|
||||
[](https://github.com/topjohnwu/Magisk/releases/tag/v27.0)
|
||||
[](https://github.com/topjohnwu/Magisk/releases/tag/v28.0)
|
||||
[](https://github.com/topjohnwu/Magisk/releases/tag/canary-28002)
|
||||
[](https://github.com/topjohnwu/Magisk/releases/tag/v28.1)
|
||||
[](https://github.com/topjohnwu/Magisk/releases/tag/v28.1)
|
||||
[](https://github.com/topjohnwu/Magisk/releases/tag/canary-28101)
|
||||
|
||||
## Useful Links
|
||||
|
||||
|
@@ -87,6 +87,9 @@
|
||||
<string name="logs_cleared">Логи успешно очищены</string>
|
||||
<string name="pid">PID: %1$d</string>
|
||||
<string name="target_uid">Целевой UID: %1$d</string>
|
||||
<string name="target_pid">Целевой PID пространства имён: %s</string>
|
||||
<string name="selinux_context">Контекст SELinux: %s</string>
|
||||
<string name="supp_group">Дополнительная группа: %s</string>
|
||||
|
||||
<!--SafetyNet-->
|
||||
|
||||
@@ -164,11 +167,16 @@
|
||||
<string name="settings_su_reauth_title">Повторная аутентификация</string>
|
||||
<string name="settings_su_reauth_summary">Повторный запрос прав суперпользователя после обновления приложений</string>
|
||||
<string name="settings_su_tapjack_title">Защита от перехвата нажатий</string>
|
||||
<string name="settings_su_auth_title">Аутентификация пользователя</string>
|
||||
<string name="settings_su_auth_summary">Требовать аутентификацию пользователя при запросах Superuser</string>
|
||||
<string name="settings_su_auth_insecure">На устройстве не настроен метод аутентификации</string>
|
||||
<string name="settings_su_tapjack_summary">Окно запроса прав суперпользователя будет неактивно пока активированы наложения экрана</string>
|
||||
<string name="settings_customization">Персонализация</string>
|
||||
<string name="setting_add_shortcut_summary">Добавить ярлык на рабочий стол для удобного восприятия приложения после его скрытия</string>
|
||||
<string name="settings_doh_title">DNS поверх HTTPS</string>
|
||||
<string name="settings_doh_description">Активировать DoH (используйте при проблемах с подключением к сети)</string>
|
||||
<string name="settings_random_name_title">Случайное имя образа</string>
|
||||
<string name="settings_random_name_description">Генерировать случайные имена для патченных образов и tar-файлов для предотвращения обнаружения</string>
|
||||
|
||||
<string name="multiuser_mode">Многопользовательский режим</string>
|
||||
<string name="settings_owner_only">Только администратор</string>
|
||||
|
@@ -130,8 +130,8 @@
|
||||
<string name="settings_update_custom">Власний</string>
|
||||
<string name="settings_update_custom_msg">Вставте власний URL</string>
|
||||
<string name="settings_zygisk_summary">Запускати частини Magisk в сервісі zygote</string>
|
||||
<string name="settings_denylist_title">Enforce DenyList</string>
|
||||
<string name="settings_denylist_summary">Processes on the denylist will have all Magisk modifications reverted</string>
|
||||
<string name="settings_denylist_title">Увімкнути DenyList</string>
|
||||
<string name="settings_denylist_summary">Всі зміни, внесені Magisk, будуть приховані від процесів, позначених у DenyList</string>
|
||||
<string name="settings_denylist_config_title">Налаштувати DenyList</string>
|
||||
<string name="settings_denylist_config_summary">Вибрати процеси, які будуть додані до denylist</string>
|
||||
<string name="settings_hosts_title">Позасистемні хости</string>
|
||||
@@ -156,7 +156,7 @@
|
||||
<string name="superuser_notification">Сповіщення суперкористувача</string>
|
||||
<string name="settings_su_reauth_title">Повторна автентифікація</string>
|
||||
<string name="settings_su_reauth_summary">Перевидача прав суперкористувача після оновлення застосунку</string>
|
||||
<string name="settings_su_tapjack_title">Увімкнути захист від Tapjack</string>
|
||||
<string name="settings_su_tapjack_title">Увімкнути захист від підміни натискань</string>
|
||||
<string name="settings_su_tapjack_summary">Діалогове вікно суперкористувача не буде отримувати ввід від користувача, коли вікно перекрито іншим застосунком чи вікном</string>
|
||||
<string name="settings_customization">Оформлення</string>
|
||||
<string name="setting_add_shortcut_summary">Додати ярлик на домашній екран для зручного сприйняття застосунку після його приховування</string>
|
||||
|
@@ -7,21 +7,26 @@ 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 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(nextClassVisitor)
|
||||
return DesugarClassVisitor(classContext, nextClassVisitor)
|
||||
}
|
||||
|
||||
override fun isInstrumentable(classData: ClassData) = classData.className != DESUGAR_CLASS_NAME
|
||||
|
||||
class DesugarClassVisitor(cv: ClassVisitor) : ClassVisitor(ASM9, cv) {
|
||||
class DesugarClassVisitor(private val classContext: ClassContext, cv: ClassVisitor) :
|
||||
ClassVisitor(ASM9, cv) {
|
||||
override fun visitMethod(
|
||||
access: Int,
|
||||
name: String?,
|
||||
@@ -29,39 +34,45 @@ abstract class DesugarClassVisitorFactory : AsmClassVisitorFactory<Instrumentati
|
||||
signature: String?,
|
||||
exceptions: Array<out String>?
|
||||
): MethodVisitor {
|
||||
return DesugarMethodVisitor(super.visitMethod(access, name, descriptor, signature, exceptions))
|
||||
}
|
||||
}
|
||||
|
||||
class DesugarMethodVisitor(mv: MethodVisitor?) : MethodVisitor(ASM9, mv) {
|
||||
override fun visitMethodInsn(
|
||||
opcode: Int,
|
||||
owner: String,
|
||||
name: String,
|
||||
descriptor: String,
|
||||
isInterface: Boolean
|
||||
) {
|
||||
if (!process(name, descriptor)) {
|
||||
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface)
|
||||
}
|
||||
return DesugarMethodVisitor(
|
||||
super.visitMethod(access, name, descriptor, signature, exceptions)
|
||||
)
|
||||
}
|
||||
|
||||
private fun process(name: String, descriptor: String): Boolean {
|
||||
if (descriptor != ZIP_ENTRY_GET_TIME_DESC)
|
||||
return false
|
||||
when (name) {
|
||||
"getLastModifiedTime", "getLastAccessTime", "getCreationTime" -> {
|
||||
mv.visitMethodInsn(
|
||||
Opcodes.INVOKESTATIC,
|
||||
DESUGAR_CLASS_NAME.replace('.', '/'),
|
||||
name,
|
||||
DESUGAR_GET_TIME_DESC,
|
||||
false
|
||||
)
|
||||
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
|
||||
}
|
||||
else -> return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,13 @@
|
||||
# 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
|
||||
|
33
docs/releases/28100.md
Normal file
33
docs/releases/28100.md
Normal file
@@ -0,0 +1,33 @@
|
||||
## 2024.12.6 Magisk v28.1
|
||||
|
||||
- [App] Fix stub APK download link
|
||||
- [App] Fix support for Android lower than 8.0
|
||||
- [General] Fix support for MTK Samsung devices
|
||||
- [MagiskInit] Fix a regression for 2SI devices
|
||||
- [MagiskPolicy] Fix a regression causing `overlay.d` replaced files to be not accessible
|
||||
|
||||
## Magisk v28.0 Changes
|
||||
|
||||
- [General] Support 16k page size
|
||||
- [General] Add basic support for RISC-V (not built in releases)
|
||||
- [General] Use a minimal libc to build static executables (`magiskinit` and `magiskboot`) for smaller sizes
|
||||
- [Core] Remove unnecessary mirror for magic mount
|
||||
- [Core] Update boot image detection logic to support more devices
|
||||
- [MagiskInit] Rewrite 2SI logic for injecting `magiskinit` as `init`
|
||||
- [MagiskInit] Update preinit partition detection
|
||||
- [Zygisk] Update internal JNI hooking implementation
|
||||
- [MagiskPolicy] Preserve sepolicy config flag after patching
|
||||
- [MagiskPolicy] Optimize patching rules to reduce the amount of new rules being injected
|
||||
- [DenyList] Support enforcing denylist when Zygisk is disabled
|
||||
- [Resetprop] Improve implementation to workaround several property modification detections
|
||||
- [Resetprop] Update to properly work with property overlays
|
||||
- [App] Major internal code refactoring
|
||||
- [App] Support patching Samsung firmware with images larger than 8GiB
|
||||
- [App] Use user-initiated job instead of foreground services on Android 14
|
||||
- [App] Support Android 13+ built-in per-app language preferences
|
||||
- [App] Add `action.sh` support to allow modules to define an action triggered from UI
|
||||
- [MagiskBoot] Support spliting kernel images without decompression
|
||||
- [MagiskBoot] Properly support vendor boot images
|
||||
- [MagiskBoot] Disable Samsung PROCA from kernel image
|
||||
|
||||
### Full Changelog: [here](https://topjohnwu.github.io/Magisk/changes.html)
|
@@ -1,5 +1,6 @@
|
||||
# Release Notes
|
||||
|
||||
- [v28.1](28100.md)
|
||||
- [v28.0](28000.md)
|
||||
- [v27.0](27000.md)
|
||||
- [v26.4](26400.md)
|
||||
|
@@ -30,5 +30,5 @@ android.nonFinalResIds=false
|
||||
|
||||
# Magisk
|
||||
magisk.stubVersion=40
|
||||
magisk.versionCode=28002
|
||||
magisk.versionCode=28101
|
||||
magisk.ondkVersion=r27.4
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[versions]
|
||||
kotlin = "2.0.21"
|
||||
android = "8.7.2"
|
||||
android = "8.7.3"
|
||||
ksp = "2.0.21-1.0.28"
|
||||
rikka = "1.3.0"
|
||||
navigation = "2.8.4"
|
||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
72
native/src/Cargo.lock
generated
72
native/src/Cargo.lock
generated
@@ -2,6 +2,12 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
|
||||
|
||||
[[package]]
|
||||
name = "argh"
|
||||
version = "0.1.12"
|
||||
@@ -111,6 +117,32 @@ version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69371e34337c4c984bbe322360c2547210bf632eb2814bbe78a6e87a2935bd2b"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e24c1b4099818523236a8ca881d2b45db98dadfb4625cf6608c12069fcbbde1"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7"
|
||||
|
||||
[[package]]
|
||||
name = "codespan-reporting"
|
||||
version = "0.11.1"
|
||||
@@ -182,16 +214,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cxx"
|
||||
version = "1.0.124"
|
||||
version = "1.0.133"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cxxbridge-cmd",
|
||||
"cxxbridge-flags",
|
||||
"cxxbridge-macro",
|
||||
"foldhash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxx-gen"
|
||||
version = "0.7.124"
|
||||
version = "0.7.133"
|
||||
dependencies = [
|
||||
"codespan-reporting",
|
||||
"proc-macro2",
|
||||
@@ -199,16 +233,28 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxxbridge-cmd"
|
||||
version = "1.0.133"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"codespan-reporting",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxxbridge-flags"
|
||||
version = "1.0.124"
|
||||
version = "1.0.133"
|
||||
|
||||
[[package]]
|
||||
name = "cxxbridge-macro"
|
||||
version = "1.0.124"
|
||||
version = "1.0.133"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn",
|
||||
]
|
||||
|
||||
@@ -305,6 +351,12 @@ version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3ea1ec5f8307826a5b71094dd91fc04d4ae75d5709b20ad351c7fb4815c86ec"
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.15"
|
||||
@@ -709,6 +761,12 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248"
|
||||
|
||||
[[package]]
|
||||
name = "sec1"
|
||||
version = "0.8.0-rc.0"
|
||||
@@ -803,6 +861,12 @@ dependencies = [
|
||||
"der",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.6.1"
|
||||
|
@@ -49,6 +49,7 @@ pub mod ffi {
|
||||
}
|
||||
|
||||
#[namespace = "rust"]
|
||||
#[allow(unused_unsafe)]
|
||||
extern "Rust" {
|
||||
unsafe fn extract_boot_from_payload(
|
||||
partition: *const c_char,
|
||||
|
@@ -148,8 +148,8 @@ static bool check_safe_mode() {
|
||||
* Boot Stage Handlers *
|
||||
***********************/
|
||||
|
||||
bool MagiskD::post_fs_data() const {
|
||||
as_rust().setup_logfile();
|
||||
bool MagiskD::post_fs_data() const noexcept {
|
||||
setup_logfile();
|
||||
|
||||
LOGI("** post-fs-data mode running\n");
|
||||
|
||||
@@ -194,8 +194,8 @@ bool MagiskD::post_fs_data() const {
|
||||
return safe_mode;
|
||||
}
|
||||
|
||||
void MagiskD::late_start() const {
|
||||
as_rust().setup_logfile();
|
||||
void MagiskD::late_start() const noexcept {
|
||||
setup_logfile();
|
||||
|
||||
LOGI("** late_start service mode running\n");
|
||||
|
||||
@@ -203,8 +203,8 @@ void MagiskD::late_start() const {
|
||||
exec_module_scripts("service");
|
||||
}
|
||||
|
||||
void MagiskD::boot_complete() const {
|
||||
as_rust().setup_logfile();
|
||||
void MagiskD::boot_complete() const noexcept {
|
||||
setup_logfile();
|
||||
|
||||
LOGI("** boot-complete triggered\n");
|
||||
|
||||
|
@@ -128,20 +128,8 @@ static void poll_ctrl_handler(pollfd *pfd) {
|
||||
}
|
||||
}
|
||||
|
||||
const MagiskD &MagiskD::get() {
|
||||
return *reinterpret_cast<const MagiskD*>(&rust::get_magiskd());
|
||||
}
|
||||
|
||||
const rust::MagiskD *MagiskD::operator->() const {
|
||||
return reinterpret_cast<const rust::MagiskD*>(this);
|
||||
}
|
||||
|
||||
const rust::MagiskD &MagiskD::as_rust() const {
|
||||
return *operator->();
|
||||
}
|
||||
|
||||
void MagiskD::reboot() const {
|
||||
if (as_rust().is_recovery())
|
||||
void MagiskD::reboot() const noexcept {
|
||||
if (is_recovery())
|
||||
exec_command_sync("/system/bin/reboot", "recovery");
|
||||
else
|
||||
exec_command_sync("/system/bin/reboot");
|
||||
@@ -171,7 +159,7 @@ static void handle_request_async(int client, int code, const sock_cred &cred) {
|
||||
write_int(client, 0);
|
||||
close(client);
|
||||
if (do_reboot) {
|
||||
MagiskD::get().reboot();
|
||||
MagiskD().reboot();
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -196,7 +184,7 @@ static void handle_request_sync(int client, int code) {
|
||||
write_int(client, MAGISK_VER_CODE);
|
||||
break;
|
||||
case +RequestCode::START_DAEMON:
|
||||
MagiskD::get()->setup_logfile();
|
||||
MagiskD().setup_logfile();
|
||||
break;
|
||||
case +RequestCode::STOP_DAEMON: {
|
||||
// Unmount all overlays
|
||||
@@ -298,7 +286,7 @@ static void handle_request(pollfd *pfd) {
|
||||
exec_task([=, fd = client.release()] { handle_request_async(fd, code, cred); });
|
||||
} else {
|
||||
exec_task([=, fd = client.release()] {
|
||||
MagiskD::get()->boot_stage_handler(fd, code);
|
||||
MagiskD().boot_stage_handler(fd, code);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::io::BufReader;
|
||||
use std::sync::{Mutex, OnceLock};
|
||||
use std::{io, mem};
|
||||
|
||||
use base::libc::{O_CLOEXEC, O_RDONLY};
|
||||
use base::{
|
||||
@@ -10,7 +10,7 @@ use base::{
|
||||
};
|
||||
|
||||
use crate::consts::MAIN_CONFIG;
|
||||
use crate::ffi::{get_magisk_tmp, CxxMagiskD, RequestCode};
|
||||
use crate::ffi::{get_magisk_tmp, RequestCode};
|
||||
use crate::get_prop;
|
||||
use crate::logging::magisk_logging;
|
||||
|
||||
@@ -64,7 +64,7 @@ impl MagiskD {
|
||||
match code {
|
||||
RequestCode::POST_FS_DATA => {
|
||||
if check_data() && !state.contains(BootState::PostFsDataDone) {
|
||||
if self.as_cxx().post_fs_data() {
|
||||
if self.post_fs_data() {
|
||||
state.set(BootState::SafeMode);
|
||||
}
|
||||
state.set(BootState::PostFsDataDone);
|
||||
@@ -75,7 +75,7 @@ impl MagiskD {
|
||||
unsafe { libc::close(client) };
|
||||
if state.contains(BootState::PostFsDataDone) && !state.contains(BootState::SafeMode)
|
||||
{
|
||||
self.as_cxx().late_start();
|
||||
self.late_start();
|
||||
state.set(BootState::LateStartDone);
|
||||
}
|
||||
}
|
||||
@@ -83,7 +83,7 @@ impl MagiskD {
|
||||
unsafe { libc::close(client) };
|
||||
if state.contains(BootState::PostFsDataDone) {
|
||||
state.set(BootState::BootComplete);
|
||||
self.as_cxx().boot_complete()
|
||||
self.boot_complete()
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
@@ -91,11 +91,6 @@ impl MagiskD {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn as_cxx(&self) -> &CxxMagiskD {
|
||||
unsafe { mem::transmute(self) }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn daemon_entry() {
|
||||
|
@@ -108,7 +108,7 @@ db_settings::db_settings() {
|
||||
data[SU_MULTIUSER_MODE] = MULTIUSER_MODE_OWNER_ONLY;
|
||||
data[SU_MNT_NS] = NAMESPACE_MODE_REQUESTER;
|
||||
data[DENYLIST_CONFIG] = false;
|
||||
data[ZYGISK_CONFIG] = MagiskD::get()->is_emulator();
|
||||
data[ZYGISK_CONFIG] = MagiskD().is_emulator();
|
||||
data[BOOTLOOP_COUNT] = 0;
|
||||
}
|
||||
|
||||
|
@@ -2,29 +2,6 @@
|
||||
|
||||
#include <base.hpp>
|
||||
|
||||
namespace rust {
|
||||
struct MagiskD;
|
||||
}
|
||||
|
||||
struct MagiskD {
|
||||
// Make sure only references can exist
|
||||
~MagiskD() = delete;
|
||||
|
||||
// Binding to Rust
|
||||
static const MagiskD &get();
|
||||
|
||||
// C++ implementation
|
||||
void reboot() const;
|
||||
bool post_fs_data() const;
|
||||
void late_start() const;
|
||||
void boot_complete() const;
|
||||
|
||||
const rust::MagiskD *operator->() const;
|
||||
|
||||
private:
|
||||
const rust::MagiskD &as_rust() const;
|
||||
};
|
||||
|
||||
const char *get_magisk_tmp();
|
||||
|
||||
// Rust bindings
|
||||
|
@@ -74,12 +74,6 @@ pub mod ffi {
|
||||
fn resolve_preinit_dir(base_dir: Utf8CStrRef) -> String;
|
||||
|
||||
fn switch_mnt_ns(pid: i32) -> i32;
|
||||
|
||||
#[cxx_name = "MagiskD"]
|
||||
type CxxMagiskD;
|
||||
fn post_fs_data(self: &CxxMagiskD) -> bool;
|
||||
fn late_start(self: &CxxMagiskD);
|
||||
fn boot_complete(self: &CxxMagiskD);
|
||||
}
|
||||
|
||||
extern "Rust" {
|
||||
@@ -99,18 +93,28 @@ pub mod ffi {
|
||||
unsafe fn persist_get_props(prop_cb: Pin<&mut PropCb>);
|
||||
unsafe fn persist_delete_prop(name: Utf8CStrRef) -> bool;
|
||||
unsafe fn persist_set_prop(name: Utf8CStrRef, value: Utf8CStrRef) -> bool;
|
||||
|
||||
#[namespace = "rust"]
|
||||
fn daemon_entry();
|
||||
}
|
||||
|
||||
#[namespace = "rust"]
|
||||
// FFI for MagiskD
|
||||
extern "Rust" {
|
||||
fn daemon_entry();
|
||||
|
||||
type MagiskD;
|
||||
fn get_magiskd() -> &'static MagiskD;
|
||||
fn setup_logfile(self: &MagiskD);
|
||||
fn is_emulator(self: &MagiskD) -> bool;
|
||||
fn is_recovery(self: &MagiskD) -> bool;
|
||||
fn boot_stage_handler(self: &MagiskD, client: i32, code: i32);
|
||||
|
||||
#[cxx_name = "MagiskD"]
|
||||
fn get_magiskd() -> &'static MagiskD;
|
||||
}
|
||||
unsafe extern "C++" {
|
||||
#[allow(dead_code)]
|
||||
fn reboot(self: &MagiskD);
|
||||
fn post_fs_data(self: &MagiskD) -> bool;
|
||||
fn late_start(self: &MagiskD);
|
||||
fn boot_complete(self: &MagiskD);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -177,26 +177,23 @@ void tmpfs_node::mount() {
|
||||
class magisk_node : public node_entry {
|
||||
public:
|
||||
explicit magisk_node(const char *name) : node_entry(name, DT_REG, this) {}
|
||||
explicit magisk_node(const char *name, const char *target)
|
||||
: node_entry(name, DT_LNK, this), target(target) {}
|
||||
|
||||
void mount() override {
|
||||
const string src = get_magisk_tmp() + "/"s + name();
|
||||
if (access(src.data(), F_OK))
|
||||
return;
|
||||
|
||||
const string dir_name = isa<tmpfs_node>(parent()) ? parent()->worker_path() : parent()->node_path();
|
||||
if (name() == "magisk") {
|
||||
for (int i = 0; applet_names[i]; ++i) {
|
||||
string dest = dir_name + "/" + applet_names[i];
|
||||
VLOGD("create", "./magisk", dest.data());
|
||||
xsymlink("./magisk", dest.data());
|
||||
}
|
||||
if (target) {
|
||||
string dest = isa<tmpfs_node>(parent()) ? worker_path() : node_path();
|
||||
VLOGD("create", target, dest.data());
|
||||
xsymlink(target, dest.data());
|
||||
} else {
|
||||
string dest = dir_name + "/supolicy";
|
||||
VLOGD("create", "./magiskpolicy", dest.data());
|
||||
xsymlink("./magiskpolicy", dest.data());
|
||||
string src = get_magisk_tmp() + "/"s + name();
|
||||
if (access(src.data(), F_OK) == 0)
|
||||
create_and_mount("magisk", src, true);
|
||||
}
|
||||
create_and_mount("magisk", src, true);
|
||||
}
|
||||
|
||||
private:
|
||||
const char *target = nullptr;
|
||||
};
|
||||
|
||||
class zygisk_node : public node_entry {
|
||||
@@ -231,10 +228,10 @@ static void inject_magisk_bins(root_node *system) {
|
||||
bin->insert(new magisk_node("magisk"));
|
||||
bin->insert(new magisk_node("magiskpolicy"));
|
||||
|
||||
// Also delete all applets to make sure no modules can override it
|
||||
// Also insert all applets to make sure no one can override it
|
||||
for (int i = 0; applet_names[i]; ++i)
|
||||
delete bin->extract(applet_names[i]);
|
||||
delete bin->extract("supolicy");
|
||||
bin->insert(new magisk_node(applet_names[i], "./magisk"));
|
||||
bin->insert(new magisk_node("supolicy", "./magiskpolicy"));
|
||||
}
|
||||
|
||||
static void inject_zygisk_libs(root_node *system) {
|
||||
|
2
native/src/external/cxx-rs
vendored
2
native/src/external/cxx-rs
vendored
Submodule native/src/external/cxx-rs updated: 7535230afb...08cb634704
@@ -11,8 +11,6 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
vector<string> mount_list;
|
||||
|
||||
template<char... cs> using chars = integer_sequence<char, cs...>;
|
||||
|
||||
// If quoted, parsing ends when we find char in [breaks]
|
||||
@@ -148,6 +146,12 @@ void BootConfig::set(const kv_pairs &kv) {
|
||||
strscpy(fstab_suffix, value.data(), sizeof(fstab_suffix));
|
||||
} else if (key == "qemu") {
|
||||
emulator = true;
|
||||
} else if (key == "androidboot.partition_map") {
|
||||
// androidboot.partition_map allows mapping a partition name to a raw block device.
|
||||
// For example, "androidboot.partition_map=vdb,metadata;vdc,userdata" maps
|
||||
// "vdb" to "metadata", and "vdc" to "userdata".
|
||||
// https://android.googlesource.com/platform/system/core/+/refs/heads/android13-release/init/devices.cpp#191
|
||||
partition_map = parse_partition_map(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -165,41 +169,29 @@ void BootConfig::print() {
|
||||
}
|
||||
|
||||
#define read_dt(name, key) \
|
||||
ssprintf(file_name, sizeof(file_name), "%s/" name, config->dt_dir); \
|
||||
ssprintf(file_name, sizeof(file_name), "%s/" name, dt_dir); \
|
||||
if (access(file_name, R_OK) == 0) { \
|
||||
string data = full_read(file_name); \
|
||||
if (!data.empty()) { \
|
||||
data.pop_back(); \
|
||||
strscpy(config->key, data.data(), sizeof(config->key)); \
|
||||
strscpy(key, data.data(), sizeof(key)); \
|
||||
} \
|
||||
}
|
||||
|
||||
void load_kernel_info(BootConfig *config) {
|
||||
// Get kernel data using procfs and sysfs
|
||||
xmkdir("/proc", 0755);
|
||||
xmount("proc", "/proc", "proc", 0, nullptr);
|
||||
xmkdir("/sys", 0755);
|
||||
xmount("sysfs", "/sys", "sysfs", 0, nullptr);
|
||||
void BootConfig::init() {
|
||||
set(parse_cmdline(full_read("/proc/cmdline")));
|
||||
set(parse_bootconfig(full_read("/proc/bootconfig")));
|
||||
|
||||
mount_list.emplace_back("/proc");
|
||||
mount_list.emplace_back("/sys");
|
||||
|
||||
// Log to kernel
|
||||
rust::setup_klog();
|
||||
|
||||
config->set(parse_cmdline(full_read("/proc/cmdline")));
|
||||
config->set(parse_bootconfig(full_read("/proc/bootconfig")));
|
||||
|
||||
parse_prop_file("/.backup/.magisk", [=](auto key, auto value) -> bool {
|
||||
parse_prop_file("/.backup/.magisk", [&](auto key, auto value) -> bool {
|
||||
if (key == "RECOVERYMODE" && value == "true") {
|
||||
config->skip_initramfs = config->emulator || !check_key_combo();
|
||||
skip_initramfs = emulator || !check_key_combo();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (config->dt_dir[0] == '\0')
|
||||
strscpy(config->dt_dir, DEFAULT_DT_DIR, sizeof(config->dt_dir));
|
||||
if (dt_dir[0] == '\0')
|
||||
strscpy(dt_dir, DEFAULT_DT_DIR, sizeof(dt_dir));
|
||||
|
||||
char file_name[128];
|
||||
read_dt("fstab_suffix", fstab_suffix)
|
||||
@@ -207,26 +199,7 @@ void load_kernel_info(BootConfig *config) {
|
||||
read_dt("hardware.platform", hardware_plat)
|
||||
|
||||
LOGD("Device config:\n");
|
||||
config->print();
|
||||
}
|
||||
|
||||
// `androidboot.partition_map` allows associating a partition name for a raw block device
|
||||
// through a comma separated and semicolon deliminated list. For example,
|
||||
// `androidboot.partition_map=vdb,metadata;vdc,userdata` maps `vdb` to `metadata` and `vdc` to
|
||||
// `userdata`.
|
||||
// https://android.googlesource.com/platform/system/core/+/refs/heads/android13-release/init/devices.cpp#191
|
||||
|
||||
kv_pairs load_partition_map() {
|
||||
const string_view kPartitionMapKey = "androidboot.partition_map";
|
||||
for (const auto &[key, value] : parse_cmdline(full_read("/proc/cmdline"))) {
|
||||
if (key == kPartitionMapKey)
|
||||
return parse_partition_map(value);
|
||||
}
|
||||
for (const auto &[key, value] : parse_bootconfig(full_read("/proc/bootconfig"))) {
|
||||
if (key == kPartitionMapKey)
|
||||
return parse_partition_map(value);
|
||||
}
|
||||
return {};
|
||||
print();
|
||||
}
|
||||
|
||||
bool check_two_stage() {
|
||||
@@ -244,7 +217,7 @@ bool check_two_stage() {
|
||||
return init.contains("selinux_setup");
|
||||
}
|
||||
|
||||
void unxz_init(const char *init_xz, const char *init) {
|
||||
static void unxz_init(const char *init_xz, const char *init) {
|
||||
LOGD("unxz %s -> %s\n", init_xz, init);
|
||||
int fd = xopen(init, O_WRONLY | O_CREAT, 0777);
|
||||
fd_stream ch(fd);
|
||||
|
@@ -60,16 +60,67 @@ void restore_ramdisk_init() {
|
||||
}
|
||||
}
|
||||
|
||||
class RecoveryInit : public BaseInit {
|
||||
public:
|
||||
using BaseInit::BaseInit;
|
||||
void start() override {
|
||||
LOGD("Ramdisk is recovery, abort\n");
|
||||
restore_ramdisk_init();
|
||||
rm_rf("/.backup");
|
||||
exec_init();
|
||||
MagiskInit::MagiskInit(char **argv) : argv(argv), config{} {
|
||||
// Get kernel data using procfs and sysfs
|
||||
if (access("/proc/cmdline", F_OK) != 0) {
|
||||
xmkdir("/proc", 0755);
|
||||
xmount("proc", "/proc", "proc", 0, nullptr);
|
||||
mount_list.emplace_back("/proc");
|
||||
}
|
||||
};
|
||||
if (access("/sys/block", F_OK) != 0) {
|
||||
xmkdir("/sys", 0755);
|
||||
xmount("sysfs", "/sys", "sysfs", 0, nullptr);
|
||||
mount_list.emplace_back("/sys");
|
||||
}
|
||||
|
||||
// Log to kernel
|
||||
rust::setup_klog();
|
||||
|
||||
// Load kernel configs
|
||||
config.init();
|
||||
}
|
||||
|
||||
static void recovery() {
|
||||
LOGI("Ramdisk is recovery, abort\n");
|
||||
restore_ramdisk_init();
|
||||
rm_rf("/.backup");
|
||||
}
|
||||
|
||||
void MagiskInit::legacy_system_as_root() {
|
||||
LOGI("Legacy SAR Init\n");
|
||||
prepare_data();
|
||||
bool is_two_stage = mount_system_root();
|
||||
if (is_two_stage)
|
||||
redirect_second_stage();
|
||||
else
|
||||
patch_ro_root();
|
||||
}
|
||||
|
||||
void MagiskInit::rootfs() {
|
||||
LOGI("RootFS Init\n");
|
||||
prepare_data();
|
||||
LOGD("Restoring /init\n");
|
||||
rename(backup_init(), "/init");
|
||||
patch_rw_root();
|
||||
}
|
||||
|
||||
void MagiskInit::start() {
|
||||
if (argv[1] != nullptr && argv[1] == "selinux_setup"sv)
|
||||
second_stage();
|
||||
else if (config.skip_initramfs)
|
||||
legacy_system_as_root();
|
||||
else if (config.force_normal_boot)
|
||||
first_stage();
|
||||
else if (access("/sbin/recovery", F_OK) == 0 || access("/system/bin/recovery", F_OK) == 0)
|
||||
recovery();
|
||||
else if (check_two_stage())
|
||||
first_stage();
|
||||
else
|
||||
rootfs();
|
||||
|
||||
// Finally execute the original init
|
||||
exec_init();
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
umask(0);
|
||||
@@ -81,29 +132,6 @@ int main(int argc, char *argv[]) {
|
||||
if (getpid() != 1)
|
||||
return 1;
|
||||
|
||||
BaseInit *init;
|
||||
BootConfig config{};
|
||||
|
||||
if (argc > 1 && argv[1] == "selinux_setup"sv) {
|
||||
rust::setup_klog();
|
||||
init = new SecondStageInit(argv);
|
||||
} else {
|
||||
// This will also mount /sys and /proc
|
||||
load_kernel_info(&config);
|
||||
|
||||
if (config.skip_initramfs)
|
||||
init = new LegacySARInit(argv, &config);
|
||||
else if (config.force_normal_boot)
|
||||
init = new FirstStageInit(argv, &config);
|
||||
else if (access("/sbin/recovery", F_OK) == 0 || access("/system/bin/recovery", F_OK) == 0)
|
||||
init = new RecoveryInit(argv, &config);
|
||||
else if (check_two_stage())
|
||||
init = new FirstStageInit(argv, &config);
|
||||
else
|
||||
init = new RootFSInit(argv, &config);
|
||||
}
|
||||
|
||||
// Run the main routine
|
||||
init->start();
|
||||
exit(1);
|
||||
MagiskInit init(argv);
|
||||
init.start();
|
||||
}
|
||||
|
@@ -15,7 +15,10 @@ struct BootConfig {
|
||||
char fstab_suffix[32];
|
||||
char hardware[32];
|
||||
char hardware_plat[32];
|
||||
kv_pairs partition_map;
|
||||
|
||||
void init();
|
||||
private:
|
||||
void set(const kv_pairs &);
|
||||
void print();
|
||||
};
|
||||
@@ -24,120 +27,45 @@ struct BootConfig {
|
||||
#define INIT_PATH "/system/bin/init"
|
||||
#define REDIR_PATH "/data/magiskinit"
|
||||
|
||||
extern std::vector<std::string> mount_list;
|
||||
|
||||
int magisk_proxy_main(int argc, char *argv[]);
|
||||
bool unxz(out_stream &strm, rust::Slice<const uint8_t> bytes);
|
||||
void load_kernel_info(BootConfig *config);
|
||||
kv_pairs load_partition_map();
|
||||
bool check_two_stage();
|
||||
const char *backup_init();
|
||||
void restore_ramdisk_init();
|
||||
|
||||
/***************
|
||||
* Base classes
|
||||
***************/
|
||||
|
||||
class BaseInit {
|
||||
protected:
|
||||
BootConfig *config = nullptr;
|
||||
char **argv = nullptr;
|
||||
|
||||
[[noreturn]] void exec_init();
|
||||
void prepare_data();
|
||||
public:
|
||||
BaseInit(char *argv[], BootConfig *config = nullptr) : config(config), argv(argv) {}
|
||||
virtual ~BaseInit() = default;
|
||||
virtual void start() = 0;
|
||||
};
|
||||
|
||||
class MagiskInit : public BaseInit {
|
||||
class MagiskInit {
|
||||
private:
|
||||
std::string preinit_dev;
|
||||
std::vector<std::string> mount_list;
|
||||
char **argv;
|
||||
BootConfig config;
|
||||
|
||||
void parse_config_file();
|
||||
void patch_sepolicy(const char *in, const char *out);
|
||||
bool hijack_sepolicy();
|
||||
// Setup mounts and environment
|
||||
void setup_tmp(const char *path);
|
||||
protected:
|
||||
void collect_devices();
|
||||
void mount_preinit_dir();
|
||||
void prepare_data();
|
||||
dev_t find_block(const char *partname);
|
||||
bool mount_system_root();
|
||||
|
||||
// Setup and patch root directory
|
||||
void parse_config_file();
|
||||
void patch_rw_root();
|
||||
void patch_ro_root();
|
||||
|
||||
// Two stage init
|
||||
void redirect_second_stage();
|
||||
void first_stage();
|
||||
void second_stage();
|
||||
|
||||
// SELinux
|
||||
void patch_sepolicy(const char *in, const char *out);
|
||||
bool hijack_sepolicy();
|
||||
|
||||
[[noreturn]] void exec_init();
|
||||
void legacy_system_as_root();
|
||||
void rootfs();
|
||||
public:
|
||||
using BaseInit::BaseInit;
|
||||
};
|
||||
|
||||
/***************
|
||||
* 2 Stage Init
|
||||
***************/
|
||||
|
||||
class FirstStageInit : public BaseInit {
|
||||
private:
|
||||
void prepare();
|
||||
public:
|
||||
FirstStageInit(char *argv[], BootConfig *config) : BaseInit(argv, config) {
|
||||
LOGD("%s\n", __FUNCTION__);
|
||||
};
|
||||
void start() override {
|
||||
prepare();
|
||||
exec_init();
|
||||
}
|
||||
};
|
||||
|
||||
class SecondStageInit : public MagiskInit {
|
||||
private:
|
||||
bool prepare();
|
||||
public:
|
||||
SecondStageInit(char *argv[]) : MagiskInit(argv) {
|
||||
LOGD("%s\n", __FUNCTION__);
|
||||
};
|
||||
|
||||
void start() override {
|
||||
bool is_rootfs = prepare();
|
||||
if (is_rootfs)
|
||||
patch_rw_root();
|
||||
else
|
||||
patch_ro_root();
|
||||
exec_init();
|
||||
}
|
||||
};
|
||||
|
||||
/*************
|
||||
* Legacy SAR
|
||||
*************/
|
||||
|
||||
class LegacySARInit : public MagiskInit {
|
||||
private:
|
||||
bool mount_system_root();
|
||||
void first_stage_prep();
|
||||
public:
|
||||
LegacySARInit(char *argv[], BootConfig *config) : MagiskInit(argv, config) {
|
||||
LOGD("%s\n", __FUNCTION__);
|
||||
};
|
||||
void start() override {
|
||||
prepare_data();
|
||||
bool is_two_stage = mount_system_root();
|
||||
if (is_two_stage)
|
||||
first_stage_prep();
|
||||
else
|
||||
patch_ro_root();
|
||||
exec_init();
|
||||
}
|
||||
};
|
||||
|
||||
/************
|
||||
* Initramfs
|
||||
************/
|
||||
|
||||
class RootFSInit : public MagiskInit {
|
||||
private:
|
||||
void prepare();
|
||||
public:
|
||||
RootFSInit(char *argv[], BootConfig *config) : MagiskInit(argv, config) {
|
||||
LOGD("%s\n", __FUNCTION__);
|
||||
}
|
||||
void start() override {
|
||||
prepare();
|
||||
patch_rw_root();
|
||||
exec_init();
|
||||
}
|
||||
explicit MagiskInit(char *argv[]);
|
||||
void start();
|
||||
};
|
||||
|
@@ -45,7 +45,7 @@ static void parse_device(devinfo *dev, const char *uevent) {
|
||||
});
|
||||
}
|
||||
|
||||
static void collect_devices(const auto &partition_map) {
|
||||
void MagiskInit::collect_devices() {
|
||||
char path[PATH_MAX];
|
||||
devinfo dev{};
|
||||
if (auto dir = xopen_dir("/sys/dev/block"); dir) {
|
||||
@@ -59,9 +59,9 @@ static void collect_devices(const auto &partition_map) {
|
||||
auto name = rtrim(full_read(path));
|
||||
strscpy(dev.dmname, name.data(), sizeof(dev.dmname));
|
||||
}
|
||||
if (auto it = std::ranges::find_if(partition_map, [&](const auto &i) {
|
||||
if (auto it = std::ranges::find_if(config.partition_map, [&](const auto &i) {
|
||||
return i.first == dev.devname;
|
||||
}); dev.partname[0] == '\0' && it != partition_map.end()) {
|
||||
}); dev.partname[0] == '\0' && it != config.partition_map.end()) {
|
||||
// use androidboot.partition_map as partname fallback.
|
||||
strscpy(dev.partname, it->second.data(), sizeof(dev.partname));
|
||||
}
|
||||
@@ -72,52 +72,45 @@ static void collect_devices(const auto &partition_map) {
|
||||
}
|
||||
}
|
||||
|
||||
static struct {
|
||||
char partname[32];
|
||||
char block_dev[64];
|
||||
} blk_info;
|
||||
|
||||
static dev_t setup_block() {
|
||||
static const auto partition_map = load_partition_map();
|
||||
dev_t MagiskInit::find_block(const char *partname) {
|
||||
if (dev_list.empty())
|
||||
collect_devices(partition_map);
|
||||
collect_devices();
|
||||
|
||||
for (int tries = 0; tries < 3; ++tries) {
|
||||
for (auto &dev : dev_list) {
|
||||
if (strcasecmp(dev.partname, blk_info.partname) == 0)
|
||||
LOGD("Setup %s: [%s] (%d, %d)\n", dev.partname, dev.devname, dev.major, dev.minor);
|
||||
else if (strcasecmp(dev.dmname, blk_info.partname) == 0)
|
||||
LOGD("Setup %s: [%s] (%d, %d)\n", dev.dmname, dev.devname, dev.major, dev.minor);
|
||||
else if (strcasecmp(dev.devname, blk_info.partname) == 0)
|
||||
LOGD("Setup %s: [%s] (%d, %d)\n", dev.devname, dev.devname, dev.major, dev.minor);
|
||||
else if (std::string_view(dev.devpath).ends_with("/"s + blk_info.partname))
|
||||
LOGD("Setup %s: [%s] (%d, %d)\n", dev.devpath, dev.devname, dev.major, dev.minor);
|
||||
const char *name;
|
||||
if (strcasecmp(dev.partname, partname) == 0)
|
||||
name = dev.partname;
|
||||
else if (strcasecmp(dev.dmname, partname) == 0)
|
||||
name = dev.dmname;
|
||||
else if (strcasecmp(dev.devname, partname) == 0)
|
||||
name = dev.devname;
|
||||
else if (std::string_view(dev.devpath).ends_with("/"s + partname))
|
||||
name = dev.devpath;
|
||||
else
|
||||
continue;
|
||||
|
||||
dev_t rdev = makedev(dev.major, dev.minor);
|
||||
xmknod(blk_info.block_dev, S_IFBLK | 0600, rdev);
|
||||
return rdev;
|
||||
LOGD("Found %s: [%s] (%d, %d)\n", name, dev.devname, dev.major, dev.minor);
|
||||
return makedev(dev.major, dev.minor);
|
||||
}
|
||||
// Wait 10ms and try again
|
||||
usleep(10000);
|
||||
dev_list.clear();
|
||||
collect_devices(partition_map);
|
||||
collect_devices();
|
||||
}
|
||||
|
||||
// The requested partname does not exist
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mount_preinit_dir(string preinit_dev) {
|
||||
void MagiskInit::mount_preinit_dir() {
|
||||
if (preinit_dev.empty()) return;
|
||||
strcpy(blk_info.partname, preinit_dev.data());
|
||||
strcpy(blk_info.block_dev, PREINITDEV);
|
||||
auto dev = setup_block();
|
||||
auto dev = find_block(preinit_dev.data());
|
||||
if (dev == 0) {
|
||||
LOGE("Cannot find preinit %s, abort!\n", preinit_dev.data());
|
||||
return;
|
||||
}
|
||||
xmknod(PREINITDEV, S_IFBLK | 0600, dev);
|
||||
xmkdir(MIRRDIR, 0);
|
||||
bool mounted = false;
|
||||
// First, find if it is already mounted
|
||||
@@ -150,40 +143,40 @@ static void mount_preinit_dir(string preinit_dev) {
|
||||
}
|
||||
}
|
||||
|
||||
bool LegacySARInit::mount_system_root() {
|
||||
bool MagiskInit::mount_system_root() {
|
||||
LOGD("Mounting system_root\n");
|
||||
|
||||
// there's no /dev in stub cpio
|
||||
xmkdir("/dev", 0777);
|
||||
|
||||
strcpy(blk_info.block_dev, "/dev/root");
|
||||
|
||||
dev_t dev;
|
||||
do {
|
||||
// Try legacy SAR dm-verity
|
||||
strcpy(blk_info.partname, "vroot");
|
||||
auto dev = setup_block();
|
||||
dev = find_block("vroot");
|
||||
if (dev > 0)
|
||||
goto mount_root;
|
||||
|
||||
// Try NVIDIA naming scheme
|
||||
strcpy(blk_info.partname, "APP");
|
||||
dev = setup_block();
|
||||
dev = find_block("APP");
|
||||
if (dev > 0)
|
||||
goto mount_root;
|
||||
|
||||
sprintf(blk_info.partname, "system%s", config->slot);
|
||||
dev = setup_block();
|
||||
// Try normal partname
|
||||
char sys_part[32];
|
||||
sprintf(sys_part, "system%s", config.slot);
|
||||
dev = find_block(sys_part);
|
||||
if (dev > 0)
|
||||
goto mount_root;
|
||||
|
||||
// Poll forever if rootwait was given in cmdline
|
||||
} while (config->rootwait);
|
||||
} while (config.rootwait);
|
||||
|
||||
// We don't really know what to do at this point...
|
||||
LOGE("Cannot find root partition, abort\n");
|
||||
exit(1);
|
||||
|
||||
mount_root:
|
||||
xmknod("/dev/root", S_IFBLK | 0600, dev);
|
||||
xmkdir("/system_root", 0755);
|
||||
|
||||
if (xmount("/dev/root", "/system_root", "ext4", MS_RDONLY, nullptr)) {
|
||||
@@ -205,20 +198,19 @@ mount_root:
|
||||
|
||||
// For API 28 AVD, it uses legacy SAR setup that requires
|
||||
// special hacks in magiskinit to work properly.
|
||||
if (!is_two_stage && config->emulator) {
|
||||
if (!is_two_stage && config.emulator) {
|
||||
avd_hack = true;
|
||||
// These values are hardcoded for API 28 AVD
|
||||
auto vendor_dev = find_block("vendor");
|
||||
xmkdir("/dev/block", 0755);
|
||||
strcpy(blk_info.block_dev, "/dev/block/vde1");
|
||||
strcpy(blk_info.partname, "vendor");
|
||||
setup_block();
|
||||
xmount(blk_info.block_dev, "/vendor", "ext4", MS_RDONLY, nullptr);
|
||||
xmknod("/dev/block/vde1", S_IFBLK | 0600, vendor_dev);
|
||||
xmount("/dev/block/vde1", "/vendor", "ext4", MS_RDONLY, nullptr);
|
||||
}
|
||||
|
||||
return is_two_stage;
|
||||
}
|
||||
|
||||
void BaseInit::exec_init() {
|
||||
void MagiskInit::exec_init() {
|
||||
// Unmount in reverse order
|
||||
for (auto &p : reversed(mount_list)) {
|
||||
if (xumount2(p.data(), MNT_DETACH) == 0)
|
||||
@@ -228,12 +220,12 @@ void BaseInit::exec_init() {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void BaseInit::prepare_data() {
|
||||
void MagiskInit::prepare_data() {
|
||||
LOGD("Setup data tmp\n");
|
||||
xmkdir("/data", 0755);
|
||||
xmount("magisk", "/data", "tmpfs", 0, "mode=755");
|
||||
|
||||
cp_afc("/init", "/data/magiskinit");
|
||||
cp_afc("/init", REDIR_PATH);
|
||||
cp_afc("/.backup", "/data/.backup");
|
||||
cp_afc("/overlay.d", "/data/overlay.d");
|
||||
}
|
||||
@@ -246,7 +238,7 @@ void MagiskInit::setup_tmp(const char *path) {
|
||||
xmkdir(DEVICEDIR, 0711);
|
||||
xmkdir(WORKERDIR, 0);
|
||||
|
||||
mount_preinit_dir(preinit_dev);
|
||||
mount_preinit_dir();
|
||||
|
||||
cp_afc(".backup/.magisk", MAIN_CONFIG);
|
||||
rm_rf(".backup");
|
||||
@@ -261,7 +253,7 @@ void MagiskInit::setup_tmp(const char *path) {
|
||||
chdir(path);
|
||||
|
||||
// Prepare worker
|
||||
xmount(WORKERDIR, WORKERDIR, nullptr, MS_BIND, nullptr);
|
||||
xmount("magisk", WORKERDIR, "tmpfs", 0, "mode=755");
|
||||
|
||||
// Use isolated devpts if kernel support
|
||||
if (access("/dev/pts/ptmx", F_OK) == 0) {
|
||||
|
@@ -347,12 +347,6 @@ void MagiskInit::patch_ro_root() {
|
||||
chdir("/");
|
||||
}
|
||||
|
||||
void RootFSInit::prepare() {
|
||||
prepare_data();
|
||||
LOGD("Restoring /init\n");
|
||||
rename(backup_init(), "/init");
|
||||
}
|
||||
|
||||
#define PRE_TMPSRC "/magisk"
|
||||
#define PRE_TMPDIR PRE_TMPSRC "/tmp"
|
||||
|
||||
|
@@ -64,7 +64,7 @@ bool MagiskInit::hijack_sepolicy() {
|
||||
// This only happens on Android 8.0 - 9.0
|
||||
|
||||
char buf[4096];
|
||||
ssprintf(buf, sizeof(buf), "%s/fstab/compatible", config->dt_dir);
|
||||
ssprintf(buf, sizeof(buf), "%s/fstab/compatible", config.dt_dir);
|
||||
dt_compat = full_read(buf);
|
||||
if (dt_compat.empty()) {
|
||||
// Device does not do early mount and uses monolithic policy
|
||||
@@ -106,7 +106,7 @@ bool MagiskInit::hijack_sepolicy() {
|
||||
int fd = xopen(MOCK_COMPAT, O_WRONLY);
|
||||
|
||||
char buf[4096];
|
||||
ssprintf(buf, sizeof(buf), "%s/fstab/compatible", config->dt_dir);
|
||||
ssprintf(buf, sizeof(buf), "%s/fstab/compatible", config.dt_dir);
|
||||
xumount2(buf, MNT_DETACH);
|
||||
|
||||
hijack();
|
||||
|
@@ -8,12 +8,13 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
void FirstStageInit::prepare() {
|
||||
void MagiskInit::first_stage() {
|
||||
LOGI("First Stage Init\n");
|
||||
prepare_data();
|
||||
|
||||
if (struct stat st{}; fstatat(-1, "/sdcard", &st, AT_SYMLINK_NOFOLLOW) != 0 &&
|
||||
fstatat(-1, "/first_stage_ramdisk/sdcard", &st, AT_SYMLINK_NOFOLLOW) != 0) {
|
||||
if (config->force_normal_boot) {
|
||||
if (config.force_normal_boot) {
|
||||
xmkdirs("/first_stage_ramdisk/storage/self", 0755);
|
||||
xsymlink("/system/system/bin/init", "/first_stage_ramdisk/storage/self/primary");
|
||||
LOGD("Symlink /first_stage_ramdisk/storage/self/primary -> /system/system/bin/init\n");
|
||||
@@ -29,8 +30,8 @@ void FirstStageInit::prepare() {
|
||||
LOGD("Bind mount /sdcard -> /sdcard\n");
|
||||
} else {
|
||||
// rootfs before 3.12
|
||||
xmount("/data/magiskinit", "/sdcard", nullptr, MS_BIND, nullptr);
|
||||
LOGD("Bind mount /sdcard -> /data/magiskinit\n");
|
||||
xmount(REDIR_PATH, "/sdcard", nullptr, MS_BIND, nullptr);
|
||||
LOGD("Bind mount " REDIR_PATH " -> /sdcard\n");
|
||||
}
|
||||
restore_ramdisk_init();
|
||||
} else {
|
||||
@@ -44,7 +45,7 @@ void FirstStageInit::prepare() {
|
||||
}
|
||||
}
|
||||
|
||||
void LegacySARInit::first_stage_prep() {
|
||||
void MagiskInit::redirect_second_stage() {
|
||||
// Patch init binary
|
||||
int src = xopen("/init", O_RDONLY);
|
||||
int dest = xopen("/data/init", O_CREAT | O_WRONLY, 0);
|
||||
@@ -61,7 +62,8 @@ void LegacySARInit::first_stage_prep() {
|
||||
xmount("/data/init", "/init", nullptr, MS_BIND, nullptr);
|
||||
}
|
||||
|
||||
bool SecondStageInit::prepare() {
|
||||
void MagiskInit::second_stage() {
|
||||
LOGI("Second Stage Init\n");
|
||||
umount2("/init", MNT_DETACH);
|
||||
umount2(INIT_PATH, MNT_DETACH); // just in case
|
||||
unlink("/data/init");
|
||||
@@ -76,7 +78,8 @@ bool SecondStageInit::prepare() {
|
||||
// We are still on rootfs, so make sure we will execute the init of the 2nd stage
|
||||
unlink("/init");
|
||||
xsymlink(INIT_PATH, "/init");
|
||||
return true;
|
||||
patch_rw_root();
|
||||
} else {
|
||||
patch_ro_root();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@@ -37,7 +37,7 @@ if [ -z "$FIRST_STAGE" ]; then
|
||||
export ASH_STANDALONE=1
|
||||
if [ $(./busybox id -u) -ne 0 ]; then
|
||||
# Re-exec script with root
|
||||
exec /system/xbin/su 0 ./busybox sh $0
|
||||
exec /system/xbin/su 0 /data/local/tmp/busybox sh $0
|
||||
else
|
||||
# Re-exec script with busybox
|
||||
exec ./busybox sh $0
|
||||
@@ -66,7 +66,7 @@ fi
|
||||
|
||||
# Stop zygote (and previous setup if exists)
|
||||
magisk --stop 2>/dev/null
|
||||
stop
|
||||
stop zygote
|
||||
if [ -d /debug_ramdisk ]; then
|
||||
umount -l /debug_ramdisk 2>/dev/null
|
||||
fi
|
||||
@@ -141,16 +141,17 @@ ln -s ./magisk $MAGISKTMP/resetprop
|
||||
ln -s ./magiskpolicy $MAGISKTMP/supolicy
|
||||
|
||||
mkdir -p $MAGISKTMP/.magisk/device
|
||||
mkdir -p $MAGISKTMP/.magisk/worker
|
||||
mount -t tmpfs -o 'mode=0755' magisk $MAGISKTMP/.magisk/worker
|
||||
mount --make-private $MAGISKTMP/.magisk/worker
|
||||
touch $MAGISKTMP/.magisk/config
|
||||
|
||||
export MAGISKTMP
|
||||
MAKEDEV=1 $MAGISKTMP/magisk --preinit-device 2>&1
|
||||
|
||||
RULESCMD=""
|
||||
for r in $MAGISKTMP/.magisk/preinit/*/sepolicy.rule; do
|
||||
[ -f "$r" ] || continue
|
||||
RULESCMD="$RULESCMD --apply $r"
|
||||
done
|
||||
rule="$MAGISKTMP/.magisk/preinit/sepolicy.rule"
|
||||
[ -f "$rule" ] && RULESCMD="--apply $rule"
|
||||
|
||||
# SELinux stuffs
|
||||
if [ -d /sys/fs/selinux ]; then
|
||||
@@ -165,5 +166,8 @@ fi
|
||||
|
||||
# Boot up
|
||||
$MAGISKTMP/magisk --post-fs-data
|
||||
start
|
||||
start zygote
|
||||
$MAGISKTMP/magisk --service
|
||||
# Make sure reset nb prop after zygote starts
|
||||
sleep 2
|
||||
$MAGISKTMP/magisk --boot-complete
|
||||
|
@@ -8,7 +8,7 @@ lsposed_url='https://github.com/LSPosed/LSPosed/releases/download/v1.9.2/LSPosed
|
||||
emu_pid=
|
||||
|
||||
atd_min_api=30
|
||||
atd_max_api=34
|
||||
atd_max_api=35
|
||||
lsposed_min_api=27
|
||||
lsposed_max_api=34
|
||||
huge_ram_min_api=26
|
||||
@@ -25,6 +25,7 @@ cleanup() {
|
||||
}
|
||||
|
||||
wait_for_bootanim() {
|
||||
set -e
|
||||
adb wait-for-device
|
||||
while true; do
|
||||
local result="$(adb exec-out getprop init.svc.bootanim)"
|
||||
@@ -38,6 +39,7 @@ wait_for_bootanim() {
|
||||
}
|
||||
|
||||
wait_for_boot() {
|
||||
set -e
|
||||
adb wait-for-device
|
||||
while true; do
|
||||
local result="$(adb exec-out getprop sys.boot_completed)"
|
||||
@@ -79,8 +81,15 @@ test_emu() {
|
||||
|
||||
test_setup $variant
|
||||
|
||||
# Install LSPosed
|
||||
local lsposed
|
||||
if [ $api -ge $lsposed_min_api -a $api -le $lsposed_max_api ]; then
|
||||
lsposed=true
|
||||
else
|
||||
lsposed=false
|
||||
fi
|
||||
|
||||
# Install LSPosed
|
||||
if $lsposed; then
|
||||
adb push out/lsposed.zip /data/local/tmp/lsposed.zip
|
||||
echo 'PATH=$PATH:/debug_ramdisk magisk --install-module /data/local/tmp/lsposed.zip' | adb shell /system/xbin/su
|
||||
fi
|
||||
@@ -91,7 +100,7 @@ test_emu() {
|
||||
test_app
|
||||
|
||||
# Try to launch LSPosed
|
||||
if [ $api -ge $lsposed_min_api -a $api -le $atd_max_api ]; then
|
||||
if $lsposed; then
|
||||
adb shell rm -f /data/local/tmp/window_dump.xml
|
||||
adb shell am start -c org.lsposed.manager.LAUNCH_MANAGER com.android.shell/.BugreportWarningActivity
|
||||
while adb shell '[ ! -f /data/local/tmp/window_dump.xml ]'; do
|
||||
@@ -113,6 +122,7 @@ run_test() {
|
||||
TiramisuPrivacySandbox) api=33 ;;
|
||||
UpsideDownCakePrivacySandbox) api=34 ;;
|
||||
VanillaIceCream) api=35 ;;
|
||||
Baklava) api=36 ;;
|
||||
*)
|
||||
print_error "! Unknown system image version '$ver'"
|
||||
exit 1
|
||||
@@ -211,11 +221,11 @@ curl -L $lsposed_url -o out/lsposed.zip
|
||||
if [ -n "$1" ]; then
|
||||
run_test $1 $2
|
||||
else
|
||||
for api in $(seq 23 34); do
|
||||
for api in $(seq 23 35); do
|
||||
run_test $api
|
||||
done
|
||||
# Android 15 Beta
|
||||
run_test 35 google_apis
|
||||
# Android 16 Beta
|
||||
run_test Baklava google_apis
|
||||
# Run 16k page tests
|
||||
run_test 35 google_apis_ps16k
|
||||
fi
|
||||
|
Reference in New Issue
Block a user