From a49002bb2c18ea6e2140b165e2ac3b441e9d1d5d Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Tue, 15 Oct 2019 03:33:22 -0400 Subject: [PATCH 01/61] Reorganize string resources --- README.MD | 6 +- app/src/main/res/values-ar/strings.xml | 3 + app/src/main/res/values-az/strings.xml | 180 +------- app/src/main/res/values-bg/strings.xml | 3 + app/src/main/res/values-ca/strings.xml | 3 + app/src/main/res/values-cs/strings.xml | 3 + app/src/main/res/values-de/strings.xml | 3 + app/src/main/res/values-el/strings.xml | 3 + app/src/main/res/values-es/strings.xml | 37 +- app/src/main/res/values-et/strings.xml | 3 + app/src/main/res/values-fr/strings.xml | 3 + app/src/main/res/values-hr/strings.xml | 3 + app/src/main/res/values-in/strings.xml | 3 + app/src/main/res/values-it/strings.xml | 389 +++++++++--------- app/src/main/res/values-ja/strings.xml | 3 + app/src/main/res/values-ko/strings.xml | 3 + app/src/main/res/values-lt/strings.xml | 3 + app/src/main/res/values-mk/strings.xml | 3 + app/src/main/res/values-nb/strings.xml | 3 + app/src/main/res/values-nl/strings.xml | 3 + app/src/main/res/values-pl/strings.xml | 61 +-- app/src/main/res/values-pt-rBR/strings.xml | 3 + app/src/main/res/values-pt-rPT/strings.xml | 3 + app/src/main/res/values-ro/strings.xml | 3 + app/src/main/res/values-ru/strings.xml | 3 + app/src/main/res/values-sk/strings.xml | 3 + app/src/main/res/values-sr/strings.xml | 3 + app/src/main/res/values-sv/strings.xml | 3 + app/src/main/res/values-th/strings.xml | 3 + app/src/main/res/values-tr/strings.xml | 3 + app/src/main/res/values-uk/strings.xml | 3 + app/src/main/res/values-vi/strings.xml | 3 + app/src/main/res/values-zh-rCN/strings.xml | 3 + app/src/main/res/values-zh-rTW/strings.xml | 3 + app/src/main/res/values/resources.xml | 11 + app/src/main/res/values/strings.xml | 3 + shared/src/main/res/values/values.xml | 1 - .../src/main/res/values-ar/strings.xml | 0 .../src/main/res/values-az/strings.xml | 0 .../src/main/res/values-bg/strings.xml | 0 .../src/main/res/values-ca/strings.xml | 4 +- .../src/main/res/values-cs/strings.xml | 0 .../src/main/res/values-de/strings.xml | 0 .../src/main/res/values-el/strings.xml | 0 .../src/main/res/values-es/strings.xml | 0 .../src/main/res/values-et/strings.xml | 1 - .../src/main/res/values-fr/strings.xml | 1 - .../src/main/res/values-hr/strings.xml | 0 .../src/main/res/values-in/strings.xml | 0 .../src/main/res/values-it/strings.xml | 0 .../src/main/res/values-ja/strings.xml | 0 .../src/main/res/values-ko/strings.xml | 0 .../src/main/res/values-lt/strings.xml | 0 .../src/main/res/values-mk/strings.xml | 1 - .../src/main/res/values-nb/strings.xml | 1 - .../src/main/res/values-nl/strings.xml | 0 .../src/main/res/values-pl/strings.xml | 0 .../src/main/res/values-pt-rBR/strings.xml | 0 .../src/main/res/values-pt-rPT/strings.xml | 0 .../src/main/res/values-ro/strings.xml | 0 .../src/main/res/values-ru/strings.xml | 0 .../src/main/res/values-sk/strings.xml | 1 - .../src/main/res/values-sr/strings.xml | 0 .../src/main/res/values-sv/strings.xml | 0 .../src/main/res/values-th/strings.xml | 3 - .../src/main/res/values-tr/strings.xml | 0 .../src/main/res/values-uk/strings.xml | 0 .../src/main/res/values-vi/strings.xml | 0 .../src/main/res/values-zh-rCN/strings.xml | 0 .../src/main/res/values-zh-rTW/strings.xml | 0 .../src/main/res/values/strings.xml | 10 +- 71 files changed, 360 insertions(+), 437 deletions(-) create mode 100644 app/src/main/res/values/resources.xml rename {shared => stub}/src/main/res/values-ar/strings.xml (100%) rename {shared => stub}/src/main/res/values-az/strings.xml (100%) rename {shared => stub}/src/main/res/values-bg/strings.xml (100%) rename {shared => stub}/src/main/res/values-ca/strings.xml (86%) rename {shared => stub}/src/main/res/values-cs/strings.xml (100%) rename {shared => stub}/src/main/res/values-de/strings.xml (100%) rename {shared => stub}/src/main/res/values-el/strings.xml (100%) rename {shared => stub}/src/main/res/values-es/strings.xml (100%) rename {shared => stub}/src/main/res/values-et/strings.xml (90%) rename {shared => stub}/src/main/res/values-fr/strings.xml (92%) rename {shared => stub}/src/main/res/values-hr/strings.xml (100%) rename {shared => stub}/src/main/res/values-in/strings.xml (100%) rename {shared => stub}/src/main/res/values-it/strings.xml (100%) rename {shared => stub}/src/main/res/values-ja/strings.xml (100%) rename {shared => stub}/src/main/res/values-ko/strings.xml (100%) rename {shared => stub}/src/main/res/values-lt/strings.xml (100%) rename {shared => stub}/src/main/res/values-mk/strings.xml (93%) rename {shared => stub}/src/main/res/values-nb/strings.xml (91%) rename {shared => stub}/src/main/res/values-nl/strings.xml (100%) rename {shared => stub}/src/main/res/values-pl/strings.xml (100%) rename {shared => stub}/src/main/res/values-pt-rBR/strings.xml (100%) rename {shared => stub}/src/main/res/values-pt-rPT/strings.xml (100%) rename {shared => stub}/src/main/res/values-ro/strings.xml (100%) rename {shared => stub}/src/main/res/values-ru/strings.xml (100%) rename {shared => stub}/src/main/res/values-sk/strings.xml (90%) rename {shared => stub}/src/main/res/values-sr/strings.xml (100%) rename {shared => stub}/src/main/res/values-sv/strings.xml (100%) rename {shared => stub}/src/main/res/values-th/strings.xml (83%) rename {shared => stub}/src/main/res/values-tr/strings.xml (100%) rename {shared => stub}/src/main/res/values-uk/strings.xml (100%) rename {shared => stub}/src/main/res/values-vi/strings.xml (100%) rename {shared => stub}/src/main/res/values-zh-rCN/strings.xml (100%) rename {shared => stub}/src/main/res/values-zh-rTW/strings.xml (100%) rename {shared => stub}/src/main/res/values/strings.xml (60%) diff --git a/README.MD b/README.MD index 2a5be0cb5..0f950d7d5 100644 --- a/README.MD +++ b/README.MD @@ -30,12 +30,12 @@ Furthermore, Magisk provides a **Systemless Interface** to alter the system (or ## Translations -Default string resources for Magisk Manager are scattered throughout +Default string resources for Magisk Manager and its stub APK are located here: - `app/src/main/res/values/strings.xml` -- `shared/src/main/res/values/strings.xml` +- `stub/src/main/res/values/strings.xml` -Translate each and place them in the respective locations (`/src/main/res/values-/strings.xml`). +Translate each and place them in the respective locations (`[module]/src/main/res/values-[lang]/strings.xml`). ## Signature Verification diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 708b2223a..1ed6f8f6e 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -89,6 +89,9 @@ إعادة التشغيل خلال خمس ثواني… + لا شكراً + نعم + موافق إغلاق تثبيت %1$s هل تريد تثبيت %1$s ? diff --git a/app/src/main/res/values-az/strings.xml b/app/src/main/res/values-az/strings.xml index 3f4d0b1c2..4fdb0b851 100644 --- a/app/src/main/res/values-az/strings.xml +++ b/app/src/main/res/values-az/strings.xml @@ -1,122 +1,70 @@ - Əlavələr - Endirmələr - Superuser - Log - Tənzimləmələr - Quraşdır - Dəstəklənməyən Magisk Versiyası - Magisk Manager\'in bu versiyası Magisk\'in v18.0 versiyasndan aşağısını dəstəkləmir.\n\nMagisk\'i əllə yüksəldə, yaxud tətbiqi əvvəlki versiyalarına qaytara bilərsiniz. - Magisk yüklənməyib. - Yeniləmələr yoxlanılır… - Etibarsız Yeniləmə Kanalı - SafetyNet vəziyətinə bax - SafetyNet vəziyəti yoxlanılır… - SafetyNet Uğurla Yoxlanıldı - SafetyNet API Xətası - Cavab etibarsızdır. - Magisk ən yenidir - Magisk Manager ən yenidir - Qabaqcıl Parametrlər - Şifrələməyə məcbur etməni qoru - AVB 2.0/dm-verity\'i qoru - Yüklənən: %1$s - Ən son: %1$s - Sil - Magisk\'i Sil - Bütün əlavələr ləğv olunacaq/silinəcək. Root silinəcək, və əgər hal-hazırda deyilsə, bütün məlumatlarınız potensiyal olaraq şifrələnəcək. - Yenilə - (Yalnız nüvə modu qoşulub) - (Məlumat təmin edilməyib) - Əlavələr yoxdur. - Əlavə sonrakı yenidən başlatmada yenilənəcək. - Əlavə sonrakı yenidən başlatmada silinəcək. - Əlavə sonrakı yenidən başlatmada silinməyəcək. - Əlavə sonrakı yenidən başlatmada qapadılacaq. - Əlavə sonrakı yenidən başlatmada açılacaq. - %1$s tərəfindən yaradılıb - Bərpa rejimində yenidən başlat - Bootloader\'ə yenidən başlat - Yükləmə rejimində yenidən başlat EDL\'ə yenidən başlat - Yeniləmə Var - Yüklənib - Yüklənməyib - Yeniləmə vaxtı: %1$s - Nizamlama Qaydası - Ada görə nizamla - Son yeniləməyə görə nizamla - Log\'u saxla - Təzələ - Log\'u indi təmizlə - Log uğurla təmizləndi. - Yeniliklər - Magisk Yeniləmələri Nəticə Bildirişləri Yükləmə bitdi @@ -127,262 +75,140 @@ Magisk Manager Yeniləməsi Var! - + Yox, sağolun + Bəli + OK Qapat - %1$s faylını yüklə - %1$s faylını indi yükləmək istəyirsiniz? - Yüklə - Yenidən Başlat - Tənzimləmələri saxlamaq üçün yenidən başladın. - Yeniliklər - Repo keşi silindi - Yükləyib quraşdırmaq üçün toxun. - DTBO yamaqlanıb! - Magisk Manager dtbo.img\'ni yamaqladı. Xahiş olunur yenidən başladın. - Qurulur - Magisk Manager gizlədilir… - Magisk Manager\'i gizlətmək alınmadı. - Keçid açmağa heçbir tətbiq tapılmadı. - Yalnız Zip yüklə - Birdəfəlik Yüklə (Tövsiyə olunur) - Fayl Seç və Yamaqla - Fəal olmayan slota quraşdır (OTA\'dan sonra) - Xəbərdarlıq - Cihazınız yenidən başladıldıqdan sonra fəal olmayan slota başlamağa MƏCBUR ediləcək!\nBu seçimi yalnız OTA bitdikdən sonra istifadə edin.\nDavam edirsiniz? - Üsul Seçin - Silməni Bitir - Surətləri Qaytar - Geri qaytarılır… - Geri qaytarma bitdi! - Stock nüsxə mövcud deyil! - Özəl kodu yükləyin - Magisk Manager açıq lisenziyalıdır və Google\'ın özəl SafetyNet API kodunu ehtiva etmir.\n\Magisk Managerə SafetyNet yoxlamaları üçün tərkibində GoogleApiClient olan əlavəni yükləməyə icazə verirsiniz? - Quraşdırma alınmadı. - Əlavə Quraşdırma Lazımdır - Cihazınızın Magisk\'in düzgün işləməsi üçün əlavə quraşdırmaya ehtiyacı var . Bu Magisk zip faylını endirəcək, davam etmək istəyirsiniz? - Əlavə quraşdırma - Quraşdırma yerinə yetirilir… - Ümumi - Qaranlıq Mövzu - Qaranlıq mövzunu aç. - Repo Keşini Təmizlə - Onlayn repolar üçün keşlənmiş məlumatı silin. Bu tətbiqi onlayn şəkildə yenilənməyə məcbur edir. - Magisk Manager\'i Gizlə - Magisk Manager\'i təsadüfi adla yenidən sıxışdır. - Magisk Manager\'i Geri Qaytar - Magisk Manager\'i orjinal sıxışdırma ilə geri qaytar - Dil - (Sistem Dili) - Tənzimləmələri Yenilə - Yeniləmələri Yoxla - Axraplanda vaxtaşırı yeniləmələri yoxla. - Kanalı Yenilə - Stabil - Beta - Özəl - Özəl URL daxil edin - Magisk Yalnız Nüvə Modu - Yalnız nüvə xüsusiyyətlərini aç. MagiskSU və MagiskHide hələ də açıq qalacaq, amma əlavələr yüklənməyəcək. - Magisk\'i fərqli növdə aşkarlamalardan gizləyin. - Sistemsiz host\'lar - Adblock tətbiqləri üçün Sistemsiz host dəstəyi. - Sistemsiz host əlavəsi quraşdırıldı - Tətbiqlər və ADB - Yalnız Tətbiqlər - Yalnız ADB - Qapalı - 10 saniyə - 15 saniyə - 20 saniyə - 30 saniyə - 45 saniyə - 60 saniyə - Superuser İcazəsi - Avtomatik Cavab - İcazə Vaxtaşımı - Superuser Bildirişləri - %1$d saniyə - Yüksəltmədən sonra Yenidən İdentifikasiya et - Tətbiq yeniləmələridən sonra superuser icazələrini yenidən identifikasiya et - Barmaq İzi İdentifikasiyasını Aç - Barmaq izi oxuyucunu superuser icazələri üçün işlət - Barmaq izini İdentifikasiya et - Çox-istifadəçi modu - Yalnız cihaz sahibi - Cihaz sahibinin idarəçiliyində - İstifadəçidən asılı olmayaraq - Yalnız cihaz sahibinin root icazəsi var. - Yalnız cihaz sahibi root icazələrini redaktə edə və icazə istəkləri qəbul edə bilər. - Hər istifadəçinin ayrı root qaydaları var. - Namespace Modunu Qoş - Qlobal Namespace - Keçmə Namespace - Ayrılmış Namespace - Bütün root sessyaları qlobal qoşma namespace\'dən istifadə edir. - Root sessyaları soruşulan namespace\'ləri birindən digərinə keçirəcək. - Hər bir root sessyasının ayrılmış namespace\'i olacaq. - Android 8.0+\'da dəstəklənmir. - Barmaq izi təyin edilməyib ya da dəstəklənmir. - Superuser Tələbi - Ləğv et - Yönləndir - Təmin et - Cihazın tam icazəsi ilə təmin edin.\nƏmin deyilsinizsə ləğv edin! - Sonsuz - Bir dəfəlik - 10 dəq - 20 dəq - 30 dəq - 60 dəq - %1$s SuperUser icazəsi ilə təmin edildi - %1$s SuperUser icazəsi ilə təmin edilmədi - Tətbiq yoxdur - %1$s üçün Superuser icazəsi verilib - %1$s üçün Superuser icazəsi verilməyib - %1$s üçün bildirişlər açıqdır - %1$s üçün bildirişlər bağlıdır - %1$s üçün giriş açıqdır - %1$s üçün giriş bağlıdır - Ləğv olunsun? - %1$s üçün haqları ləğv etməyi təsdiq edirsiniz? - Tost - Heçnə - İdentifikasiya xətası - PID: %1$d - Hədəf UID: %1$d - Komanda: %1$s - Sistem tətbiqlərini göstər - diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml index 5f7cce367..002f1a957 100644 --- a/app/src/main/res/values-bg/strings.xml +++ b/app/src/main/res/values-bg/strings.xml @@ -61,6 +61,9 @@ Списък с промени + Не, благодаря. + Да + OK Затваряне Инсталиране на %1$s Желаете ли да инсталирате %1$s сега? diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index 7f1af1549..d3076996b 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -87,6 +87,9 @@ Reinici en 5 segons… + No, gràcies + + Ok Tancar Instal·lar %1$s Vols instal·lar %1$s ara? diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 13679ed99..1059e8bc5 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -84,6 +84,9 @@ Restartování za 5 sekund… + Ne, díky + Ano + OK Zavřít Instalovat %1$s Chcete nyní nainstalovat %1$s? diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index b17951ed0..e2eb35a26 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -84,6 +84,9 @@ Neustart in 5 Sekunden… + Nein danke + Ja + OK Schließen Installiere %1$s Möchtest du %1$s installieren? diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index d8e3a535a..b81fb8d5f 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -62,6 +62,9 @@ Καταγραφή αλλαγών εφαρμογής + Όχι ευχαριστώ + Ναι + OK Κλείσιμο Εγκατάσταση %1$s Θέλετε να εγκαταστήσετε το %1$s τώρα; diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 44722a4d6..8788c1c55 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -24,7 +24,7 @@ Ajustes avanzados Mantener cifrado forzado Mantener AVB 2.0/dm-verity - Modo Recovery + Modo Recovery Instalada: %1$s Última: %1$s Desinstalar @@ -45,7 +45,7 @@ Reiniciar en Modo Recovery Reiniciar en Modo Bootloader Reiniciar en Modo Download - Reiniciar en Modo EDL + Reiniciar en Modo EDL Actualización Disponible @@ -72,20 +72,23 @@ Error descargando archivo Actualización de Magisk disponible! Actualización de Magisk Manager disponible! - - - Pulse para descargar e instalar - Descargar sólo el archivo ZIP - Instalación Directa (Recomendado) - Instalar en ranura inactiva (después de OTA) - ¡Se forzará su dispositivo para que arranque en la ranura inactiva actual después de un reinicio!\nUtilice esta opción solo después de que se haya completado la OTA.\nContinuar? - Seleccionar Método - Configuración Adicional - Seleccionar y parchear un archivo - Seleccione una imagen raw (* .img) o un archivo tar de ODIN (* .tar) - Reiniciando en 5 segundos… - + + + Pulse para descargar e instalar + Descargar sólo el archivo ZIP + Instalación Directa (Recomendado) + Instalar en ranura inactiva (después de OTA) + ¡Se forzará su dispositivo para que arranque en la ranura inactiva actual después de un reinicio!\nUtilice esta opción solo después de que se haya completado la OTA.\nContinuar? + Seleccionar Método + Configuración Adicional + Seleccionar y parchear un archivo + Seleccione una imagen raw (* .img) o un archivo tar de ODIN (* .tar) + Reiniciando en 5 segundos… + + No gracias + + Aceptar Cerrar Instalar %1$s ¿Quieres instalar %1$s ahora? @@ -121,7 +124,7 @@ Tema oscuro Habilitar el tema oscuro Ruta de Descarga - Los archivos se guardarán en %1$s + Los archivos se guardarán en %1$s Limpiar caché del repositorio Limpiar la información en caché para los repositorios en línea, fuerza a la aplicación a actualizar en línea Ocultar Magisk Manager @@ -218,5 +221,5 @@ Mostrar sistema - + diff --git a/app/src/main/res/values-et/strings.xml b/app/src/main/res/values-et/strings.xml index 46006d63b..403d400bd 100644 --- a/app/src/main/res/values-et/strings.xml +++ b/app/src/main/res/values-et/strings.xml @@ -88,6 +88,9 @@ Taaskäivitamine 5 sekundi pärast… + Tänan ei + Jah + OK Sulge Installi %1$s Kas soovid kohe installida %1$s? diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 47c188174..dfad5ac62 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -88,6 +88,9 @@ Redémarrage dans 5 secondes… + Non merci + Oui + OK Fermer Installer %1$s Voulez‐vous installer %1$s maintenant ? diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml index c3388c82c..d67260c55 100644 --- a/app/src/main/res/values-hr/strings.xml +++ b/app/src/main/res/values-hr/strings.xml @@ -55,6 +55,9 @@ Popis izmjena aplikacije + Ne hvala + Da + OK Zatvori Instaliraj %1$s Da li želite instalirati %1$s sada? diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index 41ed173d5..fc32437ae 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -86,6 +86,9 @@ Me-reboot dalam 5 detik… + Tidak, terima kasih + Ya + OK Tutup Pasang %1$s Apakah Anda ingin memasang %1$s sekarang? diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 2b1d5f4d3..add53ea18 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -1,223 +1,226 @@ - - Moduli - Download - Superuser - Registro eventi - Impostazioni - Installa - Versione di Magisk non supportata - Questa versione di Magisk Manager non supporta versioni di Magisk inferiori alla v18.0.\n\nPuoi aggiornare manualmente Magisk o tornare a una versione meno recente dell\'app. + + Moduli + Download + Superuser + Registro eventi + Impostazioni + Installa + Versione di Magisk non supportata + Questa versione di Magisk Manager non supporta versioni di Magisk inferiori alla v18.0.\n\nPuoi aggiornare manualmente Magisk o tornare a una versione meno recente dell\'app. - - Magisk non è installato. - Controllo aggiornamenti… - Canale di aggiornamento non valido - Tocca per controllare SafetyNet - Controllo stato SafetyNet… - Controllo SafetyNet Superato - Errore API SafetyNet - La risposta non è valida. - Magisk è aggiornato - Magisk Manager è aggiornato - Impostazioni avanzate - Mantieni crittografia forzata - Mantieni AVB 2.0/dm-verity - Installata: %1$s - Ultima: %1$s - Disinstalla - Disinstalla Magisk - Tutti i moduli verranno disabilitati/rimossi. Il root verrà rimosso e i tuoi dati potrebbero essere criptati, nel caso non lo siano già. - Aggiorna - (Modalità solo Core abilitata) + + Magisk non è installato. + Controllo aggiornamenti… + Canale di aggiornamento non valido + Tocca per controllare SafetyNet + Controllo stato SafetyNet… + Controllo SafetyNet Superato + Errore API SafetyNet + La risposta non è valida. + Magisk è aggiornato + Magisk Manager è aggiornato + Impostazioni avanzate + Mantieni crittografia forzata + Mantieni AVB 2.0/dm-verity + Installata: %1$s + Ultima: %1$s + Disinstalla + Disinstalla Magisk + Tutti i moduli verranno disabilitati/rimossi. Il root verrà rimosso e i tuoi dati potrebbero essere criptati, nel caso non lo siano già. + Aggiorna + (Modalità solo Core abilitata) - - (Nessuna informazione) - Nessun modulo trovato. - Il modulo sarà aggiornato al prossimo riavvio. - Il modulo sarà rimosso al prossimo riavvio. - Il modulo non sarà rimosso al prossimo riavvio. - Il modulo sarà disabilitato al prossimo riavvio. - Il modulo sarà abilitato al prossimo riavvio. - Creato da: %1$s - Riavvia in Recovery - Riavvia in Bootloader - Riavvia in Download Mode + + (Nessuna informazione) + Nessun modulo trovato. + Il modulo sarà aggiornato al prossimo riavvio. + Il modulo sarà rimosso al prossimo riavvio. + Il modulo non sarà rimosso al prossimo riavvio. + Il modulo sarà disabilitato al prossimo riavvio. + Il modulo sarà abilitato al prossimo riavvio. + Creato da: %1$s + Riavvia in Recovery + Riavvia in Bootloader + Riavvia in Download Mode - - Aggiornamento disponibile - Installato - Non installato - Aggiornato il: %1$s - Ordinamento - Ordina per nome - Ordina per ultimo aggiornamento + + Aggiornamento disponibile + Installato + Non installato + Aggiornato il: %1$s + Ordinamento + Ordina per nome + Ordina per ultimo aggiornamento - - Salva registro eventi - Ricarica - Svuota il registro eventi - Registro eventi svuotato correttamente. + + Salva registro eventi + Ricarica + Svuota il registro eventi + Registro eventi svuotato correttamente. - Novità + Novità - Aggiornamenti Magisk - Notifiche di avanzamento - Download completato + Aggiornamenti Magisk + Notifiche di avanzamento + Download completato Errore durante il download del file Mostra nella cartella padre - Mostra file - È disponibile un aggiornamento di Magisk! - È disponibile un aggiornamento di Magisk Manager! + Mostra file + È disponibile un aggiornamento di Magisk! + È disponibile un aggiornamento di Magisk Manager! - - Apri questa notifica per scaricare e installare. - Scarica solo il file zip - Installazione diretta (raccomandata) - Installa nello slot inattivo (dopo un OTA) - Questo dispositivo verrà FORZATO ad avviarsi usando lo slot inattivo!\nUsa questo metodo solo dopo che un OTA è stato installato.\nVuoi continuare? - Seleziona un metodo - Configurazione aggiuntiva - Seleziona e aggiorna un file - Seleziona un\'immagine in formato .img o un file ODIN .tar - Riavvio fra 5 secondi… - - - Chiudi - Installazione di %1$s - Vuoi installare %1$s? - Download - Riavvia - Riavvia per applicare i cambiamenti. - Note di rilascio - La cache delle repository è stata svuotata + + Apri questa notifica per scaricare e installare. + Scarica solo il file zip + Installazione diretta (raccomandata) + Installa nello slot inattivo (dopo un OTA) + Questo dispositivo verrà FORZATO ad avviarsi usando lo slot inattivo!\nUsa questo metodo solo dopo che un OTA è stato installato.\nVuoi continuare? + Seleziona un metodo + Configurazione aggiuntiva + Seleziona e aggiorna un file + Seleziona un\'immagine in formato .img o un file ODIN .tar + Riavvio fra 5 secondi… + + + No, grazie + + OK + Chiudi + Installazione di %1$s + Vuoi installare %1$s? + Download + Riavvia + Riavvia per applicare i cambiamenti. + Note di rilascio + La cache delle repository è stata svuotata DTBO è stato aggiornato! - Magisk Manager ha aggiornato dtbo.img. Riavvia per completare. - Flash in corso… - Completato! - Fallito - Nascondendo Magisk Manager… - Non è stato possibile nascondere Magisk Manager. - Nessuna app disponibile per aprire il link. - Attenzione - Disinstallazione completa - Ripristina Immagini - Ripristino… - Ripristino completato! - Non esiste un\'immagine originale di boot! - Scarica codice proprietario - Magisk Manager è FOSS e non contiene codice proprietario delle API Google SafetyNet.\n\nVuoi scaricare un\'estensione (contenente GoogleApiClient) per controllare lo stato di SafetyNet? - Configurazione fallita. - Configurazione aggiuntiva richiesta - Il tuo dispositivo necessita di una configurazione aggiuntiva per far funzionare Magisk correttamente. Verrà scaricato il file zip di Magisk, vuoi procedere ora? - Configurazione dell\'ambiente in corso… + Magisk Manager ha aggiornato dtbo.img. Riavvia per completare. + Flash in corso… + Completato! + Fallito + Nascondendo Magisk Manager… + Non è stato possibile nascondere Magisk Manager. + Nessuna app disponibile per aprire il link. + Attenzione + Disinstallazione completa + Ripristina Immagini + Ripristino… + Ripristino completato! + Non esiste un\'immagine originale di boot! + Scarica codice proprietario + Magisk Manager è FOSS e non contiene codice proprietario delle API Google SafetyNet.\n\nVuoi scaricare un\'estensione (contenente GoogleApiClient) per controllare lo stato di SafetyNet? + Configurazione fallita. + Configurazione aggiuntiva richiesta + Il tuo dispositivo necessita di una configurazione aggiuntiva per far funzionare Magisk correttamente. Verrà scaricato il file zip di Magisk, vuoi procedere ora? + Configurazione dell\'ambiente in corso… Generale - Tema scuro - Abilita il tema scuro. + Tema scuro + Abilita il tema scuro. Percorso di download I file verranno salvati in %1$s - Svuota cache repository - Svuota la cache delle repository. Questa opzione forza l\'aggiornamento online dell\'app. - Nascondi Magisk Manager - Reinstalla Magisk Manager con un nome pacchetto casuale. - Ripristina Magisk Manager - Ripristina Magisk Manager con il nome pacchetto originale - Lingua - (Sistema) - Impostazioni aggiornamento - Controlla aggiornamenti - Controlla automaticamente gli aggiornamenti in background. - Canale di aggiornamento - Stabile - Beta - Personalizzato - Inserisci un URL personalizzato - Modalità Magisk Core - Abilita solo le funzioni principali. Nessun modulo verrà caricato. MagiskSU e MagiskHide rimarranno abilitati - Nasconde Magisk da numerose rilevazioni. - Host systemless - Supporto a host systemless per le app che bloccano le pubblicità. - Aggiunto modulo per host systemless + Svuota cache repository + Svuota la cache delle repository. Questa opzione forza l\'aggiornamento online dell\'app. + Nascondi Magisk Manager + Reinstalla Magisk Manager con un nome pacchetto casuale. + Ripristina Magisk Manager + Ripristina Magisk Manager con il nome pacchetto originale + Lingua + (Sistema) + Impostazioni aggiornamento + Controlla aggiornamenti + Controlla automaticamente gli aggiornamenti in background. + Canale di aggiornamento + Stabile + Beta + Personalizzato + Inserisci un URL personalizzato + Modalità Magisk Core + Abilita solo le funzioni principali. Nessun modulo verrà caricato. MagiskSU e MagiskHide rimarranno abilitati + Nasconde Magisk da numerose rilevazioni. + Host systemless + Supporto a host systemless per le app che bloccano le pubblicità. + Aggiunto modulo per host systemless - App e ADB - Solo app - Solo ADB - Disabilitato - 10 secondi - 15 secondi - 20 secondi - 30 secondi - 45 secondi - 60 secondi - Accesso Superuser - Accesso predefinito - Timeout richiesta - Notifica Superuser - %1$d secondi - Riautentica dopo aggiornamento - Riautentica i permessi Superuser dopo un aggiornamento dell\'app - Abilita autenticazione impronta - Utilizza il sensore di impronte per accettare le richieste Superuser - Conferma impronta + App e ADB + Solo app + Solo ADB + Disabilitato + 10 secondi + 15 secondi + 20 secondi + 30 secondi + 45 secondi + 60 secondi + Accesso Superuser + Accesso predefinito + Timeout richiesta + Notifica Superuser + %1$d secondi + Riautentica dopo aggiornamento + Riautentica i permessi Superuser dopo un aggiornamento dell\'app + Abilita autenticazione impronta + Utilizza il sensore di impronte per accettare le richieste Superuser + Conferma impronta - Modalità multiutente - Solo proprietario del dispositivo - Gestito dal proprietario utente - Idipendente dall\'utente - Solo il proprietario ha i permessi di root. - Solo il proprietario può gestire accesso root e ricevere richieste. - Ogni utente ha le sue regole di root indpendenti. + Modalità multiutente + Solo proprietario del dispositivo + Gestito dal proprietario utente + Idipendente dall\'utente + Solo il proprietario ha i permessi di root. + Solo il proprietario può gestire accesso root e ricevere richieste. + Ogni utente ha le sue regole di root indpendenti. - Modalità mount namespace - Namespace globale - Namespace ereditato - Namespace isolato - Tutte le sessioni di root erediteranno il namespace globale. - Le sessioni di root erediteranno il namespace del loro richiedente. - Ogni sessione di root avrà il suo namespace isolato. - Non è supportato da Android 8.0+. - Non è presente alcuna impronta o il dispositivo non è supportato. - Errore durante la creazione della cartella. Deve essere accessibile dalla radice della memoria di archiviazione e non essere un file. + Modalità mount namespace + Namespace globale + Namespace ereditato + Namespace isolato + Tutte le sessioni di root erediteranno il namespace globale. + Le sessioni di root erediteranno il namespace del loro richiedente. + Ogni sessione di root avrà il suo namespace isolato. + Non è supportato da Android 8.0+. + Non è presente alcuna impronta o il dispositivo non è supportato. + Errore durante la creazione della cartella. Deve essere accessibile dalla radice della memoria di archiviazione e non essere un file. - - Richiesta Superuser + + Richiesta Superuser Nega - Chiedi - Concedi - Concede il pieno accesso al dispositivo.\nNega se non sei sicuro! - Sempre - Una volta - 10 minuti - 20 minuti - 30 minuti - 60 minuti - %1$s ha ottenuto i permessi Superuser - %1$s non ha ottenuto i permessi Superuser - Nessuna app trovata - %1$s ha ottenuto i permessi Superuser - %1$s non ha ottenuto i permessi Superuser - Notifiche per %1$s abilitate - Notifiche per %1$s disabilitate - Registro eventi abilitato per %1$s - Registro eventi non abilitato per %1$s + Chiedi + Concedi + Concede il pieno accesso al dispositivo.\nNega se non sei sicuro! + Sempre + Una volta + 10 minuti + 20 minuti + 30 minuti + 60 minuti + %1$s ha ottenuto i permessi Superuser + %1$s non ha ottenuto i permessi Superuser + Nessuna app trovata + %1$s ha ottenuto i permessi Superuser + %1$s non ha ottenuto i permessi Superuser + Notifiche per %1$s abilitate + Notifiche per %1$s disabilitate + Registro eventi abilitato per %1$s + Registro eventi non abilitato per %1$s Vuoi revocare? - Confermi la revoca dei diritti di %1$s? - Toast - Nessuno - Autenticatione fallita + Confermi la revoca dei diritti di %1$s? + Toast + Nessuno + Autenticatione fallita - - PID: %1$d - UID destinazione: %1$d - Comando: %1$s + + PID: %1$d + UID destinazione: %1$d + Comando: %1$s - - Mostra app di sistema + + Mostra app di sistema diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 1bdfab663..952f2c56a 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -72,6 +72,9 @@ Magisk Managerの更新があります! + いいえ + はい + OK 閉じる %1$s をインストール %1$s をインストールしますか? diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 36f165686..c3f376cdb 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -83,6 +83,9 @@ 원시 이미지 (*.img) 또는 오딘 tar 파일 (*.tar) 선택 + 아니오, 괜찮습니다 + + 확인 닫기 %1$s 설치 정말 %1$s을(를) 설치하시겠습니까? diff --git a/app/src/main/res/values-lt/strings.xml b/app/src/main/res/values-lt/strings.xml index 8b83cbbbd..915783032 100644 --- a/app/src/main/res/values-lt/strings.xml +++ b/app/src/main/res/values-lt/strings.xml @@ -61,6 +61,9 @@ Pakeitimų sąrašas + Ačiū, nereikia + Taip + Gerai Uždaryti Instaliuoti %1$s Ar jūs norite instaliuoti %1$s? diff --git a/app/src/main/res/values-mk/strings.xml b/app/src/main/res/values-mk/strings.xml index 721057a09..ca2e43e31 100644 --- a/app/src/main/res/values-mk/strings.xml +++ b/app/src/main/res/values-mk/strings.xml @@ -84,6 +84,9 @@ Рестартирање за 5 секунди… + Не, благодарам + Да + ОК Затвори Инсталирај %1$s Дали сакате да го инсталирате %1$s сега? diff --git a/app/src/main/res/values-nb/strings.xml b/app/src/main/res/values-nb/strings.xml index 7f32d75b2..f5fd61aad 100644 --- a/app/src/main/res/values-nb/strings.xml +++ b/app/src/main/res/values-nb/strings.xml @@ -69,6 +69,9 @@ En Magisk Manager-oppdatering er tilgjengelig! + Nei takk + Ja + OK Lukk Installer %1$s Vil du installere %1$s nå? diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 15d29519b..96913c937 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -62,6 +62,9 @@ App\'s changelog + Nee bedankt + Ja + Oké Sluiten %1$s installeren Zeker weten %1$s installeren? diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 2d65d2b6d..44d0c23f7 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -9,12 +9,12 @@ Instaluj Nieobsługiwana Wersja Magisk Ta wersja Magisk Managera nie obsługuje wersji Magisk niższej niż v18.0.\n\nMożesz albo ręcznie zaktualizować Magisk lub obniżyć w aplikacji do starszej wersji. - - + + Magisk nie jest zainstalowany. Sprawdzanie aktualizacji… Nieprawidłowy Kanał Aktualizacji - Dotknij aby sprawdzić SafetyNet + Dotknij aby sprawdzić SafetyNet Sprawdzanie statusu SafetyNet… SafetyNet Poprawny SafetyNet API Błędny @@ -28,11 +28,11 @@ Ostatnia: %1$s Odinstaluj Odinstaluj Magisk - Wszystkie moduły będą wyłączone/usunięte. Root zostanie usunięty i przywrócone szyfrowanie danych, jeśli nie są te dane obecnie szyfrowane + Wszystkie moduły będą wyłączone/usunięte. Root zostanie usunięty i przywrócone szyfrowanie danych, jeśli nie są te dane obecnie szyfrowane Pobierz (Włączony tylko tryb jądra) - - + + (Nie umieszczono informacji) Nie znaleziono modułów. Moduł zostanie zaktualizowany przy następnym restarcie. @@ -45,12 +45,12 @@ Restart do Bootloadera Restart do Download Restart do EDL - - + + Aktualizacja dostępna Zainstalowany Nie zainstalowany - Zaktualizowano: %1$s + Zaktualizowano: %1$s Kolejność Sortowania Sortuj po nazwie Sortuj po ostatniej aktualizacji @@ -71,22 +71,25 @@ Błąd pobierania pliku Pokaż w folderze nadrzędnym Pokaż pliki - Nowa Wersja Magisk Dostępna! + Nowa Wersja Magisk Dostępna! Nowa Wersja Magisk Manager Dostępna! - - Naciśnij aby pobrać i zainstalować - Pobierz Tylko Zip + + Naciśnij aby pobrać i zainstalować + Pobierz Tylko Zip Bezpośrednia instalacja (Zalecane) - Zainstaluj do Nieaktywnego Slotu (po OTA) + Zainstaluj do Nieaktywnego Slotu (po OTA) Urządzenie będzie MUSIAŁO uruchomić się z bieżącego nieaktywnego slotu po restarcie! /\nUżyj tylko tej opcji po zakończeniu OTA.\nKontynuować? - Wybierz Metodę - Dodatkowa konfiguracja + Wybierz Metodę + Dodatkowa konfiguracja Wybierz i Wgraj Plik Wybierz obraz raw (*.img) lub plik ODIN tar (*.tar) Ponowne uruchomienie za 5 sekund… - - + + + Nie dziękuję + Tak + OK Zamknij Instaluj %1$s Czy chcesz zainstalować %1$s ? @@ -100,14 +103,14 @@ Magisk Manager wgrał dtbo.img. Uruchom ponownie Flashowanie Gotowe! - Błąd - Ukryj Magisk Manager… + Błąd + Ukryj Magisk Manager… Błąd Ukrycia Magisk Managera. - Nie znaleziono aplikacji pod linkiem. + Nie znaleziono aplikacji pod linkiem. Uwaga Odinstalowywanie Zakończone Przywróć Obraz - Przywracanie… + Przywracanie… Przywracanie zakończone! Stock backup nie istnieje! Pobierz Kod @@ -123,7 +126,7 @@ Włącz ciemny motyw Pobierz dodatek Pliki zostaną zapisane w %1$s - Wyczyść Pamięć Repozytorium + Wyczyść Pamięć Repozytorium Wymusza na aplikacji odświeżenie repozytorium online. Ukryj Magisk Manager Przepakowanie Magisk Manager z losową nazwą pakietu @@ -145,7 +148,7 @@ Włącz systemless hosts Wsparcie systemless dla aplikacji Adblock Dodano moduł systemless hosts - + Aplikacje i ADB Tylko Aplikacje Tylko ADB @@ -166,8 +169,8 @@ Włącz Uwierzytelnienie Odciskiem Palca Użyj skanera linii papilarnych, aby zezwolić na żądania supersu Uwierzytelnianie Odciskiem Palca - - Tryb Multiusera + + Tryb Multiusera Tylko Właściciel Urządzenia Zarządzanie Właścicielami Urządzenia Niezależny Użytkownik @@ -185,8 +188,8 @@ Brak wsparcia dla Androida 8.0+ Nie ustawiono żadnych odcisków palców lub brak obsługi urządzenia Błąd podczas tworzenia folderu. Musi być dostępny z głównego katalogu pamięci i nie może być plikiem. - - + + Prośba o dostęp Superusera Odmów Zapytaj @@ -220,5 +223,5 @@ Pokaż aplikacje systemowe - + diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index d8abf1566..5b64e423a 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -63,6 +63,9 @@ Registro de mudanças + Não + Sim + OK Fechar Instalar %1$s Instalar %1$s agora? diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml index a0e0dd852..7c4d4082d 100644 --- a/app/src/main/res/values-pt-rPT/strings.xml +++ b/app/src/main/res/values-pt-rPT/strings.xml @@ -53,6 +53,9 @@ Lista de alterações da aplicação + Não, Obrigado + Sim + OK Fechar Instalar %1$s Deseja instalar%1$s agora? diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index a34362b06..95f256e05 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -87,6 +87,9 @@ Repornire în 5 secunde… + Nu, mulțumesc + Da + Ok Închide Instalează %1$s Vrei să instalezi acum %1$s? diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 06076f1d0..d46e7b3ea 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -88,6 +88,9 @@ Перезагрузка через 5 секунд… + Нет + Да + OK Закрыть Установка %1$s Установить %1$s ? diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml index 3af5729c2..95d507eaa 100644 --- a/app/src/main/res/values-sk/strings.xml +++ b/app/src/main/res/values-sk/strings.xml @@ -72,6 +72,9 @@ Je dostupná aktualizácia Magisk Manager! + Nie, ďakujem + Áno + OK Zavrieť Nainštalovať %1$s Chcete teraz nainštalovať %1$s? diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index f12be9089..6f5ba4c8d 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -55,6 +55,9 @@ Дневник промена апликације + Не хвала + Да + ОК Затвори Инсталирај %1$s Да ли желите да инсталирате %1$s? diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index b180ec304..40c121d69 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -53,6 +53,9 @@ Ändringslogg + Nej tack + Ja + OK Stäng Installera %1$s Vill du installera %1$s ? diff --git a/app/src/main/res/values-th/strings.xml b/app/src/main/res/values-th/strings.xml index 64477ff84..d62cafddd 100644 --- a/app/src/main/res/values-th/strings.xml +++ b/app/src/main/res/values-th/strings.xml @@ -69,6 +69,9 @@ มีการอัพเดต Magisk Manager! + ไม่, ขอบคุณ + ใช่ + โอเค ปิด ติดตั้ง %1$s ต้องการติดตั้ง %1$s ตอนนี้หรือไม่? diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 701a610a0..12046de21 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -88,6 +88,9 @@ 5 saniye içinde yeniden başlatılacak... + Hayır, teşekkürler + Evet + Tamam Kapat %1$s yükle %1$s yüklensin mi? diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 7a8d1a43c..017bd043a 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -88,6 +88,9 @@ Перезавантаження через 5 секунд… + Ні, дякую + Так + OK Закрити Встановити %1$s Бажаєте встановити %1$s ? diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index 5b797b94f..73ffc17c9 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -61,6 +61,9 @@ Nhật ký thay đổi của ứng dụng + Không, cảm ơn + + OK Đóng Cài đặt %1$s Bạn muốn cài đặt %1$s ? diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index a36ef1a10..02a7bba2e 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -88,6 +88,9 @@ 5 秒后重启 + 不,谢谢 + + 关闭 安装 %1$s 是否安装 %1$s ? diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 9842a9715..5b66650a9 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -84,6 +84,9 @@ 將在 5 秒後重新啟動… + 不,謝謝 + + 關閉 安裝 %1$s 即將安裝 %1$s diff --git a/app/src/main/res/values/resources.xml b/app/src/main/res/values/resources.xml new file mode 100644 index 000000000..9c785befd --- /dev/null +++ b/app/src/main/res/values/resources.xml @@ -0,0 +1,11 @@ + + + + + Magisk Manager + Manager + Magisk + Magisk Hide + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d258cacfb..a73bd0dd5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -88,6 +88,9 @@ Rebooting in 5 seconds… + No thanks + Yes + OK Close Install %1$s Do you want to install %1$s now? diff --git a/shared/src/main/res/values/values.xml b/shared/src/main/res/values/values.xml index 285dd6910..1240765d2 100644 --- a/shared/src/main/res/values/values.xml +++ b/shared/src/main/res/values/values.xml @@ -2,5 +2,4 @@ true false - false diff --git a/shared/src/main/res/values-ar/strings.xml b/stub/src/main/res/values-ar/strings.xml similarity index 100% rename from shared/src/main/res/values-ar/strings.xml rename to stub/src/main/res/values-ar/strings.xml diff --git a/shared/src/main/res/values-az/strings.xml b/stub/src/main/res/values-az/strings.xml similarity index 100% rename from shared/src/main/res/values-az/strings.xml rename to stub/src/main/res/values-az/strings.xml diff --git a/shared/src/main/res/values-bg/strings.xml b/stub/src/main/res/values-bg/strings.xml similarity index 100% rename from shared/src/main/res/values-bg/strings.xml rename to stub/src/main/res/values-bg/strings.xml diff --git a/shared/src/main/res/values-ca/strings.xml b/stub/src/main/res/values-ca/strings.xml similarity index 86% rename from shared/src/main/res/values-ca/strings.xml rename to stub/src/main/res/values-ca/strings.xml index 04cb79758..5f51d0659 100644 --- a/shared/src/main/res/values-ca/strings.xml +++ b/stub/src/main/res/values-ca/strings.xml @@ -1,9 +1,7 @@ - - No, gràcies + No, gràcies Ok Fes una actualització total de Magisk Manager per finalitzar l\'instalació. Descarregar i instalar? Si us plau, connecta\'t a internet! Es necessari fer una actualització total de Magisk Manager. - diff --git a/shared/src/main/res/values-cs/strings.xml b/stub/src/main/res/values-cs/strings.xml similarity index 100% rename from shared/src/main/res/values-cs/strings.xml rename to stub/src/main/res/values-cs/strings.xml diff --git a/shared/src/main/res/values-de/strings.xml b/stub/src/main/res/values-de/strings.xml similarity index 100% rename from shared/src/main/res/values-de/strings.xml rename to stub/src/main/res/values-de/strings.xml diff --git a/shared/src/main/res/values-el/strings.xml b/stub/src/main/res/values-el/strings.xml similarity index 100% rename from shared/src/main/res/values-el/strings.xml rename to stub/src/main/res/values-el/strings.xml diff --git a/shared/src/main/res/values-es/strings.xml b/stub/src/main/res/values-es/strings.xml similarity index 100% rename from shared/src/main/res/values-es/strings.xml rename to stub/src/main/res/values-es/strings.xml diff --git a/shared/src/main/res/values-et/strings.xml b/stub/src/main/res/values-et/strings.xml similarity index 90% rename from shared/src/main/res/values-et/strings.xml rename to stub/src/main/res/values-et/strings.xml index 50288c12a..355de0266 100644 --- a/shared/src/main/res/values-et/strings.xml +++ b/stub/src/main/res/values-et/strings.xml @@ -1,5 +1,4 @@ - Tänan ei Jah OK diff --git a/shared/src/main/res/values-fr/strings.xml b/stub/src/main/res/values-fr/strings.xml similarity index 92% rename from shared/src/main/res/values-fr/strings.xml rename to stub/src/main/res/values-fr/strings.xml index d44357e3e..a088cabc4 100644 --- a/shared/src/main/res/values-fr/strings.xml +++ b/stub/src/main/res/values-fr/strings.xml @@ -1,6 +1,5 @@ - Non merci Oui OK diff --git a/shared/src/main/res/values-hr/strings.xml b/stub/src/main/res/values-hr/strings.xml similarity index 100% rename from shared/src/main/res/values-hr/strings.xml rename to stub/src/main/res/values-hr/strings.xml diff --git a/shared/src/main/res/values-in/strings.xml b/stub/src/main/res/values-in/strings.xml similarity index 100% rename from shared/src/main/res/values-in/strings.xml rename to stub/src/main/res/values-in/strings.xml diff --git a/shared/src/main/res/values-it/strings.xml b/stub/src/main/res/values-it/strings.xml similarity index 100% rename from shared/src/main/res/values-it/strings.xml rename to stub/src/main/res/values-it/strings.xml diff --git a/shared/src/main/res/values-ja/strings.xml b/stub/src/main/res/values-ja/strings.xml similarity index 100% rename from shared/src/main/res/values-ja/strings.xml rename to stub/src/main/res/values-ja/strings.xml diff --git a/shared/src/main/res/values-ko/strings.xml b/stub/src/main/res/values-ko/strings.xml similarity index 100% rename from shared/src/main/res/values-ko/strings.xml rename to stub/src/main/res/values-ko/strings.xml diff --git a/shared/src/main/res/values-lt/strings.xml b/stub/src/main/res/values-lt/strings.xml similarity index 100% rename from shared/src/main/res/values-lt/strings.xml rename to stub/src/main/res/values-lt/strings.xml diff --git a/shared/src/main/res/values-mk/strings.xml b/stub/src/main/res/values-mk/strings.xml similarity index 93% rename from shared/src/main/res/values-mk/strings.xml rename to stub/src/main/res/values-mk/strings.xml index ad7bece43..c1870cde9 100644 --- a/shared/src/main/res/values-mk/strings.xml +++ b/stub/src/main/res/values-mk/strings.xml @@ -1,5 +1,4 @@ - Не, благодарам Да ОК diff --git a/shared/src/main/res/values-nb/strings.xml b/stub/src/main/res/values-nb/strings.xml similarity index 91% rename from shared/src/main/res/values-nb/strings.xml rename to stub/src/main/res/values-nb/strings.xml index 322190c48..954aec658 100644 --- a/shared/src/main/res/values-nb/strings.xml +++ b/stub/src/main/res/values-nb/strings.xml @@ -1,6 +1,5 @@ - Nei takk Ja OK diff --git a/shared/src/main/res/values-nl/strings.xml b/stub/src/main/res/values-nl/strings.xml similarity index 100% rename from shared/src/main/res/values-nl/strings.xml rename to stub/src/main/res/values-nl/strings.xml diff --git a/shared/src/main/res/values-pl/strings.xml b/stub/src/main/res/values-pl/strings.xml similarity index 100% rename from shared/src/main/res/values-pl/strings.xml rename to stub/src/main/res/values-pl/strings.xml diff --git a/shared/src/main/res/values-pt-rBR/strings.xml b/stub/src/main/res/values-pt-rBR/strings.xml similarity index 100% rename from shared/src/main/res/values-pt-rBR/strings.xml rename to stub/src/main/res/values-pt-rBR/strings.xml diff --git a/shared/src/main/res/values-pt-rPT/strings.xml b/stub/src/main/res/values-pt-rPT/strings.xml similarity index 100% rename from shared/src/main/res/values-pt-rPT/strings.xml rename to stub/src/main/res/values-pt-rPT/strings.xml diff --git a/shared/src/main/res/values-ro/strings.xml b/stub/src/main/res/values-ro/strings.xml similarity index 100% rename from shared/src/main/res/values-ro/strings.xml rename to stub/src/main/res/values-ro/strings.xml diff --git a/shared/src/main/res/values-ru/strings.xml b/stub/src/main/res/values-ru/strings.xml similarity index 100% rename from shared/src/main/res/values-ru/strings.xml rename to stub/src/main/res/values-ru/strings.xml diff --git a/shared/src/main/res/values-sk/strings.xml b/stub/src/main/res/values-sk/strings.xml similarity index 90% rename from shared/src/main/res/values-sk/strings.xml rename to stub/src/main/res/values-sk/strings.xml index d93b29bde..794ee0eff 100644 --- a/shared/src/main/res/values-sk/strings.xml +++ b/stub/src/main/res/values-sk/strings.xml @@ -1,5 +1,4 @@ - Nie, ďakujem Áno OK diff --git a/shared/src/main/res/values-sr/strings.xml b/stub/src/main/res/values-sr/strings.xml similarity index 100% rename from shared/src/main/res/values-sr/strings.xml rename to stub/src/main/res/values-sr/strings.xml diff --git a/shared/src/main/res/values-sv/strings.xml b/stub/src/main/res/values-sv/strings.xml similarity index 100% rename from shared/src/main/res/values-sv/strings.xml rename to stub/src/main/res/values-sv/strings.xml diff --git a/shared/src/main/res/values-th/strings.xml b/stub/src/main/res/values-th/strings.xml similarity index 83% rename from shared/src/main/res/values-th/strings.xml rename to stub/src/main/res/values-th/strings.xml index 21ac194ff..78f4e50cb 100644 --- a/shared/src/main/res/values-th/strings.xml +++ b/stub/src/main/res/values-th/strings.xml @@ -1,9 +1,6 @@ - - ไม่, ขอบคุณ ใช่ โอเค - \ No newline at end of file diff --git a/shared/src/main/res/values-tr/strings.xml b/stub/src/main/res/values-tr/strings.xml similarity index 100% rename from shared/src/main/res/values-tr/strings.xml rename to stub/src/main/res/values-tr/strings.xml diff --git a/shared/src/main/res/values-uk/strings.xml b/stub/src/main/res/values-uk/strings.xml similarity index 100% rename from shared/src/main/res/values-uk/strings.xml rename to stub/src/main/res/values-uk/strings.xml diff --git a/shared/src/main/res/values-vi/strings.xml b/stub/src/main/res/values-vi/strings.xml similarity index 100% rename from shared/src/main/res/values-vi/strings.xml rename to stub/src/main/res/values-vi/strings.xml diff --git a/shared/src/main/res/values-zh-rCN/strings.xml b/stub/src/main/res/values-zh-rCN/strings.xml similarity index 100% rename from shared/src/main/res/values-zh-rCN/strings.xml rename to stub/src/main/res/values-zh-rCN/strings.xml diff --git a/shared/src/main/res/values-zh-rTW/strings.xml b/stub/src/main/res/values-zh-rTW/strings.xml similarity index 100% rename from shared/src/main/res/values-zh-rTW/strings.xml rename to stub/src/main/res/values-zh-rTW/strings.xml diff --git a/shared/src/main/res/values/strings.xml b/stub/src/main/res/values/strings.xml similarity index 60% rename from shared/src/main/res/values/strings.xml rename to stub/src/main/res/values/strings.xml index 891efcd11..81ad51174 100644 --- a/shared/src/main/res/values/strings.xml +++ b/stub/src/main/res/values/strings.xml @@ -1,14 +1,12 @@ + - Magisk Manager - Manager - Magisk - Magisk Hide - No thanks Yes OK Upgrade to full Magisk Manager to finish the setup. Download and install? Please connect to the Internet! Upgrading to full Magisk Manager is required. - + + + \ No newline at end of file From 1b3a009da7271291b93559b4a6dd40e94248a931 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Tue, 15 Oct 2019 04:36:09 -0400 Subject: [PATCH 02/61] Remove unused WorkManager components --- shared/src/main/res/values-v23/values.xml | 5 -- shared/src/main/res/values/values.xml | 5 -- stub/src/main/AndroidManifest.xml | 73 +---------------------- 3 files changed, 1 insertion(+), 82 deletions(-) delete mode 100644 shared/src/main/res/values-v23/values.xml delete mode 100644 shared/src/main/res/values/values.xml diff --git a/shared/src/main/res/values-v23/values.xml b/shared/src/main/res/values-v23/values.xml deleted file mode 100644 index 0a0a96685..000000000 --- a/shared/src/main/res/values-v23/values.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - false - true - diff --git a/shared/src/main/res/values/values.xml b/shared/src/main/res/values/values.xml deleted file mode 100644 index 1240765d2..000000000 --- a/shared/src/main/res/values/values.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - true - false - diff --git a/stub/src/main/AndroidManifest.xml b/stub/src/main/AndroidManifest.xml index 16dfc8081..ec810354d 100644 --- a/stub/src/main/AndroidManifest.xml +++ b/stub/src/main/AndroidManifest.xml @@ -85,16 +85,10 @@ android:multiprocess="true" tools:targetApi="n" /> - @@ -105,71 +99,6 @@ android:enabled="true" android:exported="false" tools:targetApi="n" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 34ff76451501e87cb6927c23fa277009ccc56236 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Tue, 15 Oct 2019 04:37:12 -0400 Subject: [PATCH 03/61] Stabilize resource IDs --- .gitignore | 5 +++-- app/src/main/res/values/resources.xml | 12 ++++++++++++ build.gradle | 14 +++++++------- stable-ids.txt | 20 ++++++++++++++++++++ 4 files changed, 42 insertions(+), 9 deletions(-) create mode 100644 stable-ids.txt diff --git a/.gitignore b/.gitignore index 47cd35844..9630aa645 100644 --- a/.gitignore +++ b/.gitignore @@ -2,8 +2,9 @@ out *.zip *.jks *.apk -config.prop -update.sh +/config.prop +/update.sh +/stub-ids.txt # Built binaries native/out diff --git a/app/src/main/res/values/resources.xml b/app/src/main/res/values/resources.xml index 9c785befd..77f7d8ccc 100644 --- a/app/src/main/res/values/resources.xml +++ b/app/src/main/res/values/resources.xml @@ -8,4 +8,16 @@ Magisk Hide + + + + + + + + + + + + diff --git a/build.gradle b/build.gradle index 52c34561a..6731fa8f2 100644 --- a/build.gradle +++ b/build.gradle @@ -85,13 +85,13 @@ subprojects { } aaptOptions { - // Preserve stub resource IDs - File publicTxt = rootProject.file('stub-public.txt') - if (publicTxt.exists()) { - additionalParameters "--stable-ids", "${publicTxt.absolutePath}" - } else if (module.name == 'stub') { - additionalParameters "--emit-ids", "${publicTxt.absolutePath}" - } + // Handle resource IDs + File resIds = rootProject.file('stable-ids.txt') + File stubIds = rootProject.file('stub-ids.txt') + if (module.name == 'app' && resIds.exists()) + additionalParameters "--stable-ids", "${resIds.absolutePath}" + else if (module.name == 'stub') + additionalParameters "--emit-ids", "${stubIds.absolutePath}" } } } diff --git a/stable-ids.txt b/stable-ids.txt new file mode 100644 index 000000000..763209e25 --- /dev/null +++ b/stable-ids.txt @@ -0,0 +1,20 @@ +com.topjohnwu.magisk:color/ic_launcher_background = 0x7f010000 +com.topjohnwu.magisk:drawable/ic_launcher = 0x7f020000 +com.topjohnwu.magisk:drawable/ic_logo = 0x7f020001 +com.topjohnwu.magisk:drawable/ic_magisk = 0x7f020002 +com.topjohnwu.magisk:drawable/ic_splash_activity = 0x7f020003 +com.topjohnwu.magisk:style/SplashTheme = 0x7f040000 +com.topjohnwu.magisk:style/SplashThemeBase = 0x7f040001 +com.topjohnwu.magisk:style/SplashThemeBase.V19 = 0x7f040002 +com.topjohnwu.magisk:xml/file_paths = 0x7f050000 + +com.topjohnwu.magisk:string/preserve_0 = 0x7f030000 +com.topjohnwu.magisk:string/preserve_1 = 0x7f030001 +com.topjohnwu.magisk:string/preserve_2 = 0x7f030002 +com.topjohnwu.magisk:string/preserve_3 = 0x7f030003 +com.topjohnwu.magisk:string/preserve_4 = 0x7f030004 +com.topjohnwu.magisk:string/preserve_5 = 0x7f030005 +com.topjohnwu.magisk:string/preserve_6 = 0x7f030006 +com.topjohnwu.magisk:string/preserve_7 = 0x7f030007 +com.topjohnwu.magisk:string/preserve_8 = 0x7f030008 +com.topjohnwu.magisk:string/preserve_9 = 0x7f030009 From 5673a9baceec648901d47f5a97210db865d1557d Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Tue, 15 Oct 2019 05:49:23 -0400 Subject: [PATCH 04/61] Move system accessible resources to shared --- app/src/main/res/values/resources.xml | 20 ++++----- .../drawable-anydpi-v21/ic_magisk_outline.xml | 0 .../res/drawable-anydpi-v26/ic_launcher.xml | 0 .../res/drawable-v26/sc_cloud_download.xml | 2 +- .../main/res/drawable-v26/sc_extension.xml | 2 +- .../main/res/drawable-v26/sc_magiskhide.xml | 2 +- .../main/res/drawable-v26/sc_superuser.xml | 2 +- .../main/res/drawable/ic_cloud_download.xml | 2 +- .../src/main/res/drawable/ic_extension.xml | 2 +- .../main/res/drawable/ic_magisk_padded.xml | 0 .../src/main/res/drawable/ic_magiskhide.xml | 2 +- .../src/main/res/drawable/ic_superuser.xml | 2 +- shared/src/main/res/values/colors.xml | 4 +- stable-ids.txt | 42 ++++++++++++------- 14 files changed, 48 insertions(+), 34 deletions(-) rename {app => shared}/src/main/res/drawable-anydpi-v21/ic_magisk_outline.xml (100%) rename {app => shared}/src/main/res/drawable-anydpi-v26/ic_launcher.xml (100%) rename {app => shared}/src/main/res/drawable-v26/sc_cloud_download.xml (80%) rename {app => shared}/src/main/res/drawable-v26/sc_extension.xml (80%) rename {app => shared}/src/main/res/drawable-v26/sc_magiskhide.xml (80%) rename {app => shared}/src/main/res/drawable-v26/sc_superuser.xml (80%) rename {app => shared}/src/main/res/drawable/ic_cloud_download.xml (90%) rename {app => shared}/src/main/res/drawable/ic_extension.xml (92%) rename {app => shared}/src/main/res/drawable/ic_magisk_padded.xml (100%) rename {app => shared}/src/main/res/drawable/ic_magiskhide.xml (98%) rename {app => shared}/src/main/res/drawable/ic_superuser.xml (90%) diff --git a/app/src/main/res/values/resources.xml b/app/src/main/res/values/resources.xml index 77f7d8ccc..711bb5460 100644 --- a/app/src/main/res/values/resources.xml +++ b/app/src/main/res/values/resources.xml @@ -9,15 +9,15 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/app/src/main/res/drawable-anydpi-v21/ic_magisk_outline.xml b/shared/src/main/res/drawable-anydpi-v21/ic_magisk_outline.xml similarity index 100% rename from app/src/main/res/drawable-anydpi-v21/ic_magisk_outline.xml rename to shared/src/main/res/drawable-anydpi-v21/ic_magisk_outline.xml diff --git a/app/src/main/res/drawable-anydpi-v26/ic_launcher.xml b/shared/src/main/res/drawable-anydpi-v26/ic_launcher.xml similarity index 100% rename from app/src/main/res/drawable-anydpi-v26/ic_launcher.xml rename to shared/src/main/res/drawable-anydpi-v26/ic_launcher.xml diff --git a/app/src/main/res/drawable-v26/sc_cloud_download.xml b/shared/src/main/res/drawable-v26/sc_cloud_download.xml similarity index 80% rename from app/src/main/res/drawable-v26/sc_cloud_download.xml rename to shared/src/main/res/drawable-v26/sc_cloud_download.xml index 734f23865..3d3c9114a 100644 --- a/app/src/main/res/drawable-v26/sc_cloud_download.xml +++ b/shared/src/main/res/drawable-v26/sc_cloud_download.xml @@ -1,6 +1,6 @@ - + - + - + - + diff --git a/app/src/main/res/drawable/ic_extension.xml b/shared/src/main/res/drawable/ic_extension.xml similarity index 92% rename from app/src/main/res/drawable/ic_extension.xml rename to shared/src/main/res/drawable/ic_extension.xml index 549fdce23..7fb337518 100644 --- a/app/src/main/res/drawable/ic_extension.xml +++ b/shared/src/main/res/drawable/ic_extension.xml @@ -4,6 +4,6 @@ android:viewportHeight="24.0" android:viewportWidth="24.0"> diff --git a/app/src/main/res/drawable/ic_magisk_padded.xml b/shared/src/main/res/drawable/ic_magisk_padded.xml similarity index 100% rename from app/src/main/res/drawable/ic_magisk_padded.xml rename to shared/src/main/res/drawable/ic_magisk_padded.xml diff --git a/app/src/main/res/drawable/ic_magiskhide.xml b/shared/src/main/res/drawable/ic_magiskhide.xml similarity index 98% rename from app/src/main/res/drawable/ic_magiskhide.xml rename to shared/src/main/res/drawable/ic_magiskhide.xml index 6a3ce181d..4b46314af 100644 --- a/app/src/main/res/drawable/ic_magiskhide.xml +++ b/shared/src/main/res/drawable/ic_magiskhide.xml @@ -5,6 +5,6 @@ android:width="24dp"> diff --git a/app/src/main/res/drawable/ic_superuser.xml b/shared/src/main/res/drawable/ic_superuser.xml similarity index 90% rename from app/src/main/res/drawable/ic_superuser.xml rename to shared/src/main/res/drawable/ic_superuser.xml index 01fb6a803..a4f956855 100644 --- a/app/src/main/res/drawable/ic_superuser.xml +++ b/shared/src/main/res/drawable/ic_superuser.xml @@ -4,6 +4,6 @@ android:viewportWidth="24" android:viewportHeight="24"> \ No newline at end of file diff --git a/shared/src/main/res/values/colors.xml b/shared/src/main/res/values/colors.xml index f307cc63e..df6f5cef5 100644 --- a/shared/src/main/res/values/colors.xml +++ b/shared/src/main/res/values/colors.xml @@ -1,4 +1,6 @@ #00AF9C - \ No newline at end of file + #00796B + #e0e0e0 + diff --git a/stable-ids.txt b/stable-ids.txt index 763209e25..ac6eed8c8 100644 --- a/stable-ids.txt +++ b/stable-ids.txt @@ -1,20 +1,32 @@ -com.topjohnwu.magisk:color/ic_launcher_background = 0x7f010000 -com.topjohnwu.magisk:drawable/ic_launcher = 0x7f020000 -com.topjohnwu.magisk:drawable/ic_logo = 0x7f020001 -com.topjohnwu.magisk:drawable/ic_magisk = 0x7f020002 -com.topjohnwu.magisk:drawable/ic_splash_activity = 0x7f020003 +com.topjohnwu.magisk:color/dark = 0x7f010000 +com.topjohnwu.magisk:color/ic_launcher_background = 0x7f010001 +com.topjohnwu.magisk:color/light = 0x7f010002 +com.topjohnwu.magisk:drawable/ic_cloud_download = 0x7f020000 +com.topjohnwu.magisk:drawable/ic_extension = 0x7f020001 +com.topjohnwu.magisk:drawable/ic_launcher = 0x7f020002 +com.topjohnwu.magisk:drawable/ic_logo = 0x7f020003 +com.topjohnwu.magisk:drawable/ic_magisk = 0x7f020004 +com.topjohnwu.magisk:drawable/ic_magisk_outline = 0x7f020005 +com.topjohnwu.magisk:drawable/ic_magisk_padded = 0x7f020006 +com.topjohnwu.magisk:drawable/ic_magiskhide = 0x7f020007 +com.topjohnwu.magisk:drawable/ic_splash_activity = 0x7f020008 +com.topjohnwu.magisk:drawable/ic_superuser = 0x7f020009 +com.topjohnwu.magisk:drawable/sc_cloud_download = 0x7f02000a +com.topjohnwu.magisk:drawable/sc_extension = 0x7f02000b +com.topjohnwu.magisk:drawable/sc_magiskhide = 0x7f02000c +com.topjohnwu.magisk:drawable/sc_superuser = 0x7f02000d com.topjohnwu.magisk:style/SplashTheme = 0x7f040000 com.topjohnwu.magisk:style/SplashThemeBase = 0x7f040001 com.topjohnwu.magisk:style/SplashThemeBase.V19 = 0x7f040002 com.topjohnwu.magisk:xml/file_paths = 0x7f050000 -com.topjohnwu.magisk:string/preserve_0 = 0x7f030000 -com.topjohnwu.magisk:string/preserve_1 = 0x7f030001 -com.topjohnwu.magisk:string/preserve_2 = 0x7f030002 -com.topjohnwu.magisk:string/preserve_3 = 0x7f030003 -com.topjohnwu.magisk:string/preserve_4 = 0x7f030004 -com.topjohnwu.magisk:string/preserve_5 = 0x7f030005 -com.topjohnwu.magisk:string/preserve_6 = 0x7f030006 -com.topjohnwu.magisk:string/preserve_7 = 0x7f030007 -com.topjohnwu.magisk:string/preserve_8 = 0x7f030008 -com.topjohnwu.magisk:string/preserve_9 = 0x7f030009 +com.topjohnwu.magisk:string/stub_0 = 0x7f030000 +com.topjohnwu.magisk:string/stub_1 = 0x7f030001 +com.topjohnwu.magisk:string/stub_2 = 0x7f030002 +com.topjohnwu.magisk:string/stub_3 = 0x7f030003 +com.topjohnwu.magisk:string/stub_4 = 0x7f030004 +com.topjohnwu.magisk:string/stub_5 = 0x7f030005 +com.topjohnwu.magisk:string/stub_6 = 0x7f030006 +com.topjohnwu.magisk:string/stub_7 = 0x7f030007 +com.topjohnwu.magisk:string/stub_8 = 0x7f030008 +com.topjohnwu.magisk:string/stub_9 = 0x7f030009 From c7033dd7570f63f96771907298cb1208c0c670b3 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Wed, 16 Oct 2019 01:54:59 -0400 Subject: [PATCH 05/61] Allow injecting custom channel URL for debug --- stub/build.gradle | 1 + stub/src/main/java/com/topjohnwu/magisk/DownloadActivity.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/stub/build.gradle b/stub/build.gradle index b9e76ddae..932b547fc 100644 --- a/stub/build.gradle +++ b/stub/build.gradle @@ -5,6 +5,7 @@ android { applicationId 'com.topjohnwu.magisk' versionCode 1 versionName props['appVersion'] + buildConfigField 'String', 'DEV_CHANNEL', props['DEV_CHANNEL'] ?: 'null' } buildTypes { diff --git a/stub/src/main/java/com/topjohnwu/magisk/DownloadActivity.java b/stub/src/main/java/com/topjohnwu/magisk/DownloadActivity.java index f020a2b0f..62a2baa29 100644 --- a/stub/src/main/java/com/topjohnwu/magisk/DownloadActivity.java +++ b/stub/src/main/java/com/topjohnwu/magisk/DownloadActivity.java @@ -22,7 +22,7 @@ public class DownloadActivity extends Activity { static final String TAG = "MMStub"; private static final boolean IS_CANARY = BuildConfig.VERSION_NAME.contains("-"); - private static final String URL = + private static final String URL = BuildConfig.DEV_CHANNEL != null ? BuildConfig.DEV_CHANNEL : "https://raw.githubusercontent.com/topjohnwu/magisk_files/" + (IS_CANARY ? "canary/release.json" : "master/stable.json"); From 43bda2d4a49a39bbc33f008224d5fefb5b378b4f Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Wed, 16 Oct 2019 04:38:31 -0400 Subject: [PATCH 06/61] Allow component classname obfuscation --- app/src/main/java/a/e.java | 10 +++++- app/src/main/java/com/topjohnwu/magisk/App.kt | 7 +++- .../java/com/topjohnwu/magisk/ClassMap.kt | 26 ++++++++++++--- .../magisk/model/download/DownloadService.kt | 5 ++- .../magisk/model/download/ManagerUpgrade.kt | 7 ++-- .../magisk/model/receiver/GeneralReceiver.kt | 4 +-- .../com/topjohnwu/magisk/ui/MainActivity.kt | 7 ++-- .../com/topjohnwu/magisk/ui/SplashActivity.kt | 3 +- .../magisk/ui/flash/FlashActivity.kt | 4 +-- .../magisk/ui/module/ModulesFragment.kt | 3 +- .../com/topjohnwu/magisk/utils/PatchAPK.kt | 4 +-- .../java/com/topjohnwu/magisk/utils/Utils.kt | 2 +- .../topjohnwu/magisk/view/Notifications.kt | 20 +++++------- .../com/topjohnwu/magisk/view/Shortcuts.kt | 9 +++--- stub/src/main/AndroidManifest.xml | 16 +++++----- stub/src/main/java/a/w.java | 6 ++++ stub/src/main/java/a/{a.java => x.java} | 2 +- stub/src/main/java/a/{e.java => y.java} | 2 +- stub/src/main/java/a/{c.java => z.java} | 2 +- .../com/topjohnwu/magisk/ComponentMap.java | 32 +++++++++++++++++++ .../topjohnwu/magisk/DelegateApplication.java | 4 ++- .../magisk/DelegateComponentFactory.java | 20 +++++++++--- 22 files changed, 132 insertions(+), 63 deletions(-) create mode 100644 stub/src/main/java/a/w.java rename stub/src/main/java/a/{a.java => x.java} (57%) rename stub/src/main/java/a/{e.java => y.java} (58%) rename stub/src/main/java/a/{c.java => z.java} (59%) create mode 100644 stub/src/main/java/com/topjohnwu/magisk/ComponentMap.java diff --git a/app/src/main/java/a/e.java b/app/src/main/java/a/e.java index da51b8f55..56396b034 100644 --- a/app/src/main/java/a/e.java +++ b/app/src/main/java/a/e.java @@ -2,6 +2,14 @@ package a; import com.topjohnwu.magisk.App; +import java.util.Map; + public class e extends App { - /* stub */ + public e() { + super(); + } + + public e(Map map) { + super(map); + } } diff --git a/app/src/main/java/com/topjohnwu/magisk/App.kt b/app/src/main/java/com/topjohnwu/magisk/App.kt index 3a3f6961c..8c448a784 100644 --- a/app/src/main/java/com/topjohnwu/magisk/App.kt +++ b/app/src/main/java/com/topjohnwu/magisk/App.kt @@ -23,7 +23,12 @@ import org.koin.android.ext.koin.androidContext import org.koin.core.context.startKoin import timber.log.Timber -open class App : Application() { +open class App() : Application() { + + constructor(map: Map) : this() { + isRunningAsStub = true + ClassMap.componentMap = map + } init { AppCompatDelegate.setCompatVectorFromResourcesEnabled(true) diff --git a/app/src/main/java/com/topjohnwu/magisk/ClassMap.kt b/app/src/main/java/com/topjohnwu/magisk/ClassMap.kt index adf76b4b6..79217a2d2 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ClassMap.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ClassMap.kt @@ -1,5 +1,8 @@ package com.topjohnwu.magisk +import android.content.ComponentName +import android.content.Context +import android.content.Intent import com.topjohnwu.magisk.model.download.DownloadService import com.topjohnwu.magisk.model.receiver.GeneralReceiver import com.topjohnwu.magisk.model.update.UpdateCheckService @@ -9,7 +12,8 @@ import com.topjohnwu.magisk.ui.flash.FlashActivity import com.topjohnwu.magisk.ui.surequest.SuRequestActivity object ClassMap { - private val map = mapOf( + + private val classMap = mapOf( App::class.java to a.e::class.java, MainActivity::class.java to a.b::class.java, SplashActivity::class.java to a.c::class.java, @@ -20,7 +24,21 @@ object ClassMap { SuRequestActivity::class.java to a.m::class.java ) - operator fun >get(c: Class<*>): T { - return map.getOrElse(c) { throw IllegalArgumentException() } as T - } + // This will be set if running as guest app + var componentMap: Map? = null + + operator fun get(c: Class<*>) = classMap.getOrElse(c) { throw IllegalArgumentException() } +} + +fun Class<*>.cmp(pkg: String = BuildConfig.APPLICATION_ID): ComponentName { + val name = ClassMap[this].name + return ComponentName(pkg, ClassMap.componentMap?.get(name) ?: name) +} + +fun Context.intent(c: Class<*>): Intent { + val cls = ClassMap[c] + return ClassMap.componentMap?.let { + val className = it.getOrElse(cls.name) { cls.name } + Intent().setComponent(ComponentName(this, className)) + } ?: Intent(this, cls) } diff --git a/app/src/main/java/com/topjohnwu/magisk/model/download/DownloadService.kt b/app/src/main/java/com/topjohnwu/magisk/model/download/DownloadService.kt index 4fbf8c456..ae39a7fb9 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/download/DownloadService.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/download/DownloadService.kt @@ -7,11 +7,11 @@ import android.content.Intent import android.os.Build import android.webkit.MimeTypeMap import androidx.core.app.NotificationCompat -import com.topjohnwu.magisk.ClassMap import com.topjohnwu.magisk.R import com.topjohnwu.magisk.extensions.chooser import com.topjohnwu.magisk.extensions.exists import com.topjohnwu.magisk.extensions.provide +import com.topjohnwu.magisk.intent import com.topjohnwu.magisk.model.entity.internal.Configuration.* import com.topjohnwu.magisk.model.entity.internal.Configuration.Flash.Secondary import com.topjohnwu.magisk.model.entity.internal.DownloadSubject @@ -140,8 +140,7 @@ open class DownloadService : RemoteFileService() { inline operator fun invoke(context: Context, argBuilder: Builder.() -> Unit) { val app = context.applicationContext val builder = Builder().apply(argBuilder) - val intent = Intent(app, ClassMap[DownloadService::class.java]) - .putExtra(ARG_URL, builder.subject) + val intent = app.intent(DownloadService::class.java).putExtra(ARG_URL, builder.subject) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { app.startForegroundService(intent) diff --git a/app/src/main/java/com/topjohnwu/magisk/model/download/ManagerUpgrade.kt b/app/src/main/java/com/topjohnwu/magisk/model/download/ManagerUpgrade.kt index 278edafb0..bc8e85dff 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/download/ManagerUpgrade.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/download/ManagerUpgrade.kt @@ -1,10 +1,9 @@ package com.topjohnwu.magisk.model.download -import android.content.ComponentName import com.topjohnwu.magisk.BuildConfig -import com.topjohnwu.magisk.ClassMap import com.topjohnwu.magisk.Config import com.topjohnwu.magisk.R +import com.topjohnwu.magisk.cmp import com.topjohnwu.magisk.extensions.DynamicClassLoader import com.topjohnwu.magisk.model.entity.internal.Configuration.APK.Restore import com.topjohnwu.magisk.model.entity.internal.Configuration.APK.Upgrade @@ -52,9 +51,7 @@ private fun RemoteFileService.restore(apk: File, id: Int) { // Make it world readable apk.setReadable(true, false) if (Shell.su("pm install $apk").exec().isSuccess) { - val component = ComponentName(BuildConfig.APPLICATION_ID, - ClassMap.get>(SplashActivity::class.java).name) - Utils.rmAndLaunch(packageName, component) + Utils.rmAndLaunch(packageName, SplashActivity::class.java.cmp()) } } diff --git a/app/src/main/java/com/topjohnwu/magisk/model/receiver/GeneralReceiver.kt b/app/src/main/java/com/topjohnwu/magisk/model/receiver/GeneralReceiver.kt index 587712370..f9c591304 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/receiver/GeneralReceiver.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/receiver/GeneralReceiver.kt @@ -2,7 +2,6 @@ package com.topjohnwu.magisk.model.receiver import android.content.ContextWrapper import android.content.Intent -import com.topjohnwu.magisk.ClassMap import com.topjohnwu.magisk.Config import com.topjohnwu.magisk.Const import com.topjohnwu.magisk.Info @@ -10,6 +9,7 @@ import com.topjohnwu.magisk.base.BaseReceiver import com.topjohnwu.magisk.data.database.PolicyDao import com.topjohnwu.magisk.data.database.base.su import com.topjohnwu.magisk.extensions.reboot +import com.topjohnwu.magisk.intent import com.topjohnwu.magisk.model.download.DownloadService import com.topjohnwu.magisk.model.entity.ManagerJson import com.topjohnwu.magisk.model.entity.internal.Configuration @@ -51,7 +51,7 @@ open class GeneralReceiver : BaseReceiver() { } when (action) { REQUEST -> { - val i = Intent(context, ClassMap[SuRequestActivity::class.java]) + val i = context.intent(SuRequestActivity::class.java) .setAction(action) .putExtra("socket", intent.getStringExtra("socket")) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/MainActivity.kt b/app/src/main/java/com/topjohnwu/magisk/ui/MainActivity.kt index 848192ca6..24ec6658f 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/MainActivity.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/MainActivity.kt @@ -7,11 +7,8 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentTransaction import com.ncapdevi.fragnav.FragNavController import com.ncapdevi.fragnav.FragNavTransactionOptions -import com.topjohnwu.magisk.ClassMap -import com.topjohnwu.magisk.Config +import com.topjohnwu.magisk.* import com.topjohnwu.magisk.Const.Key.OPEN_SECTION -import com.topjohnwu.magisk.Info -import com.topjohnwu.magisk.R import com.topjohnwu.magisk.base.BaseActivity import com.topjohnwu.magisk.base.BaseFragment import com.topjohnwu.magisk.databinding.ActivityMainBinding @@ -61,7 +58,7 @@ open class MainActivity : BaseActivity(), Na override fun onCreate(savedInstanceState: Bundle?) { if (!SplashActivity.DONE) { - startActivity(Intent(this, ClassMap[SplashActivity::class.java])) + startActivity(intent(SplashActivity::class.java)) finish() } diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/SplashActivity.kt b/app/src/main/java/com/topjohnwu/magisk/ui/SplashActivity.kt index 728720b1b..6a43ddb73 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/SplashActivity.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/SplashActivity.kt @@ -2,7 +2,6 @@ package com.topjohnwu.magisk.ui import android.app.Activity import android.content.Context -import android.content.Intent import android.os.Bundle import android.text.TextUtils import androidx.appcompat.app.AlertDialog @@ -62,7 +61,7 @@ open class SplashActivity : Activity() { // Setup shortcuts Shortcuts.setup(this) - val intent = Intent(this, ClassMap[MainActivity::class.java]) + val intent = intent(MainActivity::class.java) intent.putExtra(Const.Key.OPEN_SECTION, getIntent().getStringExtra(Const.Key.OPEN_SECTION)) DONE = true startActivity(intent) diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashActivity.kt b/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashActivity.kt index 143db2a3e..cade5a5f1 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashActivity.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashActivity.kt @@ -6,12 +6,12 @@ import android.net.Uri import android.os.Bundle import androidx.core.app.NotificationManagerCompat import androidx.core.net.toUri -import com.topjohnwu.magisk.ClassMap import com.topjohnwu.magisk.Const import com.topjohnwu.magisk.R import com.topjohnwu.magisk.base.BaseActivity import com.topjohnwu.magisk.databinding.ActivityFlashBinding import com.topjohnwu.magisk.extensions.snackbar +import com.topjohnwu.magisk.intent import com.topjohnwu.magisk.model.events.BackPressEvent import com.topjohnwu.magisk.model.events.PermissionEvent import com.topjohnwu.magisk.model.events.SnackbarEvent @@ -60,7 +60,7 @@ open class FlashActivity : BaseActivity() companion object { - private fun intent(context: Context) = Intent(context, ClassMap[FlashActivity::class.java]) + private fun intent(context: Context) = context.intent(FlashActivity::class.java) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) private fun intent(context: Context, file: File) = intent(context).setData(file.toUri()) diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/module/ModulesFragment.kt b/app/src/main/java/com/topjohnwu/magisk/ui/module/ModulesFragment.kt index fa57d6605..c06d4b487 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/module/ModulesFragment.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/module/ModulesFragment.kt @@ -14,6 +14,7 @@ import com.topjohnwu.magisk.R import com.topjohnwu.magisk.base.BaseFragment import com.topjohnwu.magisk.databinding.FragmentModulesBinding import com.topjohnwu.magisk.extensions.reboot +import com.topjohnwu.magisk.intent import com.topjohnwu.magisk.model.events.OpenFilePickerEvent import com.topjohnwu.magisk.model.events.ViewEvent import com.topjohnwu.magisk.ui.flash.FlashActivity @@ -28,7 +29,7 @@ class ModulesFragment : BaseFragment() override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { if (requestCode == Const.ID.FETCH_ZIP && resultCode == Activity.RESULT_OK && data != null) { // Get the URI of the selected file - val intent = Intent(activity, ClassMap[FlashActivity::class.java]) + val intent = activity.intent(FlashActivity::class.java) intent.setData(data.data).putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_ZIP) startActivity(intent) } diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.kt b/app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.kt index 1ed022ead..f70dc291f 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.kt +++ b/app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.kt @@ -1,6 +1,5 @@ package com.topjohnwu.magisk.utils -import android.content.ComponentName import android.content.Context import android.widget.Toast import com.topjohnwu.magisk.* @@ -102,8 +101,7 @@ object PatchAPK { Config.suManager = pkg Config.export() - Utils.rmAndLaunch(BuildConfig.APPLICATION_ID, - ComponentName(pkg, ClassMap.get>(SplashActivity::class.java).name)) + Utils.rmAndLaunch(BuildConfig.APPLICATION_ID, SplashActivity::class.java.cmp(pkg)) return true } diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/Utils.kt b/app/src/main/java/com/topjohnwu/magisk/utils/Utils.kt index 4e873aa8a..48ca4d3c1 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Utils.kt +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Utils.kt @@ -46,7 +46,7 @@ object Utils { .setRequiresDeviceIdle(true) .build() val request = PeriodicWorkRequest - .Builder(ClassMap[UpdateCheckService::class.java], 12, TimeUnit.HOURS) + .Builder(ClassMap[UpdateCheckService::class.java] as Class, 12, TimeUnit.HOURS) .setConstraints(constraints) .build() WorkManager.getInstance(context).enqueueUniquePeriodicWork( diff --git a/app/src/main/java/com/topjohnwu/magisk/view/Notifications.kt b/app/src/main/java/com/topjohnwu/magisk/view/Notifications.kt index 38770a8d8..cb036d544 100644 --- a/app/src/main/java/com/topjohnwu/magisk/view/Notifications.kt +++ b/app/src/main/java/com/topjohnwu/magisk/view/Notifications.kt @@ -4,15 +4,11 @@ import android.app.NotificationChannel import android.app.NotificationManager import android.app.PendingIntent import android.content.Context -import android.content.Intent import android.os.Build import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat import androidx.core.app.TaskStackBuilder -import com.topjohnwu.magisk.ClassMap -import com.topjohnwu.magisk.Const -import com.topjohnwu.magisk.Info -import com.topjohnwu.magisk.R +import com.topjohnwu.magisk.* import com.topjohnwu.magisk.extensions.get import com.topjohnwu.magisk.model.receiver.GeneralReceiver import com.topjohnwu.magisk.ui.SplashActivity @@ -34,10 +30,10 @@ object Notifications { } fun magiskUpdate(context: Context) { - val intent = Intent(context, ClassMap[SplashActivity::class.java]) - intent.putExtra(Const.Key.OPEN_SECTION, "magisk") + val intent = context.intent(SplashActivity::class.java) + .putExtra(Const.Key.OPEN_SECTION, "magisk") val stackBuilder = TaskStackBuilder.create(context) - stackBuilder.addParentStack(ClassMap.get>(SplashActivity::class.java)) + stackBuilder.addParentStack(SplashActivity::class.java.cmp(context.packageName)) stackBuilder.addNextIntent(intent) val pendingIntent = stackBuilder.getPendingIntent(Const.ID.MAGISK_UPDATE_NOTIFICATION_ID, PendingIntent.FLAG_UPDATE_CURRENT) @@ -54,9 +50,9 @@ object Notifications { } fun managerUpdate(context: Context) { - val intent = Intent(context, ClassMap[GeneralReceiver::class.java]) - intent.action = Const.Key.BROADCAST_MANAGER_UPDATE - intent.putExtra(Const.Key.INTENT_SET_APP, Info.remote.app) + val intent = context.intent(GeneralReceiver::class.java) + .setAction(Const.Key.BROADCAST_MANAGER_UPDATE) + .putExtra(Const.Key.INTENT_SET_APP, Info.remote.app) val pendingIntent = PendingIntent.getBroadcast(context, Const.ID.APK_UPDATE_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT) @@ -73,7 +69,7 @@ object Notifications { } fun dtboPatched(context: Context) { - val intent = Intent(context, ClassMap[GeneralReceiver::class.java]) + val intent = context.intent(GeneralReceiver::class.java) .setAction(Const.Key.BROADCAST_REBOOT) val pendingIntent = PendingIntent.getBroadcast(context, Const.ID.DTBO_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT) diff --git a/app/src/main/java/com/topjohnwu/magisk/view/Shortcuts.kt b/app/src/main/java/com/topjohnwu/magisk/view/Shortcuts.kt index a97720bb8..2b9c13d2f 100644 --- a/app/src/main/java/com/topjohnwu/magisk/view/Shortcuts.kt +++ b/app/src/main/java/com/topjohnwu/magisk/view/Shortcuts.kt @@ -25,10 +25,11 @@ object Shortcuts { private fun getShortCuts(context: Context): List { val shortCuts = mutableListOf() val root = Shell.rootAccess() + val intent = context.intent(SplashActivity::class.java) if (Utils.showSuperUser()) { shortCuts.add(ShortcutInfo.Builder(context, "superuser") .setShortLabel(context.getString(R.string.superuser)) - .setIntent(Intent(context, ClassMap[SplashActivity::class.java]) + .setIntent(Intent(intent) .putExtra(Const.Key.OPEN_SECTION, "superuser") .setAction(Intent.ACTION_VIEW) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)) @@ -39,7 +40,7 @@ object Shortcuts { if (root && Config.magiskHide) { shortCuts.add(ShortcutInfo.Builder(context, "magiskhide") .setShortLabel(context.getString(R.string.magiskhide)) - .setIntent(Intent(context, ClassMap[SplashActivity::class.java]) + .setIntent(Intent(intent) .putExtra(Const.Key.OPEN_SECTION, "magiskhide") .setAction(Intent.ACTION_VIEW) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)) @@ -50,7 +51,7 @@ object Shortcuts { if (!Config.coreOnly && root && Info.magiskVersionCode >= 0) { shortCuts.add(ShortcutInfo.Builder(context, "modules") .setShortLabel(context.getString(R.string.modules)) - .setIntent(Intent(context, ClassMap[SplashActivity::class.java]) + .setIntent(Intent(intent) .putExtra(Const.Key.OPEN_SECTION, "modules") .setAction(Intent.ACTION_VIEW) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)) @@ -59,7 +60,7 @@ object Shortcuts { .build()) shortCuts.add(ShortcutInfo.Builder(context, "downloads") .setShortLabel(context.getString(R.string.downloads)) - .setIntent(Intent(context, ClassMap[SplashActivity::class.java]) + .setIntent(Intent(intent) .putExtra(Const.Key.OPEN_SECTION, "downloads") .setAction(Intent.ACTION_VIEW) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)) diff --git a/stub/src/main/AndroidManifest.xml b/stub/src/main/AndroidManifest.xml index ec810354d..e29f2888d 100644 --- a/stub/src/main/AndroidManifest.xml +++ b/stub/src/main/AndroidManifest.xml @@ -16,8 +16,8 @@ @@ -25,7 +25,7 @@ @@ -37,23 +37,23 @@ @@ -68,7 +68,7 @@ map = new HashMap<>(6); + + // This mapping will be sent into the guest app + static Map inverseMap; + + static { + map.put(a.z.class.getName(), "a.c"); + map.put("a.x", "a.f"); + map.put("a.o", "a.b"); + map.put("a.g", "a.m"); + map.put(a.w.class.getName(), "a.h"); + map.put("a.v", "a.j"); + map.put("a.s", "androidx.work.impl.WorkManagerInitializer"); + + inverseMap = new HashMap<>(map.size()); + for (Map.Entry e : map.entrySet()) { + inverseMap.put(e.getValue(), e.getKey()); + } + } + + static String get(String name) { + String n = map.get(name); + return n != null ? n : name; + } + +} diff --git a/stub/src/main/java/com/topjohnwu/magisk/DelegateApplication.java b/stub/src/main/java/com/topjohnwu/magisk/DelegateApplication.java index e56d66ae8..83ef6879c 100644 --- a/stub/src/main/java/com/topjohnwu/magisk/DelegateApplication.java +++ b/stub/src/main/java/com/topjohnwu/magisk/DelegateApplication.java @@ -13,6 +13,7 @@ import com.topjohnwu.magisk.utils.DynamicClassLoader; import java.io.File; import java.lang.reflect.Method; +import java.util.Map; import static com.topjohnwu.magisk.DownloadActivity.TAG; @@ -44,7 +45,8 @@ public class DelegateApplication extends Application { Object df = cl.loadClass("a.a").newInstance(); // Create the delegate Application - delegate = (Application) cl.loadClass("a.e").newInstance(); + delegate = (Application) cl.loadClass("a.e").getConstructor(Map.class) + .newInstance(ComponentMap.inverseMap); // Call attachBaseContext without ContextImpl to show it is being wrapped Method m = ContextWrapper.class.getDeclaredMethod("attachBaseContext", Context.class); diff --git a/stub/src/main/java/com/topjohnwu/magisk/DelegateComponentFactory.java b/stub/src/main/java/com/topjohnwu/magisk/DelegateComponentFactory.java index 4a60ee911..f7f7e7a08 100644 --- a/stub/src/main/java/com/topjohnwu/magisk/DelegateComponentFactory.java +++ b/stub/src/main/java/com/topjohnwu/magisk/DelegateComponentFactory.java @@ -8,12 +8,15 @@ import android.app.Service; import android.content.BroadcastReceiver; import android.content.ContentProvider; import android.content.Intent; +import android.util.Log; import com.topjohnwu.magisk.dummy.DummyActivity; import com.topjohnwu.magisk.dummy.DummyProvider; import com.topjohnwu.magisk.dummy.DummyReceiver; import com.topjohnwu.magisk.dummy.DummyService; +import static com.topjohnwu.magisk.DownloadActivity.TAG; + @SuppressLint("NewApi") public class DelegateComponentFactory extends AppComponentFactory { @@ -22,39 +25,45 @@ public class DelegateComponentFactory extends AppComponentFactory { @Override public Application instantiateApplication(ClassLoader cl, String className) { - loader = cl; + if (loader == null) loader = cl; + Log.d(TAG, className); return new DelegateApplication(this); } @Override public Activity instantiateActivity(ClassLoader cl, String className, Intent intent) throws ClassNotFoundException, IllegalAccessException, InstantiationException { + Log.d(TAG, className); if (delegate != null) - return delegate.instantiateActivity(loader, className, intent); + return delegate.instantiateActivity(loader, ComponentMap.get(className), intent); return create(className, DummyActivity.class); } @Override public BroadcastReceiver instantiateReceiver(ClassLoader cl, String className, Intent intent) throws ClassNotFoundException, IllegalAccessException, InstantiationException { + Log.d(TAG, className); if (delegate != null) - return delegate.instantiateReceiver(loader, className, intent); + return delegate.instantiateReceiver(loader, ComponentMap.get(className), intent); return create(className, DummyReceiver.class); } @Override public Service instantiateService(ClassLoader cl, String className, Intent intent) throws ClassNotFoundException, IllegalAccessException, InstantiationException { + Log.d(TAG, className); if (delegate != null) - return delegate.instantiateService(loader, className, intent); + return delegate.instantiateService(loader, ComponentMap.get(className), intent); return create(className, DummyService.class); } @Override public ContentProvider instantiateProvider(ClassLoader cl, String className) throws ClassNotFoundException, IllegalAccessException, InstantiationException { + Log.d(TAG, className); + if (loader == null) loader = cl; if (delegate != null) - return delegate.instantiateProvider(loader, className); + return delegate.instantiateProvider(loader, ComponentMap.get(className)); return create(className, DummyProvider.class); } @@ -63,6 +72,7 @@ public class DelegateComponentFactory extends AppComponentFactory { */ private T create(String name, Class dummy) throws InstantiationException, IllegalAccessException { + Log.d(TAG, "create " + name); try { return (T) loader.loadClass(name).newInstance(); } catch (IllegalAccessException | InstantiationException | ClassNotFoundException ignored) { From a910c8ccd8fa53c7e4b00db47798513362bd7a69 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Wed, 16 Oct 2019 05:07:29 -0400 Subject: [PATCH 07/61] Support stub APK upgrades --- .../magisk/model/download/DownloadService.kt | 14 ++++++++++++-- .../magisk/model/download/RemoteFileService.kt | 3 ++- .../com/topjohnwu/magisk/utils/DynAPK.java | 18 ++++++++++++++---- .../topjohnwu/magisk/DelegateApplication.java | 4 +++- 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/model/download/DownloadService.kt b/app/src/main/java/com/topjohnwu/magisk/model/download/DownloadService.kt index ae39a7fb9..70adc04e3 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/download/DownloadService.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/download/DownloadService.kt @@ -7,6 +7,7 @@ import android.content.Intent import android.os.Build import android.webkit.MimeTypeMap import androidx.core.app.NotificationCompat +import com.topjohnwu.magisk.ProcessPhoenix import com.topjohnwu.magisk.R import com.topjohnwu.magisk.extensions.chooser import com.topjohnwu.magisk.extensions.exists @@ -18,6 +19,8 @@ import com.topjohnwu.magisk.model.entity.internal.DownloadSubject import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.* import com.topjohnwu.magisk.ui.flash.FlashActivity import com.topjohnwu.magisk.utils.APKInstall +import com.topjohnwu.magisk.utils.DynAPK +import com.topjohnwu.magisk.utils.isRunningAsStub import org.koin.core.get import java.io.File import kotlin.random.Random.Default.nextInt @@ -62,8 +65,15 @@ open class DownloadService : RemoteFileService() { ) { remove(id) when (subject.configuration) { - is APK.Upgrade -> APKInstall.install(this, subject.file) - else -> Unit + is APK.Upgrade -> { + if (isRunningAsStub) { + subject.file.renameTo(DynAPK.update(this)) + ProcessPhoenix.triggerRebirth(this) + } else { + APKInstall.install(this, subject.file) + } + } + is APK.Restore -> Unit } } diff --git a/app/src/main/java/com/topjohnwu/magisk/model/download/RemoteFileService.kt b/app/src/main/java/com/topjohnwu/magisk/model/download/RemoteFileService.kt index 1c5fea005..ceb35cc85 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/download/RemoteFileService.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/download/RemoteFileService.kt @@ -12,6 +12,7 @@ import com.topjohnwu.magisk.extensions.writeTo import com.topjohnwu.magisk.model.entity.internal.DownloadSubject import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.* import com.topjohnwu.magisk.utils.ProgressInputStream +import com.topjohnwu.magisk.utils.isRunningAsStub import com.topjohnwu.magisk.view.Notifications import com.topjohnwu.superuser.ShellUtils import io.reactivex.Completable @@ -71,7 +72,7 @@ abstract class RemoteFileService : NotificationService() { else -> Completable.fromAction { stream.writeTo(subject.file) } } }.doOnComplete { - if (subject is Manager) + if (!isRunningAsStub && subject is Manager) handleAPK(subject) } diff --git a/shared/src/main/java/com/topjohnwu/magisk/utils/DynAPK.java b/shared/src/main/java/com/topjohnwu/magisk/utils/DynAPK.java index 4c1d170c5..f75d855a7 100644 --- a/shared/src/main/java/com/topjohnwu/magisk/utils/DynAPK.java +++ b/shared/src/main/java/com/topjohnwu/magisk/utils/DynAPK.java @@ -8,9 +8,19 @@ public class DynAPK { private static File dynDir; - public static File current(Context context) { - if (dynDir == null) - dynDir = new File(context.getFilesDir().getParent(), "dyn"); - return new File(dynDir, "current.apk"); + private static File getDynDir(Context c) { + if (dynDir == null) { + dynDir = new File(c.getFilesDir().getParent(), "dyn"); + dynDir.mkdir(); + } + return dynDir; + } + + public static File current(Context c) { + return new File(getDynDir(c), "current.apk"); + } + + public static File update(Context c) { + return new File(getDynDir(c), "update.apk"); } } diff --git a/stub/src/main/java/com/topjohnwu/magisk/DelegateApplication.java b/stub/src/main/java/com/topjohnwu/magisk/DelegateApplication.java index 83ef6879c..c6a46f00e 100644 --- a/stub/src/main/java/com/topjohnwu/magisk/DelegateApplication.java +++ b/stub/src/main/java/com/topjohnwu/magisk/DelegateApplication.java @@ -37,7 +37,9 @@ public class DelegateApplication extends Application { // If 9.0+, try to dynamically load the APK DelegateComponentFactory factory = (DelegateComponentFactory) this.factory; MANAGER_APK = DynAPK.current(this); - MANAGER_APK.getParentFile().mkdir(); + File update = DynAPK.update(this); + if (update.exists()) + update.renameTo(MANAGER_APK); if (MANAGER_APK.exists()) { ClassLoader cl = new DynamicClassLoader(MANAGER_APK, factory.loader); try { From 9f9de8c43bb8669031f8a253d34fc769a69486d7 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Wed, 16 Oct 2019 17:03:55 -0400 Subject: [PATCH 08/61] Obfuscate WorkManager components Remove unused components and hack the context sent into WorkManager --- app/src/main/AndroidManifest.xml | 6 + app/src/main/java/a/w.java | 4 +- app/src/main/java/com/topjohnwu/magisk/App.kt | 5 +- .../java/com/topjohnwu/magisk/ClassMap.kt | 44 ---- .../main/java/com/topjohnwu/magisk/Hacks.kt | 223 ++++++++++++++++++ .../com/topjohnwu/magisk/base/BaseActivity.kt | 2 +- .../com/topjohnwu/magisk/base/BaseReceiver.kt | 2 +- .../com/topjohnwu/magisk/base/BaseService.kt | 2 +- .../magisk/model/download/DownloadService.kt | 2 +- .../model/download/RemoteFileService.kt | 2 +- .../com/topjohnwu/magisk/ui/SplashActivity.kt | 2 +- .../magisk/ui/settings/SettingsFragment.kt | 5 +- .../com/topjohnwu/magisk/utils/Locales.kt | 49 ++++ .../com/topjohnwu/magisk/utils/ResourceMgr.kt | 126 ---------- .../com/topjohnwu/magisk/utils/RootInit.kt | 1 + stub/src/main/AndroidManifest.xml | 28 +-- .../com/topjohnwu/magisk/ComponentMap.java | 4 +- 17 files changed, 295 insertions(+), 212 deletions(-) delete mode 100644 app/src/main/java/com/topjohnwu/magisk/ClassMap.kt create mode 100644 app/src/main/java/com/topjohnwu/magisk/Hacks.kt create mode 100644 app/src/main/java/com/topjohnwu/magisk/utils/Locales.kt delete mode 100644 app/src/main/java/com/topjohnwu/magisk/utils/ResourceMgr.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4d76d7753..b4d2737fa 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -97,6 +97,12 @@ android:name="com.google.android.gms.version" android:value="12451000" /> + + + diff --git a/app/src/main/java/a/w.java b/app/src/main/java/a/w.java index 6fa3e50f6..f1307a025 100644 --- a/app/src/main/java/a/w.java +++ b/app/src/main/java/a/w.java @@ -6,8 +6,8 @@ import androidx.annotation.NonNull; import androidx.work.Worker; import androidx.work.WorkerParameters; +import com.topjohnwu.magisk.HacksKt; import com.topjohnwu.magisk.base.DelegateWorker; -import com.topjohnwu.magisk.utils.ResourceMgrKt; import java.lang.reflect.ParameterizedType; @@ -19,7 +19,7 @@ public abstract class w extends Worker { @SuppressWarnings("unchecked") w(@NonNull Context context, @NonNull WorkerParameters workerParams) { - super(ResourceMgrKt.wrap(context, false), workerParams); + super(HacksKt.wrap(context, false), workerParams); try { base = ((Class) ((ParameterizedType) getClass().getGenericSuperclass()) .getActualTypeArguments()[0]).newInstance(); diff --git a/app/src/main/java/com/topjohnwu/magisk/App.kt b/app/src/main/java/com/topjohnwu/magisk/App.kt index 8c448a784..b70f6d753 100644 --- a/app/src/main/java/com/topjohnwu/magisk/App.kt +++ b/app/src/main/java/com/topjohnwu/magisk/App.kt @@ -6,6 +6,7 @@ import android.content.res.Configuration import androidx.appcompat.app.AppCompatDelegate import androidx.multidex.MultiDex import androidx.room.Room +import androidx.work.WorkManager import androidx.work.impl.WorkDatabase import androidx.work.impl.WorkDatabase_Impl import com.topjohnwu.magisk.data.database.RepoDatabase @@ -14,10 +15,7 @@ import com.topjohnwu.magisk.di.ActivityTracker import com.topjohnwu.magisk.di.koinModules import com.topjohnwu.magisk.extensions.get import com.topjohnwu.magisk.extensions.unwrap -import com.topjohnwu.magisk.utils.ResourceMgr import com.topjohnwu.magisk.utils.RootInit -import com.topjohnwu.magisk.utils.isRunningAsStub -import com.topjohnwu.magisk.utils.wrap import com.topjohnwu.superuser.Shell import org.koin.android.ext.koin.androidContext import org.koin.core.context.startKoin @@ -72,6 +70,7 @@ open class App() : Application() { } ResourceMgr.reload() app.registerActivityLifecycleCallbacks(get()) + WorkManager.initialize(impl.wrapJob(), androidx.work.Configuration.Builder().build()) } // This is required as some platforms expect ContextImpl diff --git a/app/src/main/java/com/topjohnwu/magisk/ClassMap.kt b/app/src/main/java/com/topjohnwu/magisk/ClassMap.kt deleted file mode 100644 index 79217a2d2..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/ClassMap.kt +++ /dev/null @@ -1,44 +0,0 @@ -package com.topjohnwu.magisk - -import android.content.ComponentName -import android.content.Context -import android.content.Intent -import com.topjohnwu.magisk.model.download.DownloadService -import com.topjohnwu.magisk.model.receiver.GeneralReceiver -import com.topjohnwu.magisk.model.update.UpdateCheckService -import com.topjohnwu.magisk.ui.MainActivity -import com.topjohnwu.magisk.ui.SplashActivity -import com.topjohnwu.magisk.ui.flash.FlashActivity -import com.topjohnwu.magisk.ui.surequest.SuRequestActivity - -object ClassMap { - - private val classMap = mapOf( - App::class.java to a.e::class.java, - MainActivity::class.java to a.b::class.java, - SplashActivity::class.java to a.c::class.java, - FlashActivity::class.java to a.f::class.java, - UpdateCheckService::class.java to a.g::class.java, - GeneralReceiver::class.java to a.h::class.java, - DownloadService::class.java to a.j::class.java, - SuRequestActivity::class.java to a.m::class.java - ) - - // This will be set if running as guest app - var componentMap: Map? = null - - operator fun get(c: Class<*>) = classMap.getOrElse(c) { throw IllegalArgumentException() } -} - -fun Class<*>.cmp(pkg: String = BuildConfig.APPLICATION_ID): ComponentName { - val name = ClassMap[this].name - return ComponentName(pkg, ClassMap.componentMap?.get(name) ?: name) -} - -fun Context.intent(c: Class<*>): Intent { - val cls = ClassMap[c] - return ClassMap.componentMap?.let { - val className = it.getOrElse(cls.name) { cls.name } - Intent().setComponent(ComponentName(this, className)) - } ?: Intent(this, cls) -} diff --git a/app/src/main/java/com/topjohnwu/magisk/Hacks.kt b/app/src/main/java/com/topjohnwu/magisk/Hacks.kt new file mode 100644 index 000000000..4f12a5b56 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/Hacks.kt @@ -0,0 +1,223 @@ +@file:Suppress("DEPRECATION") + +package com.topjohnwu.magisk + +import android.annotation.SuppressLint +import android.app.job.JobInfo +import android.app.job.JobScheduler +import android.app.job.JobWorkItem +import android.content.ComponentName +import android.content.Context +import android.content.ContextWrapper +import android.content.Intent +import android.content.res.AssetManager +import android.content.res.Configuration +import android.content.res.Resources +import androidx.annotation.RequiresApi +import androidx.annotation.StringRes +import com.topjohnwu.magisk.extensions.langTagToLocale +import com.topjohnwu.magisk.model.download.DownloadService +import com.topjohnwu.magisk.model.receiver.GeneralReceiver +import com.topjohnwu.magisk.model.update.UpdateCheckService +import com.topjohnwu.magisk.ui.MainActivity +import com.topjohnwu.magisk.ui.SplashActivity +import com.topjohnwu.magisk.ui.flash.FlashActivity +import com.topjohnwu.magisk.ui.surequest.SuRequestActivity +import com.topjohnwu.magisk.utils.DynAPK +import com.topjohnwu.magisk.utils.currentLocale +import com.topjohnwu.magisk.utils.defaultLocale +import java.util.* + +var isRunningAsStub = false + +private val addAssetPath by lazy { + AssetManager::class.java.getMethod("addAssetPath", String::class.java) +} + +fun AssetManager.addAssetPath(path: String) { + addAssetPath.invoke(this, path) +} + +fun Context.wrap(global: Boolean = true): Context + = if (!global) ResContext(this) else GlobalResContext(this) + +fun Context.wrapJob(): Context = object : GlobalResContext(this) { + + @SuppressLint("NewApi") + override fun getSystemService(name: String): Any? { + return if (!isRunningAsStub) super.getSystemService(name) else + when (name) { + Context.JOB_SCHEDULER_SERVICE -> + JobSchedulerWrapper(super.getSystemService(name) as JobScheduler) + else -> super.getSystemService(name) + } + } +} + +// Override locale and inject resources from dynamic APK +private fun Resources.patch(config: Configuration = Configuration(configuration)): Resources { + config.setLocale(currentLocale) + updateConfiguration(config, displayMetrics) + if (isRunningAsStub) + assets.addAssetPath(ResourceMgr.resApk) + return this +} + +fun Class<*>.cmp(pkg: String = BuildConfig.APPLICATION_ID): ComponentName { + val name = ClassMap[this].name + return ComponentName(pkg, ClassMap.componentMap?.get(name) + ?: name) +} + +fun Context.intent(c: Class<*>): Intent { + val cls = ClassMap[c] + return ClassMap.componentMap?.let { + val className = it.getOrElse(cls.name) { cls.name } + Intent().setComponent(ComponentName(this, className)) + } ?: Intent(this, cls) +} + +private open class GlobalResContext(base: Context) : ContextWrapper(base) { + open val mRes: Resources get() = ResourceMgr.resource + private val loader by lazy { javaClass.classLoader!! } + + override fun getApplicationContext(): Context { + return this + } + + override fun getResources(): Resources { + return mRes + } + + override fun getClassLoader(): ClassLoader { + return loader + } + + override fun createConfigurationContext(config: Configuration): Context { + return ResContext(super.createConfigurationContext(config)) + } +} + +private class ResContext(base: Context) : GlobalResContext(base) { + override val mRes by lazy { base.resources.patch() } +} + +object ResourceMgr { + + internal lateinit var resource: Resources + internal lateinit var resApk: String + + fun init(context: Context) { + resource = context.resources + if (isRunningAsStub) + resApk = DynAPK.current(context).path + } + + fun reload(config: Configuration = Configuration(resource.configuration)) { + val localeConfig = Config.locale + currentLocale = when { + localeConfig.isEmpty() -> defaultLocale + else -> localeConfig.langTagToLocale() + } + Locale.setDefault(currentLocale) + resource.patch(config) + } + + fun getString(locale: Locale, @StringRes id: Int): String { + val config = Configuration() + config.setLocale(locale) + return Resources(resource.assets, resource.displayMetrics, config).getString(id) + } + +} + +@RequiresApi(api = 28) +private class JobSchedulerWrapper(private val base: JobScheduler) : JobScheduler() { + + override fun schedule(job: JobInfo): Int { + return base.schedule(job.patch()) + } + + override fun enqueue(job: JobInfo, work: JobWorkItem): Int { + return base.enqueue(job.patch(), work) + } + + override fun cancel(jobId: Int) { + base.cancel(jobId) + } + + override fun cancelAll() { + base.cancelAll() + } + + override fun getAllPendingJobs(): List { + return base.allPendingJobs + } + + override fun getPendingJob(jobId: Int): JobInfo? { + return base.getPendingJob(jobId) + } + + fun JobInfo.patch(): JobInfo { + // We need to patch the component of JobInfo to access WorkManager SystemJobService + + val name = service.className + val component = ComponentName(service.packageName, ClassMap.componentMap?.get(name) + ?: name) + + // Clone the JobInfo except component + val builder = JobInfo.Builder(id, component) + .setExtras(extras) + .setTransientExtras(transientExtras) + .setClipData(clipData, clipGrantFlags) + .setRequiredNetwork(requiredNetwork) + .setEstimatedNetworkBytes(estimatedNetworkDownloadBytes, estimatedNetworkUploadBytes) + .setRequiresCharging(isRequireCharging) + .setRequiresDeviceIdle(isRequireDeviceIdle) + .setRequiresBatteryNotLow(isRequireBatteryNotLow) + .setRequiresStorageNotLow(isRequireStorageNotLow) + .also { + triggerContentUris?.let { uris -> + for (uri in uris) + it.addTriggerContentUri(uri) + } + } + .setTriggerContentUpdateDelay(triggerContentUpdateDelay) + .setTriggerContentMaxDelay(triggerContentMaxDelay) + .setImportantWhileForeground(isImportantWhileForeground) + .setPrefetch(isPrefetch) + .setPersisted(isPersisted) + + if (isPeriodic) { + builder.setPeriodic(intervalMillis, flexMillis) + } else { + if (minLatencyMillis > 0) + builder.setMinimumLatency(minLatencyMillis) + if (maxExecutionDelayMillis > 0) + builder.setOverrideDeadline(maxExecutionDelayMillis) + } + if (!isRequireDeviceIdle) + builder.setBackoffCriteria(initialBackoffMillis, backoffPolicy) + + return builder.build() + } +} + +object ClassMap { + + private val classMap = mapOf( + App::class.java to a.e::class.java, + MainActivity::class.java to a.b::class.java, + SplashActivity::class.java to a.c::class.java, + FlashActivity::class.java to a.f::class.java, + UpdateCheckService::class.java to a.g::class.java, + GeneralReceiver::class.java to a.h::class.java, + DownloadService::class.java to a.j::class.java, + SuRequestActivity::class.java to a.m::class.java + ) + + // This will be set if running as guest app + var componentMap: Map? = null + + operator fun get(c: Class<*>) = classMap.getOrElse(c) { throw IllegalArgumentException() } +} diff --git a/app/src/main/java/com/topjohnwu/magisk/base/BaseActivity.kt b/app/src/main/java/com/topjohnwu/magisk/base/BaseActivity.kt index 0b8fed26f..0c4435dee 100644 --- a/app/src/main/java/com/topjohnwu/magisk/base/BaseActivity.kt +++ b/app/src/main/java/com/topjohnwu/magisk/base/BaseActivity.kt @@ -21,7 +21,7 @@ import com.topjohnwu.magisk.extensions.set import com.topjohnwu.magisk.model.events.EventHandler import com.topjohnwu.magisk.model.permissions.PermissionRequestBuilder import com.topjohnwu.magisk.utils.currentLocale -import com.topjohnwu.magisk.utils.wrap +import com.topjohnwu.magisk.wrap import kotlin.random.Random typealias RequestCallback = BaseActivity<*, *>.(Int, Intent?) -> Unit diff --git a/app/src/main/java/com/topjohnwu/magisk/base/BaseReceiver.kt b/app/src/main/java/com/topjohnwu/magisk/base/BaseReceiver.kt index 2e96a6b11..e3f07e620 100644 --- a/app/src/main/java/com/topjohnwu/magisk/base/BaseReceiver.kt +++ b/app/src/main/java/com/topjohnwu/magisk/base/BaseReceiver.kt @@ -4,7 +4,7 @@ import android.content.BroadcastReceiver import android.content.Context import android.content.ContextWrapper import android.content.Intent -import com.topjohnwu.magisk.utils.wrap +import com.topjohnwu.magisk.wrap import org.koin.core.KoinComponent abstract class BaseReceiver : BroadcastReceiver(), KoinComponent { diff --git a/app/src/main/java/com/topjohnwu/magisk/base/BaseService.kt b/app/src/main/java/com/topjohnwu/magisk/base/BaseService.kt index dc7801664..b7a65ccc2 100644 --- a/app/src/main/java/com/topjohnwu/magisk/base/BaseService.kt +++ b/app/src/main/java/com/topjohnwu/magisk/base/BaseService.kt @@ -2,7 +2,7 @@ package com.topjohnwu.magisk.base import android.app.Service import android.content.Context -import com.topjohnwu.magisk.utils.wrap +import com.topjohnwu.magisk.wrap import org.koin.core.KoinComponent abstract class BaseService : Service(), KoinComponent { diff --git a/app/src/main/java/com/topjohnwu/magisk/model/download/DownloadService.kt b/app/src/main/java/com/topjohnwu/magisk/model/download/DownloadService.kt index 70adc04e3..f22ba0af7 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/download/DownloadService.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/download/DownloadService.kt @@ -20,7 +20,7 @@ import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.* import com.topjohnwu.magisk.ui.flash.FlashActivity import com.topjohnwu.magisk.utils.APKInstall import com.topjohnwu.magisk.utils.DynAPK -import com.topjohnwu.magisk.utils.isRunningAsStub +import com.topjohnwu.magisk.isRunningAsStub import org.koin.core.get import java.io.File import kotlin.random.Random.Default.nextInt diff --git a/app/src/main/java/com/topjohnwu/magisk/model/download/RemoteFileService.kt b/app/src/main/java/com/topjohnwu/magisk/model/download/RemoteFileService.kt index ceb35cc85..8e6dfa6be 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/download/RemoteFileService.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/download/RemoteFileService.kt @@ -12,7 +12,7 @@ import com.topjohnwu.magisk.extensions.writeTo import com.topjohnwu.magisk.model.entity.internal.DownloadSubject import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.* import com.topjohnwu.magisk.utils.ProgressInputStream -import com.topjohnwu.magisk.utils.isRunningAsStub +import com.topjohnwu.magisk.isRunningAsStub import com.topjohnwu.magisk.view.Notifications import com.topjohnwu.superuser.ShellUtils import io.reactivex.Completable diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/SplashActivity.kt b/app/src/main/java/com/topjohnwu/magisk/ui/SplashActivity.kt index 6a43ddb73..75d814ce2 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/SplashActivity.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/SplashActivity.kt @@ -7,7 +7,7 @@ import android.text.TextUtils import androidx.appcompat.app.AlertDialog import com.topjohnwu.magisk.* import com.topjohnwu.magisk.utils.Utils -import com.topjohnwu.magisk.utils.wrap +import com.topjohnwu.magisk.wrap import com.topjohnwu.magisk.view.Notifications import com.topjohnwu.magisk.view.Shortcuts import com.topjohnwu.superuser.Shell diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt b/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt index a3457ddd0..c67ce091a 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt @@ -13,10 +13,7 @@ import androidx.preference.ListPreference import androidx.preference.Preference import androidx.preference.PreferenceCategory import androidx.preference.SwitchPreferenceCompat -import com.topjohnwu.magisk.BuildConfig -import com.topjohnwu.magisk.Config -import com.topjohnwu.magisk.Const -import com.topjohnwu.magisk.R +import com.topjohnwu.magisk.* import com.topjohnwu.magisk.base.BasePreferenceFragment import com.topjohnwu.magisk.data.database.RepoDao import com.topjohnwu.magisk.databinding.CustomDownloadDialogBinding diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/Locales.kt b/app/src/main/java/com/topjohnwu/magisk/utils/Locales.kt new file mode 100644 index 000000000..f5fe0c8ea --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Locales.kt @@ -0,0 +1,49 @@ +package com.topjohnwu.magisk.utils + +import android.annotation.SuppressLint +import android.content.res.Configuration +import android.content.res.Resources +import com.topjohnwu.magisk.R +import com.topjohnwu.magisk.ResourceMgr +import com.topjohnwu.magisk.extensions.langTagToLocale +import io.reactivex.Single +import java.util.* +import kotlin.Comparator + +var currentLocale: Locale = Locale.getDefault() + +@SuppressLint("ConstantLocale") +val defaultLocale: Locale = Locale.getDefault() + +@Suppress("DEPRECATION") +val availableLocales = Single.fromCallable { + val compareId = R.string.app_changelog + mutableListOf().apply { + // Add default locale + add(Locale.ENGLISH) + + // Add some special locales + add(Locale.TAIWAN) + add(Locale("pt", "BR")) + + val config = Configuration() + val metrics = ResourceMgr.resource.displayMetrics + val res = Resources(ResourceMgr.resource.assets, metrics, config) + + // Other locales + val otherLocales = ResourceMgr.resource.assets.locales + .map { it.langTagToLocale() } + .distinctBy { + config.setLocale(it) + res.updateConfiguration(config, metrics) + res.getString(compareId) + } + + listOf("", "").toTypedArray() + + addAll(otherLocales) + }.sortedWith(Comparator { a, b -> + a.getDisplayName(a).toLowerCase(a) + .compareTo(b.getDisplayName(b).toLowerCase(b)) + }) +}.cache()!! diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/ResourceMgr.kt b/app/src/main/java/com/topjohnwu/magisk/utils/ResourceMgr.kt deleted file mode 100644 index fb3d7d503..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/utils/ResourceMgr.kt +++ /dev/null @@ -1,126 +0,0 @@ -@file:Suppress("DEPRECATION") - -package com.topjohnwu.magisk.utils - -import android.annotation.SuppressLint -import android.content.Context -import android.content.ContextWrapper -import android.content.res.AssetManager -import android.content.res.Configuration -import android.content.res.Resources -import androidx.annotation.StringRes -import com.topjohnwu.magisk.Config -import com.topjohnwu.magisk.R -import com.topjohnwu.magisk.extensions.langTagToLocale -import io.reactivex.Single -import java.util.* - -var isRunningAsStub = false - -var currentLocale: Locale = Locale.getDefault() - private set - -@SuppressLint("ConstantLocale") -val defaultLocale: Locale = Locale.getDefault() - -val availableLocales = Single.fromCallable { - val compareId = R.string.app_changelog - mutableListOf().apply { - // Add default locale - add(Locale.ENGLISH) - - // Add some special locales - add(Locale.TAIWAN) - add(Locale("pt", "BR")) - - val config = Configuration() - val metrics = ResourceMgr.resource.displayMetrics - val res = Resources(ResourceMgr.resource.assets, metrics, config) - - // Other locales - val otherLocales = ResourceMgr.resource.assets.locales - .map { it.langTagToLocale() } - .distinctBy { - config.setLocale(it) - res.updateConfiguration(config, metrics) - res.getString(compareId) - } - - listOf("", "").toTypedArray() - - addAll(otherLocales) - }.sortedWith(Comparator { a, b -> - a.getDisplayName(a).toLowerCase(a) - .compareTo(b.getDisplayName(b).toLowerCase(b)) - }) -}.cache()!! - -private val addAssetPath by lazy { - AssetManager::class.java.getMethod("addAssetPath", String::class.java) -} - -fun AssetManager.addAssetPath(path: String) { - addAssetPath.invoke(this, path) -} - -fun Context.wrap(global: Boolean = true): Context - = if (!global) ResourceMgr.ResContext(this) else ResourceMgr.GlobalResContext(this) - -object ResourceMgr { - - lateinit var resource: Resources - private lateinit var resApk: String - - fun init(context: Context) { - resource = context.resources - if (isRunningAsStub) - resApk = DynAPK.current(context).path - } - - // Override locale and inject resources from dynamic APK - private fun Resources.patch(config: Configuration = Configuration(configuration)): Resources { - config.setLocale(currentLocale) - updateConfiguration(config, displayMetrics) - if (isRunningAsStub) - assets.addAssetPath(resApk) - return this - } - - fun reload(config: Configuration = Configuration(resource.configuration)) { - val localeConfig = Config.locale - currentLocale = when { - localeConfig.isEmpty() -> defaultLocale - else -> localeConfig.langTagToLocale() - } - Locale.setDefault(currentLocale) - resource.patch(config) - } - - fun getString(locale: Locale, @StringRes id: Int): String { - val config = Configuration() - config.setLocale(locale) - return Resources(resource.assets, resource.displayMetrics, config).getString(id) - } - - open class GlobalResContext(base: Context) : ContextWrapper(base) { - open val mRes: Resources get() = resource - private val loader by lazy { javaClass.classLoader!! } - - override fun getResources(): Resources { - return mRes - } - - override fun getClassLoader(): ClassLoader { - return loader - } - - override fun createConfigurationContext(config: Configuration): Context { - return ResContext(super.createConfigurationContext(config)) - } - } - - class ResContext(base: Context) : GlobalResContext(base) { - override val mRes by lazy { base.resources.patch() } - } - -} diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/RootInit.kt b/app/src/main/java/com/topjohnwu/magisk/utils/RootInit.kt index c4bbfde4e..481ce2d02 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/RootInit.kt +++ b/app/src/main/java/com/topjohnwu/magisk/utils/RootInit.kt @@ -5,6 +5,7 @@ import com.topjohnwu.magisk.Const import com.topjohnwu.magisk.Info import com.topjohnwu.magisk.R import com.topjohnwu.magisk.extensions.rawResource +import com.topjohnwu.magisk.wrap import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.ShellUtils import com.topjohnwu.superuser.io.SuFile diff --git a/stub/src/main/AndroidManifest.xml b/stub/src/main/AndroidManifest.xml index e29f2888d..36428315f 100644 --- a/stub/src/main/AndroidManifest.xml +++ b/stub/src/main/AndroidManifest.xml @@ -75,36 +75,14 @@ android:name="com.google.android.gms.version" android:value="12451000" /> - - - + - - - - - - + android:permission="android.permission.BIND_JOB_SERVICE" /> diff --git a/stub/src/main/java/com/topjohnwu/magisk/ComponentMap.java b/stub/src/main/java/com/topjohnwu/magisk/ComponentMap.java index dfd03b253..bc067e09b 100644 --- a/stub/src/main/java/com/topjohnwu/magisk/ComponentMap.java +++ b/stub/src/main/java/com/topjohnwu/magisk/ComponentMap.java @@ -4,7 +4,7 @@ import java.util.HashMap; import java.util.Map; class ComponentMap { - private static Map map = new HashMap<>(6); + private static Map map = new HashMap<>(); // This mapping will be sent into the guest app static Map inverseMap; @@ -16,7 +16,7 @@ class ComponentMap { map.put("a.g", "a.m"); map.put(a.w.class.getName(), "a.h"); map.put("a.v", "a.j"); - map.put("a.s", "androidx.work.impl.WorkManagerInitializer"); + map.put("a.j", "androidx.work.impl.background.systemjob.SystemJobService"); inverseMap = new HashMap<>(map.size()); for (Map.Entry e : map.entrySet()) { From 40eda05a3094a0669c8a8fdc6ef9a1b25c01d44b Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Thu, 17 Oct 2019 02:04:22 -0400 Subject: [PATCH 09/61] Make main app fully independent from the stub - Skip 0x7f01XXXX - 0x7f05XXXX resource IDs in the main app; they are reserved for stub resources - Support sending additional data from host to guest - Use resource mapping passed from host when they are being sent to the system framework (notifications and shortcuts) --- .gitignore | 1 - app/res-ids.txt | 5 ++ app/src/main/java/a/e.java | 6 +- app/src/main/java/com/topjohnwu/magisk/App.kt | 7 +- .../main/java/com/topjohnwu/magisk/Hacks.kt | 39 ++++++----- .../topjohnwu/magisk/view/Notifications.kt | 8 ++- .../com/topjohnwu/magisk/view/Shortcuts.kt | 13 ++-- app/src/main/res/values/resources.xml | 12 ---- build.gradle | 11 ++-- .../com/topjohnwu/magisk/utils/DynAPK.java | 32 ++++++++++ stable-ids.txt | 32 ---------- stub/res-ids.txt | 27 ++++++++ .../work/impl/WorkManagerInitializer.java | 12 ---- .../topjohnwu/magisk/DelegateApplication.java | 64 ++++++++++--------- .../magisk/DelegateComponentFactory.java | 8 +-- .../{ComponentMap.java => Mapping.java} | 17 +++-- 16 files changed, 161 insertions(+), 133 deletions(-) create mode 100644 app/res-ids.txt delete mode 100644 stable-ids.txt create mode 100644 stub/res-ids.txt delete mode 100644 stub/src/main/java/androidx/work/impl/WorkManagerInitializer.java rename stub/src/main/java/com/topjohnwu/magisk/{ComponentMap.java => Mapping.java} (56%) diff --git a/.gitignore b/.gitignore index 9630aa645..83911abb4 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,6 @@ out *.apk /config.prop /update.sh -/stub-ids.txt # Built binaries native/out diff --git a/app/res-ids.txt b/app/res-ids.txt new file mode 100644 index 000000000..3a47acfe6 --- /dev/null +++ b/app/res-ids.txt @@ -0,0 +1,5 @@ +com.topjohnwu.magisk:color/xxxxxxxx = 0x7f010000 +com.topjohnwu.magisk:drawable/xxxxxxxx = 0x7f020000 +com.topjohnwu.magisk:string/xxxxxxxx = 0x7f030000 +com.topjohnwu.magisk:style/xxxxxxxx = 0x7f040000 +com.topjohnwu.magisk:xml/xxxxxxxx = 0x7f050000 diff --git a/app/src/main/java/a/e.java b/app/src/main/java/a/e.java index 56396b034..e2f243e94 100644 --- a/app/src/main/java/a/e.java +++ b/app/src/main/java/a/e.java @@ -2,14 +2,12 @@ package a; import com.topjohnwu.magisk.App; -import java.util.Map; - public class e extends App { public e() { super(); } - public e(Map map) { - super(map); + public e(Object o) { + super(o); } } diff --git a/app/src/main/java/com/topjohnwu/magisk/App.kt b/app/src/main/java/com/topjohnwu/magisk/App.kt index b70f6d753..4bc13958b 100644 --- a/app/src/main/java/com/topjohnwu/magisk/App.kt +++ b/app/src/main/java/com/topjohnwu/magisk/App.kt @@ -15,6 +15,7 @@ import com.topjohnwu.magisk.di.ActivityTracker import com.topjohnwu.magisk.di.koinModules import com.topjohnwu.magisk.extensions.get import com.topjohnwu.magisk.extensions.unwrap +import com.topjohnwu.magisk.utils.DynAPK import com.topjohnwu.magisk.utils.RootInit import com.topjohnwu.superuser.Shell import org.koin.android.ext.koin.androidContext @@ -23,9 +24,8 @@ import timber.log.Timber open class App() : Application() { - constructor(map: Map) : this() { - isRunningAsStub = true - ClassMap.componentMap = map + constructor(o: Any) : this() { + ClassMap.data = DynAPK.load(o) } init { @@ -53,7 +53,6 @@ open class App() : Application() { val app: Application val impl: Context if (base is Application) { - isRunningAsStub = true app = base impl = base.baseContext } else { diff --git a/app/src/main/java/com/topjohnwu/magisk/Hacks.kt b/app/src/main/java/com/topjohnwu/magisk/Hacks.kt index 4f12a5b56..8b638e32c 100644 --- a/app/src/main/java/com/topjohnwu/magisk/Hacks.kt +++ b/app/src/main/java/com/topjohnwu/magisk/Hacks.kt @@ -28,7 +28,7 @@ import com.topjohnwu.magisk.utils.currentLocale import com.topjohnwu.magisk.utils.defaultLocale import java.util.* -var isRunningAsStub = false +val isRunningAsStub get() = ClassMap.data != null private val addAssetPath by lazy { AssetManager::class.java.getMethod("addAssetPath", String::class.java) @@ -39,10 +39,14 @@ fun AssetManager.addAssetPath(path: String) { } fun Context.wrap(global: Boolean = true): Context - = if (!global) ResContext(this) else GlobalResContext(this) + = if (global) GlobalResContext(this) else ResContext(this) fun Context.wrapJob(): Context = object : GlobalResContext(this) { + override fun getApplicationContext(): Context { + return this + } + @SuppressLint("NewApi") override fun getSystemService(name: String): Any? { return if (!isRunningAsStub) super.getSystemService(name) else @@ -65,26 +69,32 @@ private fun Resources.patch(config: Configuration = Configuration(configuration) fun Class<*>.cmp(pkg: String = BuildConfig.APPLICATION_ID): ComponentName { val name = ClassMap[this].name - return ComponentName(pkg, ClassMap.componentMap?.get(name) - ?: name) + return ComponentName(pkg, ClassMap.data?.componentMap?.get(name) ?: name) } fun Context.intent(c: Class<*>): Intent { val cls = ClassMap[c] - return ClassMap.componentMap?.let { - val className = it.getOrElse(cls.name) { cls.name } + return ClassMap.data?.let { + val className = it.componentMap.getOrElse(cls.name) { cls.name } Intent().setComponent(ComponentName(this, className)) } ?: Intent(this, cls) } +fun resolveRes(idx: Int): Int { + return ClassMap.data?.resourceMap?.get(idx) ?: when(idx) { + DynAPK.NOTIFICATION -> R.drawable.ic_magisk_outline + DynAPK.DOWNLOAD -> R.drawable.sc_cloud_download + DynAPK.SUPERUSER -> R.drawable.sc_superuser + DynAPK.MODULES -> R.drawable.sc_extension + DynAPK.MAGISKHIDE -> R.drawable.sc_magiskhide + else -> -1 + } +} + private open class GlobalResContext(base: Context) : ContextWrapper(base) { open val mRes: Resources get() = ResourceMgr.resource private val loader by lazy { javaClass.classLoader!! } - override fun getApplicationContext(): Context { - return this - } - override fun getResources(): Resources { return mRes } @@ -162,7 +172,7 @@ private class JobSchedulerWrapper(private val base: JobScheduler) : JobScheduler // We need to patch the component of JobInfo to access WorkManager SystemJobService val name = service.className - val component = ComponentName(service.packageName, ClassMap.componentMap?.get(name) + val component = ComponentName(service.packageName, ClassMap.data?.componentMap?.get(name) ?: name) // Clone the JobInfo except component @@ -205,7 +215,7 @@ private class JobSchedulerWrapper(private val base: JobScheduler) : JobScheduler object ClassMap { - private val classMap = mapOf( + private val map = mapOf( App::class.java to a.e::class.java, MainActivity::class.java to a.b::class.java, SplashActivity::class.java to a.c::class.java, @@ -216,8 +226,7 @@ object ClassMap { SuRequestActivity::class.java to a.m::class.java ) - // This will be set if running as guest app - var componentMap: Map? = null + internal var data: DynAPK.Data? = null - operator fun get(c: Class<*>) = classMap.getOrElse(c) { throw IllegalArgumentException() } + operator fun get(c: Class<*>) = map.getOrElse(c) { throw IllegalArgumentException() } } diff --git a/app/src/main/java/com/topjohnwu/magisk/view/Notifications.kt b/app/src/main/java/com/topjohnwu/magisk/view/Notifications.kt index cb036d544..20f113ae8 100644 --- a/app/src/main/java/com/topjohnwu/magisk/view/Notifications.kt +++ b/app/src/main/java/com/topjohnwu/magisk/view/Notifications.kt @@ -12,10 +12,12 @@ import com.topjohnwu.magisk.* import com.topjohnwu.magisk.extensions.get import com.topjohnwu.magisk.model.receiver.GeneralReceiver import com.topjohnwu.magisk.ui.SplashActivity +import com.topjohnwu.magisk.utils.DynAPK object Notifications { val mgr by lazy { NotificationManagerCompat.from(get()) } + private val icon by lazy { resolveRes(DynAPK.NOTIFICATION) } fun setup(context: Context) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { @@ -39,7 +41,7 @@ object Notifications { PendingIntent.FLAG_UPDATE_CURRENT) val builder = NotificationCompat.Builder(context, Const.ID.UPDATE_NOTIFICATION_CHANNEL) - builder.setSmallIcon(R.drawable.ic_magisk_outline) + builder.setSmallIcon(icon) .setContentTitle(context.getString(R.string.magisk_update_title)) .setContentText(context.getString(R.string.manager_download_install)) .setVibrate(longArrayOf(0, 100, 100, 100)) @@ -58,7 +60,7 @@ object Notifications { Const.ID.APK_UPDATE_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT) val builder = NotificationCompat.Builder(context, Const.ID.UPDATE_NOTIFICATION_CHANNEL) - builder.setSmallIcon(R.drawable.ic_magisk_outline) + builder.setSmallIcon(icon) .setContentTitle(context.getString(R.string.manager_update_title)) .setContentText(context.getString(R.string.manager_download_install)) .setVibrate(longArrayOf(0, 100, 100, 100)) @@ -75,7 +77,7 @@ object Notifications { Const.ID.DTBO_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT) val builder = NotificationCompat.Builder(context, Const.ID.UPDATE_NOTIFICATION_CHANNEL) - builder.setSmallIcon(R.drawable.ic_magisk_outline) + builder.setSmallIcon(icon) .setContentTitle(context.getString(R.string.dtbo_patched_title)) .setContentText(context.getString(R.string.dtbo_patched_reboot)) .setVibrate(longArrayOf(0, 100, 100, 100)) diff --git a/app/src/main/java/com/topjohnwu/magisk/view/Shortcuts.kt b/app/src/main/java/com/topjohnwu/magisk/view/Shortcuts.kt index 2b9c13d2f..7a2d210b6 100644 --- a/app/src/main/java/com/topjohnwu/magisk/view/Shortcuts.kt +++ b/app/src/main/java/com/topjohnwu/magisk/view/Shortcuts.kt @@ -9,19 +9,20 @@ import android.os.Build import androidx.annotation.RequiresApi import com.topjohnwu.magisk.* import com.topjohnwu.magisk.ui.SplashActivity +import com.topjohnwu.magisk.utils.DynAPK import com.topjohnwu.magisk.utils.Utils import com.topjohnwu.superuser.Shell object Shortcuts { fun setup(context: Context) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { + if (Build.VERSION.SDK_INT >= 25) { val manager = context.getSystemService(ShortcutManager::class.java) manager?.dynamicShortcuts = getShortCuts(context) } } - @RequiresApi(api = Build.VERSION_CODES.N_MR1) + @RequiresApi(api = 25) private fun getShortCuts(context: Context): List { val shortCuts = mutableListOf() val root = Shell.rootAccess() @@ -33,7 +34,7 @@ object Shortcuts { .putExtra(Const.Key.OPEN_SECTION, "superuser") .setAction(Intent.ACTION_VIEW) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)) - .setIcon(Icon.createWithResource(context, R.drawable.sc_superuser)) + .setIcon(Icon.createWithResource(context, resolveRes(DynAPK.SUPERUSER))) .setRank(0) .build()) } @@ -44,7 +45,7 @@ object Shortcuts { .putExtra(Const.Key.OPEN_SECTION, "magiskhide") .setAction(Intent.ACTION_VIEW) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)) - .setIcon(Icon.createWithResource(context, R.drawable.sc_magiskhide)) + .setIcon(Icon.createWithResource(context, resolveRes(DynAPK.MAGISKHIDE))) .setRank(1) .build()) } @@ -55,7 +56,7 @@ object Shortcuts { .putExtra(Const.Key.OPEN_SECTION, "modules") .setAction(Intent.ACTION_VIEW) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)) - .setIcon(Icon.createWithResource(context, R.drawable.sc_extension)) + .setIcon(Icon.createWithResource(context, resolveRes(DynAPK.MODULES))) .setRank(3) .build()) shortCuts.add(ShortcutInfo.Builder(context, "downloads") @@ -64,7 +65,7 @@ object Shortcuts { .putExtra(Const.Key.OPEN_SECTION, "downloads") .setAction(Intent.ACTION_VIEW) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)) - .setIcon(Icon.createWithResource(context, R.drawable.sc_cloud_download)) + .setIcon(Icon.createWithResource(context, resolveRes(DynAPK.DOWNLOAD))) .setRank(2) .build()) } diff --git a/app/src/main/res/values/resources.xml b/app/src/main/res/values/resources.xml index 711bb5460..9c785befd 100644 --- a/app/src/main/res/values/resources.xml +++ b/app/src/main/res/values/resources.xml @@ -8,16 +8,4 @@ Magisk Hide - - - - - - - - - - - - diff --git a/build.gradle b/build.gradle index 6731fa8f2..7e11ef1d5 100644 --- a/build.gradle +++ b/build.gradle @@ -86,12 +86,11 @@ subprojects { aaptOptions { // Handle resource IDs - File resIds = rootProject.file('stable-ids.txt') - File stubIds = rootProject.file('stub-ids.txt') - if (module.name == 'app' && resIds.exists()) - additionalParameters "--stable-ids", "${resIds.absolutePath}" - else if (module.name == 'stub') - additionalParameters "--emit-ids", "${stubIds.absolutePath}" + File resId = project.file('res-ids.txt') + if (resId.exists()) + additionalParameters "--stable-ids", "${resId.absolutePath}" + else + additionalParameters "--emit-ids", "${resId.absolutePath}" } } } diff --git a/shared/src/main/java/com/topjohnwu/magisk/utils/DynAPK.java b/shared/src/main/java/com/topjohnwu/magisk/utils/DynAPK.java index f75d855a7..93dfbf84c 100644 --- a/shared/src/main/java/com/topjohnwu/magisk/utils/DynAPK.java +++ b/shared/src/main/java/com/topjohnwu/magisk/utils/DynAPK.java @@ -3,9 +3,21 @@ package com.topjohnwu.magisk.utils; import android.content.Context; import java.io.File; +import java.util.Map; public class DynAPK { + // Indices of the object array + private static final int COMPONENT_MAP = 0; + private static final int RESOURCE_MAP = 1; + + // Indices of the resource map + public static final int NOTIFICATION = 0; + public static final int DOWNLOAD = 1; + public static final int SUPERUSER = 2; + public static final int MODULES = 3; + public static final int MAGISKHIDE = 4; + private static File dynDir; private static File getDynDir(Context c) { @@ -23,4 +35,24 @@ public class DynAPK { public static File update(Context c) { return new File(getDynDir(c), "update.apk"); } + + public static Data load(Object o) { + Object[] arr = (Object[]) o; + Data data = new Data(); + data.componentMap = (Map) arr[COMPONENT_MAP]; + data.resourceMap = (int[]) arr[RESOURCE_MAP]; + return data; + } + + public static Object pack(Data data) { + Object[] arr = new Object[2]; + arr[COMPONENT_MAP] = data.componentMap; + arr[RESOURCE_MAP] = data.resourceMap; + return arr; + } + + public static class Data { + public Map componentMap; + public int[] resourceMap; + } } diff --git a/stable-ids.txt b/stable-ids.txt deleted file mode 100644 index ac6eed8c8..000000000 --- a/stable-ids.txt +++ /dev/null @@ -1,32 +0,0 @@ -com.topjohnwu.magisk:color/dark = 0x7f010000 -com.topjohnwu.magisk:color/ic_launcher_background = 0x7f010001 -com.topjohnwu.magisk:color/light = 0x7f010002 -com.topjohnwu.magisk:drawable/ic_cloud_download = 0x7f020000 -com.topjohnwu.magisk:drawable/ic_extension = 0x7f020001 -com.topjohnwu.magisk:drawable/ic_launcher = 0x7f020002 -com.topjohnwu.magisk:drawable/ic_logo = 0x7f020003 -com.topjohnwu.magisk:drawable/ic_magisk = 0x7f020004 -com.topjohnwu.magisk:drawable/ic_magisk_outline = 0x7f020005 -com.topjohnwu.magisk:drawable/ic_magisk_padded = 0x7f020006 -com.topjohnwu.magisk:drawable/ic_magiskhide = 0x7f020007 -com.topjohnwu.magisk:drawable/ic_splash_activity = 0x7f020008 -com.topjohnwu.magisk:drawable/ic_superuser = 0x7f020009 -com.topjohnwu.magisk:drawable/sc_cloud_download = 0x7f02000a -com.topjohnwu.magisk:drawable/sc_extension = 0x7f02000b -com.topjohnwu.magisk:drawable/sc_magiskhide = 0x7f02000c -com.topjohnwu.magisk:drawable/sc_superuser = 0x7f02000d -com.topjohnwu.magisk:style/SplashTheme = 0x7f040000 -com.topjohnwu.magisk:style/SplashThemeBase = 0x7f040001 -com.topjohnwu.magisk:style/SplashThemeBase.V19 = 0x7f040002 -com.topjohnwu.magisk:xml/file_paths = 0x7f050000 - -com.topjohnwu.magisk:string/stub_0 = 0x7f030000 -com.topjohnwu.magisk:string/stub_1 = 0x7f030001 -com.topjohnwu.magisk:string/stub_2 = 0x7f030002 -com.topjohnwu.magisk:string/stub_3 = 0x7f030003 -com.topjohnwu.magisk:string/stub_4 = 0x7f030004 -com.topjohnwu.magisk:string/stub_5 = 0x7f030005 -com.topjohnwu.magisk:string/stub_6 = 0x7f030006 -com.topjohnwu.magisk:string/stub_7 = 0x7f030007 -com.topjohnwu.magisk:string/stub_8 = 0x7f030008 -com.topjohnwu.magisk:string/stub_9 = 0x7f030009 diff --git a/stub/res-ids.txt b/stub/res-ids.txt new file mode 100644 index 000000000..14667b1b6 --- /dev/null +++ b/stub/res-ids.txt @@ -0,0 +1,27 @@ +com.topjohnwu.magisk:style/SplashThemeBase.V19 = 0x7f040000 +com.topjohnwu.magisk:string/app_name = 0x7f030000 +com.topjohnwu.magisk:string/yes = 0x7f030001 +com.topjohnwu.magisk:style/SplashTheme = 0x7f040001 +com.topjohnwu.magisk:drawable/sc_superuser = 0x7f020000 +com.topjohnwu.magisk:string/no_thanks = 0x7f030002 +com.topjohnwu.magisk:drawable/ic_splash_activity = 0x7f020001 +com.topjohnwu.magisk:drawable/sc_magiskhide = 0x7f020002 +com.topjohnwu.magisk:color/light = 0x7f010000 +com.topjohnwu.magisk:string/no_internet_msg = 0x7f030003 +com.topjohnwu.magisk:drawable/sc_extension = 0x7f020003 +com.topjohnwu.magisk:drawable/ic_magisk_outline = 0x7f020004 +com.topjohnwu.magisk:color/ic_launcher_background = 0x7f010001 +com.topjohnwu.magisk:xml/file_paths = 0x7f050000 +com.topjohnwu.magisk:drawable/sc_cloud_download = 0x7f020005 +com.topjohnwu.magisk:string/ok = 0x7f030004 +com.topjohnwu.magisk:drawable/ic_magisk = 0x7f020006 +com.topjohnwu.magisk:drawable/ic_superuser = 0x7f020007 +com.topjohnwu.magisk:drawable/ic_cloud_download = 0x7f020008 +com.topjohnwu.magisk:style/SplashThemeBase = 0x7f040002 +com.topjohnwu.magisk:drawable/ic_magiskhide = 0x7f020009 +com.topjohnwu.magisk:drawable/ic_launcher = 0x7f02000a +com.topjohnwu.magisk:drawable/ic_logo = 0x7f02000b +com.topjohnwu.magisk:drawable/ic_extension = 0x7f02000c +com.topjohnwu.magisk:string/upgrade_msg = 0x7f030005 +com.topjohnwu.magisk:color/dark = 0x7f010002 +com.topjohnwu.magisk:drawable/ic_magisk_padded = 0x7f02000d diff --git a/stub/src/main/java/androidx/work/impl/WorkManagerInitializer.java b/stub/src/main/java/androidx/work/impl/WorkManagerInitializer.java deleted file mode 100644 index 706a63085..000000000 --- a/stub/src/main/java/androidx/work/impl/WorkManagerInitializer.java +++ /dev/null @@ -1,12 +0,0 @@ -package androidx.work.impl; - -import com.topjohnwu.magisk.dummy.DummyProvider; - -public class WorkManagerInitializer extends DummyProvider { - /* This class have to exist, or else pre 9.0 devices - * will experience ClassNotFoundException crashes when - * launching the stub, as ContentProviders are constructed - * when an app starts up. Pre 9.0 devices do not have - * our custom DelegateComponentFactory to help creating - * dummies. */ -} diff --git a/stub/src/main/java/com/topjohnwu/magisk/DelegateApplication.java b/stub/src/main/java/com/topjohnwu/magisk/DelegateApplication.java index c6a46f00e..0b390571e 100644 --- a/stub/src/main/java/com/topjohnwu/magisk/DelegateApplication.java +++ b/stub/src/main/java/com/topjohnwu/magisk/DelegateApplication.java @@ -1,5 +1,6 @@ package com.topjohnwu.magisk; +import android.annotation.SuppressLint; import android.app.AppComponentFactory; import android.app.Application; import android.content.Context; @@ -13,7 +14,6 @@ import com.topjohnwu.magisk.utils.DynamicClassLoader; import java.io.File; import java.lang.reflect.Method; -import java.util.Map; import static com.topjohnwu.magisk.DownloadActivity.TAG; @@ -34,35 +34,7 @@ public class DelegateApplication extends Application { protected void attachBaseContext(Context base) { super.attachBaseContext(base); if (Build.VERSION.SDK_INT >= 28) { - // If 9.0+, try to dynamically load the APK - DelegateComponentFactory factory = (DelegateComponentFactory) this.factory; - MANAGER_APK = DynAPK.current(this); - File update = DynAPK.update(this); - if (update.exists()) - update.renameTo(MANAGER_APK); - if (MANAGER_APK.exists()) { - ClassLoader cl = new DynamicClassLoader(MANAGER_APK, factory.loader); - try { - // Create the delegate AppComponentFactory - Object df = cl.loadClass("a.a").newInstance(); - - // Create the delegate Application - delegate = (Application) cl.loadClass("a.e").getConstructor(Map.class) - .newInstance(ComponentMap.inverseMap); - - // Call attachBaseContext without ContextImpl to show it is being wrapped - Method m = ContextWrapper.class.getDeclaredMethod("attachBaseContext", Context.class); - m.setAccessible(true); - m.invoke(delegate, this); - - // If everything went well, set our loader and delegate - factory.delegate = (AppComponentFactory) df; - factory.loader = cl; - } catch (Exception e) { - Log.e(TAG, "dyn load", e); - MANAGER_APK.delete(); - } - } + setUpDynAPK(); } else { MANAGER_APK = new File(base.getCacheDir(), "manager.apk"); } @@ -73,4 +45,36 @@ public class DelegateApplication extends Application { super.onConfigurationChanged(newConfig); delegate.onConfigurationChanged(newConfig); } + + @SuppressLint("NewApi") + private void setUpDynAPK() { + DelegateComponentFactory factory = (DelegateComponentFactory) this.factory; + MANAGER_APK = DynAPK.current(this); + File update = DynAPK.update(this); + if (update.exists()) + update.renameTo(MANAGER_APK); + if (MANAGER_APK.exists()) { + ClassLoader cl = new DynamicClassLoader(MANAGER_APK, factory.loader); + try { + // Create the delegate AppComponentFactory + Object df = cl.loadClass("a.a").newInstance(); + + // Create the delegate Application + delegate = (Application) cl.loadClass("a.e").getConstructor(Object.class) + .newInstance(DynAPK.pack(Mapping.data)); + + // Call attachBaseContext without ContextImpl to show it is being wrapped + Method m = ContextWrapper.class.getDeclaredMethod("attachBaseContext", Context.class); + m.setAccessible(true); + m.invoke(delegate, this); + + // If everything went well, set our loader and delegate + factory.delegate = (AppComponentFactory) df; + factory.loader = cl; + } catch (Exception e) { + Log.e(TAG, "dyn load", e); + MANAGER_APK.delete(); + } + } + } } diff --git a/stub/src/main/java/com/topjohnwu/magisk/DelegateComponentFactory.java b/stub/src/main/java/com/topjohnwu/magisk/DelegateComponentFactory.java index f7f7e7a08..89874c93f 100644 --- a/stub/src/main/java/com/topjohnwu/magisk/DelegateComponentFactory.java +++ b/stub/src/main/java/com/topjohnwu/magisk/DelegateComponentFactory.java @@ -35,7 +35,7 @@ public class DelegateComponentFactory extends AppComponentFactory { throws ClassNotFoundException, IllegalAccessException, InstantiationException { Log.d(TAG, className); if (delegate != null) - return delegate.instantiateActivity(loader, ComponentMap.get(className), intent); + return delegate.instantiateActivity(loader, Mapping.get(className), intent); return create(className, DummyActivity.class); } @@ -44,7 +44,7 @@ public class DelegateComponentFactory extends AppComponentFactory { throws ClassNotFoundException, IllegalAccessException, InstantiationException { Log.d(TAG, className); if (delegate != null) - return delegate.instantiateReceiver(loader, ComponentMap.get(className), intent); + return delegate.instantiateReceiver(loader, Mapping.get(className), intent); return create(className, DummyReceiver.class); } @@ -53,7 +53,7 @@ public class DelegateComponentFactory extends AppComponentFactory { throws ClassNotFoundException, IllegalAccessException, InstantiationException { Log.d(TAG, className); if (delegate != null) - return delegate.instantiateService(loader, ComponentMap.get(className), intent); + return delegate.instantiateService(loader, Mapping.get(className), intent); return create(className, DummyService.class); } @@ -63,7 +63,7 @@ public class DelegateComponentFactory extends AppComponentFactory { Log.d(TAG, className); if (loader == null) loader = cl; if (delegate != null) - return delegate.instantiateProvider(loader, ComponentMap.get(className)); + return delegate.instantiateProvider(loader, Mapping.get(className)); return create(className, DummyProvider.class); } diff --git a/stub/src/main/java/com/topjohnwu/magisk/ComponentMap.java b/stub/src/main/java/com/topjohnwu/magisk/Mapping.java similarity index 56% rename from stub/src/main/java/com/topjohnwu/magisk/ComponentMap.java rename to stub/src/main/java/com/topjohnwu/magisk/Mapping.java index bc067e09b..0b15cfe0a 100644 --- a/stub/src/main/java/com/topjohnwu/magisk/ComponentMap.java +++ b/stub/src/main/java/com/topjohnwu/magisk/Mapping.java @@ -3,11 +3,13 @@ package com.topjohnwu.magisk; import java.util.HashMap; import java.util.Map; -class ComponentMap { +import static com.topjohnwu.magisk.utils.DynAPK.*; + +class Mapping { private static Map map = new HashMap<>(); // This mapping will be sent into the guest app - static Map inverseMap; + static Data data = new Data(); static { map.put(a.z.class.getName(), "a.c"); @@ -18,10 +20,17 @@ class ComponentMap { map.put("a.v", "a.j"); map.put("a.j", "androidx.work.impl.background.systemjob.SystemJobService"); - inverseMap = new HashMap<>(map.size()); + data.componentMap = new HashMap<>(map.size()); for (Map.Entry e : map.entrySet()) { - inverseMap.put(e.getValue(), e.getKey()); + data.componentMap.put(e.getValue(), e.getKey()); } + int[] res = new int[5]; + res[NOTIFICATION] = R.drawable.ic_magisk_outline; + res[SUPERUSER] = R.drawable.sc_superuser; + res[MAGISKHIDE] = R.drawable.sc_magiskhide; + res[DOWNLOAD] = R.drawable.sc_cloud_download; + res[MODULES] = R.drawable.sc_extension; + data.resourceMap = res; } static String get(String name) { From 78daa2eb62fefde8ad7049d3224572b2819b7bbc Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Thu, 17 Oct 2019 04:47:46 -0400 Subject: [PATCH 10/61] Do not use string resources for app label This not only simplifies hiding stub APKs (no resource IDs involved), but also opens the opportunity to allow users to customize whatever app name they want after it is hidden. --- app/proguard-rules.pro | 2 +- app/src/main/java/a/a.java | 7 +- .../magisk/model/download/ManagerUpgrade.kt | 14 +--- .../magisk/ui/settings/SettingsFragment.kt | 5 +- .../com/topjohnwu/magisk/utils/PatchAPK.kt | 69 +++++++++++-------- shared/src/main/AndroidManifest.xml | 2 +- 6 files changed, 50 insertions(+), 49 deletions(-) diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index c95d10abb..10d54c59d 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -32,7 +32,7 @@ -keep,allowobfuscation class * extends com.topjohnwu.magisk.base.DelegateWorker # BootSigner --keepclassmembers class com.topjohnwu.signing.BootSigner { *; } +-keep class a.a { *; } # Strip logging -assumenosideeffects class timber.log.Timber.Tree { *; } diff --git a/app/src/main/java/a/a.java b/app/src/main/java/a/a.java index 5ccb6738b..23927a021 100644 --- a/app/src/main/java/a/a.java +++ b/app/src/main/java/a/a.java @@ -1,18 +1,21 @@ package a; -import androidx.annotation.Keep; import androidx.core.app.AppComponentFactory; import com.topjohnwu.magisk.utils.PatchAPK; import com.topjohnwu.signing.BootSigner; -@Keep public class a extends AppComponentFactory { + @Deprecated public static boolean patchAPK(String in, String out, String pkg) { return PatchAPK.patch(in, out, pkg); } + public static boolean patchAPK(String in, String out, String pkg, String label) { + return PatchAPK.patch(in, out, pkg, label); + } + public static void main(String[] args) throws Exception { BootSigner.main(args); } diff --git a/app/src/main/java/com/topjohnwu/magisk/model/download/ManagerUpgrade.kt b/app/src/main/java/com/topjohnwu/magisk/model/download/ManagerUpgrade.kt index bc8e85dff..f75a8a0c1 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/download/ManagerUpgrade.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/download/ManagerUpgrade.kt @@ -4,7 +4,6 @@ import com.topjohnwu.magisk.BuildConfig import com.topjohnwu.magisk.Config import com.topjohnwu.magisk.R import com.topjohnwu.magisk.cmp -import com.topjohnwu.magisk.extensions.DynamicClassLoader import com.topjohnwu.magisk.model.entity.internal.Configuration.APK.Restore import com.topjohnwu.magisk.model.entity.internal.Configuration.APK.Upgrade import com.topjohnwu.magisk.model.entity.internal.DownloadSubject @@ -12,7 +11,6 @@ import com.topjohnwu.magisk.ui.SplashActivity import com.topjohnwu.magisk.utils.PatchAPK import com.topjohnwu.magisk.utils.Utils import com.topjohnwu.superuser.Shell -import timber.log.Timber import java.io.File private fun RemoteFileService.patchPackage(apk: File, id: Int) { @@ -24,17 +22,7 @@ private fun RemoteFileService.patchPackage(apk: File, id: Int) { .setContentText("") } val patched = File(apk.parent, "patched.apk") - try { - // Try using the new APK to patch itself - val loader = DynamicClassLoader(apk) - loader.loadClass("a.a") - .getMethod("patchAPK", String::class.java, String::class.java, String::class.java) - .invoke(null, apk.path, patched.path, packageName) - } catch (e: Exception) { - Timber.e(e) - // Fallback to use the current implementation - PatchAPK.patch(apk.path, patched.path, packageName) - } + PatchAPK.patch(apk, patched, packageName, applicationInfo.nonLocalizedLabel.toString()) apk.delete() patched.renameTo(apk) } diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt b/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt index c67ce091a..9da82ee24 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt @@ -67,7 +67,8 @@ class SettingsFragment : BasePreferenceFragment() { val suCategory = findPreference("superuser")!! val hideManager = findPreference("hide")!! hideManager.setOnPreferenceClickListener { - PatchAPK.hideManager(requireContext()) + // TODO: Add UI to allow user to customize app name + PatchAPK.hideManager(requireContext(), "Manager") true } val restoreManager = findPreference("restore") @@ -326,4 +327,4 @@ class SettingsFragment : BasePreferenceFragment() { .setNegativeButton(R.string.close, null) .show() } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.kt b/app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.kt index f70dc291f..edd1cff66 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.kt +++ b/app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.kt @@ -3,6 +3,7 @@ package com.topjohnwu.magisk.utils import android.content.Context import android.widget.Toast import com.topjohnwu.magisk.* +import com.topjohnwu.magisk.extensions.DynamicClassLoader import com.topjohnwu.magisk.extensions.subscribeK import com.topjohnwu.magisk.ui.SplashActivity import com.topjohnwu.magisk.view.Notifications @@ -46,52 +47,38 @@ object PatchAPK { } private fun findAndPatch(xml: ByteArray, from: String, to: String): Boolean { - if (from.length != to.length) + if (to.length > from.length) return false val buf = ByteBuffer.wrap(xml).order(ByteOrder.LITTLE_ENDIAN).asCharBuffer() val offList = mutableListOf() var i = 0 - while (i < buf.length - from.length) { - var match = true - for (j in 0 until from.length) { + loop@ while (i < buf.length - from.length) { + for (j in from.indices) { if (buf.get(i + j) != from[j]) { - match = false - break + ++i + continue@loop } } - if (match) { - offList.add(i) - i += from.length - } - ++i + offList.add(i) + i += from.length } if (offList.isEmpty()) return false + + val toBuf = to.toCharArray().copyOf(from.length) for (off in offList) { buf.position(off) - buf.put(to) + buf.put(toBuf) } return true } - private fun findAndPatch(xml: ByteArray, a: Int, b: Int): Boolean { - val buf = ByteBuffer.wrap(xml).order(ByteOrder.LITTLE_ENDIAN).asIntBuffer() - val len = xml.size / 4 - for (i in 0 until len) { - if (buf.get(i) == a) { - buf.put(i, b) - return true - } - } - return false - } - - private fun patchAndHide(context: Context): Boolean { + private fun patchAndHide(context: Context, label: String): Boolean { // Generate a new app with random package name val repack = File(context.filesDir, "patched.apk") val pkg = genPackageName("com.", BuildConfig.APPLICATION_ID.length) - if (!patch(context.packageCodePath, repack.path, pkg)) + if (!patch(context.packageCodePath, repack.path, pkg, label)) return false // Install the application @@ -107,14 +94,15 @@ object PatchAPK { } @JvmStatic - fun patch(apk: String, out: String, pkg: String): Boolean { + @JvmOverloads + fun patch(apk: String, out: String, pkg: String, label: String = "Manager"): Boolean { try { val jar = JarMap(apk) val je = jar.getJarEntry(Const.ANDROID_MANIFEST) val xml = jar.getRawData(je) if (!findAndPatch(xml, BuildConfig.APPLICATION_ID, pkg) || - !findAndPatch(xml, R.string.app_name, R.string.re_app_name)) + !findAndPatch(xml, "Magisk Manager", label)) return false // Write apk changes @@ -128,11 +116,32 @@ object PatchAPK { return true } - fun hideManager(context: Context) { + fun patch(apk: File, out: File, pkg: String, label: String): Boolean { + try { + // Try using the new APK to patch itself + val loader = DynamicClassLoader(apk) + val cls = loader.loadClass("a.a") + + for (m in cls.declaredMethods) { + val pars = m.parameterTypes + if (pars.size == 4 && pars[0] == String::class.java) { + return m.invoke(null, apk.path, out.path, pkg, label) as Boolean + } + } + throw Exception("No matching method found") + } catch (e: Exception) { + Timber.e(e) + // Fallback to use the current implementation + patch(apk.path, out.path, pkg, label) + } + return false + } + + fun hideManager(context: Context, label: String) { Completable.fromAction { val progress = Notifications.progress(context, context.getString(R.string.hide_manager_title)) Notifications.mgr.notify(Const.ID.HIDE_MANAGER_NOTIFICATION_ID, progress.build()) - if (!patchAndHide(context)) + if (!patchAndHide(context, label)) Utils.toast(R.string.hide_manager_fail_toast, Toast.LENGTH_LONG) Notifications.mgr.cancel(Const.ID.HIDE_MANAGER_NOTIFICATION_ID) }.subscribeK() diff --git a/shared/src/main/AndroidManifest.xml b/shared/src/main/AndroidManifest.xml index 73a5f831e..c42a2dd7f 100644 --- a/shared/src/main/AndroidManifest.xml +++ b/shared/src/main/AndroidManifest.xml @@ -8,7 +8,7 @@ Date: Thu, 17 Oct 2019 16:20:01 -0400 Subject: [PATCH 11/61] Assign signing keystore location in config --- build.gradle | 2 +- build.py | 92 +++++++++++++++++++++++++--------------------- config.prop.sample | 3 +- 3 files changed, 53 insertions(+), 44 deletions(-) diff --git a/build.gradle b/build.gradle index 7e11ef1d5..f0236679e 100644 --- a/build.gradle +++ b/build.gradle @@ -62,7 +62,7 @@ subprojects { android { signingConfigs { config { - storeFile rootProject.file('release-key.jks') + storeFile new File(props['keyStore']) storePassword props['keyStorePass'] keyAlias props['keyAlias'] keyPassword props['keyPass'] diff --git a/build.py b/build.py index 513fbe29b..618eed2d2 100755 --- a/build.py +++ b/build.py @@ -54,7 +54,6 @@ cpu_count = multiprocessing.cpu_count() gradlew = os.path.join('.', 'gradlew' + ('.bat' if os.name == 'nt' else '')) archs = ['armeabi-v7a', 'x86'] arch64 = ['arm64-v8a', 'x86_64'] -keystore = 'release-key.jks' config = {} support_targets = ['magisk', 'magiskinit', 'magiskboot', 'magiskpolicy', 'busybox', 'test'] default_targets = ['magisk', 'magiskinit', 'magiskboot', 'busybox'] @@ -96,18 +95,53 @@ def mkdir_p(path, mode=0o777): os.makedirs(path, mode, exist_ok=True) -def execv(cmd, redirect=None): - return subprocess.run(cmd, stdout=redirect if redirect != None else STDOUT) +def execv(cmd): + return subprocess.run(cmd, stdout=STDOUT) -def system(cmd, redirect=None): - return subprocess.run(cmd, shell=True, stdout=redirect if redirect != None else STDOUT) +def system(cmd): + return subprocess.run(cmd, shell=True, stdout=STDOUT) def xz(data): return lzma.compress(data, preset=9, check=lzma.CHECK_NONE) +def load_config(args): + # Some default values + config['outdir'] = 'out' + config['prettyName'] = 'false' + config['keyStore'] = 'release-key.jks' + + # Load prop file + with open(args.config, 'r') as f: + for line in [l.strip(' \t\r\n') for l in f]: + if line.startswith('#') or len(line) == 0: + continue + prop = line.split('=') + if len(prop) != 2: + continue + config[prop[0].strip(' \t\r\n')] = prop[1].strip(' \t\r\n') + + config['prettyName'] = config['prettyName'].lower() == 'true' + + # Sanitize configs + if 'version' not in config or 'versionCode' not in config: + error('Config error: "version" and "versionCode" is required') + + try: + config['versionCode'] = int(config['versionCode']) + except ValueError: + error('Config error: "versionCode" is required to be an integer') + + if args.release and not os.path.exists(config['keyStore']): + error(f'Config error: assign "keyStore" to a java keystore') + + mkdir_p(config['outdir']) + global STDOUT + STDOUT = None if args.verbose else subprocess.DEVNULL + + def zip_with_msg(zip_file, source, target): if not os.path.exists(source): error(f'{source} does not exist! Try build \'binary\' and \'apk\' before zipping!') @@ -152,7 +186,7 @@ def sign_zip(unsigned, output, release): header('* Signing Zip') - proc = execv(['java', '-jar', zipsigner, keystore, config['keyStorePass'], + proc = execv(['java', '-jar', zipsigner, config['keyStore'], config['keyStorePass'], config['keyAlias'], config['keyPass'], unsigned, output]) if proc.returncode != 0: @@ -444,28 +478,28 @@ def build_all(args): parser = argparse.ArgumentParser(description='Magisk build script') parser.add_argument('-r', '--release', action='store_true', - help='compile Magisk for release') + help='compile in release mode') parser.add_argument('-v', '--verbose', action='store_true', help='verbose output') parser.add_argument('-c', '--config', default='config.prop', - help='config file location') + help='override config file (default: config.prop)') subparsers = parser.add_subparsers(title='actions') all_parser = subparsers.add_parser( - 'all', help='build everything (binaries/apks/zips)') + 'all', help='build binaries, apks, zips') all_parser.set_defaults(func=build_all) binary_parser = subparsers.add_parser('binary', help='build binaries') binary_parser.add_argument( - 'target', nargs='*', help=f"Either {', '.join(support_targets)}, \ + 'target', nargs='*', help=f"{', '.join(support_targets)}, \ or empty for defaults ({', '.join(default_targets)})") binary_parser.set_defaults(func=build_binary) -apk_parser = subparsers.add_parser('apk', help='build Magisk Manager APK') -apk_parser.set_defaults(func=build_app) +app_parser = subparsers.add_parser('app', help='build Magisk Manager') +app_parser.set_defaults(func=build_app) stub_parser = subparsers.add_parser( - 'stub', help='build stub Magisk Manager APK') + 'stub', help='build stub Magisk Manager') stub_parser.set_defaults(func=build_stub) snet_parser = subparsers.add_parser( @@ -480,9 +514,9 @@ un_parser = subparsers.add_parser( 'uninstaller', help='create flashable uninstaller') un_parser.set_defaults(func=zip_uninstaller) -clean_parser = subparsers.add_parser('clean', help='cleanup.') +clean_parser = subparsers.add_parser('clean', help='cleanup') clean_parser.add_argument( - 'target', nargs='*', help='Either native, java, or empty to clean both.') + 'target', nargs='*', help='native, java, or empty to clean both') clean_parser.set_defaults(func=cleanup) if len(sys.argv) == 1: @@ -490,33 +524,7 @@ if len(sys.argv) == 1: sys.exit(1) args = parser.parse_args() - -# Some default values -config['outdir'] = 'out' -config['prettyName'] = 'false' - -with open(args.config, 'r') as f: - for line in [l.strip(' \t\r\n') for l in f]: - if line.startswith('#') or len(line) == 0: - continue - prop = line.split('=') - config[prop[0].strip(' \t\r\n')] = prop[1].strip(' \t\r\n') - -if 'version' not in config or 'versionCode' not in config: - error('"version" and "versionCode" is required in "config.prop"') - -try: - config['versionCode'] = int(config['versionCode']) -except ValueError: - error('"versionCode" is required to be an integer') - -config['prettyName'] = config['prettyName'].lower() == 'true' - -mkdir_p(config['outdir']) - -if args.release and not os.path.exists(keystore): - error(f'Please generate a java keystore and place it in "{keystore}"') -STDOUT = None if args.verbose else subprocess.DEVNULL +load_config(args) # Call corresponding functions args.func(args) diff --git a/config.prop.sample b/config.prop.sample index ffeb3678d..261e3f750 100644 --- a/config.prop.sample +++ b/config.prop.sample @@ -13,8 +13,9 @@ outdir=out prettyName=false # Only used when building with release flag -# These passwords are used along with release-key.jks to sign APKs and zips +# These passwords are used along with keyStore to sign APKs and zips # keyPass is the pwd for the specified keyAlias +keyStore=release-key.jks keyStorePass= keyAlias= keyPass= From 935bd01f593f3dd2a1fe54be411148c0e2264f2f Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Thu, 17 Oct 2019 18:02:31 -0400 Subject: [PATCH 12/61] Post process release APKs --- build.py | 63 +++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 53 insertions(+), 10 deletions(-) diff --git a/build.py b/build.py index 618eed2d2..cb07bc5d0 100755 --- a/build.py +++ b/build.py @@ -3,7 +3,8 @@ import sys import os import subprocess -if os.name == 'nt': +is_windows = os.name == 'nt' +if is_windows: import colorama colorama.init() @@ -44,6 +45,7 @@ import shutil import lzma import tempfile +# Constants if 'ANDROID_NDK_HOME' in os.environ: ndk_build = os.path.join(os.environ['ANDROID_NDK_HOME'], 'ndk-build') else: @@ -51,13 +53,16 @@ else: os.environ['ANDROID_HOME'], 'ndk-bundle', 'ndk-build') cpu_count = multiprocessing.cpu_count() -gradlew = os.path.join('.', 'gradlew' + ('.bat' if os.name == 'nt' else '')) +gradlew = os.path.join('.', 'gradlew' + ('.bat' if is_windows else '')) archs = ['armeabi-v7a', 'x86'] arch64 = ['arm64-v8a', 'x86_64'] -config = {} support_targets = ['magisk', 'magiskinit', 'magiskboot', 'magiskpolicy', 'busybox', 'test'] default_targets = ['magisk', 'magiskinit', 'magiskboot', 'busybox'] +build_tools = os.path.join(os.environ['ANDROID_HOME'], 'build-tools', '29.0.2') +# Global vars +config = {} +STDOUT = None def mv(source, target): try: @@ -159,12 +164,13 @@ def collect_binary(): def clean_elf(): - if os.name == 'nt': + if is_windows: elf_cleaner = os.path.join('tools', 'elf-cleaner.exe') else: elf_cleaner = os.path.join('native', 'out', 'elf-cleaner') - if not os.path.exists(elf_cleaner): - execv(['g++', 'tools/termux-elf-cleaner/termux-elf-cleaner.cpp', '-o', elf_cleaner]) + if not os.path.exists(elf_cleaner): + execv(['g++', 'tools/termux-elf-cleaner/termux-elf-cleaner.cpp', + '-o', elf_cleaner]) args = [elf_cleaner] args.extend(os.path.join('native', 'out', arch, 'magisk') for arch in archs + arch64) execv(args) @@ -293,14 +299,47 @@ def build_apk(args, module): proc = execv([gradlew, f'{module}:assemble{build_type}', '-PconfigPath=' + os.path.abspath(args.config)]) if proc.returncode != 0: - error('Build Magisk Manager failed!') + error(f'Build {module} failed!') build_type = build_type.lower() apk = f'{module}-{build_type}.apk' source = os.path.join(module, 'build', 'outputs', 'apk', build_type, apk) target = os.path.join(config['outdir'], apk) - mv(source, target) + + if args.release: + zipalign = os.path.join(build_tools, 'zipalign' + ('.exe' if is_windows else '')) + aapt2 = os.path.join(build_tools, 'aapt2' + ('.exe' if is_windows else '')) + apksigner = os.path.join(build_tools, 'apksigner' + ('.bat' if is_windows else '')) + try: + with tempfile.NamedTemporaryFile(delete=False) as f: + tmp = f.name + + # AAPT2 optimization + execv([aapt2, 'optimize', '-o', tmp, '--enable-resource-obfuscation', + '--enable-resource-path-shortening', source]) + + # Recompress everything just to piss people off + with zipfile.ZipFile(source, 'w', compression=zipfile.ZIP_DEFLATED) as zout: + with zipfile.ZipFile(tmp) as zin: + for e in zin.namelist(): + zout.writestr(e, zin.read(e)) + + # Zipalign + execv([zipalign, '-fz', '4', source, target]) + + # Sign APK + execv([apksigner, 'sign', '--v1-signer-name', 'CERT', + '--ks', config['keyStore'], + '--ks-pass', f'pass:{config["keyStorePass"]}', + '--ks-key-alias', config['keyAlias'], + '--key-pass', f'pass:{config["keyPass"]}', target]) + finally: + rm(tmp) + rm(source) + else: + mv(source, target) + header('Output: ' + target) return target @@ -343,7 +382,8 @@ def build_snet(args): def zip_main(args): header('* Packing Flashable Zip') - unsigned = tempfile.mkstemp()[1] + with tempfile.NamedTemporaryFile(delete=False) as f: + unsigned = f.name with zipfile.ZipFile(unsigned, 'w', compression=zipfile.ZIP_DEFLATED, allowZip64=False) as zipf: # update-binary @@ -401,13 +441,15 @@ def zip_main(args): output = os.path.join(config['outdir'], f'Magisk-v{config["version"]}.zip' if config['prettyName'] else 'magisk-release.zip' if args.release else 'magisk-debug.zip') sign_zip(unsigned, output, args.release) + rm(unsigned) header('Output: ' + output) def zip_uninstaller(args): header('* Packing Uninstaller Zip') - unsigned = tempfile.mkstemp()[1] + with tempfile.NamedTemporaryFile(delete=False) as f: + unsigned = f.name with zipfile.ZipFile(unsigned, 'w', compression=zipfile.ZIP_DEFLATED, allowZip64=False) as zipf: # update-binary @@ -446,6 +488,7 @@ def zip_uninstaller(args): output = os.path.join(config['outdir'], f'Magisk-uninstaller-{datestr}.zip' if config['prettyName'] else 'magisk-uninstaller.zip') sign_zip(unsigned, output, args.release) + rm(unsigned) header('Output: ' + output) From 9c27d691dd2d54f8ca704870aeb22a36fe65a12e Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sat, 19 Oct 2019 03:11:54 -0400 Subject: [PATCH 13/61] Drop API 17 (Android 4.2) support --- build.gradle | 2 +- native/jni/core/applets.cpp | 2 +- native/jni/init/rootdir.cpp | 27 +++++++++++++-------------- native/jni/utils/include/selinux.h | 3 +-- native/jni/utils/selinux.cpp | 15 --------------- scripts/flash_script.sh | 2 +- 6 files changed, 17 insertions(+), 34 deletions(-) diff --git a/build.gradle b/build.gradle index f0236679e..28680819c 100644 --- a/build.gradle +++ b/build.gradle @@ -47,7 +47,7 @@ subprojects { defaultConfig { if (minSdkVersion == null) - minSdkVersion 17 + minSdkVersion 18 targetSdkVersion 28 } diff --git a/native/jni/core/applets.cpp b/native/jni/core/applets.cpp index 4932bc9e0..f1ab263bf 100644 --- a/native/jni/core/applets.cpp +++ b/native/jni/core/applets.cpp @@ -26,7 +26,7 @@ static int (*applet_main[]) (int, char *[]) = int main(int argc, char *argv[]) { umask(0); - dload_selinux(); + selinux_builtin_impl(); cmdline_logging(); init_argv0(argc, argv); diff --git a/native/jni/init/rootdir.cpp b/native/jni/init/rootdir.cpp index e5a362e8f..6d39bce33 100644 --- a/native/jni/init/rootdir.cpp +++ b/native/jni/init/rootdir.cpp @@ -153,24 +153,23 @@ void SARCompatInit::setup_rootfs() { } bool MagiskInit::patch_sepolicy(const char *file) { - bool patch_init = false; - - if (access(SPLIT_PLAT_CIL, R_OK) == 0) { - LOGD("sepol: split policy\n"); - patch_init = true; - } else if (access("/sepolicy", R_OK) == 0) { - LOGD("sepol: monolithic policy\n"); - load_policydb("/sepolicy"); - } else { - LOGD("sepol: no selinux\n"); - return false; - } + bool require_patch = false; // Mount selinuxfs to communicate with kernel xmount("selinuxfs", SELINUX_MNT, "selinuxfs", 0, nullptr); - if (patch_init) + if (access(SPLIT_PLAT_CIL, R_OK) == 0) { + LOGD("sepol: split policy\n"); load_split_cil(); + require_patch = true; + } else if (access("/sepolicy", R_OK) == 0) { + LOGD("sepol: monolithic policy\n"); + load_policydb("/sepolicy"); + } else { + // Fatal error!! + LOGD("sepol: no selinux\n"); + return false; + } sepol_magisk_rules(); sepol_allow(SEPOL_PROC_DOMAIN, ALL, ALL, ALL); @@ -182,7 +181,7 @@ bool MagiskInit::patch_sepolicy(const char *file) { link("/sepolicy", "/sepolicy_debug"); } - return patch_init; + return require_patch; } constexpr const char wrapper[] = diff --git a/native/jni/utils/include/selinux.h b/native/jni/utils/include/selinux.h index 322afaaff..15e4615e8 100644 --- a/native/jni/utils/include/selinux.h +++ b/native/jni/utils/include/selinux.h @@ -20,7 +20,7 @@ __BEGIN_DECLS -extern void (*freecon)(char *con); +#define freecon free extern int (*setcon)(const char *con); extern int (*getfilecon)(const char *path, char **con); extern int (*lgetfilecon)(const char *path, char **con); @@ -32,7 +32,6 @@ void getfilecon_at(int dirfd, const char *name, char **con); void setfilecon_at(int dirfd, const char *name, const char *con); void selinux_builtin_impl(); -void dload_selinux(); void restorecon(); void restore_rootcon(); diff --git a/native/jni/utils/selinux.cpp b/native/jni/utils/selinux.cpp index ed3696191..d530c3392 100644 --- a/native/jni/utils/selinux.cpp +++ b/native/jni/utils/selinux.cpp @@ -38,10 +38,6 @@ static int stub(int, char **ctx) { // Builtin implementation -static void __freecon(char *s) { - free(s); -} - static int __setcon(const char *ctx) { int fd = open("/proc/self/attr/current", O_WRONLY | O_CLOEXEC); if (fd < 0) @@ -114,7 +110,6 @@ static int __fsetfilecon(int fd, const char *ctx) { // Function pointers -void (*freecon)(char *) = __freecon; int (*setcon)(const char *) = stub; int (*getfilecon)(const char *, char **) = stub; int (*lgetfilecon)(const char *, char **) = stub; @@ -146,16 +141,6 @@ void selinux_builtin_impl() { fsetfilecon = __fsetfilecon; } -void dload_selinux() { - if (access("/system/lib/libselinux.so", F_OK)) - return; - /* We only check whether libselinux.so exists but don't dlopen. - * For some reason calling symbols returned from dlsym - * will result to SEGV_ACCERR on some devices. - * Always use builtin implementations for SELinux stuffs. */ - selinux_builtin_impl(); -} - static void restore_syscon(int dirfd) { struct dirent *entry; DIR *dir; diff --git a/scripts/flash_script.sh b/scripts/flash_script.sh index f8f47e4cf..0239db1de 100644 --- a/scripts/flash_script.sh +++ b/scripts/flash_script.sh @@ -53,7 +53,7 @@ ui_print "- Target image: $BOOTIMAGE" # Detect version and architecture api_level_arch_detect -[ $API -lt 17 ] && abort "! Magisk is only for Android 4.2 and above" +[ $API -lt 18 ] && abort "! Magisk is only for Android 4.3 and above" ui_print "- Device platform: $ARCH" From a02493fbaa70b98378843287d57bf82d71c51486 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sat, 19 Oct 2019 05:44:56 -0400 Subject: [PATCH 14/61] Workaround R8 bug --- app/proguard-rules.pro | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 10d54c59d..03cf6bdb6 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -34,6 +34,9 @@ # BootSigner -keep class a.a { *; } +# Workaround R8 bug +-keep,allowobfuscation class com.topjohnwu.magisk.model.receiver.GeneralReceiver + # Strip logging -assumenosideeffects class timber.log.Timber.Tree { *; } From 325d9a0b8670d37d7f6bb49d496fbbbe0c897657 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sun, 20 Oct 2019 06:56:33 -0400 Subject: [PATCH 15/61] Generate keys for signing hidden Magisk Manager --- .../main/java/com/topjohnwu/magisk/Config.kt | 6 +- .../java/com/topjohnwu/magisk/utils/Keygen.kt | 133 ++++++++++++++++++ .../com/topjohnwu/magisk/utils/PatchAPK.kt | 2 +- .../com/topjohnwu/signing/CryptoUtils.java | 6 +- .../java/com/topjohnwu/signing/SignAPK.java | 41 ++---- .../java/com/topjohnwu/signing/ZipSigner.java | 50 ++++++- 6 files changed, 196 insertions(+), 42 deletions(-) create mode 100644 app/src/main/java/com/topjohnwu/magisk/utils/Keygen.kt diff --git a/app/src/main/java/com/topjohnwu/magisk/Config.kt b/app/src/main/java/com/topjohnwu/magisk/Config.kt index e6dddcbf9..54ab1b499 100644 --- a/app/src/main/java/com/topjohnwu/magisk/Config.kt +++ b/app/src/main/java/com/topjohnwu/magisk/Config.kt @@ -32,8 +32,9 @@ object Config : PreferenceModel, DBConfig { const val ROOT_ACCESS = "root_access" const val SU_MULTIUSER_MODE = "multiuser_mode" const val SU_MNT_NS = "mnt_ns" - const val SU_MANAGER = "requester" const val SU_FINGERPRINT = "su_fingerprint" + const val SU_MANAGER = "requester" + const val KEYSTORE = "keystore" // prefs const val SU_REQUEST_TIMEOUT = "su_request_timeout" @@ -123,6 +124,7 @@ object Config : PreferenceModel, DBConfig { var suMultiuserMode by dbSettings(Key.SU_MULTIUSER_MODE, Value.MULTIUSER_MODE_OWNER_ONLY) var suFingerprint by dbSettings(Key.SU_FINGERPRINT, false) var suManager by dbStrings(Key.SU_MANAGER, "", true) + var keyStoreRaw by dbStrings(Key.KEYSTORE, "", true) // Always return a path in external storage where we can write val downloadDirectory get() = @@ -205,4 +207,4 @@ object Config : PreferenceModel, DBConfig { Shell.su("cat $xml > /data/adb/${Const.MANAGER_CONFIGS}").exec() } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/Keygen.kt b/app/src/main/java/com/topjohnwu/magisk/utils/Keygen.kt new file mode 100644 index 000000000..6620f7a14 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Keygen.kt @@ -0,0 +1,133 @@ +package com.topjohnwu.magisk.utils + +import android.content.pm.PackageManager +import android.util.Base64 +import android.util.Base64OutputStream +import com.topjohnwu.magisk.Config +import com.topjohnwu.magisk.di.koinModules +import com.topjohnwu.signing.CryptoUtils.readCertificate +import com.topjohnwu.signing.CryptoUtils.readPrivateKey +import com.topjohnwu.superuser.internal.InternalUtils +import org.bouncycastle.asn1.x500.X500Name +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter +import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder +import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder +import org.koin.core.context.GlobalContext +import org.koin.core.context.startKoin +import timber.log.Timber +import java.io.ByteArrayInputStream +import java.io.ByteArrayOutputStream +import java.math.BigInteger +import java.security.KeyPairGenerator +import java.security.KeyStore +import java.security.MessageDigest +import java.security.PrivateKey +import java.security.cert.X509Certificate +import java.util.* +import java.util.zip.GZIPInputStream +import java.util.zip.GZIPOutputStream + +private interface CertKeyProvider { + val cert: X509Certificate + val key: PrivateKey +} + +@Suppress("DEPRECATION") +object Keygen: CertKeyProvider { + private const val ALIAS = "magisk" + private val PASSWORD = "magisk".toCharArray() + private const val TESTKEY_CERT = "61ed377e85d386a8dfee6b864bd85b0bfaa5af81" + + private val start get() = Calendar.getInstance() + private val end get() = Calendar.getInstance().apply { + add(Calendar.YEAR, 20) + } + + override val cert get() = provider.cert + override val key get() = provider.key + + private val provider: CertKeyProvider + + class KeyStoreProvider : CertKeyProvider { + private val ks by lazy { init() } + override val cert by lazy { ks.getCertificate(ALIAS) as X509Certificate } + override val key by lazy { ks.getKey(ALIAS, PASSWORD) as PrivateKey } + } + + class TestProvider : CertKeyProvider { + override val cert by lazy { + readCertificate(javaClass.getResourceAsStream("/keys/testkey.x509.pem")) + } + override val key by lazy { + readPrivateKey(javaClass.getResourceAsStream("/keys/testkey.pk8")) + } + } + + init { + // This object could possibly be accessed from an external app + // Get context from reflection into Android's framework + val context = InternalUtils.getContext() + val pm = context.packageManager + val info = pm.getPackageInfo(context.packageName, PackageManager.GET_SIGNATURES) + val sig = info.signatures[0] + val digest = MessageDigest.getInstance("SHA1") + val chksum = digest.digest(sig.toByteArray()) + + val sb = StringBuilder() + for (b in chksum) { + sb.append("%02x".format(0xFF and b.toInt())) + } + + provider = if (sb.toString() == TESTKEY_CERT) { + // The app was signed by the test key, continue to use it (legacy mode) + TestProvider() + } else { + KeyStoreProvider() + } + } + + private fun init(): KeyStore { + GlobalContext.getOrNull() ?: { + // Invoked externally, do some basic initialization + startKoin { + modules(koinModules) + } + Timber.plant(Timber.DebugTree()) + }() + + val raw = Config.keyStoreRaw + val ks = KeyStore.getInstance("PKCS12") + if (raw.isEmpty()) { + ks.load(null) + } else { + GZIPInputStream(ByteArrayInputStream( + Base64.decode(raw, Base64.NO_PADDING or Base64.NO_WRAP) + )).use { + ks.load(it, PASSWORD) + } + } + + // Keys already exist + if (ks.containsAlias(ALIAS)) + return ks + + // Generate new private key and certificate + val kp = KeyPairGenerator.getInstance("RSA").apply { initialize(2048) }.genKeyPair() + val dn = X500Name("CN=Magisk") + val builder = JcaX509v3CertificateBuilder(dn, + BigInteger.valueOf(start.timeInMillis), start.time, end.time, dn, kp.public) + val signer = JcaContentSignerBuilder("SHA256WithRSA").build(kp.private) + val cert = JcaX509CertificateConverter().getCertificate(builder.build(signer)) + + // Store them into keystore + ks.setKeyEntry(ALIAS, kp.private, PASSWORD, arrayOf(cert)) + val bytes = ByteArrayOutputStream() + GZIPOutputStream(Base64OutputStream(bytes, Base64.NO_PADDING or Base64.NO_WRAP)).use { + ks.store(it, PASSWORD) + } + Config.keyStoreRaw = bytes.toString() + + return ks + } + +} diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.kt b/app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.kt index edd1cff66..9ab490787 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.kt +++ b/app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.kt @@ -107,7 +107,7 @@ object PatchAPK { // Write apk changes jar.getOutputStream(je).write(xml) - SignAPK.sign(jar, FileOutputStream(out).buffered()) + SignAPK.sign(Keygen.cert, Keygen.key, jar, FileOutputStream(out).buffered()) } catch (e: Exception) { Timber.e(e) return false diff --git a/signing/src/main/java/com/topjohnwu/signing/CryptoUtils.java b/signing/src/main/java/com/topjohnwu/signing/CryptoUtils.java index a80963f06..2bbc22a16 100644 --- a/signing/src/main/java/com/topjohnwu/signing/CryptoUtils.java +++ b/signing/src/main/java/com/topjohnwu/signing/CryptoUtils.java @@ -24,7 +24,7 @@ import java.security.spec.PKCS8EncodedKeySpec; import java.util.HashMap; import java.util.Map; -class CryptoUtils { +public class CryptoUtils { static final Map ID_TO_ALG; static final Map ALG_TO_ID; @@ -81,7 +81,7 @@ class CryptoUtils { return new AlgorithmIdentifier(new ASN1ObjectIdentifier(id)); } - static X509Certificate readCertificate(InputStream input) + public static X509Certificate readCertificate(InputStream input) throws IOException, GeneralSecurityException { try { CertificateFactory cf = CertificateFactory.getInstance("X.509"); @@ -92,7 +92,7 @@ class CryptoUtils { } /** Read a PKCS#8 format private key. */ - static PrivateKey readPrivateKey(InputStream input) + public static PrivateKey readPrivateKey(InputStream input) throws IOException, GeneralSecurityException { try { ByteArrayStream buf = new ByteArrayStream(); diff --git a/signing/src/main/java/com/topjohnwu/signing/SignAPK.java b/signing/src/main/java/com/topjohnwu/signing/SignAPK.java index f965fdfa8..1c84f33de 100644 --- a/signing/src/main/java/com/topjohnwu/signing/SignAPK.java +++ b/signing/src/main/java/com/topjohnwu/signing/SignAPK.java @@ -30,7 +30,6 @@ import java.io.PrintStream; import java.io.RandomAccessFile; import java.security.DigestOutputStream; import java.security.GeneralSecurityException; -import java.security.KeyStore; import java.security.MessageDigest; import java.security.PrivateKey; import java.security.cert.CertificateEncodingException; @@ -61,29 +60,8 @@ public class SignAPK { private static final int USE_SHA1 = 1; private static final int USE_SHA256 = 2; - public static void sign(JarMap input, OutputStream output) throws Exception { - sign(SignAPK.class.getResourceAsStream("/keys/testkey.x509.pem"), - SignAPK.class.getResourceAsStream("/keys/testkey.pk8"), input, output); - } - - public static void sign(InputStream certIs, InputStream keyIs, - JarMap input, OutputStream output) throws Exception { - X509Certificate cert = CryptoUtils.readCertificate(certIs); - PrivateKey key = CryptoUtils.readPrivateKey(keyIs); - sign(cert, key, input, output); - } - - public static void sign(InputStream jks, String keyStorePass, String alias, String keyPass, - JarMap input, OutputStream output) throws Exception { - KeyStore ks = KeyStore.getInstance("JKS"); - ks.load(jks, keyStorePass.toCharArray()); - X509Certificate cert = (X509Certificate) ks.getCertificate(alias); - PrivateKey key = (PrivateKey) ks.getKey(alias, keyPass.toCharArray()); - sign(cert, key, input, output); - } - - private static void sign(X509Certificate cert, PrivateKey key, - JarMap input, OutputStream output) throws Exception { + public static void signAndAdjust(X509Certificate cert, PrivateKey key, + JarMap input, OutputStream output) throws Exception { File temp1 = File.createTempFile("signAPK", null); File temp2 = File.createTempFile("signAPK", null); @@ -103,6 +81,11 @@ public class SignAPK { } } + public static void sign(X509Certificate cert, PrivateKey key, + JarMap input, OutputStream output) throws Exception { + sign(cert, key, input, output, false); + } + private static void sign(X509Certificate cert, PrivateKey key, JarMap input, OutputStream output, boolean minSign) throws Exception { int hashes = 0; @@ -498,11 +481,11 @@ public class SignAPK { outputStream.close(); } private static void signFile(Manifest manifest, JarMap inputJar, - X509Certificate publicKey, PrivateKey privateKey, + X509Certificate cert, PrivateKey privateKey, JarOutputStream outputJar) throws Exception { // Assume the certificate is valid for at least an hour. - long timestamp = publicKey.getNotBefore().getTime() + 3600L * 1000; + long timestamp = cert.getNotBefore().getTime() + 3600L * 1000; // MANIFEST.MF JarEntry je = new JarEntry(JarFile.MANIFEST_NAME); je.setTime(timestamp); @@ -512,15 +495,15 @@ public class SignAPK { je.setTime(timestamp); outputJar.putNextEntry(je); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - writeSignatureFile(manifest, baos, getDigestAlgorithm(publicKey)); + writeSignatureFile(manifest, baos, getDigestAlgorithm(cert)); byte[] signedData = baos.toByteArray(); outputJar.write(signedData); // CERT.{EC,RSA} / CERT#.{EC,RSA} - final String keyType = publicKey.getPublicKey().getAlgorithm(); + final String keyType = cert.getPublicKey().getAlgorithm(); je = new JarEntry(String.format(CERT_SIG_NAME, keyType)); je.setTime(timestamp); outputJar.putNextEntry(je); writeSignatureBlock(new CMSProcessableByteArray(signedData), - publicKey, privateKey, outputJar); + cert, privateKey, outputJar); } } diff --git a/signing/src/main/java/com/topjohnwu/signing/ZipSigner.java b/signing/src/main/java/com/topjohnwu/signing/ZipSigner.java index 8e68de715..9e3fce6ed 100644 --- a/signing/src/main/java/com/topjohnwu/signing/ZipSigner.java +++ b/signing/src/main/java/com/topjohnwu/signing/ZipSigner.java @@ -4,23 +4,61 @@ import org.bouncycastle.jce.provider.BouncyCastleProvider; import java.io.FileInputStream; import java.io.FileOutputStream; +import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; import java.security.Security; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; public class ZipSigner { - public static void usage() { + private static void usage() { System.err.println("ZipSigner usage:"); System.err.println(" zipsigner.jar input.jar output.jar"); System.err.println(" sign jar with AOSP test keys"); System.err.println(" zipsigner.jar x509.pem pk8 input.jar output.jar"); System.err.println(" sign jar with certificate / private key pair"); - System.err.println(" zipsigner.jar jks keyStorePass keyAlias keyPass input.jar output.jar"); + System.err.println(" zipsigner.jar keyStore keyStorePass alias keyPass input.jar output.jar"); System.err.println(" sign jar with Java KeyStore"); System.exit(2); } + private static void sign(JarMap input, OutputStream output) throws Exception { + sign(SignAPK.class.getResourceAsStream("/keys/testkey.x509.pem"), + SignAPK.class.getResourceAsStream("/keys/testkey.pk8"), input, output); + } + + private static void sign(InputStream certIs, InputStream keyIs, + JarMap input, OutputStream output) throws Exception { + X509Certificate cert = CryptoUtils.readCertificate(certIs); + PrivateKey key = CryptoUtils.readPrivateKey(keyIs); + SignAPK.signAndAdjust(cert, key, input, output); + } + + private static void sign(String keyStore, String keyStorePass, String alias, String keyPass, + JarMap in, OutputStream out) throws Exception { + KeyStore ks; + try { + ks = KeyStore.getInstance("JKS"); + try (InputStream is = new FileInputStream(keyStore)) { + ks.load(is, keyStorePass.toCharArray()); + } + } catch (KeyStoreException|IOException|CertificateException|NoSuchAlgorithmException e) { + ks = KeyStore.getInstance("PKCS12"); + try (InputStream is = new FileInputStream(keyStore)) { + ks.load(is, keyStorePass.toCharArray()); + } + } + X509Certificate cert = (X509Certificate) ks.getCertificate(alias); + PrivateKey key = (PrivateKey) ks.getKey(alias, keyPass.toCharArray()); + SignAPK.signAndAdjust(cert, key, in, out); + } + public static void main(String[] args) throws Exception { if (args.length != 2 && args.length != 4 && args.length != 6) usage(); @@ -30,16 +68,14 @@ public class ZipSigner { try (JarMap in = new JarMap(args[args.length - 2], false); OutputStream out = new FileOutputStream(args[args.length - 1])) { if (args.length == 2) { - SignAPK.sign(in, out); + sign(in, out); } else if (args.length == 4) { try (InputStream cert = new FileInputStream(args[0]); InputStream key = new FileInputStream(args[1])) { - SignAPK.sign(cert, key, in, out); + sign(cert, key, in, out); } } else if (args.length == 6) { - try (InputStream jks = new FileInputStream(args[0])) { - SignAPK.sign(jks, args[1], args[2], args[3], in, out); - } + sign(args[0], args[1], args[2], args[3], in, out); } } } From 75306f658fa518cd901c653175aff5bd0b1cad50 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sun, 20 Oct 2019 07:13:03 -0400 Subject: [PATCH 16/61] Revert "Drop API 17 (Android 4.2) support" Turns out that we cannot use AndroidKeystore anyways, so we don't actually need to drop API 17. Revert this change. --- build.gradle | 2 +- native/jni/core/applets.cpp | 2 +- native/jni/init/rootdir.cpp | 17 +++++++++-------- native/jni/utils/include/selinux.h | 3 ++- native/jni/utils/selinux.cpp | 15 +++++++++++++++ scripts/flash_script.sh | 2 +- 6 files changed, 29 insertions(+), 12 deletions(-) diff --git a/build.gradle b/build.gradle index 28680819c..f0236679e 100644 --- a/build.gradle +++ b/build.gradle @@ -47,7 +47,7 @@ subprojects { defaultConfig { if (minSdkVersion == null) - minSdkVersion 18 + minSdkVersion 17 targetSdkVersion 28 } diff --git a/native/jni/core/applets.cpp b/native/jni/core/applets.cpp index f1ab263bf..4932bc9e0 100644 --- a/native/jni/core/applets.cpp +++ b/native/jni/core/applets.cpp @@ -26,7 +26,7 @@ static int (*applet_main[]) (int, char *[]) = int main(int argc, char *argv[]) { umask(0); - selinux_builtin_impl(); + dload_selinux(); cmdline_logging(); init_argv0(argc, argv); diff --git a/native/jni/init/rootdir.cpp b/native/jni/init/rootdir.cpp index 6d39bce33..e5a362e8f 100644 --- a/native/jni/init/rootdir.cpp +++ b/native/jni/init/rootdir.cpp @@ -153,24 +153,25 @@ void SARCompatInit::setup_rootfs() { } bool MagiskInit::patch_sepolicy(const char *file) { - bool require_patch = false; - - // Mount selinuxfs to communicate with kernel - xmount("selinuxfs", SELINUX_MNT, "selinuxfs", 0, nullptr); + bool patch_init = false; if (access(SPLIT_PLAT_CIL, R_OK) == 0) { LOGD("sepol: split policy\n"); - load_split_cil(); - require_patch = true; + patch_init = true; } else if (access("/sepolicy", R_OK) == 0) { LOGD("sepol: monolithic policy\n"); load_policydb("/sepolicy"); } else { - // Fatal error!! LOGD("sepol: no selinux\n"); return false; } + // Mount selinuxfs to communicate with kernel + xmount("selinuxfs", SELINUX_MNT, "selinuxfs", 0, nullptr); + + if (patch_init) + load_split_cil(); + sepol_magisk_rules(); sepol_allow(SEPOL_PROC_DOMAIN, ALL, ALL, ALL); dump_policydb(file); @@ -181,7 +182,7 @@ bool MagiskInit::patch_sepolicy(const char *file) { link("/sepolicy", "/sepolicy_debug"); } - return require_patch; + return patch_init; } constexpr const char wrapper[] = diff --git a/native/jni/utils/include/selinux.h b/native/jni/utils/include/selinux.h index 15e4615e8..322afaaff 100644 --- a/native/jni/utils/include/selinux.h +++ b/native/jni/utils/include/selinux.h @@ -20,7 +20,7 @@ __BEGIN_DECLS -#define freecon free +extern void (*freecon)(char *con); extern int (*setcon)(const char *con); extern int (*getfilecon)(const char *path, char **con); extern int (*lgetfilecon)(const char *path, char **con); @@ -32,6 +32,7 @@ void getfilecon_at(int dirfd, const char *name, char **con); void setfilecon_at(int dirfd, const char *name, const char *con); void selinux_builtin_impl(); +void dload_selinux(); void restorecon(); void restore_rootcon(); diff --git a/native/jni/utils/selinux.cpp b/native/jni/utils/selinux.cpp index d530c3392..ed3696191 100644 --- a/native/jni/utils/selinux.cpp +++ b/native/jni/utils/selinux.cpp @@ -38,6 +38,10 @@ static int stub(int, char **ctx) { // Builtin implementation +static void __freecon(char *s) { + free(s); +} + static int __setcon(const char *ctx) { int fd = open("/proc/self/attr/current", O_WRONLY | O_CLOEXEC); if (fd < 0) @@ -110,6 +114,7 @@ static int __fsetfilecon(int fd, const char *ctx) { // Function pointers +void (*freecon)(char *) = __freecon; int (*setcon)(const char *) = stub; int (*getfilecon)(const char *, char **) = stub; int (*lgetfilecon)(const char *, char **) = stub; @@ -141,6 +146,16 @@ void selinux_builtin_impl() { fsetfilecon = __fsetfilecon; } +void dload_selinux() { + if (access("/system/lib/libselinux.so", F_OK)) + return; + /* We only check whether libselinux.so exists but don't dlopen. + * For some reason calling symbols returned from dlsym + * will result to SEGV_ACCERR on some devices. + * Always use builtin implementations for SELinux stuffs. */ + selinux_builtin_impl(); +} + static void restore_syscon(int dirfd) { struct dirent *entry; DIR *dir; diff --git a/scripts/flash_script.sh b/scripts/flash_script.sh index 0239db1de..f8f47e4cf 100644 --- a/scripts/flash_script.sh +++ b/scripts/flash_script.sh @@ -53,7 +53,7 @@ ui_print "- Target image: $BOOTIMAGE" # Detect version and architecture api_level_arch_detect -[ $API -lt 18 ] && abort "! Magisk is only for Android 4.3 and above" +[ $API -lt 17 ] && abort "! Magisk is only for Android 4.2 and above" ui_print "- Device platform: $ARCH" From 96a8a2a8b8626b37569de0398c75553556ad6c3a Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sun, 20 Oct 2019 17:35:38 -0400 Subject: [PATCH 17/61] Make SuRequest default to Translucent.NoTitleBar Close #1959 --- app/src/main/AndroidManifest.xml | 1 + stub/src/main/AndroidManifest.xml | 1 + 2 files changed, 2 insertions(+) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b4d2737fa..d3863ebb9 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -65,6 +65,7 @@ diff --git a/stub/src/main/AndroidManifest.xml b/stub/src/main/AndroidManifest.xml index 36428315f..b1b4af47c 100644 --- a/stub/src/main/AndroidManifest.xml +++ b/stub/src/main/AndroidManifest.xml @@ -48,6 +48,7 @@ From 271b0287d8f5dd73a89c5fdea4a909828c2bf24c Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sun, 20 Oct 2019 17:47:55 -0400 Subject: [PATCH 18/61] Pass in stub version just in case --- .../main/java/com/topjohnwu/magisk/utils/DynAPK.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/shared/src/main/java/com/topjohnwu/magisk/utils/DynAPK.java b/shared/src/main/java/com/topjohnwu/magisk/utils/DynAPK.java index 93dfbf84c..24d139c3f 100644 --- a/shared/src/main/java/com/topjohnwu/magisk/utils/DynAPK.java +++ b/shared/src/main/java/com/topjohnwu/magisk/utils/DynAPK.java @@ -7,9 +7,12 @@ import java.util.Map; public class DynAPK { + private static final int STUB_VERSION = 1; + // Indices of the object array - private static final int COMPONENT_MAP = 0; - private static final int RESOURCE_MAP = 1; + private static final int STUB_VERSION_ENTRY = 0; + private static final int COMPONENT_MAP = 1; + private static final int RESOURCE_MAP = 2; // Indices of the resource map public static final int NOTIFICATION = 0; @@ -39,19 +42,22 @@ public class DynAPK { public static Data load(Object o) { Object[] arr = (Object[]) o; Data data = new Data(); + data.version = (int) arr[STUB_VERSION_ENTRY]; data.componentMap = (Map) arr[COMPONENT_MAP]; data.resourceMap = (int[]) arr[RESOURCE_MAP]; return data; } public static Object pack(Data data) { - Object[] arr = new Object[2]; + Object[] arr = new Object[3]; + arr[STUB_VERSION_ENTRY] = STUB_VERSION; arr[COMPONENT_MAP] = data.componentMap; arr[RESOURCE_MAP] = data.resourceMap; return arr; } public static class Data { + public int version; public Map componentMap; public int[] resourceMap; } From 953c40b0831fa992997c69d08712ddba030e4614 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Mon, 21 Oct 2019 13:58:57 -0400 Subject: [PATCH 19/61] Allow upgrade Magisk daemon in emulator --- scripts/emulator.sh | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/scripts/emulator.sh b/scripts/emulator.sh index af7be4a6a..ceb3e8388 100755 --- a/scripts/emulator.sh +++ b/scripts/emulator.sh @@ -36,7 +36,6 @@ if [ ! -f /system/build.prop ]; then else adb push native/out/x86/magiskinit /data/local/tmp fi - adb root || abort 'adb root failed' adb shell sh /data/local/tmp/emulator.sh exit 0 fi @@ -45,12 +44,10 @@ cd /data/local/tmp chmod 777 busybox chmod 777 magiskinit -# Emulator's adb shell should have root -[ `./busybox id -u` -eq 0 ] || abort 'ADB shell should have root access' - -# Check whether already setup -[ -f /sbin/magisk ] && abort "Magisk is already setup" -./busybox pgrep magiskd && abort "Magisk is already setup" +if [ `./busybox id -u` -ne 0 ]; then + # Re-run script with root + exec /system/xbin/su 0 sh $0 +fi # First setup a good env to work with rm -rf bin @@ -59,6 +56,10 @@ rm -rf bin OLD_PATH="$PATH" PATH="/data/local/tmp/bin:$PATH" +# Remove previous setup if exist +pgrep magiskd >/dev/null && pkill -9 magiskd +[ -f /sbin/magisk ] && umount -l /sbin + # SELinux stuffs [ -e /sys/fs/selinux ] && SELINUX=true || SELINUX=false if $SELINUX; then From 0f74e89b44e6af6a7939ebf24050ce92546c2b5c Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Mon, 21 Oct 2019 13:59:04 -0400 Subject: [PATCH 20/61] Introduce component agnostic communication Usually, the communication between native and the app is done via sending intents to either broadcast or activity. These communication channels are for launching root requests dialogs, sending root request notifications (the toast you see when an app gained root access), and root request logging. Sending intents by am (activity manager) usually requires specifying the component name in the format of /. This means parts of Magisk Manager cannot be randomized or else the native daemon is unable to know where to send data to the app. On modern Android (not sure which API is it introduced), it is possible to send broadcasts to a package, not a specific component. Which component will receive the intent depends on the intent filter declared in AndroidManifest.xml. Since we already have a mechanism in native code to keep track of the package name of Magisk Manager, this makes it perfect to pass intents to Magisk Manager that have components being randomly obfuscated (stub APKs). There are a few caveats though. Although this broadcasting method works perfectly fine on AOSP and most systems, there are OEMs out there shipping ROMs blocking broadcasts unexpectedly. In order to make sure Magisk works in all kinds of scenarios, we run actual tests every boot to determine which communication method should be used. We have 3 methods in total, ordered in preference: 1. Broadcasting to a package 2. Broadcasting to a specific component 3. Starting a specific activity component Method 3 will always work on any device, but the downside is anytime a communication happens, Magisk Manager will steal foreground focus regardless of whether UI is drawn. Method 1 is the only way to support obfuscated stub APKs. The communication test will test method 1 and 2, and if Magisk Manager is able to receive the messages, it will then update the daemon configuration to use whichever is preferable. If none of the broadcasts can be delivered, then the fallback method 3 will be used. --- app/src/main/AndroidManifest.xml | 1 + .../topjohnwu/magisk/extensions/XAndroid.kt | 49 ++++--- .../magisk/model/receiver/GeneralReceiver.kt | 36 +++-- .../magisk/ui/surequest/SuRequestActivity.kt | 19 ++- .../com/topjohnwu/magisk/utils/SuLogger.kt | 25 ++-- native/jni/core/daemon.cpp | 8 +- native/jni/core/db.cpp | 9 +- native/jni/core/magisk.cpp | 25 ++-- native/jni/include/daemon.h | 10 +- native/jni/su/connect.cpp | 135 +++++++++++++----- native/jni/su/su.h | 2 +- native/jni/su/su_daemon.cpp | 2 +- 12 files changed, 205 insertions(+), 116 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d3863ebb9..9ba7c0f60 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -76,6 +76,7 @@ android:name="a.h" android:directBootAware="true"> + diff --git a/app/src/main/java/com/topjohnwu/magisk/extensions/XAndroid.kt b/app/src/main/java/com/topjohnwu/magisk/extensions/XAndroid.kt index 4a893ab8b..29120d6f8 100644 --- a/app/src/main/java/com/topjohnwu/magisk/extensions/XAndroid.kt +++ b/app/src/main/java/com/topjohnwu/magisk/extensions/XAndroid.kt @@ -20,13 +20,15 @@ import androidx.annotation.ColorRes import androidx.annotation.DrawableRes import androidx.core.content.ContextCompat import androidx.core.net.toUri +import com.topjohnwu.magisk.Const import com.topjohnwu.magisk.utils.DynamicClassLoader import com.topjohnwu.magisk.utils.FileProvider import com.topjohnwu.magisk.utils.Utils import com.topjohnwu.magisk.utils.currentLocale +import com.topjohnwu.superuser.Shell import java.io.File import java.io.FileNotFoundException -import java.util.* +import java.lang.reflect.Array as JArray val packageName: String get() = get().packageName @@ -97,33 +99,38 @@ fun Context.readUri(uri: Uri) = fun Intent.startActivity(context: Context) = context.startActivity(this) -fun Intent.toCommand(args: MutableList) { - if (action != null) { +fun Intent.startActivityWithRoot() { + val args = mutableListOf("am", "start", "--user", Const.USER_ID.toString()) + val cmd = toCommand(args).joinToString(" ") + Shell.su(cmd).submit() +} + +fun Intent.toCommand(args: MutableList = mutableListOf()): MutableList { + action?.also { args.add("-a") - args.add(action!!) + args.add(it) } - if (component != null) { + component?.also { args.add("-n") - args.add(component!!.flattenToString()) + args.add(it.flattenToString()) } - if (data != null) { + data?.also { args.add("-d") - args.add(dataString!!) + args.add(it.toString()) } - if (categories != null) { - for (cat in categories) { + categories?.also { + for (cat in it) { args.add("-c") args.add(cat) } } - if (type != null) { + type?.also { args.add("-t") - args.add(type!!) + args.add(it) } - val extras = extras - if (extras != null) { - loop@ for (key in extras.keySet()) { - val v = extras.get(key) ?: continue + extras?.also { + loop@ for (key in it.keySet()) { + val v = it[key] ?: continue var value: Any = v val arg: String when { @@ -137,9 +144,8 @@ fun Intent.toCommand(args: MutableList) { arg = "--ecn" value = v.flattenToString() } - v is ArrayList<*> -> { - if (v.size <= 0) - /* Impossible to know the type due to type erasure */ + v is List<*> -> { + if (v.isEmpty()) continue@loop arg = if (v[0] is Int) @@ -175,9 +181,9 @@ fun Intent.toCommand(args: MutableList) { continue@loop /* Unsupported */ val sb = StringBuilder() - val len = java.lang.reflect.Array.getLength(v) + val len = JArray.getLength(v) for (i in 0 until len) { - sb.append(java.lang.reflect.Array.get(v, i)!!.toString().replace(",", "\\,")) + sb.append(JArray.get(v, i)!!.toString().replace(",", "\\,")) sb.append(',') } // Remove trailing comma @@ -194,6 +200,7 @@ fun Intent.toCommand(args: MutableList) { } args.add("-f") args.add(flags.toString()) + return args } fun File.provide(context: Context = get()): Uri { diff --git a/app/src/main/java/com/topjohnwu/magisk/model/receiver/GeneralReceiver.kt b/app/src/main/java/com/topjohnwu/magisk/model/receiver/GeneralReceiver.kt index f9c591304..6a0ca9a4f 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/receiver/GeneralReceiver.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/receiver/GeneralReceiver.kt @@ -2,14 +2,14 @@ package com.topjohnwu.magisk.model.receiver import android.content.ContextWrapper import android.content.Intent -import com.topjohnwu.magisk.Config -import com.topjohnwu.magisk.Const -import com.topjohnwu.magisk.Info +import android.os.Build.VERSION.SDK_INT +import com.topjohnwu.magisk.* import com.topjohnwu.magisk.base.BaseReceiver import com.topjohnwu.magisk.data.database.PolicyDao import com.topjohnwu.magisk.data.database.base.su import com.topjohnwu.magisk.extensions.reboot -import com.topjohnwu.magisk.intent +import com.topjohnwu.magisk.extensions.startActivity +import com.topjohnwu.magisk.extensions.startActivityWithRoot import com.topjohnwu.magisk.model.download.DownloadService import com.topjohnwu.magisk.model.entity.ManagerJson import com.topjohnwu.magisk.model.entity.internal.Configuration @@ -20,6 +20,7 @@ import com.topjohnwu.magisk.view.Notifications import com.topjohnwu.magisk.view.Shortcuts import com.topjohnwu.superuser.Shell import org.koin.core.inject +import timber.log.Timber open class GeneralReceiver : BaseReceiver() { @@ -38,6 +39,17 @@ open class GeneralReceiver : BaseReceiver() { override fun onReceive(context: ContextWrapper, intent: Intent?) { intent ?: return + + // Debug messages + if (BuildConfig.DEBUG) { + Timber.d(intent.action) + intent.extras?.let { bundle -> + bundle.keySet().forEach { + Timber.d("[%s]=[%s]", it, bundle[it]) + } + } + } + when (intent.action ?: return) { Intent.ACTION_REBOOT, Intent.ACTION_BOOT_COMPLETED -> { val action = intent.getStringExtra("action") @@ -56,11 +68,19 @@ open class GeneralReceiver : BaseReceiver() { .putExtra("socket", intent.getStringExtra("socket")) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) .addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK) - context.startActivity(i) + if (SDK_INT >= 29) { + // Android Q does not allow starting activity from background + i.startActivityWithRoot() + } else { + i.startActivity(context) + } + } + LOG -> SuLogger.handleLogs(context, intent) + NOTIFY -> SuLogger.handleNotify(context, intent) + TEST -> { + val mode = intent.getIntExtra("mode", 1 shl 1) + Shell.su("magisk --connect-mode $mode").submit() } - LOG -> SuLogger.handleLogs(intent) - NOTIFY -> SuLogger.handleNotify(intent) - TEST -> Shell.su("magisk --use-broadcast").submit() } } Intent.ACTION_PACKAGE_REPLACED -> diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/surequest/SuRequestActivity.kt b/app/src/main/java/com/topjohnwu/magisk/ui/surequest/SuRequestActivity.kt index b55e108c2..4ce2a60be 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/surequest/SuRequestActivity.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/surequest/SuRequestActivity.kt @@ -3,7 +3,6 @@ package com.topjohnwu.magisk.ui.surequest import android.content.pm.ActivityInfo import android.os.Build import android.os.Bundle -import android.text.TextUtils import android.view.Window import com.topjohnwu.magisk.R import com.topjohnwu.magisk.base.BaseActivity @@ -31,19 +30,17 @@ open class SuRequestActivity : BaseActivity { + if (!viewModel.handleRequest(intent)) + finish() + return + } + GeneralReceiver.LOG -> SuLogger.handleLogs(this, intent) + GeneralReceiver.NOTIFY -> SuLogger.handleNotify(this, intent) } - if (TextUtils.equals(action, GeneralReceiver.LOG)) - SuLogger.handleLogs(intent) - else if (TextUtils.equals(action, GeneralReceiver.NOTIFY)) - SuLogger.handleNotify(intent) - finish() } diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/SuLogger.kt b/app/src/main/java/com/topjohnwu/magisk/utils/SuLogger.kt index b6134d584..98b201235 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/SuLogger.kt +++ b/app/src/main/java/com/topjohnwu/magisk/utils/SuLogger.kt @@ -2,14 +2,13 @@ package com.topjohnwu.magisk.utils import android.content.Context import android.content.Intent -import android.content.pm.PackageManager import android.os.Process import android.widget.Toast import com.topjohnwu.magisk.Config import com.topjohnwu.magisk.R import com.topjohnwu.magisk.data.database.PolicyDao import com.topjohnwu.magisk.data.repository.LogRepository -import com.topjohnwu.magisk.extensions.inject +import com.topjohnwu.magisk.extensions.get import com.topjohnwu.magisk.model.entity.MagiskPolicy import com.topjohnwu.magisk.model.entity.toLog import com.topjohnwu.magisk.model.entity.toPolicy @@ -17,15 +16,13 @@ import java.util.* object SuLogger { - private val context: Context by inject() - - fun handleLogs(intent: Intent) { + fun handleLogs(context: Context, intent: Intent) { val fromUid = intent.getIntExtra("from.uid", -1) if (fromUid < 0) return if (fromUid == Process.myUid()) return - val pm: PackageManager by inject() + val pm = context.packageManager val notify: Boolean val data = intent.extras @@ -36,7 +33,7 @@ object SuLogger { }.getOrElse { return } } else { // Doesn't report whether notify or not, check database ourselves - val policyDB: PolicyDao by inject() + val policyDB = get() val policy = policyDB.fetch(fromUid).blockingGet() ?: return notify = policy.notification policy @@ -46,7 +43,7 @@ object SuLogger { return if (notify) - handleNotify(policy) + handleNotify(context, policy) val toUid = intent.getIntExtra("to.uid", -1) if (toUid < 0) return @@ -62,11 +59,11 @@ object SuLogger { date = Date() ) - val logRepo: LogRepository by inject() + val logRepo = get() logRepo.put(log).blockingGet()?.printStackTrace() } - private fun handleNotify(policy: MagiskPolicy) { + private fun handleNotify(context: Context, policy: MagiskPolicy) { if (policy.notification && Config.suNotification == Config.Value.NOTIFICATION_TOAST) { Utils.toast( context.getString( @@ -80,16 +77,16 @@ object SuLogger { } } - fun handleNotify(intent: Intent) { + fun handleNotify(context: Context, intent: Intent) { val fromUid = intent.getIntExtra("from.uid", -1) if (fromUid < 0) return if (fromUid == Process.myUid()) return runCatching { - val packageManager: PackageManager by inject() - val policy = fromUid.toPolicy(packageManager) + val pm = context.packageManager + val policy = fromUid.toPolicy(pm) .copy(policy = intent.getIntExtra("policy", -1)) if (policy.policy >= 0) - handleNotify(policy) + handleNotify(context, policy) } } } diff --git a/native/jni/core/daemon.cpp b/native/jni/core/daemon.cpp index 41dc7d97c..f13f05d3e 100644 --- a/native/jni/core/daemon.cpp +++ b/native/jni/core/daemon.cpp @@ -54,6 +54,7 @@ static void *request_handler(void *args) { case BOOT_COMPLETE: case SQLITE_CMD: case BROADCAST_ACK: + case BROADCAST_TEST: if (credential.uid != 0) { write_int(client, ROOT_REQUIRED); close(client); @@ -91,9 +92,10 @@ static void *request_handler(void *args) { exec_sql(client); break; case BROADCAST_ACK: - LOGD("* Use broadcasts for su logging and notify\n"); - CONNECT_BROADCAST = true; - close(client); + broadcast_ack(client); + break; + case BROADCAST_TEST: + broadcast_test(client); break; case REMOVE_MODULES: if (credential.uid == UID_SHELL || credential.uid == UID_ROOT) { diff --git a/native/jni/core/db.cpp b/native/jni/core/db.cpp index 701f62c41..bd451b64d 100644 --- a/native/jni/core/db.cpp +++ b/native/jni/core/db.cpp @@ -219,7 +219,6 @@ int get_db_strings(db_strings &str, int key) { char *err; auto string_cb = [&](db_row &row) -> bool { str[row["key"]] = row["value"]; - LOGD("magiskdb: query %s=[%s]\n", row["key"].data(), row["value"].data()); return true; }; if (key >= 0) { @@ -273,6 +272,7 @@ int validate_manager(string &alt_pkg, int userid, struct stat *st) { } void exec_sql(int client) { + run_finally f([=]{ close(client); }); char *sql = read_string(client); char *err = db_exec(sql, [&](db_row &row) -> bool { string out; @@ -289,9 +289,6 @@ void exec_sql(int client) { return true; }); free(sql); - db_err_cmd(err, - write_int(client, 0); - return; - ); - close(client); + write_int(client, 0); + db_err_cmd(err, return; ); } diff --git a/native/jni/core/magisk.cpp b/native/jni/core/magisk.cpp index a93ea1eaa..821e53be1 100644 --- a/native/jni/core/magisk.cpp +++ b/native/jni/core/magisk.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #include using namespace std::literals; @@ -36,7 +35,8 @@ Advanced Options (Internal APIs): --clone-attr SRC DEST clone permission, owner, and selinux context --clone SRC DEST clone SRC to DEST --sqlite SQL exec SQL commands to Magisk database - --use-broadcast use broadcast for su logging and notify + --connect-mode [MODE] get/set connect mode for su request and notify + --broadcast-test manually trigger broadcast tests Supported init triggers: post-fs-data, service, boot-complete @@ -79,12 +79,10 @@ int magisk_main(int argc, char *argv[]) { restore_rootcon(); restorecon(); return 0; - } else if (argv[1] == "--clone-attr"sv) { - if (argc < 4) usage(); + } else if (argc >= 4 && argv[1] == "--clone-attr"sv) {; clone_attr(argv[2], argv[3]); return 0; - } else if (argv[1] == "--clone"sv) { - if (argc < 4) usage(); + } else if (argc >= 4 && argv[1] == "--clone"sv) { cp_afc(argv[2], argv[3]); return 0; } else if (argv[1] == "--daemon"sv) { @@ -103,7 +101,7 @@ int magisk_main(int argc, char *argv[]) { int fd = connect_daemon(true); write_int(fd, BOOT_COMPLETE); return read_int(fd); - } else if (argv[1] == "--sqlite"sv) { + } else if (argc >= 3 && argv[1] == "--sqlite"sv) { int fd = connect_daemon(); write_int(fd, SQLITE_CMD); write_string(fd, argv[2]); @@ -115,14 +113,23 @@ int magisk_main(int argc, char *argv[]) { printf("%s\n", res); free(res); } - } else if (argv[1] == "--use-broadcast"sv) { + } else if (argv[1] == "--connect-mode"sv) { int fd = connect_daemon(); write_int(fd, BROADCAST_ACK); - return 0; + if (argc >= 3) { + write_int(fd, parse_int(argv[2])); + } else { + write_int(fd, -1); + } + return read_int(fd); } else if (argv[1] == "--remove-modules"sv) { int fd = connect_daemon(); write_int(fd, REMOVE_MODULES); return read_int(fd); + } else if (argv[1] == "--broadcast-test"sv) { + int fd = connect_daemon(); + write_int(fd, BROADCAST_TEST); + return read_int(fd); } #if 0 /* Entry point for testing stuffs */ diff --git a/native/jni/include/daemon.h b/native/jni/include/daemon.h index 92e1b5b62..0f6956b0e 100644 --- a/native/jni/include/daemon.h +++ b/native/jni/include/daemon.h @@ -19,6 +19,7 @@ enum { SQLITE_CMD, BROADCAST_ACK, REMOVE_MODULES, + BROADCAST_TEST, }; // Return codes for daemon @@ -84,10 +85,13 @@ void magiskhide_handler(int client); *************/ void su_daemon_handler(int client, struct ucred *credential); -void broadcast_test(); +void broadcast_test(int client = -1); +void broadcast_ack(int client); + +/********************* + * Daemon Global Vars + *********************/ extern int SDK_INT; extern bool RECOVERY_MODE; -extern bool CONNECT_BROADCAST; - #define APP_DATA_DIR (SDK_INT >= 24 ? "/data/user_de" : "/data/user") diff --git a/native/jni/su/connect.cpp b/native/jni/su/connect.cpp index f59155863..f83cf2c9c 100644 --- a/native/jni/su/connect.cpp +++ b/native/jni/su/connect.cpp @@ -7,12 +7,20 @@ #include #include +#include #include "su.h" using namespace std; -bool CONNECT_BROADCAST; +enum connect_mode { + UNINITIALIZED = 0, + MODE_ACTIVITY, + MODE_BROADCAST_COMPONENT, + MODE_BROADCAST_PACKAGE +}; + +static connect_mode current_mode = UNINITIALIZED; #define START_ACTIVITY \ "/system/bin/app_process", "/system/bin", "com.android.commands.am.Am", \ @@ -25,9 +33,28 @@ bool CONNECT_BROADCAST; "broadcast", "-n", nullptr, "--user", nullptr, "-f", "0x00000020", \ "-a", "android.intent.action.REBOOT", "--es", "action" +#define START_BROADCAST_PKG \ +"/system/bin/app_process", "/system/bin", "com.android.commands.am.Am", \ +"broadcast", "-p", nullptr, "--user", nullptr, "-f", "0x00000020", \ +"-a", "android.intent.action.REBOOT", "--es", "action" + // 0x00000020 = FLAG_INCLUDE_STOPPED_PACKAGES -static inline const char *get_command(const su_request *to) { +#define am_app_info(info, ...) \ +if (current_mode == MODE_BROADCAST_PACKAGE) { \ + const char *cmd[] = { START_BROADCAST_PKG, __VA_ARGS__, nullptr }; \ + exec_am_cmd(cmd, info); \ +} else if (current_mode == MODE_BROADCAST_COMPONENT) { \ + const char *cmd[] = { START_BROADCAST, __VA_ARGS__, nullptr }; \ + exec_am_cmd(cmd, info); \ +} else { \ + const char *cmd[] = { START_ACTIVITY, __VA_ARGS__, nullptr }; \ + exec_am_cmd(cmd, info); \ +} + +#define am_app(...) am_app_info(ctx.info.get(), __VA_ARGS__) + +static const char *get_command(const su_request *to) { if (to->command[0]) return to->command; if (to->shell[0]) @@ -35,14 +62,14 @@ static inline const char *get_command(const su_request *to) { return DEFAULT_SHELL; } -static inline void get_user(char *user, const su_info *info) { +static void get_user(char *user, const su_info *info) { sprintf(user, "%d", info->cfg[SU_MULTIUSER_MODE] == MULTIUSER_MODE_USER ? info->uid / 100000 : 0); } -static inline void get_uid(char *uid, const su_info *info) { +static void get_uid(char *uid, const su_info *info) { sprintf(uid, "%d", info->cfg[SU_MULTIUSER_MODE] == MULTIUSER_MODE_OWNER_MANAGED ? info->uid % 100000 @@ -50,13 +77,25 @@ static inline void get_uid(char *uid, const su_info *info) { } static void exec_am_cmd(const char **args, const su_info *info) { - char component[128]; - sprintf(component, "%s/%s", info->str[SU_MANAGER].data(), args[3][0] == 'b' ? "a.h" : "a.m"); + char target[128]; + if (args[3][0] == 'b') { + // Broadcast + if (args[4][1] == 'p') { + // Broadcast to package (receiver can be obfuscated) + strcpy(target, info->str[SU_MANAGER].data()); + } else { + // a.h is the broadcast receiver + sprintf(target, "%s/a.h", info->str[SU_MANAGER].data()); + } + } else { + // a.m is the activity + sprintf(target, "%s/a.m", info->str[SU_MANAGER].data()); + } char user[8]; get_user(user, info); - /* Fill in dynamic arguments */ - args[5] = component; + // Fill in non static arguments + args[5] = target; args[7] = user; exec_t exec { @@ -79,8 +118,7 @@ static void exec_am_cmd(const char **args, const su_info *info) { "--ei", "pid", pid, \ "--ei", "policy", policy, \ "--es", "command", get_command(&ctx.req), \ -"--ez", "notify", ctx.info->access.notify ? "true" : "false", \ -nullptr +"--ez", "notify", ctx.info->access.notify ? "true" : "false" void app_log(const su_context &ctx) { char fromUid[8]; @@ -95,20 +133,13 @@ void app_log(const su_context &ctx) { char policy[2]; sprintf(policy, "%d", ctx.info->access.policy); - if (CONNECT_BROADCAST) { - const char *cmd[] = { START_BROADCAST, LOG_BODY }; - exec_am_cmd(cmd, ctx.info.get()); - } else { - const char *cmd[] = { START_ACTIVITY, LOG_BODY }; - exec_am_cmd(cmd, ctx.info.get()); - } + am_app(LOG_BODY) } #define NOTIFY_BODY \ "notify", \ "--ei", "from.uid", fromUid, \ -"--ei", "policy", policy, \ -nullptr +"--ei", "policy", policy void app_notify(const su_context &ctx) { char fromUid[8]; @@ -117,33 +148,59 @@ void app_notify(const su_context &ctx) { char policy[2]; sprintf(policy, "%d", ctx.info->access.policy); - if (CONNECT_BROADCAST) { - const char *cmd[] = { START_BROADCAST, NOTIFY_BODY }; - exec_am_cmd(cmd, ctx.info.get()); - } else { - const char *cmd[] = { START_ACTIVITY, NOTIFY_BODY }; - exec_am_cmd(cmd, ctx.info.get()); + am_app(NOTIFY_BODY) +} + +#define SOCKET_BODY \ +"request", \ +"--es", "socket", socket + +void app_socket(const char *socket, const shared_ptr &info) { + am_app_info(info.get(), SOCKET_BODY) +} + +#define TEST_BODY \ +"test", "--ei", "mode", mode, nullptr + +void broadcast_test(int client) { + if (client >= 0) { + // Make it not uninitialized + current_mode = MODE_ACTIVITY; + write_int(client, 0); + close(client); } -} - -void app_connect(const char *socket, const shared_ptr &info) { - const char *cmd[] = { - START_ACTIVITY, "request", - "--es", "socket", socket, - nullptr - }; - exec_am_cmd(cmd, info.get()); -} - -void broadcast_test() { su_info info; get_db_settings(info.cfg); get_db_strings(info.str); validate_manager(info.str[SU_MANAGER], 0, &info.mgr_st); - const char *cmd[] = { START_BROADCAST, "test", nullptr }; - exec_am_cmd(cmd, &info); + char mode[2]; + { + sprintf(mode, "%d", MODE_BROADCAST_PACKAGE); + const char *cmd[] = { START_BROADCAST_PKG, TEST_BODY }; + exec_am_cmd(cmd, &info); + } + { + sprintf(mode, "%d", MODE_BROADCAST_COMPONENT); + const char *cmd[] = { START_BROADCAST, TEST_BODY }; + exec_am_cmd(cmd, &info); + } +} + +void broadcast_ack(int client) { + int mode = read_int(client); + if (mode < 0) { + // Return connection mode to client + write_int(client, current_mode); + } else { + if (mode > current_mode) { + LOGD("* Use connect mode [%d] for su request and notify\n", mode); + current_mode = static_cast(mode); + } + write_int(client, 0); + } + close(client); } void socket_send_request(int fd, const shared_ptr &info) { diff --git a/native/jni/su/su.h b/native/jni/su/su.h index c496e5bbf..2c18fc5c8 100644 --- a/native/jni/su/su.h +++ b/native/jni/su/su.h @@ -68,5 +68,5 @@ struct su_context { void app_log(const su_context &ctx); void app_notify(const su_context &ctx); -void app_connect(const char *socket, const std::shared_ptr &info); +void app_socket(const char *socket, const std::shared_ptr &info); void socket_send_request(int fd, const std::shared_ptr &info); diff --git a/native/jni/su/su_daemon.cpp b/native/jni/su/su_daemon.cpp index 5debb5cd5..660ca1175 100644 --- a/native/jni/su/su_daemon.cpp +++ b/native/jni/su/su_daemon.cpp @@ -144,7 +144,7 @@ static shared_ptr get_su_info(unsigned uid) { int sockfd = create_rand_socket(&addr); // Connect manager - app_connect(addr.sun_path + 1, info); + app_socket(addr.sun_path + 1, info); int fd = socket_accept(sockfd, 60); if (fd < 0) { info->access.policy = DENY; From 7ded7de39a55b4d86f12d91f14d3f94132981c9c Mon Sep 17 00:00:00 2001 From: Viktor De Pasquale Date: Sun, 20 Oct 2019 15:56:56 +0200 Subject: [PATCH 21/61] Added custom dialog for setting app's name after repackaging --- .../topjohnwu/magisk/extensions/XString.kt | 2 + .../magisk/ui/settings/SettingsFragment.kt | 63 +++++++++++++------ .../magisk/utils/DataBindingAdapters.kt | 8 +++ .../main/res/layout/dialog_custom_name.xml | 46 ++++++++++++++ app/src/main/res/values/strings.xml | 4 ++ 5 files changed, 104 insertions(+), 19 deletions(-) create mode 100644 app/src/main/res/layout/dialog_custom_name.xml diff --git a/app/src/main/java/com/topjohnwu/magisk/extensions/XString.kt b/app/src/main/java/com/topjohnwu/magisk/extensions/XString.kt index fb0a65840..ee2d279e2 100644 --- a/app/src/main/java/com/topjohnwu/magisk/extensions/XString.kt +++ b/app/src/main/java/com/topjohnwu/magisk/extensions/XString.kt @@ -25,3 +25,5 @@ fun String.trimEmptyToNull(): String? = if (isBlank()) null else this fun String.legalFilename() = replace(" ", "_").replace("'", "").replace("\"", "") .replace("$", "").replace("`", "").replace("*", "").replace("/", "_") .replace("#", "").replace("@", "").replace("\\", "_") + +fun String.isEmptyInternal() = isNullOrBlank() \ No newline at end of file diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt b/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt index 9da82ee24..3a4012d1b 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt @@ -17,6 +17,7 @@ import com.topjohnwu.magisk.* import com.topjohnwu.magisk.base.BasePreferenceFragment import com.topjohnwu.magisk.data.database.RepoDao import com.topjohnwu.magisk.databinding.CustomDownloadDialogBinding +import com.topjohnwu.magisk.databinding.DialogCustomNameBinding import com.topjohnwu.magisk.extensions.subscribeK import com.topjohnwu.magisk.extensions.toLangTag import com.topjohnwu.magisk.model.download.DownloadService @@ -67,8 +68,9 @@ class SettingsFragment : BasePreferenceFragment() { val suCategory = findPreference("superuser")!! val hideManager = findPreference("hide")!! hideManager.setOnPreferenceClickListener { - // TODO: Add UI to allow user to customize app name - PatchAPK.hideManager(requireContext(), "Manager") + showManagerNameDialog { + PatchAPK.hideManager(requireContext(), "Manager") + } true } val restoreManager = findPreference("restore") @@ -224,26 +226,26 @@ class SettingsFragment : BasePreferenceFragment() { private fun setLocalePreference(lp: ListPreference) { lp.isEnabled = false availableLocales.map { - val names = mutableListOf() - val values = mutableListOf() + val names = mutableListOf() + val values = mutableListOf() - names.add( - ResourceMgr.getString(defaultLocale, R.string.system_default) - ) - values.add("") + names.add( + ResourceMgr.getString(defaultLocale, R.string.system_default) + ) + values.add("") - it.forEach { locale -> - names.add(locale.getDisplayName(locale)) - values.add(locale.toLangTag()) - } - - Pair(names.toTypedArray(), values.toTypedArray()) - }.subscribeK { (names, values) -> - lp.isEnabled = true - lp.entries = names - lp.entryValues = values - lp.summary = currentLocale.getDisplayName(currentLocale) + it.forEach { locale -> + names.add(locale.getDisplayName(locale)) + values.add(locale.toLangTag()) } + + Pair(names.toTypedArray(), values.toTypedArray()) + }.subscribeK { (names, values) -> + lp.isEnabled = true + lp.entries = names + lp.entryValues = values + lp.summary = currentLocale.getDisplayName(currentLocale) + } } private fun setSummary(key: String) { @@ -327,4 +329,27 @@ class SettingsFragment : BasePreferenceFragment() { .setNegativeButton(R.string.close, null) .show() } + + private inline fun showManagerNameDialog( + crossinline onSuccess: (String) -> Unit + ) { + val data = ManagerNameData() + val view = DialogCustomNameBinding + .inflate(LayoutInflater.from(requireContext())) + .also { it.data = data } + + AlertDialog.Builder(requireActivity()) + .setTitle(R.string.settings_app_name) + .setView(view.root) + .setPositiveButton(R.string.ok) { _, _ -> + if (view.dialogNameInput.error.isNullOrBlank()) { + onSuccess(data.name.value) + } + } + .show() + } + + inner class ManagerNameData { + val name = KObservableField(resources.getString(R.string.re_app_name)) + } } diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/DataBindingAdapters.kt b/app/src/main/java/com/topjohnwu/magisk/utils/DataBindingAdapters.kt index 17b0a2552..c1304aaff 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/DataBindingAdapters.kt +++ b/app/src/main/java/com/topjohnwu/magisk/utils/DataBindingAdapters.kt @@ -16,6 +16,7 @@ import androidx.recyclerview.widget.RecyclerView import androidx.viewpager.widget.ViewPager import com.google.android.material.floatingactionbutton.FloatingActionButton import com.google.android.material.navigation.NavigationView +import com.google.android.material.textfield.TextInputLayout import com.topjohnwu.magisk.R import com.topjohnwu.magisk.extensions.replaceRandomWithSpecial import com.topjohnwu.magisk.extensions.subscribeK @@ -220,4 +221,11 @@ fun getScrollPosition(view: RecyclerView) = (view.layoutManager as? LinearLayout @BindingAdapter("isEnabled") fun setEnabled(view: View, isEnabled: Boolean) { view.isEnabled = isEnabled +} + +@BindingAdapter("error") +fun TextInputLayout.setErrorString(error: String) { + val newError = error.let { if (it.isEmpty()) null else it } + if (this.error == null && newError == null) return + this.error = newError } \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_custom_name.xml b/app/src/main/res/layout/dialog_custom_name.xml new file mode 100644 index 000000000..45d4ffafd --- /dev/null +++ b/app/src/main/res/layout/dialog_custom_name.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a73bd0dd5..664976811 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -150,6 +150,10 @@ Systemless hosts support for Adblock apps. Added systemless hosts module + Type desired app name + New name + App will be repackaged to this name + Invalid format Apps and ADB Apps only ADB only From 9656878ef3ad8dbc5c445485dfb5a31961d91f37 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Tue, 22 Oct 2019 05:06:17 -0400 Subject: [PATCH 22/61] Actually apply the input name --- .../java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt b/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt index 3a4012d1b..f191defb3 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt @@ -69,7 +69,7 @@ class SettingsFragment : BasePreferenceFragment() { val hideManager = findPreference("hide")!! hideManager.setOnPreferenceClickListener { showManagerNameDialog { - PatchAPK.hideManager(requireContext(), "Manager") + PatchAPK.hideManager(requireContext(), it) } true } @@ -346,6 +346,7 @@ class SettingsFragment : BasePreferenceFragment() { onSuccess(data.name.value) } } + .setNegativeButton(R.string.close, null) .show() } From a18c552ddf050d68dc00fb7384d6c35f7afb1e2c Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Tue, 22 Oct 2019 15:37:55 -0400 Subject: [PATCH 23/61] Guard env state behind cached objects --- .../main/java/com/topjohnwu/magisk/Info.kt | 29 +++++++++++++------ .../data/repository/MagiskRepository.kt | 4 +-- .../magisk/model/update/UpdateCheckService.kt | 2 +- .../com/topjohnwu/magisk/ui/MainActivity.kt | 10 ++++--- .../com/topjohnwu/magisk/ui/SplashActivity.kt | 3 +- .../topjohnwu/magisk/ui/home/HomeViewModel.kt | 17 +++++++---- .../com/topjohnwu/magisk/utils/CachedValue.kt | 24 +++++++++++++++ .../com/topjohnwu/magisk/utils/RootInit.kt | 3 +- .../com/topjohnwu/magisk/view/Shortcuts.kt | 4 +-- 9 files changed, 68 insertions(+), 28 deletions(-) create mode 100644 app/src/main/java/com/topjohnwu/magisk/utils/CachedValue.kt diff --git a/app/src/main/java/com/topjohnwu/magisk/Info.kt b/app/src/main/java/com/topjohnwu/magisk/Info.kt index f226ae5cf..1e5e63649 100644 --- a/app/src/main/java/com/topjohnwu/magisk/Info.kt +++ b/app/src/main/java/com/topjohnwu/magisk/Info.kt @@ -1,26 +1,37 @@ package com.topjohnwu.magisk import com.topjohnwu.magisk.model.entity.UpdateInfo +import com.topjohnwu.magisk.utils.CachedValue import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.ShellUtils object Info { - var magiskVersionCode = -1 + val envRef = CachedValue { loadState() } - var magiskVersionString = "" - - var remote = UpdateInfo() + val env by envRef // Local + var remote = UpdateInfo() // Remote var keepVerity = false var keepEnc = false var recovery = false - fun loadMagiskInfo() { - runCatching { - magiskVersionString = ShellUtils.fastCmd("magisk -v").split(":".toRegex())[0] - magiskVersionCode = ShellUtils.fastCmd("magisk -V").toInt() - Config.magiskHide = Shell.su("magiskhide --status").exec().isSuccess + private fun loadState() = runCatching { + val str = ShellUtils.fastCmd("magisk -v").split(":".toRegex())[0] + val code = ShellUtils.fastCmd("magisk -V").toInt() + val hide = Shell.su("magiskhide --status").exec().isSuccess + Env(code, str, hide) + }.getOrElse { Env() } + + class Env( + val magiskVersionCode: Int = -1, + val magiskVersionString: String = "", + hide: Boolean = false + ) { + val magiskHide get() = Config.magiskHide + + init { + Config.magiskHide = hide } } } diff --git a/app/src/main/java/com/topjohnwu/magisk/data/repository/MagiskRepository.kt b/app/src/main/java/com/topjohnwu/magisk/data/repository/MagiskRepository.kt index 0d73fc6c1..b9a4ae98b 100644 --- a/app/src/main/java/com/topjohnwu/magisk/data/repository/MagiskRepository.kt +++ b/app/src/main/java/com/topjohnwu/magisk/data/repository/MagiskRepository.kt @@ -29,7 +29,7 @@ class MagiskRepository( else -> throw IllegalArgumentException() }.flatMap { // If remote version is lower than current installed, try switching to beta - if (it.magisk.versionCode < Info.magiskVersionCode + if (it.magisk.versionCode < Info.env.magiskVersionCode && Config.updateChannel == Config.Value.DEFAULT_CHANNEL) { Config.updateChannel = Config.Value.BETA_CHANNEL apiRaw.fetchBetaUpdate() @@ -74,4 +74,4 @@ class MagiskRepository( ) } } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/topjohnwu/magisk/model/update/UpdateCheckService.kt b/app/src/main/java/com/topjohnwu/magisk/model/update/UpdateCheckService.kt index 17841cd0c..190e05802 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/update/UpdateCheckService.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/update/UpdateCheckService.kt @@ -20,7 +20,7 @@ class UpdateCheckService : DelegateWorker() { magiskRepo.fetchUpdate().blockingGet() if (BuildConfig.VERSION_CODE < Info.remote.app.versionCode) Notifications.managerUpdate(applicationContext) - else if (Info.magiskVersionCode < Info.remote.magisk.versionCode) + else if (Info.env.magiskVersionCode < Info.remote.magisk.versionCode) Notifications.magiskUpdate(applicationContext) ListenableWorker.Result.success() }.getOrElse { diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/MainActivity.kt b/app/src/main/java/com/topjohnwu/magisk/ui/MainActivity.kt index 24ec6658f..05fcaa90d 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/MainActivity.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/MainActivity.kt @@ -7,13 +7,15 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentTransaction import com.ncapdevi.fragnav.FragNavController import com.ncapdevi.fragnav.FragNavTransactionOptions -import com.topjohnwu.magisk.* import com.topjohnwu.magisk.Const.Key.OPEN_SECTION +import com.topjohnwu.magisk.Info +import com.topjohnwu.magisk.R import com.topjohnwu.magisk.base.BaseActivity import com.topjohnwu.magisk.base.BaseFragment import com.topjohnwu.magisk.databinding.ActivityMainBinding import com.topjohnwu.magisk.extensions.addOnPropertyChangedCallback import com.topjohnwu.magisk.extensions.snackbar +import com.topjohnwu.magisk.intent import com.topjohnwu.magisk.model.events.* import com.topjohnwu.magisk.model.navigation.MagiskAnimBuilder import com.topjohnwu.magisk.model.navigation.MagiskNavigationEvent @@ -152,11 +154,11 @@ open class MainActivity : BaseActivity(), Na private fun checkHideSection() { val menu = binding.navView.menu menu.findItem(R.id.magiskHideFragment).isVisible = - Shell.rootAccess() && Config.magiskHide + Shell.rootAccess() && Info.env.magiskHide menu.findItem(R.id.modulesFragment).isVisible = - Shell.rootAccess() && Info.magiskVersionCode >= 0 + Shell.rootAccess() && Info.env.magiskVersionCode >= 0 menu.findItem(R.id.reposFragment).isVisible = - (viewModel.isConnected.value && Shell.rootAccess() && Info.magiskVersionCode >= 0) + (viewModel.isConnected.value && Shell.rootAccess() && Info.env.magiskVersionCode >= 0) menu.findItem(R.id.logFragment).isVisible = Shell.rootAccess() menu.findItem(R.id.superuserFragment).isVisible = diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/SplashActivity.kt b/app/src/main/java/com/topjohnwu/magisk/ui/SplashActivity.kt index 75d814ce2..f31ffbc4c 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/SplashActivity.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/SplashActivity.kt @@ -7,7 +7,6 @@ import android.text.TextUtils import androidx.appcompat.app.AlertDialog import com.topjohnwu.magisk.* import com.topjohnwu.magisk.utils.Utils -import com.topjohnwu.magisk.wrap import com.topjohnwu.magisk.view.Notifications import com.topjohnwu.magisk.view.Shortcuts import com.topjohnwu.superuser.Shell @@ -22,7 +21,7 @@ open class SplashActivity : Activity() { super.onCreate(savedInstanceState) Shell.getShell { - if (Info.magiskVersionCode > 0 && Info.magiskVersionCode < Const.MagiskVersion.MIN_SUPPORT) { + if (Info.env.magiskVersionCode > 0 && Info.env.magiskVersionCode < Const.MagiskVersion.MIN_SUPPORT) { AlertDialog.Builder(this) .setTitle(R.string.unsupport_magisk_title) .setMessage(R.string.unsupport_magisk_message) diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt index fd5da72b0..821a79d1f 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt @@ -107,10 +107,10 @@ class HomeViewModel( Info.recovery = it ?: return@addOnPropertyChangedCallback } isConnected.addOnPropertyChangedCallback { - if (it == true) refresh() + if (it == true) refresh(false) } - refresh() + refresh(false) } fun paypalPressed() = OpenLinkEvent(Const.Url.PAYPAL_URL).publish() @@ -170,7 +170,11 @@ class HomeViewModel( } } - fun refresh() { + @JvmOverloads + fun refresh(invalidate: Boolean = true) { + if (invalidate) + Info.envRef.invalidate() + hasRoot.value = Shell.rootAccess() val fetchUpdate = if (isConnected.value) @@ -179,7 +183,8 @@ class HomeViewModel( Completable.complete() Completable.fromAction { - Info.loadMagiskInfo() + // Ensure value is ready + Info.env }.andThen(fetchUpdate) .applyViewModel(this) .doOnSubscribeUi { @@ -197,7 +202,7 @@ class HomeViewModel( private fun refreshVersions() { magiskCurrentVersion.value = if (magiskState.value != MagiskState.NOT_INSTALLED) { - version.format(Info.magiskVersionString, Info.magiskVersionCode) + version.format(Info.env.magiskVersionString, Info.env.magiskVersionCode) } else { "" } @@ -207,7 +212,7 @@ class HomeViewModel( } private fun updateSelf() { - magiskState.value = when (Info.magiskVersionCode) { + magiskState.value = when (Info.env.magiskVersionCode) { in Int.MIN_VALUE until 0 -> MagiskState.NOT_INSTALLED !in Info.remote.magisk.versionCode..Int.MAX_VALUE -> MagiskState.OBSOLETE else -> MagiskState.UP_TO_DATE diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/CachedValue.kt b/app/src/main/java/com/topjohnwu/magisk/utils/CachedValue.kt new file mode 100644 index 000000000..b4b6f6a80 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/utils/CachedValue.kt @@ -0,0 +1,24 @@ +package com.topjohnwu.magisk.utils + +class CachedValue(private val factory: () -> T) : Lazy { + + private var _val : T? = null + + override val value: T + get() { + val local = _val + return local ?: synchronized(this) { + val newInstance = factory() + _val = newInstance + newInstance + } + } + + override fun isInitialized() = _val != null + + fun invalidate() { + synchronized(this) { + _val = null + } + } +} diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/RootInit.kt b/app/src/main/java/com/topjohnwu/magisk/utils/RootInit.kt index 481ce2d02..e503b84ea 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/RootInit.kt +++ b/app/src/main/java/com/topjohnwu/magisk/utils/RootInit.kt @@ -20,9 +20,8 @@ class RootInit : Shell.Initializer() { val job = shell.newJob() if (shell.isRoot) { job.add(context.rawResource(R.raw.util_functions)) - .add(context.rawResource(R.raw.utils)) + .add(context.rawResource(R.raw.utils)) Const.MAGISK_DISABLE_FILE = SuFile("/cache/.disable_magisk") - Info.loadMagiskInfo() } else { job.add(context.rawResource(R.raw.nonroot_utils)) } diff --git a/app/src/main/java/com/topjohnwu/magisk/view/Shortcuts.kt b/app/src/main/java/com/topjohnwu/magisk/view/Shortcuts.kt index 7a2d210b6..3a541c155 100644 --- a/app/src/main/java/com/topjohnwu/magisk/view/Shortcuts.kt +++ b/app/src/main/java/com/topjohnwu/magisk/view/Shortcuts.kt @@ -38,7 +38,7 @@ object Shortcuts { .setRank(0) .build()) } - if (root && Config.magiskHide) { + if (root && Info.env.magiskHide) { shortCuts.add(ShortcutInfo.Builder(context, "magiskhide") .setShortLabel(context.getString(R.string.magiskhide)) .setIntent(Intent(intent) @@ -49,7 +49,7 @@ object Shortcuts { .setRank(1) .build()) } - if (!Config.coreOnly && root && Info.magiskVersionCode >= 0) { + if (!Config.coreOnly && root && Info.env.magiskVersionCode >= 0) { shortCuts.add(ShortcutInfo.Builder(context, "modules") .setShortLabel(context.getString(R.string.modules)) .setIntent(Intent(intent) From 71136d7347be3bb92be61c4de38e56ba7fdeceff Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Tue, 22 Oct 2019 16:04:20 -0400 Subject: [PATCH 24/61] Manually trigger broadcast tests if necessary --- app/src/main/java/com/topjohnwu/magisk/Const.kt | 3 ++- app/src/main/java/com/topjohnwu/magisk/Info.kt | 8 ++++++-- .../topjohnwu/magisk/model/receiver/GeneralReceiver.kt | 2 ++ .../main/java/com/topjohnwu/magisk/ui/SplashActivity.kt | 2 +- app/src/main/java/com/topjohnwu/magisk/utils/RootInit.kt | 9 +++++++++ 5 files changed, 20 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/Const.kt b/app/src/main/java/com/topjohnwu/magisk/Const.kt index 1f6dd169f..79738f20f 100644 --- a/app/src/main/java/com/topjohnwu/magisk/Const.kt +++ b/app/src/main/java/com/topjohnwu/magisk/Const.kt @@ -22,8 +22,9 @@ object Const { const val MANAGER_CONFIGS = ".tmp.magisk.config" val USER_ID = Process.myUid() / 100000 - object MagiskVersion { + object Version { const val MIN_SUPPORT = 18000 + const val CONNECT_MODE = 20002 } object ID { diff --git a/app/src/main/java/com/topjohnwu/magisk/Info.kt b/app/src/main/java/com/topjohnwu/magisk/Info.kt index 1e5e63649..54de52dd6 100644 --- a/app/src/main/java/com/topjohnwu/magisk/Info.kt +++ b/app/src/main/java/com/topjohnwu/magisk/Info.kt @@ -20,13 +20,17 @@ object Info { val str = ShellUtils.fastCmd("magisk -v").split(":".toRegex())[0] val code = ShellUtils.fastCmd("magisk -V").toInt() val hide = Shell.su("magiskhide --status").exec().isSuccess - Env(code, str, hide) + var mode = Int.MAX_VALUE + if (code >= Const.Version.CONNECT_MODE) + mode = Shell.su("magisk --connect-mode").exec().code + Env(code, str, hide, mode) }.getOrElse { Env() } class Env( val magiskVersionCode: Int = -1, val magiskVersionString: String = "", - hide: Boolean = false + hide: Boolean = false, + var connectionMode: Int = Int.MAX_VALUE ) { val magiskHide get() = Config.magiskHide diff --git a/app/src/main/java/com/topjohnwu/magisk/model/receiver/GeneralReceiver.kt b/app/src/main/java/com/topjohnwu/magisk/model/receiver/GeneralReceiver.kt index 6a0ca9a4f..86ade4d75 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/receiver/GeneralReceiver.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/receiver/GeneralReceiver.kt @@ -79,6 +79,8 @@ open class GeneralReceiver : BaseReceiver() { NOTIFY -> SuLogger.handleNotify(context, intent) TEST -> { val mode = intent.getIntExtra("mode", 1 shl 1) + if (mode > Info.env.connectionMode) + Info.env.connectionMode = mode Shell.su("magisk --connect-mode $mode").submit() } } diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/SplashActivity.kt b/app/src/main/java/com/topjohnwu/magisk/ui/SplashActivity.kt index f31ffbc4c..f0316b7fe 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/SplashActivity.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/SplashActivity.kt @@ -21,7 +21,7 @@ open class SplashActivity : Activity() { super.onCreate(savedInstanceState) Shell.getShell { - if (Info.env.magiskVersionCode > 0 && Info.env.magiskVersionCode < Const.MagiskVersion.MIN_SUPPORT) { + if (Info.env.magiskVersionCode > 0 && Info.env.magiskVersionCode < Const.Version.MIN_SUPPORT) { AlertDialog.Builder(this) .setTitle(R.string.unsupport_magisk_title) .setMessage(R.string.unsupport_magisk_message) diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/RootInit.kt b/app/src/main/java/com/topjohnwu/magisk/utils/RootInit.kt index e503b84ea..c9b13c70c 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/RootInit.kt +++ b/app/src/main/java/com/topjohnwu/magisk/utils/RootInit.kt @@ -17,6 +17,9 @@ class RootInit : Shell.Initializer() { } fun init(context: Context, shell: Shell): Boolean { + // Invalidate env state if shell is recreated + Info.envRef.invalidate() + val job = shell.newJob() if (shell.isRoot) { job.add(context.rawResource(R.raw.util_functions)) @@ -35,6 +38,12 @@ class RootInit : Shell.Initializer() { Info.keepVerity = ShellUtils.fastCmd("echo \$KEEPVERITY").toBoolean() Info.keepEnc = ShellUtils.fastCmd("echo \$KEEPFORCEENCRYPT").toBoolean() Info.recovery = ShellUtils.fastCmd("echo \$RECOVERYMODE").toBoolean() + + if (Info.env.connectionMode == 0) { + // Manually trigger broadcast test + Shell.su("magisk --broadcast-test").exec() + } + return true } } From d010cb7e424e8330408a5a00d6e2e171a3231c31 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Wed, 23 Oct 2019 05:19:54 -0400 Subject: [PATCH 25/61] Update stub --- stub/build.gradle | 2 +- .../main/java/com/topjohnwu/magisk/DownloadActivity.java | 9 ++++----- stub/src/main/res/values/misc.xml | 4 ++++ stub/src/main/res/values/strings.xml | 7 ++----- 4 files changed, 11 insertions(+), 11 deletions(-) create mode 100644 stub/src/main/res/values/misc.xml diff --git a/stub/build.gradle b/stub/build.gradle index 932b547fc..c43fcc5a8 100644 --- a/stub/build.gradle +++ b/stub/build.gradle @@ -4,7 +4,7 @@ android { defaultConfig { applicationId 'com.topjohnwu.magisk' versionCode 1 - versionName props['appVersion'] + versionName "1.0" buildConfigField 'String', 'DEV_CHANNEL', props['DEV_CHANNEL'] ?: 'null' } diff --git a/stub/src/main/java/com/topjohnwu/magisk/DownloadActivity.java b/stub/src/main/java/com/topjohnwu/magisk/DownloadActivity.java index 62a2baa29..12d22ffcd 100644 --- a/stub/src/main/java/com/topjohnwu/magisk/DownloadActivity.java +++ b/stub/src/main/java/com/topjohnwu/magisk/DownloadActivity.java @@ -21,10 +21,8 @@ import static com.topjohnwu.magisk.DelegateApplication.MANAGER_APK; public class DownloadActivity extends Activity { static final String TAG = "MMStub"; - private static final boolean IS_CANARY = BuildConfig.VERSION_NAME.contains("-"); private static final String URL = BuildConfig.DEV_CHANNEL != null ? BuildConfig.DEV_CHANNEL : - "https://raw.githubusercontent.com/topjohnwu/magisk_files/" + - (IS_CANARY ? "canary/release.json" : "master/stable.json"); + "https://raw.githubusercontent.com/topjohnwu/magisk_files/master/stable.json"; private String apkLink; private ErrorHandler err = (conn, e) -> { @@ -34,8 +32,9 @@ public class DownloadActivity extends Activity { private void showDialog() { ProgressDialog.show(this, - "Downloading...", - "Downloading Magisk Manager", true); + getString(R.string.dling), + getString(R.string.dling) + " " + getString(R.string.app_name), + true); } private void dlAPK() { diff --git a/stub/src/main/res/values/misc.xml b/stub/src/main/res/values/misc.xml new file mode 100644 index 000000000..f60a4b322 --- /dev/null +++ b/stub/src/main/res/values/misc.xml @@ -0,0 +1,4 @@ + + + Magisk Manager + diff --git a/stub/src/main/res/values/strings.xml b/stub/src/main/res/values/strings.xml index 81ad51174..75117a28c 100644 --- a/stub/src/main/res/values/strings.xml +++ b/stub/src/main/res/values/strings.xml @@ -1,12 +1,9 @@ - Magisk Manager - No thanks Yes OK Upgrade to full Magisk Manager to finish the setup. Download and install? Please connect to the Internet! Upgrading to full Magisk Manager is required. - - - \ No newline at end of file + Downloading + From 0b5fd3ee761037d071d239b2f098c2ced35810fd Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Wed, 23 Oct 2019 05:43:01 -0400 Subject: [PATCH 26/61] Only allow hide/restore app if connected --- .../main/java/com/topjohnwu/magisk/Info.kt | 24 +++- .../magisk/base/viewmodel/BaseViewModel.kt | 14 +- .../magisk/ui/settings/SettingsFragment.kt | 124 +++++++++--------- .../magisk/utils/KObservableField.kt | 31 +---- .../com/topjohnwu/magisk/utils/RootInit.kt | 5 - 5 files changed, 93 insertions(+), 105 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/Info.kt b/app/src/main/java/com/topjohnwu/magisk/Info.kt index 54de52dd6..33b8715d4 100644 --- a/app/src/main/java/com/topjohnwu/magisk/Info.kt +++ b/app/src/main/java/com/topjohnwu/magisk/Info.kt @@ -1,7 +1,11 @@ package com.topjohnwu.magisk +import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork +import com.topjohnwu.magisk.extensions.get +import com.topjohnwu.magisk.extensions.subscribeK import com.topjohnwu.magisk.model.entity.UpdateInfo import com.topjohnwu.magisk.utils.CachedValue +import com.topjohnwu.magisk.utils.KObservableField import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.ShellUtils @@ -16,13 +20,27 @@ object Info { var keepEnc = false var recovery = false + val isConnected by lazy { + KObservableField(false).also { field -> + ReactiveNetwork.observeNetworkConnectivity(get()) + .subscribeK { + field.value = it.available() + } + } + } + private fun loadState() = runCatching { val str = ShellUtils.fastCmd("magisk -v").split(":".toRegex())[0] val code = ShellUtils.fastCmd("magisk -V").toInt() val hide = Shell.su("magiskhide --status").exec().isSuccess - var mode = Int.MAX_VALUE - if (code >= Const.Version.CONNECT_MODE) + var mode = -1 + if (code >= Const.Version.CONNECT_MODE) { mode = Shell.su("magisk --connect-mode").exec().code + if (mode == 0) { + // Manually trigger broadcast test + Shell.su("magisk --broadcast-test").exec() + } + } Env(code, str, hide, mode) }.getOrElse { Env() } @@ -30,7 +48,7 @@ object Info { val magiskVersionCode: Int = -1, val magiskVersionString: String = "", hide: Boolean = false, - var connectionMode: Int = Int.MAX_VALUE + var connectionMode: Int = -1 ) { val magiskHide get() = Config.magiskHide diff --git a/app/src/main/java/com/topjohnwu/magisk/base/viewmodel/BaseViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/base/viewmodel/BaseViewModel.kt index a9acc6ebb..ef9082aaa 100644 --- a/app/src/main/java/com/topjohnwu/magisk/base/viewmodel/BaseViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/base/viewmodel/BaseViewModel.kt @@ -1,10 +1,8 @@ package com.topjohnwu.magisk.base.viewmodel import android.app.Activity -import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork +import com.topjohnwu.magisk.Info.isConnected as gIsConnected import com.topjohnwu.magisk.extensions.doOnSubscribeUi -import com.topjohnwu.magisk.extensions.get -import com.topjohnwu.magisk.extensions.subscribeK import com.topjohnwu.magisk.model.events.BackPressEvent import com.topjohnwu.magisk.model.events.PermissionEvent import com.topjohnwu.magisk.model.events.ViewActionEvent @@ -17,12 +15,10 @@ abstract class BaseViewModel( initialState: State = State.LOADING ) : LoadingViewModel(initialState) { - val isConnected = KObservableField(false) - - init { - ReactiveNetwork.observeNetworkConnectivity(get()) - .subscribeK { isConnected.value = it.available() } - .add() + val isConnected = object : KObservableField(gIsConnected.value, gIsConnected) { + override fun get(): Boolean { + return gIsConnected.value + } } fun withView(action: Activity.() -> Unit) { diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt b/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt index f191defb3..10c1059cf 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt @@ -24,7 +24,6 @@ import com.topjohnwu.magisk.model.download.DownloadService import com.topjohnwu.magisk.model.entity.internal.Configuration import com.topjohnwu.magisk.model.entity.internal.DownloadSubject import com.topjohnwu.magisk.model.observer.Observer -import com.topjohnwu.magisk.net.Networking import com.topjohnwu.magisk.utils.* import com.topjohnwu.magisk.view.dialogs.FingerprintAuthDialog import com.topjohnwu.superuser.Shell @@ -54,6 +53,7 @@ class SettingsFragment : BasePreferenceFragment() { preferenceManager.setStorageDeviceProtected() setPreferencesFromResource(R.xml.app_settings, rootKey) + // Get preferences updateChannel = findPreference(Config.Key.UPDATE_CHANNEL)!! rootConfig = findPreference(Config.Key.ROOT_ACCESS)!! autoRes = findPreference(Config.Key.SU_AUTO_RESPONSE)!! @@ -67,19 +67,68 @@ class SettingsFragment : BasePreferenceFragment() { val magiskCategory = findPreference("magisk")!! val suCategory = findPreference("superuser")!! val hideManager = findPreference("hide")!! - hideManager.setOnPreferenceClickListener { - showManagerNameDialog { - PatchAPK.hideManager(requireContext(), it) - } - true + val restoreManager = findPreference("restore")!! + + // Remove/Disable entries + + // Only show canary channels if user is already on canary channel + // or the user have already chosen canary channel + if (!Utils.isCanary && Config.updateChannel < Config.Value.CANARY_CHANNEL) { + // Remove the last 2 entries + val entries = updateChannel.entries + updateChannel.entries = entries.copyOf(entries.size - 2) } - val restoreManager = findPreference("restore") - restoreManager?.setOnPreferenceClickListener { - DownloadService(requireContext()) { - subject = DownloadSubject.Manager(Configuration.APK.Restore) - } - true + + // Remove dangerous settings in secondary user + if (Const.USER_ID > 0) { + suCategory.removePreference(multiuserConfig) } + + // Remove re-authentication option on Android O, it will not work + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + suCategory.removePreference(reauth) + } + + // Disable fingerprint option if not possible + if (!FingerprintHelper.canUseFingerprint()) { + fingerprint.isEnabled = false + fingerprint.isChecked = false + fingerprint.setSummary(R.string.disable_fingerprint) + } + + if (Const.USER_ID == 0 && Info.isConnected.value && Shell.rootAccess()) { + if (activity.packageName == BuildConfig.APPLICATION_ID) { + generalCatagory.removePreference(restoreManager) + hideManager.setOnPreferenceClickListener { + showManagerNameDialog { + PatchAPK.hideManager(requireContext(), it) + } + true + } + } else { + generalCatagory.removePreference(hideManager) + restoreManager.setOnPreferenceClickListener { + DownloadService(requireContext()) { + subject = DownloadSubject.Manager(Configuration.APK.Restore) + } + true + } + } + } else { + // Remove if not primary user, no connection, or no root + generalCatagory.removePreference(restoreManager) + generalCatagory.removePreference(hideManager) + } + + if (!Utils.showSuperUser()) { + preferenceScreen.removePreference(suCategory) + } + + if (!Shell.rootAccess()) { + preferenceScreen.removePreference(magiskCategory) + generalCatagory.removePreference(hideManager) + } + findPreference("clear")?.setOnPreferenceClickListener { Completable.fromAction { repoDB.clear() }.subscribeK { Utils.toast(R.string.repo_cache_cleared, Toast.LENGTH_SHORT) @@ -123,58 +172,7 @@ class SettingsFragment : BasePreferenceFragment() { setLocalePreference(findPreference(Config.Key.LOCALE)!!) - /* We only show canary channels if user is already on canary channel - * or the user have already chosen canary channel */ - if (!Utils.isCanary && Config.updateChannel < Config.Value.CANARY_CHANNEL) { - // Remove the last 2 entries - val entries = updateChannel.entries - updateChannel.entries = entries.copyOf(entries.size - 2) - - } - setSummary() - - // Disable dangerous settings in secondary user - if (Const.USER_ID > 0) { - suCategory.removePreference(multiuserConfig) - } - - // Disable re-authentication option on Android O, it will not work - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - reauth.isEnabled = false - reauth.isChecked = false - reauth.setSummary(R.string.android_o_not_support) - } - - // Disable fingerprint option if not possible - if (!FingerprintHelper.canUseFingerprint()) { - fingerprint.isEnabled = false - fingerprint.isChecked = false - fingerprint.setSummary(R.string.disable_fingerprint) - } - - if (Shell.rootAccess() && Const.USER_ID == 0) { - if (activity.packageName == BuildConfig.APPLICATION_ID) { - generalCatagory.removePreference(restoreManager) - } else { - if (!Networking.checkNetworkStatus(requireContext())) { - generalCatagory.removePreference(restoreManager) - } - generalCatagory.removePreference(hideManager) - } - } else { - generalCatagory.removePreference(restoreManager) - generalCatagory.removePreference(hideManager) - } - - if (!Utils.showSuperUser()) { - preferenceScreen.removePreference(suCategory) - } - - if (!Shell.rootAccess()) { - preferenceScreen.removePreference(magiskCategory) - generalCatagory.removePreference(hideManager) - } } override fun onSharedPreferenceChanged(prefs: SharedPreferences, key: String) { diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/KObservableField.kt b/app/src/main/java/com/topjohnwu/magisk/utils/KObservableField.kt index 7ecf125f4..cda0e5eb0 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/KObservableField.kt +++ b/app/src/main/java/com/topjohnwu/magisk/utils/KObservableField.kt @@ -9,15 +9,11 @@ import java.io.Serializable * You can define if wrapped type is Nullable or not. * You can use kotlin get/set syntax for value */ -class KObservableField : ObservableField, Serializable { +open class KObservableField : ObservableField, Serializable { var value: T - set(value) { - if (field != value) { - field = value - notifyChange() - } - } + get() = get() + set(value) { set(value) } constructor(init: T) { value = init @@ -27,23 +23,8 @@ class KObservableField : ObservableField, Serializable { value = init } - @Deprecated( - message = "Needed for data binding, use KObservableField.value syntax from code", - replaceWith = ReplaceWith("value") - ) + @Suppress("UNCHECKED_CAST") override fun get(): T { - return value + return super.get() as T } - - @Deprecated( - message = "Needed for data binding, use KObservableField.value = ... syntax from code", - replaceWith = ReplaceWith("value = newValue") - ) - override fun set(newValue: T) { - value = newValue - } - - override fun toString(): String { - return "KObservableField(value=$value)" - } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/RootInit.kt b/app/src/main/java/com/topjohnwu/magisk/utils/RootInit.kt index c9b13c70c..c7c01a1d1 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/RootInit.kt +++ b/app/src/main/java/com/topjohnwu/magisk/utils/RootInit.kt @@ -39,11 +39,6 @@ class RootInit : Shell.Initializer() { Info.keepEnc = ShellUtils.fastCmd("echo \$KEEPFORCEENCRYPT").toBoolean() Info.recovery = ShellUtils.fastCmd("echo \$RECOVERYMODE").toBoolean() - if (Info.env.connectionMode == 0) { - // Manually trigger broadcast test - Shell.su("magisk --broadcast-test").exec() - } - return true } } From f8fcaadb5b5e7b7213935eb1c95809747d834670 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Wed, 23 Oct 2019 05:50:06 -0400 Subject: [PATCH 27/61] Hide manager with stub if feasible --- .../magisk/model/entity/UpdateInfo.kt | 9 ++++++- .../com/topjohnwu/magisk/utils/PatchAPK.kt | 25 +++++++++++++++++-- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/model/entity/UpdateInfo.kt b/app/src/main/java/com/topjohnwu/magisk/model/entity/UpdateInfo.kt index 43f6fc924..d7b75580b 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/entity/UpdateInfo.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/entity/UpdateInfo.kt @@ -8,7 +8,8 @@ import se.ansman.kotshi.JsonSerializable data class UpdateInfo( val app: ManagerJson = ManagerJson(), val uninstaller: UninstallerJson = UninstallerJson(), - val magisk: MagiskJson = MagiskJson() + val magisk: MagiskJson = MagiskJson(), + val stub: StubJson = StubJson() ) @JsonSerializable @@ -33,3 +34,9 @@ data class ManagerJson( val link: String = "", val note: String = "" ) : Parcelable + +@JsonSerializable +data class StubJson( + val versionCode: Int = -1, + val link: String = "" +) diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.kt b/app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.kt index 9ab490787..91a4ab791 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.kt +++ b/app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.kt @@ -1,10 +1,14 @@ package com.topjohnwu.magisk.utils import android.content.Context +import android.os.Build.VERSION.SDK_INT import android.widget.Toast import com.topjohnwu.magisk.* +import com.topjohnwu.magisk.data.network.GithubRawServices import com.topjohnwu.magisk.extensions.DynamicClassLoader +import com.topjohnwu.magisk.extensions.get import com.topjohnwu.magisk.extensions.subscribeK +import com.topjohnwu.magisk.extensions.writeTo import com.topjohnwu.magisk.ui.SplashActivity import com.topjohnwu.magisk.view.Notifications import com.topjohnwu.signing.JarMap @@ -74,11 +78,28 @@ object PatchAPK { } private fun patchAndHide(context: Context, label: String): Boolean { + // If not running as stub, and we are compatible with stub, use stub + val src = if (!isRunningAsStub && SDK_INT >= 28 && Info.env.connectionMode == 3) { + val stub = File(context.cacheDir, "stub.apk") + val svc = get() + runCatching { + svc.fetchFile(Info.remote.stub.link).blockingGet().byteStream().use { + it.writeTo(stub) + } + }.onFailure { + Timber.e(it) + return false + } + stub.path + } else { + context.packageCodePath + } + // Generate a new app with random package name - val repack = File(context.filesDir, "patched.apk") + val repack = File(context.cacheDir, "patched.apk") val pkg = genPackageName("com.", BuildConfig.APPLICATION_ID.length) - if (!patch(context.packageCodePath, repack.path, pkg, label)) + if (!patch(src, repack.path, pkg, label)) return false // Install the application From 6378abf45467a93eed5d0d2326a6447b6fd6468f Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Wed, 23 Oct 2019 05:52:32 -0400 Subject: [PATCH 28/61] Make stub support directBootAware --- shared/src/main/java/com/topjohnwu/magisk/utils/DynAPK.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/shared/src/main/java/com/topjohnwu/magisk/utils/DynAPK.java b/shared/src/main/java/com/topjohnwu/magisk/utils/DynAPK.java index 24d139c3f..a9a363708 100644 --- a/shared/src/main/java/com/topjohnwu/magisk/utils/DynAPK.java +++ b/shared/src/main/java/com/topjohnwu/magisk/utils/DynAPK.java @@ -5,6 +5,8 @@ import android.content.Context; import java.io.File; import java.util.Map; +import static android.os.Build.VERSION.SDK_INT; + public class DynAPK { private static final int STUB_VERSION = 1; @@ -25,6 +27,10 @@ public class DynAPK { private static File getDynDir(Context c) { if (dynDir == null) { + if (SDK_INT >= 24) { + // Use protected context to allow directBootAware + c = c.createDeviceProtectedStorageContext(); + } dynDir = new File(c.getFilesDir().getParent(), "dyn"); dynDir.mkdir(); } From 0d31e5c8b16f430069bcff98fbf568acc813ecd3 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Wed, 23 Oct 2019 06:41:25 -0400 Subject: [PATCH 29/61] Properly migrate update channels when repackaging --- app/src/main/java/com/topjohnwu/magisk/Config.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/Config.kt b/app/src/main/java/com/topjohnwu/magisk/Config.kt index 54ab1b499..9a317aa91 100644 --- a/app/src/main/java/com/topjohnwu/magisk/Config.kt +++ b/app/src/main/java/com/topjohnwu/magisk/Config.kt @@ -133,9 +133,6 @@ object Config : PreferenceModel, DBConfig { fun initialize() = prefs.edit { parsePrefs(this) - if (!prefs.contains(Key.UPDATE_CHANNEL)) - putString(Key.UPDATE_CHANNEL, defaultChannel.toString()) - // Get actual state putBoolean(Key.COREONLY, Const.MAGISK_DISABLE_FILE.exists()) @@ -144,6 +141,9 @@ object Config : PreferenceModel, DBConfig { putString(Key.SU_MNT_NS, suMntNamespaceMode.toString()) putString(Key.SU_MULTIUSER_MODE, suMultiuserMode.toString()) putBoolean(Key.SU_FINGERPRINT, FingerprintHelper.useFingerprint()) + }.also { + if (!prefs.contains(Key.UPDATE_CHANNEL)) + prefs.edit().putString(Key.UPDATE_CHANNEL, defaultChannel.toString()).apply() } private fun parsePrefs(editor: SharedPreferences.Editor) = editor.apply { From 45c1f6bc2775cf6f9fea33c53591dbd3188f2677 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Wed, 23 Oct 2019 06:43:08 -0400 Subject: [PATCH 30/61] Fix restore manager when running as stub --- .../com/topjohnwu/magisk/model/download/ManagerUpgrade.kt | 7 ++----- .../topjohnwu/magisk/model/download/RemoteFileService.kt | 5 ++--- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/model/download/ManagerUpgrade.kt b/app/src/main/java/com/topjohnwu/magisk/model/download/ManagerUpgrade.kt index f75a8a0c1..b4d6d8cc5 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/download/ManagerUpgrade.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/download/ManagerUpgrade.kt @@ -1,9 +1,6 @@ package com.topjohnwu.magisk.model.download -import com.topjohnwu.magisk.BuildConfig -import com.topjohnwu.magisk.Config -import com.topjohnwu.magisk.R -import com.topjohnwu.magisk.cmp +import com.topjohnwu.magisk.* import com.topjohnwu.magisk.model.entity.internal.Configuration.APK.Restore import com.topjohnwu.magisk.model.entity.internal.Configuration.APK.Upgrade import com.topjohnwu.magisk.model.entity.internal.DownloadSubject @@ -14,7 +11,7 @@ import com.topjohnwu.superuser.Shell import java.io.File private fun RemoteFileService.patchPackage(apk: File, id: Int) { - if (packageName != BuildConfig.APPLICATION_ID) { + if (!isRunningAsStub && packageName != BuildConfig.APPLICATION_ID) { update(id) { notification -> notification.setProgress(0, 0, true) .setProgress(0, 0, true) diff --git a/app/src/main/java/com/topjohnwu/magisk/model/download/RemoteFileService.kt b/app/src/main/java/com/topjohnwu/magisk/model/download/RemoteFileService.kt index 8e6dfa6be..febd7fb2f 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/download/RemoteFileService.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/download/RemoteFileService.kt @@ -12,7 +12,6 @@ import com.topjohnwu.magisk.extensions.writeTo import com.topjohnwu.magisk.model.entity.internal.DownloadSubject import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.* import com.topjohnwu.magisk.utils.ProgressInputStream -import com.topjohnwu.magisk.isRunningAsStub import com.topjohnwu.magisk.view.Notifications import com.topjohnwu.superuser.ShellUtils import io.reactivex.Completable @@ -72,7 +71,7 @@ abstract class RemoteFileService : NotificationService() { else -> Completable.fromAction { stream.writeTo(subject.file) } } }.doOnComplete { - if (!isRunningAsStub && subject is Manager) + if (subject is Manager) handleAPK(subject) } @@ -116,4 +115,4 @@ abstract class RemoteFileService : NotificationService() { const val ARG_URL = "arg_url" } -} \ No newline at end of file +} From 81b65ea6469e789bc11e5739a981869d430d601b Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Wed, 23 Oct 2019 06:45:47 -0400 Subject: [PATCH 31/61] Exclude stub id mappings from git --- stub/.gitignore | 1 + stub/res-ids.txt | 27 --------------------------- 2 files changed, 1 insertion(+), 27 deletions(-) delete mode 100644 stub/res-ids.txt diff --git a/stub/.gitignore b/stub/.gitignore index 796b96d1c..b5977f73e 100644 --- a/stub/.gitignore +++ b/stub/.gitignore @@ -1 +1,2 @@ /build +/res-ids.txt diff --git a/stub/res-ids.txt b/stub/res-ids.txt deleted file mode 100644 index 14667b1b6..000000000 --- a/stub/res-ids.txt +++ /dev/null @@ -1,27 +0,0 @@ -com.topjohnwu.magisk:style/SplashThemeBase.V19 = 0x7f040000 -com.topjohnwu.magisk:string/app_name = 0x7f030000 -com.topjohnwu.magisk:string/yes = 0x7f030001 -com.topjohnwu.magisk:style/SplashTheme = 0x7f040001 -com.topjohnwu.magisk:drawable/sc_superuser = 0x7f020000 -com.topjohnwu.magisk:string/no_thanks = 0x7f030002 -com.topjohnwu.magisk:drawable/ic_splash_activity = 0x7f020001 -com.topjohnwu.magisk:drawable/sc_magiskhide = 0x7f020002 -com.topjohnwu.magisk:color/light = 0x7f010000 -com.topjohnwu.magisk:string/no_internet_msg = 0x7f030003 -com.topjohnwu.magisk:drawable/sc_extension = 0x7f020003 -com.topjohnwu.magisk:drawable/ic_magisk_outline = 0x7f020004 -com.topjohnwu.magisk:color/ic_launcher_background = 0x7f010001 -com.topjohnwu.magisk:xml/file_paths = 0x7f050000 -com.topjohnwu.magisk:drawable/sc_cloud_download = 0x7f020005 -com.topjohnwu.magisk:string/ok = 0x7f030004 -com.topjohnwu.magisk:drawable/ic_magisk = 0x7f020006 -com.topjohnwu.magisk:drawable/ic_superuser = 0x7f020007 -com.topjohnwu.magisk:drawable/ic_cloud_download = 0x7f020008 -com.topjohnwu.magisk:style/SplashThemeBase = 0x7f040002 -com.topjohnwu.magisk:drawable/ic_magiskhide = 0x7f020009 -com.topjohnwu.magisk:drawable/ic_launcher = 0x7f02000a -com.topjohnwu.magisk:drawable/ic_logo = 0x7f02000b -com.topjohnwu.magisk:drawable/ic_extension = 0x7f02000c -com.topjohnwu.magisk:string/upgrade_msg = 0x7f030005 -com.topjohnwu.magisk:color/dark = 0x7f010002 -com.topjohnwu.magisk:drawable/ic_magisk_padded = 0x7f02000d From ac67b482475d83225b93ca779c59135f13f728a9 Mon Sep 17 00:00:00 2001 From: onevt Date: Fri, 18 Oct 2019 21:26:41 +0200 Subject: [PATCH 32/61] Fix swedish translation typo --- app/src/main/res/values-sv/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 40c121d69..309337b0c 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -65,7 +65,7 @@ Starta om för att tillämpa inställningar Release notes Repo-cache rensad - En uppdatering av Magisk maneger finns tillgänglig! + En uppdatering av Magisk Manager finns tillgänglig! Tryck för att ladda ner och installera Magiska uppdateringar Fel vid nerladdning av fil From 3eb963323118eaf55899be884fd6b376b64a3772 Mon Sep 17 00:00:00 2001 From: Abhishek Dubey Date: Wed, 23 Oct 2019 16:23:46 +0530 Subject: [PATCH 33/61] Add Hindi Translation --- app/src/main/res/values-hi/strings.xml | 228 ++++++++++++++++++++++++ stub/src/main/res/values-hi/strings.xml | 8 + 2 files changed, 236 insertions(+) create mode 100644 app/src/main/res/values-hi/strings.xml create mode 100644 stub/src/main/res/values-hi/strings.xml diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml new file mode 100644 index 000000000..2b91dbb9e --- /dev/null +++ b/app/src/main/res/values-hi/strings.xml @@ -0,0 +1,228 @@ + + + + मॉड्यूल + डाउनलोड + उत्तम उपयोगकर्ता + अभिलेख + सेटिंग्स + स्थापित करें + असमर्थित Magisk संस्करण + Magisk Manager का यह संस्करण Magisk के v18.0 संस्करण से कम का समर्थन नहीं करता है.\n\nआप या तो खुद से Magisk को अपग्रेड करें, या फिर एप्लीकेशन को पुराने संस्करण पे डाउनग्रेड करें . + + + Magisk स्थापित नहीं है + अपडेट्स के लिए जांच हो रही है… + अमान्य अपडेट चैनल + SafetyNet की जांच शुरू करें + SafetyNet के स्थिति की जाँच हो रही है… + SafetyNet की जांच सफल हुई + SafetyNet API त्रुटि + अनुक्रिया अमान्य है. + Magisk अप टू डेट है + Magisk Manager अप टू डेट है + एडवांस सेटिंग्स + बल एन्क्रिप्शन को बनाये रखें + AVB 2.0/dm-verity को बनाये रखें + रिकवरी मोड + स्थापित: %1$s + नवीनतम: %1$s + स्थापना रद्द करें + Magisk की स्थापना रद्द करें + सभी मॉड्यूल अक्षम/हटा दिए जाएंगे. रुट और आपका संभावित रूप से एन्क्रिप्ट डाटा हटा दिया जाएगा. + अपडेट करें + (केवल मूल मोड समर्थकृत) + + + (कोई जानकारी प्रदान नहीं की गई) + कोई मॉड्यूल नहीं मिला + मॉड्यूल अगले रिबूट पे अपडेट किया जाएगा ! + मॉड्यूल अगले रिबूट पे हटाया जाएगा ! + मॉड्यूल अगले रिबूट पे नहीं हटाया जाएगा ! + मॉड्यूल अगले रिबूट पे निर्योग्य किया जाएगा ! + मॉड्यूल अगले रिबूट पे योग्य किया जाएगा ! + %1$s के द्वारा बनाया गया + रिकवरी मोड में रिबूट करें + बूटलोडर में रिबूट करें + डाउनलोड में रिबूट करें + EDL मोड में रिबूट करें + + + अपडेट उपलब्ध है + स्थापित + स्थापित नहीं है + %1$s को अपडेट किया गया + छँटाई क्रम + नाम द्वारा छांटें + आखिरी अपडेट द्वारा छांटें + + + अभिलेख सेव करें + पुनः लोड करें + अभिलेख साफ़ करें + अभिलेख सफलतापूर्वक साफ़ हो गया. + + + परिवर्तन अभिलेख + + + Magisk की अपडेट + प्रगति सूचनाएँ + डाउनलोड सम्पन्न हुआ + फ़ाइल डाउनलोड करने में त्रुटि + मूल फ़ोल्डर में दिखाएँ + फाइल दिखाएँ + Magisk की अपडेट उपलब्ध है! + Magisk Manager की अपडेट उपलब्ध है! + + + डाउनलोड और स्थापित करने के लिए दबाएँ. + खाली Zip डाउनलोड करें + सीधा स्थापित करें (अनुशंसित) + निष्क्रिय स्लॉट में स्थापित करें (OTA के बाद) + आपके डिवाइस को रीबूट के बाद वर्तमान निष्क्रिय स्लॉट में बूट करने के लिए मजबूर किया जाएगा!\nOTA होने के बाद ही इस विकल्प का उपयोग करें.\nजारी रखें? + विधि का चयन करें + अतिरिक्त सेटअप + एक फ़ाइल का चयन और पैच करें + एक कच्ची इमेज चुनें (*.img) या एक ODIN tarfile (*.tar) + 5 सेकंड में रिबूट हो रहा है ... + + + नहीं शुक्रिया + हां + ठीक + बंद करें + %1$s को स्थापित करें + क्या आप %1$s को स्थापित करना चाहते हैं ? + डाउनलोड + रिबूट + सेटिंग्स लागू करने के लिए रिबूट करें. + रिलीज नोट्स + Repo cache साफ़ हो गया + + DTBO पैच कर दिया गया! + Magisk Manager ने dtbo.img को पैच कर दिया. कृपया रिबूट करें. + फ़्लैश हो रहा है... + हो गया! + विफल हुआ + Magisk Manager छुप रहा है... + Magisk Manager छुपने में असफल रहा. + लिंक खोलने के लिए कोई एप्लिकेशन नहीं मिला. + चेतावनी + पूरी तरह से स्थापना रद्द करें + इमेजेज को पुनर्स्थापित करें + वापस लाया जा रहा... + वापस ले आया गया! + स्टॉक बैकअप मौजूद नहीं है! + मालिकाना कोड डाउनलोड करें + Magisk Manager FOSS है और उस्में Google का मालिकाना SafetyNet API कोड शामिल नहीं है.\n\nक्या आप Magisk Manager को SafetyNet चेक के लिए एक्सटेंशन (GoogleApiClient शामिल) डाउनलोड करने की अनुमति देंगे ? + सेटअप असफल हुआ. + अतिरिक्त सेटअप की आवश्यकता है + ठीक से काम करने के लिए आपके डिवाइस को Magisk के लिए अतिरिक्त सेटअप की आवश्यकता है. यह Magisk सेटअप zip डाउनलोड करेगा, क्या आप आगे बढ़ना चाहते हैं?/string> + पर्यावरण सेटअप चल रहा है... + + + सामान्य + डार्क थीम + डार्क थीम सक्षम करें. + डाउनलोड करने की जगह + %1$s में फाइल्स रखी जाएँगी + Repo Cache साफ़ करें + ऑनलाइन Repo के लिए Cached जानकारी साफ़ करें. यह एप्लिकेशन को ऑनलाइन रिफ्रेश होने के लिए मजबूर करता है. + Magisk Manager को छुपाएं + Magisk Manager को क्रमरहित नाम से फिर से पैकेज करें. + Magisk Manager को पुनर्स्थापित करें + Magisk Manager को अपने मूल पैकेज नाम से पुनर्स्थापित करें + भाषा + (सिस्टम डिफ़ॉल्ट) + सेटिंग्स अपडेट करें + अपडेट के लिए जाँच करें + समय-समय पर बैकग्राउंड में अपडेट की जांच करते रहें. + अपडेट का चैनल + स्थिर + बीटा + कस्टम + एक कस्टम URL डालें + Magisk का केवल मूल मोड + केवल मुख्य विशेषताएं सक्षम करें. MagiskSU और MagiskHide अभी भी सक्षम रहेंगे, लेकिन कोई मॉड्यूल लोड नहीं किया जाएगा. + पता लगाने के विभिन्न रूपों से Magisk को छुपाएं. + सिस्टमलेस होस्ट्स + एडब्लॉक ऍप्लिकेशन्स के लिए सिस्टमलेस होस्ट्स का समर्थन + सिस्टमलेस होस्ट्स का मॉड्यूल जोड़ दिया गया + + ऍप्लिकेशन्स और ADB + केवल ऍप्लिकेशन्स + केवल ADB + निर्योग्य + 10 सेकंड्‌स + 15 सेकंड्‌स + 20 सेकंड्‌स + 30 सेकंड्‌स + 45 सेकंड्‌स + 60 सेकंड्‌स + उत्तम उपयोगकर्ता की पहुँच + स्वचालित प्रतिक्रिया + निवेदन का समय समाप्त + उत्तम उपयोगकर्ता सूचना + %1$d सेकंड्‌स + अपग्रेड के बाद फिर से प्रमाणित करें + एप्लीकेशन अपग्रेड होने के बाद उत्तम उपयोगकर्ता की अनुमतियों को फिर से प्रमाणित करें + फिंगरप्रिंट प्रमाणीकरण सक्षम करें + उत्तम उपयोगकर्ता के अनुरोधों की अनुमति के लिए फिंगरप्रिंट स्कैनर का उपयोग करें + फिंगरप्रिंट को प्रमाणित करें + + बहु उपयोगकर्ता मोड + केवल डिवाइस का मालिक + केवल डिवाइस के मालिक द्वौरा प्रभंदित + उपयोगकर्ता स्वतंत्र + केवल मालिक के पास ही रूट की पहुँच है. + केवल मालिक ही रूट की पहुँच का प्रबंधन कर सकता है और अनुरोध संकेत प्राप्त कर सकता है. + प्रत्येक उपयोगकर्ता का अपना अलग रूट नियम होता है. + + माउंट नेमस्पेस मोड + वैश्विक नेमस्पेस + नेमस्पेस को इन्हेरिट करें + संगरोध नेमस्पेस + सभी रूट सत्र वैश्विक माउंट नेमस्पेस का उपयोग करते हैं. + रूट सत्रों को उनके अनुरोधकर्ताओं के नेमस्पेस विरासत में मिलेंगे. + प्रत्येक रूट सत्र का अपना अलग नेमस्पेस होगा. + Android 8.0+ का समर्थन नहीं करता है. + कोई फ़िंगरप्रिंट नहीं सेट किया गया या डिवाइस का समर्थन नहीं है. + फोल्डर बनाने में त्रुटि. यह स्टोरेज रूट डायरेक्टरी से एक्सेस होना चाहिए और फाइल नहीं होना चाहिए. + + + उत्तम उपयोगकर्ता का अनुरोध + इंकार करें + आदेश + अनुमति दें + यह आपके डिवाइस की पूरी पहुँच की अनुमति देगा. यदि आप सुनिश्चित नहीं हैं तो इंकार करें! + सदैव + एक बार + 10 मिनट + 20 मिनट + 30 मिनट + 60 मिनट + %1$s को उत्तम उपयोगकर्ता के अधिकार की अनुमति दी गई + %1$s को उत्तम उपयोगकर्ता के अधिकार से इनकार किया गया + कोई एप्लीकेशन नहीं मिला + %1$s को उत्तम उपयोगकर्ता के अधिकार की अनुमति है + %1$s को उत्तम उपयोगकर्ता के अधिकार की अनुमति नहीं है + %1$s की सूचनाएं सक्षम हैं + %1$s की सूचनाएं अक्षम हैं + %1$s के लिए अभिलेख सक्षम है + %1$s के लिए अभिलेख अक्षम है + वापस लें? + %1$s के अधिकारों को वापस लेने की पुष्टि करें? + पॉप-अप नोट + कोई नहीं + प्रमाणीकरण विफल हुआ + + + PID: %1$d + लक्ष्य UID: %1$d + Command: %1$s + + + सिस्टम ऍप्लिकेशन्स दिखाएं + + diff --git a/stub/src/main/res/values-hi/strings.xml b/stub/src/main/res/values-hi/strings.xml new file mode 100644 index 000000000..7b29600b5 --- /dev/null +++ b/stub/src/main/res/values-hi/strings.xml @@ -0,0 +1,8 @@ + + + नहीं शुक्रिया + हां + ठीक + सेटअप को पूरा करने के लिए पूर्ण Magisk Manager में अपग्रेड करें. डाउनलोड करके स्थापित करें ? + कृपया इन्टरनेट से जुड़िये! पूर्ण Magisk Manager के उन्नयन की आवश्यकता है. + From a5fc7891a604f1bc99d8d68a96e542a1ef08c46e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8D=E3=81=A8=20=E3=83=9F=E3=82=BA=E3=82=AD?= =?UTF-8?q?=E3=83=88?= Date: Wed, 23 Oct 2019 19:57:47 +0900 Subject: [PATCH 34/61] build: Addressed file not found --- build.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build.py b/build.py index cb07bc5d0..595eb2e81 100755 --- a/build.py +++ b/build.py @@ -119,6 +119,9 @@ def load_config(args): config['keyStore'] = 'release-key.jks' # Load prop file + if not os.path.exists(args.config): + error(f'Please make sure {args.config} existed') + with open(args.config, 'r') as f: for line in [l.strip(' \t\r\n') for l in f]: if line.startswith('#') or len(line) == 0: From 1512c350df61e5fc941a3260604bf6fdd2f769ac Mon Sep 17 00:00:00 2001 From: osm0sis Date: Sun, 20 Oct 2019 21:13:13 -0300 Subject: [PATCH 35/61] magiskboot: add SPRD dt support - per https://github.com/USA-RedDragon/sprd-mkbootimg-tools/blob/master/dtbtool.c - touch up hdr and table naming to be more uniform --- native/jni/magiskboot/dtb.cpp | 42 ++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/native/jni/magiskboot/dtb.cpp b/native/jni/magiskboot/dtb.cpp index 6ca6442af..d1641a12c 100644 --- a/native/jni/magiskboot/dtb.cpp +++ b/native/jni/magiskboot/dtb.cpp @@ -17,7 +17,8 @@ using namespace std; #define QCDT_MAGIC "QCDT" #define DTBH_MAGIC "DTBH" #define PXADT_MAGIC "PXA-DT" -#define PXA_19xx_MAGIC "PXA-19xx" +#define PXA19xx_MAGIC "PXA-19xx" +#define SPRD_MAGIC "SPRD" struct qcdt_hdr { char magic[4]; /* "QCDT" */ @@ -58,19 +59,31 @@ struct bhtable_v2 { struct pxadt_hdr { char magic[6]; /* "PXA-DT" */ - uint32_t version; /* PXA-DT version */ + uint32_t version; /* PXA-* version */ uint32_t num_dtbs; /* Number of DTBs */ } __attribute__((packed)); -struct pxa_19xx_hdr { +struct pxa19xx_hdr { char magic[8]; /* "PXA-19xx" */ - uint32_t version; /* PXA-DT version */ + uint32_t version; /* PXA-* version */ uint32_t num_dtbs; /* Number of DTBs */ } __attribute__((packed)); -struct pxa_table_v1 { +struct pxatable_v1 { uint32_t cpu_info[2]; /* Some CPU info */ - uint32_t offset; /* DTB offset in PXA-DT */ + uint32_t offset; /* DTB offset in PXA-* */ + uint32_t len; /* DTB size */ +} __attribute__((packed)); + +struct sprd_hdr { + char magic[4]; /* "SPRD" */ + uint32_t version; /* SPRD version */ + uint32_t num_dtbs; /* Number of DTBs */ +} __attribute__((packed)); + +struct sprdtable_v1 { + uint32_t cpu_info[3]; /* Some CPU info */ + uint32_t offset; /* DTB offset in SPRD */ uint32_t len; /* DTB size */ } __attribute__((packed)); @@ -358,16 +371,25 @@ static int dtb_patch(const char *in, const char *out) { switch (hdr->version) { case 1: fprintf(stderr, "PXA-DT v1\n"); - return dtb_patch(hdr, in, out); + return dtb_patch(hdr, in, out); default: return 1; } - } else if (MATCH(PXA_19xx_MAGIC)) { - auto hdr = reinterpret_cast(dtb); + } else if (MATCH(PXA19xx_MAGIC)) { + auto hdr = reinterpret_cast(dtb); switch (hdr->version) { case 1: fprintf(stderr, "PXA-19xx v1\n"); - return dtb_patch(hdr, in, out); + return dtb_patch(hdr, in, out); + default: + return 1; + } + } else if (MATCH(SPRD_MAGIC)) { + auto hdr = reinterpret_cast(dtb); + switch (hdr->version) { + case 1: + fprintf(stderr, "SPRD v1\n"); + return dtb_patch(hdr, in, out); default: return 1; } From 5133e5910e536b155e20c378348db987e35acc6a Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Wed, 23 Oct 2019 07:07:51 -0400 Subject: [PATCH 36/61] Don't relaunch app immediately --- .../topjohnwu/magisk/model/download/ManagerUpgrade.kt | 11 +++++------ .../main/java/com/topjohnwu/magisk/utils/PatchAPK.kt | 3 +-- app/src/main/java/com/topjohnwu/magisk/utils/Utils.kt | 5 ----- app/src/main/res/raw/utils.sh | 6 ------ 4 files changed, 6 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/model/download/ManagerUpgrade.kt b/app/src/main/java/com/topjohnwu/magisk/model/download/ManagerUpgrade.kt index b4d6d8cc5..18cb448a7 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/download/ManagerUpgrade.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/download/ManagerUpgrade.kt @@ -1,12 +1,13 @@ package com.topjohnwu.magisk.model.download -import com.topjohnwu.magisk.* +import com.topjohnwu.magisk.BuildConfig +import com.topjohnwu.magisk.Config +import com.topjohnwu.magisk.R +import com.topjohnwu.magisk.isRunningAsStub import com.topjohnwu.magisk.model.entity.internal.Configuration.APK.Restore import com.topjohnwu.magisk.model.entity.internal.Configuration.APK.Upgrade import com.topjohnwu.magisk.model.entity.internal.DownloadSubject -import com.topjohnwu.magisk.ui.SplashActivity import com.topjohnwu.magisk.utils.PatchAPK -import com.topjohnwu.magisk.utils.Utils import com.topjohnwu.superuser.Shell import java.io.File @@ -35,9 +36,7 @@ private fun RemoteFileService.restore(apk: File, id: Int) { Config.export() // Make it world readable apk.setReadable(true, false) - if (Shell.su("pm install $apk").exec().isSuccess) { - Utils.rmAndLaunch(packageName, SplashActivity::class.java.cmp()) - } + Shell.su("pm install $apk && pm uninstall $packageName").exec() } fun RemoteFileService.handleAPK(subject: DownloadSubject.Manager) diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.kt b/app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.kt index 91a4ab791..2d8d3b356 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.kt +++ b/app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.kt @@ -9,7 +9,6 @@ import com.topjohnwu.magisk.extensions.DynamicClassLoader import com.topjohnwu.magisk.extensions.get import com.topjohnwu.magisk.extensions.subscribeK import com.topjohnwu.magisk.extensions.writeTo -import com.topjohnwu.magisk.ui.SplashActivity import com.topjohnwu.magisk.view.Notifications import com.topjohnwu.signing.JarMap import com.topjohnwu.signing.SignAPK @@ -109,7 +108,7 @@ object PatchAPK { Config.suManager = pkg Config.export() - Utils.rmAndLaunch(BuildConfig.APPLICATION_ID, SplashActivity::class.java.cmp(pkg)) + Shell.su("pm uninstall ${BuildConfig.APPLICATION_ID}").submit() return true } diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/Utils.kt b/app/src/main/java/com/topjohnwu/magisk/utils/Utils.kt index 48ca4d3c1..252b7b6d8 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Utils.kt +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Utils.kt @@ -1,6 +1,5 @@ package com.topjohnwu.magisk.utils -import android.content.ComponentName import android.content.Context import android.content.Intent import android.content.res.Resources @@ -73,8 +72,4 @@ object Utils { if ((exists() && isDirectory) || mkdirs()) this else null } - fun rmAndLaunch(rm: String, component: ComponentName) { - Shell.su("(rm_launch $rm ${component.flattenToString()})").exec() - } - } diff --git a/app/src/main/res/raw/utils.sh b/app/src/main/res/raw/utils.sh index 4e2a298a1..136b6adf3 100644 --- a/app/src/main/res/raw/utils.sh +++ b/app/src/main/res/raw/utils.sh @@ -109,9 +109,3 @@ EOF touch hosts/auto_mount cd / } - -rm_launch() { - pm uninstall $1 - am start -n $2 - exit -} From 5c7b59524d3a52c87ea63da07d3b414aa2d519e8 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Wed, 23 Oct 2019 07:15:28 -0400 Subject: [PATCH 37/61] Fix strings --- app/src/main/res/values-hi/strings.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index 2b91dbb9e..a7818a6ab 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -85,7 +85,7 @@ अतिरिक्त सेटअप एक फ़ाइल का चयन और पैच करें एक कच्ची इमेज चुनें (*.img) या एक ODIN tarfile (*.tar) - 5 सेकंड में रिबूट हो रहा है ... + 5 सेकंड में रिबूट हो रहा है … नहीं शुक्रिया @@ -102,24 +102,24 @@ DTBO पैच कर दिया गया! Magisk Manager ने dtbo.img को पैच कर दिया. कृपया रिबूट करें. - फ़्लैश हो रहा है... + फ़्लैश हो रहा है… हो गया! विफल हुआ - Magisk Manager छुप रहा है... + Magisk Manager छुप रहा है… Magisk Manager छुपने में असफल रहा. लिंक खोलने के लिए कोई एप्लिकेशन नहीं मिला. चेतावनी पूरी तरह से स्थापना रद्द करें इमेजेज को पुनर्स्थापित करें - वापस लाया जा रहा... + वापस लाया जा रहा… वापस ले आया गया! स्टॉक बैकअप मौजूद नहीं है! मालिकाना कोड डाउनलोड करें Magisk Manager FOSS है और उस्में Google का मालिकाना SafetyNet API कोड शामिल नहीं है.\n\nक्या आप Magisk Manager को SafetyNet चेक के लिए एक्सटेंशन (GoogleApiClient शामिल) डाउनलोड करने की अनुमति देंगे ? सेटअप असफल हुआ. अतिरिक्त सेटअप की आवश्यकता है - ठीक से काम करने के लिए आपके डिवाइस को Magisk के लिए अतिरिक्त सेटअप की आवश्यकता है. यह Magisk सेटअप zip डाउनलोड करेगा, क्या आप आगे बढ़ना चाहते हैं?/string> - पर्यावरण सेटअप चल रहा है... + ठीक से काम करने के लिए आपके डिवाइस को Magisk के लिए अतिरिक्त सेटअप की आवश्यकता है. यह Magisk सेटअप zip डाउनलोड करेगा, क्या आप आगे बढ़ना चाहते हैं? + पर्यावरण सेटअप चल रहा है… सामान्य From 7f971f717313ca5294bdb88c7515f3899a0df08a Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Wed, 23 Oct 2019 07:51:32 -0400 Subject: [PATCH 38/61] Make sure our constructor is preserved --- app/proguard-rules.pro | 1 + 1 file changed, 1 insertion(+) diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 03cf6bdb6..accd5efc2 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -36,6 +36,7 @@ # Workaround R8 bug -keep,allowobfuscation class com.topjohnwu.magisk.model.receiver.GeneralReceiver +-keepclassmembers class a.e { *; } # Strip logging -assumenosideeffects class timber.log.Timber.Tree { *; } From 294db93fdeb12a5c0db92aabd5981b75d0a9ad66 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Wed, 23 Oct 2019 17:20:55 -0400 Subject: [PATCH 39/61] Copy instead of move We might be copying from CE to DE storage, which cannot be moved --- .../com/topjohnwu/magisk/model/download/DownloadService.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/model/download/DownloadService.kt b/app/src/main/java/com/topjohnwu/magisk/model/download/DownloadService.kt index f22ba0af7..082978af0 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/download/DownloadService.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/download/DownloadService.kt @@ -13,6 +13,7 @@ import com.topjohnwu.magisk.extensions.chooser import com.topjohnwu.magisk.extensions.exists import com.topjohnwu.magisk.extensions.provide import com.topjohnwu.magisk.intent +import com.topjohnwu.magisk.isRunningAsStub import com.topjohnwu.magisk.model.entity.internal.Configuration.* import com.topjohnwu.magisk.model.entity.internal.Configuration.Flash.Secondary import com.topjohnwu.magisk.model.entity.internal.DownloadSubject @@ -20,7 +21,6 @@ import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.* import com.topjohnwu.magisk.ui.flash.FlashActivity import com.topjohnwu.magisk.utils.APKInstall import com.topjohnwu.magisk.utils.DynAPK -import com.topjohnwu.magisk.isRunningAsStub import org.koin.core.get import java.io.File import kotlin.random.Random.Default.nextInt @@ -67,7 +67,8 @@ open class DownloadService : RemoteFileService() { when (subject.configuration) { is APK.Upgrade -> { if (isRunningAsStub) { - subject.file.renameTo(DynAPK.update(this)) + subject.file.copyTo(DynAPK.update(this), overwrite = true) + subject.file.delete() ProcessPhoenix.triggerRebirth(this) } else { APKInstall.install(this, subject.file) @@ -161,4 +162,4 @@ open class DownloadService : RemoteFileService() { } -} \ No newline at end of file +} From 2be0cef446ea4b9b7b46e33488eaad176dbdb0d9 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Wed, 23 Oct 2019 17:55:26 -0400 Subject: [PATCH 40/61] Add proper intent filters to stub --- shared/src/main/java/com/topjohnwu/magisk/utils/DynAPK.java | 2 +- stub/src/main/AndroidManifest.xml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/shared/src/main/java/com/topjohnwu/magisk/utils/DynAPK.java b/shared/src/main/java/com/topjohnwu/magisk/utils/DynAPK.java index a9a363708..0128bed88 100644 --- a/shared/src/main/java/com/topjohnwu/magisk/utils/DynAPK.java +++ b/shared/src/main/java/com/topjohnwu/magisk/utils/DynAPK.java @@ -9,7 +9,7 @@ import static android.os.Build.VERSION.SDK_INT; public class DynAPK { - private static final int STUB_VERSION = 1; + private static final int STUB_VERSION = 2; // Indices of the object array private static final int STUB_VERSION_ENTRY = 0; diff --git a/stub/src/main/AndroidManifest.xml b/stub/src/main/AndroidManifest.xml index b1b4af47c..729d39a19 100644 --- a/stub/src/main/AndroidManifest.xml +++ b/stub/src/main/AndroidManifest.xml @@ -57,6 +57,7 @@ android:name="a.w" android:directBootAware="true"> + From d4598593617fe7f61685da1ebb0f577886481026 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Thu, 24 Oct 2019 00:54:40 -0400 Subject: [PATCH 41/61] Show stub version --- .../topjohnwu/magisk/ui/home/HomeViewModel.kt | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt index 821a79d1f..6db20f535 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt @@ -202,13 +202,15 @@ class HomeViewModel( private fun refreshVersions() { magiskCurrentVersion.value = if (magiskState.value != MagiskState.NOT_INSTALLED) { - version.format(Info.env.magiskVersionString, Info.env.magiskVersionCode) + VERSION_FMT.format(Info.env.magiskVersionString, Info.env.magiskVersionCode) } else { "" } - managerCurrentVersion.value = version - .format(BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE) + managerCurrentVersion.value = if (isRunningAsStub) MGR_VER_FMT + .format(BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE, ClassMap.data!!.version) + else + VERSION_FMT.format(BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE) } private fun updateSelf() { @@ -218,8 +220,8 @@ class HomeViewModel( else -> MagiskState.UP_TO_DATE } - magiskLatestVersion.value = version - .format(Info.remote.magisk.version, Info.remote.magisk.versionCode) + magiskLatestVersion.value = + VERSION_FMT.format(Info.remote.magisk.version, Info.remote.magisk.versionCode) _managerState.value = when (Info.remote.app.versionCode) { in Int.MIN_VALUE until 0 -> MagiskState.NOT_INSTALLED //wrong update channel @@ -227,8 +229,8 @@ class HomeViewModel( else -> MagiskState.UP_TO_DATE } - managerLatestVersion.value = version - .format(Info.remote.app.version, Info.remote.app.versionCode) + managerLatestVersion.value = MGR_VER_FMT + .format(Info.remote.app.version, Info.remote.app.versionCode, Info.remote.stub.versionCode) } private fun ensureEnv() { @@ -245,7 +247,8 @@ class HomeViewModel( } companion object { - private const val version = "%s (%d)" + private const val VERSION_FMT = "%s (%d)" + private const val MGR_VER_FMT = "%s (%d) (%d)" } } From 676e9c659372f3a9f86de3384ecfef7b62926c62 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Thu, 24 Oct 2019 02:47:40 -0400 Subject: [PATCH 42/61] Provide upgrade path for stubs --- .../magisk/model/download/DownloadService.kt | 13 +---- .../magisk/model/download/ManagerUpgrade.kt | 52 +++++++++++++------ .../model/download/RemoteFileService.kt | 2 +- .../com/topjohnwu/magisk/utils/PatchAPK.kt | 8 ++- 4 files changed, 44 insertions(+), 31 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/model/download/DownloadService.kt b/app/src/main/java/com/topjohnwu/magisk/model/download/DownloadService.kt index 082978af0..3f0eca392 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/download/DownloadService.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/download/DownloadService.kt @@ -7,20 +7,17 @@ import android.content.Intent import android.os.Build import android.webkit.MimeTypeMap import androidx.core.app.NotificationCompat -import com.topjohnwu.magisk.ProcessPhoenix import com.topjohnwu.magisk.R import com.topjohnwu.magisk.extensions.chooser import com.topjohnwu.magisk.extensions.exists import com.topjohnwu.magisk.extensions.provide import com.topjohnwu.magisk.intent -import com.topjohnwu.magisk.isRunningAsStub import com.topjohnwu.magisk.model.entity.internal.Configuration.* import com.topjohnwu.magisk.model.entity.internal.Configuration.Flash.Secondary import com.topjohnwu.magisk.model.entity.internal.DownloadSubject import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.* import com.topjohnwu.magisk.ui.flash.FlashActivity import com.topjohnwu.magisk.utils.APKInstall -import com.topjohnwu.magisk.utils.DynAPK import org.koin.core.get import java.io.File import kotlin.random.Random.Default.nextInt @@ -65,15 +62,7 @@ open class DownloadService : RemoteFileService() { ) { remove(id) when (subject.configuration) { - is APK.Upgrade -> { - if (isRunningAsStub) { - subject.file.copyTo(DynAPK.update(this), overwrite = true) - subject.file.delete() - ProcessPhoenix.triggerRebirth(this) - } else { - APKInstall.install(this, subject.file) - } - } + is APK.Upgrade -> APKInstall.install(this, subject.file) is APK.Restore -> Unit } } diff --git a/app/src/main/java/com/topjohnwu/magisk/model/download/ManagerUpgrade.kt b/app/src/main/java/com/topjohnwu/magisk/model/download/ManagerUpgrade.kt index 18cb448a7..3f5d98976 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/download/ManagerUpgrade.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/download/ManagerUpgrade.kt @@ -1,28 +1,48 @@ package com.topjohnwu.magisk.model.download -import com.topjohnwu.magisk.BuildConfig -import com.topjohnwu.magisk.Config -import com.topjohnwu.magisk.R -import com.topjohnwu.magisk.isRunningAsStub +import com.topjohnwu.magisk.* +import com.topjohnwu.magisk.extensions.writeTo import com.topjohnwu.magisk.model.entity.internal.Configuration.APK.Restore import com.topjohnwu.magisk.model.entity.internal.Configuration.APK.Upgrade import com.topjohnwu.magisk.model.entity.internal.DownloadSubject +import com.topjohnwu.magisk.utils.DynAPK import com.topjohnwu.magisk.utils.PatchAPK import com.topjohnwu.superuser.Shell import java.io.File -private fun RemoteFileService.patchPackage(apk: File, id: Int) { - if (!isRunningAsStub && packageName != BuildConfig.APPLICATION_ID) { - update(id) { notification -> - notification.setProgress(0, 0, true) - .setProgress(0, 0, true) - .setContentTitle(getString(R.string.hide_manager_title)) - .setContentText("") - } - val patched = File(apk.parent, "patched.apk") - PatchAPK.patch(apk, patched, packageName, applicationInfo.nonLocalizedLabel.toString()) +private fun RemoteFileService.patch(apk: File, id: Int) { + if (packageName == BuildConfig.APPLICATION_ID) + return + + update(id) { notification -> + notification.setProgress(0, 0, true) + .setProgress(0, 0, true) + .setContentTitle(getString(R.string.hide_manager_title)) + .setContentText("") + } + val patched = File(apk.parent, "patched.apk") + PatchAPK.patch(apk, patched, packageName, applicationInfo.nonLocalizedLabel.toString()) + apk.delete() + patched.renameTo(apk) +} + +private fun RemoteFileService.upgrade(apk: File, id: Int) { + if (isRunningAsStub) { + // Move to upgrade location + apk.copyTo(DynAPK.update(this), overwrite = true) apk.delete() - patched.renameTo(apk) + if (ClassMap.data!!.version < Info.remote.stub.versionCode) { + // We also want to upgrade stub + service.fetchFile(Info.remote.stub.link).blockingGet().byteStream().use { + it.writeTo(apk) + } + patch(apk, id) + } else { + // Simply relaunch the app + ProcessPhoenix.triggerRebirth(this) + } + } else { + patch(apk, id) } } @@ -41,6 +61,6 @@ private fun RemoteFileService.restore(apk: File, id: Int) { fun RemoteFileService.handleAPK(subject: DownloadSubject.Manager) = when (subject.configuration) { - is Upgrade -> patchPackage(subject.file, subject.hashCode()) + is Upgrade -> upgrade(subject.file, subject.hashCode()) is Restore -> restore(subject.file, subject.hashCode()) } diff --git a/app/src/main/java/com/topjohnwu/magisk/model/download/RemoteFileService.kt b/app/src/main/java/com/topjohnwu/magisk/model/download/RemoteFileService.kt index febd7fb2f..418a4d3de 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/download/RemoteFileService.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/download/RemoteFileService.kt @@ -22,7 +22,7 @@ import java.io.InputStream abstract class RemoteFileService : NotificationService() { - private val service: GithubRawServices by inject() + val service: GithubRawServices by inject() override val defaultNotification: NotificationCompat.Builder get() = Notifications.progress(this, "") diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.kt b/app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.kt index 2d8d3b356..3c82b4642 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.kt +++ b/app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.kt @@ -138,6 +138,11 @@ object PatchAPK { fun patch(apk: File, out: File, pkg: String, label: String): Boolean { try { + if (apk.length() < 1 shl 18) { + // APK is smaller than 256K, must be stub + return patch(apk.path, out.path, pkg, label) + } + // Try using the new APK to patch itself val loader = DynamicClassLoader(apk) val cls = loader.loadClass("a.a") @@ -152,9 +157,8 @@ object PatchAPK { } catch (e: Exception) { Timber.e(e) // Fallback to use the current implementation - patch(apk.path, out.path, pkg, label) + return patch(apk.path, out.path, pkg, label) } - return false } fun hideManager(context: Context, label: String) { From 25c64db0a137d503bbccf18d5f1401981ae05643 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Thu, 24 Oct 2019 03:54:16 -0400 Subject: [PATCH 43/61] Treat outdated stub as outdated manager --- .../com/topjohnwu/magisk/ui/home/HomeViewModel.kt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt index 6db20f535..4c6f7e32b 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt @@ -216,7 +216,7 @@ class HomeViewModel( private fun updateSelf() { magiskState.value = when (Info.env.magiskVersionCode) { in Int.MIN_VALUE until 0 -> MagiskState.NOT_INSTALLED - !in Info.remote.magisk.versionCode..Int.MAX_VALUE -> MagiskState.OBSOLETE + in 1 until (Info.remote.magisk.versionCode - 1) -> MagiskState.OBSOLETE else -> MagiskState.UP_TO_DATE } @@ -225,8 +225,13 @@ class HomeViewModel( _managerState.value = when (Info.remote.app.versionCode) { in Int.MIN_VALUE until 0 -> MagiskState.NOT_INSTALLED //wrong update channel - in (BuildConfig.VERSION_CODE + 1)..Int.MAX_VALUE -> MagiskState.OBSOLETE - else -> MagiskState.UP_TO_DATE + in (BuildConfig.VERSION_CODE + 1) until Int.MAX_VALUE -> MagiskState.OBSOLETE + else -> { + if (isRunningAsStub && ClassMap.data!!.version < Info.remote.stub.versionCode) + MagiskState.OBSOLETE + else + MagiskState.UP_TO_DATE + } } managerLatestVersion.value = MGR_VER_FMT From c30be20e49098ba61bead4d5e74953eb4352f895 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Thu, 24 Oct 2019 04:02:01 -0400 Subject: [PATCH 44/61] Minor CachedValue fix --- app/src/main/java/com/topjohnwu/magisk/utils/CachedValue.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/CachedValue.kt b/app/src/main/java/com/topjohnwu/magisk/utils/CachedValue.kt index b4b6f6a80..889eb9fa0 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/CachedValue.kt +++ b/app/src/main/java/com/topjohnwu/magisk/utils/CachedValue.kt @@ -8,9 +8,7 @@ class CachedValue(private val factory: () -> T) : Lazy { get() { val local = _val return local ?: synchronized(this) { - val newInstance = factory() - _val = newInstance - newInstance + _val ?: factory().also { _val = it } } } From 7fc7809cfc67a96f3ae0707ee1f640202de077c1 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Thu, 24 Oct 2019 04:25:05 -0400 Subject: [PATCH 45/61] More precise channel targeting --- app/src/main/java/com/topjohnwu/magisk/Config.kt | 7 ++++++- .../main/java/com/topjohnwu/magisk/DownloadActivity.java | 6 ++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/Config.kt b/app/src/main/java/com/topjohnwu/magisk/Config.kt index 9a317aa91..d065a86be 100644 --- a/app/src/main/java/com/topjohnwu/magisk/Config.kt +++ b/app/src/main/java/com/topjohnwu/magisk/Config.kt @@ -98,7 +98,12 @@ object Config : PreferenceModel, DBConfig { } private val defaultChannel = - if (Utils.isCanary) Value.CANARY_DEBUG_CHANNEL + if (Utils.isCanary) { + if (BuildConfig.DEBUG) + Value.CANARY_DEBUG_CHANNEL + else + Value.CANARY_CHANNEL + } else Value.DEFAULT_CHANNEL var downloadPath by preference(Key.DOWNLOAD_PATH, Environment.DIRECTORY_DOWNLOADS) diff --git a/stub/src/main/java/com/topjohnwu/magisk/DownloadActivity.java b/stub/src/main/java/com/topjohnwu/magisk/DownloadActivity.java index 12d22ffcd..dfad034d5 100644 --- a/stub/src/main/java/com/topjohnwu/magisk/DownloadActivity.java +++ b/stub/src/main/java/com/topjohnwu/magisk/DownloadActivity.java @@ -21,8 +21,10 @@ import static com.topjohnwu.magisk.DelegateApplication.MANAGER_APK; public class DownloadActivity extends Activity { static final String TAG = "MMStub"; - private static final String URL = BuildConfig.DEV_CHANNEL != null ? BuildConfig.DEV_CHANNEL : - "https://raw.githubusercontent.com/topjohnwu/magisk_files/master/stable.json"; + private static final String URL = + BuildConfig.DEV_CHANNEL != null ? BuildConfig.DEV_CHANNEL : + "https://raw.githubusercontent.com/topjohnwu/magisk_files/" + + (BuildConfig.DEBUG ? "canary/debug.json" : "master/stable.json"); private String apkLink; private ErrorHandler err = (conn, e) -> { From 0b87108174947e8dfb4aa7bce3ca652284f9885b Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Thu, 24 Oct 2019 05:21:42 -0400 Subject: [PATCH 46/61] Move things around --- app/src/main/java/com/topjohnwu/magisk/App.kt | 3 +-- app/src/main/java/com/topjohnwu/magisk/Hacks.kt | 13 ++++--------- app/src/main/java/com/topjohnwu/magisk/Info.kt | 7 +++++-- .../magisk/base/viewmodel/BaseViewModel.kt | 2 +- .../com/topjohnwu/magisk/extensions/XAndroid.kt | 2 +- .../magisk/model/download/ManagerUpgrade.kt | 3 +-- .../com/topjohnwu/magisk/ui/home/HomeViewModel.kt | 4 ++-- .../topjohnwu/magisk/ui/module/ModulesFragment.kt | 1 - .../java/com/topjohnwu/magisk/view/Notifications.kt | 1 - .../java/com/topjohnwu/magisk/view/Shortcuts.kt | 1 - shared/src/main/java/a/p.java | 2 +- .../com/topjohnwu/magisk/{utils => }/DynAPK.java | 2 +- .../topjohnwu/magisk/{utils => }/FileProvider.java | 2 +- .../java/com/topjohnwu/magisk/utils/APKInstall.java | 2 ++ .../com/topjohnwu/magisk/DelegateApplication.java | 1 - .../src/main/java/com/topjohnwu/magisk/Mapping.java | 2 +- 16 files changed, 21 insertions(+), 27 deletions(-) rename shared/src/main/java/com/topjohnwu/magisk/{utils => }/DynAPK.java (98%) rename shared/src/main/java/com/topjohnwu/magisk/{utils => }/FileProvider.java (99%) diff --git a/app/src/main/java/com/topjohnwu/magisk/App.kt b/app/src/main/java/com/topjohnwu/magisk/App.kt index 4bc13958b..0569ac57a 100644 --- a/app/src/main/java/com/topjohnwu/magisk/App.kt +++ b/app/src/main/java/com/topjohnwu/magisk/App.kt @@ -15,7 +15,6 @@ import com.topjohnwu.magisk.di.ActivityTracker import com.topjohnwu.magisk.di.koinModules import com.topjohnwu.magisk.extensions.get import com.topjohnwu.magisk.extensions.unwrap -import com.topjohnwu.magisk.utils.DynAPK import com.topjohnwu.magisk.utils.RootInit import com.topjohnwu.superuser.Shell import org.koin.android.ext.koin.androidContext @@ -25,7 +24,7 @@ import timber.log.Timber open class App() : Application() { constructor(o: Any) : this() { - ClassMap.data = DynAPK.load(o) + Info.stub = DynAPK.load(o) } init { diff --git a/app/src/main/java/com/topjohnwu/magisk/Hacks.kt b/app/src/main/java/com/topjohnwu/magisk/Hacks.kt index 8b638e32c..52926eb77 100644 --- a/app/src/main/java/com/topjohnwu/magisk/Hacks.kt +++ b/app/src/main/java/com/topjohnwu/magisk/Hacks.kt @@ -23,13 +23,10 @@ import com.topjohnwu.magisk.ui.MainActivity import com.topjohnwu.magisk.ui.SplashActivity import com.topjohnwu.magisk.ui.flash.FlashActivity import com.topjohnwu.magisk.ui.surequest.SuRequestActivity -import com.topjohnwu.magisk.utils.DynAPK import com.topjohnwu.magisk.utils.currentLocale import com.topjohnwu.magisk.utils.defaultLocale import java.util.* -val isRunningAsStub get() = ClassMap.data != null - private val addAssetPath by lazy { AssetManager::class.java.getMethod("addAssetPath", String::class.java) } @@ -69,19 +66,19 @@ private fun Resources.patch(config: Configuration = Configuration(configuration) fun Class<*>.cmp(pkg: String = BuildConfig.APPLICATION_ID): ComponentName { val name = ClassMap[this].name - return ComponentName(pkg, ClassMap.data?.componentMap?.get(name) ?: name) + return ComponentName(pkg, Info.stub?.componentMap?.get(name) ?: name) } fun Context.intent(c: Class<*>): Intent { val cls = ClassMap[c] - return ClassMap.data?.let { + return Info.stub?.let { val className = it.componentMap.getOrElse(cls.name) { cls.name } Intent().setComponent(ComponentName(this, className)) } ?: Intent(this, cls) } fun resolveRes(idx: Int): Int { - return ClassMap.data?.resourceMap?.get(idx) ?: when(idx) { + return Info.stub?.resourceMap?.get(idx) ?: when(idx) { DynAPK.NOTIFICATION -> R.drawable.ic_magisk_outline DynAPK.DOWNLOAD -> R.drawable.sc_cloud_download DynAPK.SUPERUSER -> R.drawable.sc_superuser @@ -172,7 +169,7 @@ private class JobSchedulerWrapper(private val base: JobScheduler) : JobScheduler // We need to patch the component of JobInfo to access WorkManager SystemJobService val name = service.className - val component = ComponentName(service.packageName, ClassMap.data?.componentMap?.get(name) + val component = ComponentName(service.packageName, Info.stub?.componentMap?.get(name) ?: name) // Clone the JobInfo except component @@ -226,7 +223,5 @@ object ClassMap { SuRequestActivity::class.java to a.m::class.java ) - internal var data: DynAPK.Data? = null - operator fun get(c: Class<*>) = map.getOrElse(c) { throw IllegalArgumentException() } } diff --git a/app/src/main/java/com/topjohnwu/magisk/Info.kt b/app/src/main/java/com/topjohnwu/magisk/Info.kt index 33b8715d4..2eec3295a 100644 --- a/app/src/main/java/com/topjohnwu/magisk/Info.kt +++ b/app/src/main/java/com/topjohnwu/magisk/Info.kt @@ -9,12 +9,15 @@ import com.topjohnwu.magisk.utils.KObservableField import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.ShellUtils +val isRunningAsStub get() = Info.stub != null + object Info { val envRef = CachedValue { loadState() } - val env by envRef // Local - var remote = UpdateInfo() // Remote + val env by envRef // Local + var remote = UpdateInfo() // Remote + var stub: DynAPK.Data? = null // Stub var keepVerity = false var keepEnc = false diff --git a/app/src/main/java/com/topjohnwu/magisk/base/viewmodel/BaseViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/base/viewmodel/BaseViewModel.kt index ef9082aaa..987f1bf6d 100644 --- a/app/src/main/java/com/topjohnwu/magisk/base/viewmodel/BaseViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/base/viewmodel/BaseViewModel.kt @@ -1,7 +1,6 @@ package com.topjohnwu.magisk.base.viewmodel import android.app.Activity -import com.topjohnwu.magisk.Info.isConnected as gIsConnected import com.topjohnwu.magisk.extensions.doOnSubscribeUi import com.topjohnwu.magisk.model.events.BackPressEvent import com.topjohnwu.magisk.model.events.PermissionEvent @@ -9,6 +8,7 @@ import com.topjohnwu.magisk.model.events.ViewActionEvent import com.topjohnwu.magisk.utils.KObservableField import io.reactivex.Observable import io.reactivex.subjects.PublishSubject +import com.topjohnwu.magisk.Info.isConnected as gIsConnected abstract class BaseViewModel( diff --git a/app/src/main/java/com/topjohnwu/magisk/extensions/XAndroid.kt b/app/src/main/java/com/topjohnwu/magisk/extensions/XAndroid.kt index 29120d6f8..5bd64ce20 100644 --- a/app/src/main/java/com/topjohnwu/magisk/extensions/XAndroid.kt +++ b/app/src/main/java/com/topjohnwu/magisk/extensions/XAndroid.kt @@ -21,8 +21,8 @@ import androidx.annotation.DrawableRes import androidx.core.content.ContextCompat import androidx.core.net.toUri import com.topjohnwu.magisk.Const +import com.topjohnwu.magisk.FileProvider import com.topjohnwu.magisk.utils.DynamicClassLoader -import com.topjohnwu.magisk.utils.FileProvider import com.topjohnwu.magisk.utils.Utils import com.topjohnwu.magisk.utils.currentLocale import com.topjohnwu.superuser.Shell diff --git a/app/src/main/java/com/topjohnwu/magisk/model/download/ManagerUpgrade.kt b/app/src/main/java/com/topjohnwu/magisk/model/download/ManagerUpgrade.kt index 3f5d98976..9e7079bb7 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/download/ManagerUpgrade.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/download/ManagerUpgrade.kt @@ -5,7 +5,6 @@ import com.topjohnwu.magisk.extensions.writeTo import com.topjohnwu.magisk.model.entity.internal.Configuration.APK.Restore import com.topjohnwu.magisk.model.entity.internal.Configuration.APK.Upgrade import com.topjohnwu.magisk.model.entity.internal.DownloadSubject -import com.topjohnwu.magisk.utils.DynAPK import com.topjohnwu.magisk.utils.PatchAPK import com.topjohnwu.superuser.Shell import java.io.File @@ -31,7 +30,7 @@ private fun RemoteFileService.upgrade(apk: File, id: Int) { // Move to upgrade location apk.copyTo(DynAPK.update(this), overwrite = true) apk.delete() - if (ClassMap.data!!.version < Info.remote.stub.versionCode) { + if (Info.stub!!.version < Info.remote.stub.versionCode) { // We also want to upgrade stub service.fetchFile(Info.remote.stub.link).blockingGet().byteStream().use { it.writeTo(apk) diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt index 4c6f7e32b..ee86ab652 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt @@ -208,7 +208,7 @@ class HomeViewModel( } managerCurrentVersion.value = if (isRunningAsStub) MGR_VER_FMT - .format(BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE, ClassMap.data!!.version) + .format(BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE, Info.stub!!.version) else VERSION_FMT.format(BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE) } @@ -227,7 +227,7 @@ class HomeViewModel( in Int.MIN_VALUE until 0 -> MagiskState.NOT_INSTALLED //wrong update channel in (BuildConfig.VERSION_CODE + 1) until Int.MAX_VALUE -> MagiskState.OBSOLETE else -> { - if (isRunningAsStub && ClassMap.data!!.version < Info.remote.stub.versionCode) + if (isRunningAsStub && Info.stub!!.version < Info.remote.stub.versionCode) MagiskState.OBSOLETE else MagiskState.UP_TO_DATE diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/module/ModulesFragment.kt b/app/src/main/java/com/topjohnwu/magisk/ui/module/ModulesFragment.kt index c06d4b487..61892804b 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/module/ModulesFragment.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/module/ModulesFragment.kt @@ -8,7 +8,6 @@ import android.view.MenuInflater import android.view.MenuItem import android.view.View import androidx.recyclerview.widget.RecyclerView -import com.topjohnwu.magisk.ClassMap import com.topjohnwu.magisk.Const import com.topjohnwu.magisk.R import com.topjohnwu.magisk.base.BaseFragment diff --git a/app/src/main/java/com/topjohnwu/magisk/view/Notifications.kt b/app/src/main/java/com/topjohnwu/magisk/view/Notifications.kt index 20f113ae8..ef8d5e026 100644 --- a/app/src/main/java/com/topjohnwu/magisk/view/Notifications.kt +++ b/app/src/main/java/com/topjohnwu/magisk/view/Notifications.kt @@ -12,7 +12,6 @@ import com.topjohnwu.magisk.* import com.topjohnwu.magisk.extensions.get import com.topjohnwu.magisk.model.receiver.GeneralReceiver import com.topjohnwu.magisk.ui.SplashActivity -import com.topjohnwu.magisk.utils.DynAPK object Notifications { diff --git a/app/src/main/java/com/topjohnwu/magisk/view/Shortcuts.kt b/app/src/main/java/com/topjohnwu/magisk/view/Shortcuts.kt index 3a541c155..61af35fda 100644 --- a/app/src/main/java/com/topjohnwu/magisk/view/Shortcuts.kt +++ b/app/src/main/java/com/topjohnwu/magisk/view/Shortcuts.kt @@ -9,7 +9,6 @@ import android.os.Build import androidx.annotation.RequiresApi import com.topjohnwu.magisk.* import com.topjohnwu.magisk.ui.SplashActivity -import com.topjohnwu.magisk.utils.DynAPK import com.topjohnwu.magisk.utils.Utils import com.topjohnwu.superuser.Shell diff --git a/shared/src/main/java/a/p.java b/shared/src/main/java/a/p.java index 2f93235d7..5cfd5256c 100644 --- a/shared/src/main/java/a/p.java +++ b/shared/src/main/java/a/p.java @@ -1,6 +1,6 @@ package a; -import com.topjohnwu.magisk.utils.FileProvider; +import com.topjohnwu.magisk.FileProvider; public class p extends FileProvider { /* Stub */ diff --git a/shared/src/main/java/com/topjohnwu/magisk/utils/DynAPK.java b/shared/src/main/java/com/topjohnwu/magisk/DynAPK.java similarity index 98% rename from shared/src/main/java/com/topjohnwu/magisk/utils/DynAPK.java rename to shared/src/main/java/com/topjohnwu/magisk/DynAPK.java index 0128bed88..28be1d9e7 100644 --- a/shared/src/main/java/com/topjohnwu/magisk/utils/DynAPK.java +++ b/shared/src/main/java/com/topjohnwu/magisk/DynAPK.java @@ -1,4 +1,4 @@ -package com.topjohnwu.magisk.utils; +package com.topjohnwu.magisk; import android.content.Context; diff --git a/shared/src/main/java/com/topjohnwu/magisk/utils/FileProvider.java b/shared/src/main/java/com/topjohnwu/magisk/FileProvider.java similarity index 99% rename from shared/src/main/java/com/topjohnwu/magisk/utils/FileProvider.java rename to shared/src/main/java/com/topjohnwu/magisk/FileProvider.java index 5d478f1b6..9b7ea0a73 100644 --- a/shared/src/main/java/com/topjohnwu/magisk/utils/FileProvider.java +++ b/shared/src/main/java/com/topjohnwu/magisk/FileProvider.java @@ -1,4 +1,4 @@ -package com.topjohnwu.magisk.utils; +package com.topjohnwu.magisk; import android.content.ContentProvider; import android.content.ContentValues; diff --git a/shared/src/main/java/com/topjohnwu/magisk/utils/APKInstall.java b/shared/src/main/java/com/topjohnwu/magisk/utils/APKInstall.java index 66f7567aa..2270017ec 100644 --- a/shared/src/main/java/com/topjohnwu/magisk/utils/APKInstall.java +++ b/shared/src/main/java/com/topjohnwu/magisk/utils/APKInstall.java @@ -5,6 +5,8 @@ import android.content.Intent; import android.net.Uri; import android.os.Build; +import com.topjohnwu.magisk.FileProvider; + import java.io.File; public class APKInstall { diff --git a/stub/src/main/java/com/topjohnwu/magisk/DelegateApplication.java b/stub/src/main/java/com/topjohnwu/magisk/DelegateApplication.java index 0b390571e..817d4da40 100644 --- a/stub/src/main/java/com/topjohnwu/magisk/DelegateApplication.java +++ b/stub/src/main/java/com/topjohnwu/magisk/DelegateApplication.java @@ -9,7 +9,6 @@ import android.content.res.Configuration; import android.os.Build; import android.util.Log; -import com.topjohnwu.magisk.utils.DynAPK; import com.topjohnwu.magisk.utils.DynamicClassLoader; import java.io.File; diff --git a/stub/src/main/java/com/topjohnwu/magisk/Mapping.java b/stub/src/main/java/com/topjohnwu/magisk/Mapping.java index 0b15cfe0a..b069c145d 100644 --- a/stub/src/main/java/com/topjohnwu/magisk/Mapping.java +++ b/stub/src/main/java/com/topjohnwu/magisk/Mapping.java @@ -3,7 +3,7 @@ package com.topjohnwu.magisk; import java.util.HashMap; import java.util.Map; -import static com.topjohnwu.magisk.utils.DynAPK.*; +import static com.topjohnwu.magisk.DynAPK.*; class Mapping { private static Map map = new HashMap<>(); From 9d948f2c2ba418453be0113f7ef0e899b2889022 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Thu, 24 Oct 2019 12:23:03 -0400 Subject: [PATCH 47/61] Temporary disable verification when hiding app For some reason, Google Play Protect randomly blocks our self-signed repackaged Magisk Manager APKs. Since we are root, the sky is our limit, so yeah, disable package verification temporarily when installing patched APKs, LOLz Close #1979 --- .../main/java/com/topjohnwu/magisk/utils/PatchAPK.kt | 2 +- app/src/main/res/raw/utils.sh | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.kt b/app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.kt index 3c82b4642..16ae948db 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.kt +++ b/app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.kt @@ -103,7 +103,7 @@ object PatchAPK { // Install the application repack.setReadable(true, false) - if (!Shell.su("pm install $repack").exec().isSuccess) + if (!Shell.su("force_pm_install $repack").exec().isSuccess) return false Config.suManager = pkg diff --git a/app/src/main/res/raw/utils.sh b/app/src/main/res/raw/utils.sh index 136b6adf3..17603ea66 100644 --- a/app/src/main/res/raw/utils.sh +++ b/app/src/main/res/raw/utils.sh @@ -109,3 +109,13 @@ EOF touch hosts/auto_mount cd / } + +force_pm_install() { + local APK=$1 + local VERIFY=`settings get global package_verifier_enable` + [ "$VERIFY" -eq 1 ] && settings set global package_verifier_enable 0 + pm install -r $APK + local res=$? + [ "$VERIFY" -eq 1 ] && settings set global package_verifier_enable 1 + return $res +} From 97a691ce2f1e41025f3e5cc190b4bc0c96437ca4 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Thu, 24 Oct 2019 13:04:15 -0400 Subject: [PATCH 48/61] Improve keygen for signing repackaged manager --- .../java/com/topjohnwu/magisk/utils/Keygen.kt | 21 +++++++++++-------- .../com/topjohnwu/magisk/utils/PatchAPK.kt | 6 ++++-- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/Keygen.kt b/app/src/main/java/com/topjohnwu/magisk/utils/Keygen.kt index 6620f7a14..bdd2b7f4a 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Keygen.kt +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Keygen.kt @@ -33,10 +33,14 @@ private interface CertKeyProvider { } @Suppress("DEPRECATION") -object Keygen: CertKeyProvider { - private const val ALIAS = "magisk" - private val PASSWORD = "magisk".toCharArray() - private const val TESTKEY_CERT = "61ed377e85d386a8dfee6b864bd85b0bfaa5af81" +class Keygen: CertKeyProvider { + + companion object { + private const val ALIAS = "magisk" + private val PASSWORD = "magisk".toCharArray() + private const val TESTKEY_CERT = "61ed377e85d386a8dfee6b864bd85b0bfaa5af81" + private const val DNAME = "CN=Android, OU=Android, O=Google Inc., L=Mountain View, ST=California, C=US" + } private val start get() = Calendar.getInstance() private val end get() = Calendar.getInstance().apply { @@ -48,7 +52,7 @@ object Keygen: CertKeyProvider { private val provider: CertKeyProvider - class KeyStoreProvider : CertKeyProvider { + inner class KeyStoreProvider : CertKeyProvider { private val ks by lazy { init() } override val cert by lazy { ks.getCertificate(ALIAS) as X509Certificate } override val key by lazy { ks.getKey(ALIAS, PASSWORD) as PrivateKey } @@ -113,9 +117,9 @@ object Keygen: CertKeyProvider { // Generate new private key and certificate val kp = KeyPairGenerator.getInstance("RSA").apply { initialize(2048) }.genKeyPair() - val dn = X500Name("CN=Magisk") - val builder = JcaX509v3CertificateBuilder(dn, - BigInteger.valueOf(start.timeInMillis), start.time, end.time, dn, kp.public) + val dname = X500Name(DNAME) + val builder = JcaX509v3CertificateBuilder(dname, + BigInteger.valueOf(start.timeInMillis), start.time, end.time, dname, kp.public) val signer = JcaContentSignerBuilder("SHA256WithRSA").build(kp.private) val cert = JcaX509CertificateConverter().getCertificate(builder.build(signer)) @@ -129,5 +133,4 @@ object Keygen: CertKeyProvider { return ks } - } diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.kt b/app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.kt index 16ae948db..fa1cf6aa2 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.kt +++ b/app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.kt @@ -94,9 +94,10 @@ object PatchAPK { context.packageCodePath } - // Generate a new app with random package name + // Generate a new random package name and signature val repack = File(context.cacheDir, "patched.apk") val pkg = genPackageName("com.", BuildConfig.APPLICATION_ID.length) + Config.keyStoreRaw = "" if (!patch(src, repack.path, pkg, label)) return false @@ -127,7 +128,8 @@ object PatchAPK { // Write apk changes jar.getOutputStream(je).write(xml) - SignAPK.sign(Keygen.cert, Keygen.key, jar, FileOutputStream(out).buffered()) + val keys = Keygen() + SignAPK.sign(keys.cert, keys.key, jar, FileOutputStream(out).buffered()) } catch (e: Exception) { Timber.e(e) return false From 815efa7791187fd83f7c2afe75824eac9179c519 Mon Sep 17 00:00:00 2001 From: vvb2060 Date: Thu, 24 Oct 2019 22:38:48 +0800 Subject: [PATCH 49/61] Update zh-rCN translation --- app/src/main/res/values-zh-rCN/strings.xml | 6 +++++- stub/src/main/res/values-zh-rCN/strings.xml | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 02a7bba2e..b5dc25982 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -96,7 +96,7 @@ 是否安装 %1$s ? 下载 重启 - 重启以应用设置 + 重启设备以应用设置 发布说明 仓库缓存已清除 @@ -150,6 +150,10 @@ 为广告屏蔽应用提供 Systemless hosts 支持 已添加 systemless hosts 模块 + 输入想要的应用名称 + 新名称 + 新应用将使用此名称 + 输入无效 应用和 ADB 仅应用 仅 ADB diff --git a/stub/src/main/res/values-zh-rCN/strings.xml b/stub/src/main/res/values-zh-rCN/strings.xml index 6a7ca6dd2..32d2d1d81 100644 --- a/stub/src/main/res/values-zh-rCN/strings.xml +++ b/stub/src/main/res/values-zh-rCN/strings.xml @@ -4,4 +4,5 @@ 需要升级到完整的 Magisk Manager 来完成安装。 现在下载? 请连接到互联网! 这是升级到完整 Magisk Manager 所必需的。 + 正在下载 From 588b3d14a382753a385ae86ea610b0eaeb3c5478 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Thu, 24 Oct 2019 15:23:57 -0400 Subject: [PATCH 50/61] Fix typo --- app/src/main/res/raw/utils.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/raw/utils.sh b/app/src/main/res/raw/utils.sh index 17603ea66..79ca207b4 100644 --- a/app/src/main/res/raw/utils.sh +++ b/app/src/main/res/raw/utils.sh @@ -113,9 +113,9 @@ EOF force_pm_install() { local APK=$1 local VERIFY=`settings get global package_verifier_enable` - [ "$VERIFY" -eq 1 ] && settings set global package_verifier_enable 0 + [ "$VERIFY" -eq 1 ] && settings put global package_verifier_enable 0 pm install -r $APK local res=$? - [ "$VERIFY" -eq 1 ] && settings set global package_verifier_enable 1 + [ "$VERIFY" -eq 1 ] && settings put global package_verifier_enable 1 return $res } From 626507093a399f90009cf175d372a88ab8d1a028 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sat, 26 Oct 2019 15:37:12 -0400 Subject: [PATCH 51/61] Don't need to wrap another layer of context --- app/src/main/java/a/w.java | 3 +- .../main/java/com/topjohnwu/magisk/Hacks.kt | 45 ++++++++++--------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/a/w.java b/app/src/main/java/a/w.java index f1307a025..f852a8968 100644 --- a/app/src/main/java/a/w.java +++ b/app/src/main/java/a/w.java @@ -6,7 +6,6 @@ import androidx.annotation.NonNull; import androidx.work.Worker; import androidx.work.WorkerParameters; -import com.topjohnwu.magisk.HacksKt; import com.topjohnwu.magisk.base.DelegateWorker; import java.lang.reflect.ParameterizedType; @@ -19,7 +18,7 @@ public abstract class w extends Worker { @SuppressWarnings("unchecked") w(@NonNull Context context, @NonNull WorkerParameters workerParams) { - super(HacksKt.wrap(context, false), workerParams); + super(context, workerParams); try { base = ((Class) ((ParameterizedType) getClass().getGenericSuperclass()) .getActualTypeArguments()[0]).newInstance(); diff --git a/app/src/main/java/com/topjohnwu/magisk/Hacks.kt b/app/src/main/java/com/topjohnwu/magisk/Hacks.kt index 52926eb77..f0b2380ab 100644 --- a/app/src/main/java/com/topjohnwu/magisk/Hacks.kt +++ b/app/src/main/java/com/topjohnwu/magisk/Hacks.kt @@ -165,35 +165,36 @@ private class JobSchedulerWrapper(private val base: JobScheduler) : JobScheduler return base.getPendingJob(jobId) } - fun JobInfo.patch(): JobInfo { + private fun JobInfo.patch(): JobInfo { // We need to patch the component of JobInfo to access WorkManager SystemJobService val name = service.className - val component = ComponentName(service.packageName, Info.stub?.componentMap?.get(name) - ?: name) + val component = ComponentName( + service.packageName, + Info.stub!!.componentMap[name] ?: name) // Clone the JobInfo except component val builder = JobInfo.Builder(id, component) - .setExtras(extras) - .setTransientExtras(transientExtras) - .setClipData(clipData, clipGrantFlags) - .setRequiredNetwork(requiredNetwork) - .setEstimatedNetworkBytes(estimatedNetworkDownloadBytes, estimatedNetworkUploadBytes) - .setRequiresCharging(isRequireCharging) - .setRequiresDeviceIdle(isRequireDeviceIdle) - .setRequiresBatteryNotLow(isRequireBatteryNotLow) - .setRequiresStorageNotLow(isRequireStorageNotLow) - .also { - triggerContentUris?.let { uris -> - for (uri in uris) - it.addTriggerContentUri(uri) - } + .setExtras(extras) + .setTransientExtras(transientExtras) + .setClipData(clipData, clipGrantFlags) + .setRequiredNetwork(requiredNetwork) + .setEstimatedNetworkBytes(estimatedNetworkDownloadBytes, estimatedNetworkUploadBytes) + .setRequiresCharging(isRequireCharging) + .setRequiresDeviceIdle(isRequireDeviceIdle) + .setRequiresBatteryNotLow(isRequireBatteryNotLow) + .setRequiresStorageNotLow(isRequireStorageNotLow) + .also { + triggerContentUris?.let { uris -> + for (uri in uris) + it.addTriggerContentUri(uri) } - .setTriggerContentUpdateDelay(triggerContentUpdateDelay) - .setTriggerContentMaxDelay(triggerContentMaxDelay) - .setImportantWhileForeground(isImportantWhileForeground) - .setPrefetch(isPrefetch) - .setPersisted(isPersisted) + } + .setTriggerContentUpdateDelay(triggerContentUpdateDelay) + .setTriggerContentMaxDelay(triggerContentMaxDelay) + .setImportantWhileForeground(isImportantWhileForeground) + .setPrefetch(isPrefetch) + .setPersisted(isPersisted) if (isPeriodic) { builder.setPeriodic(intervalMillis, flexMillis) From 3c1db7d2f75798dd6182126f0cdf5db8c638a19d Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sat, 26 Oct 2019 17:12:35 -0400 Subject: [PATCH 52/61] Fix some A/B devices unable to boot into recovery Some newer recovery ramdisk no longer have /sbin/recovery. Add /system/bin/recovery as an additional indication for recovery. Close #1920 --- native/jni/init/init.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/native/jni/init/init.cpp b/native/jni/init/init.cpp index c95b29fdb..c1b56dd9e 100644 --- a/native/jni/init/init.cpp +++ b/native/jni/init/init.cpp @@ -215,7 +215,7 @@ int main(int argc, char *argv[]) { init = make_unique(argv, &cmd); } else { decompress_ramdisk(); - if (access("/sbin/recovery", F_OK) == 0) + if (access("/sbin/recovery", F_OK) == 0 || access("/system/bin/recovery", F_OK) == 0) init = make_unique(argv, &cmd); else if (access("/apex", F_OK) == 0) init = make_unique(argv, &cmd); From 19a769c12e2b9d92680849d9f1be82ce258624c2 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sat, 26 Oct 2019 19:02:11 -0400 Subject: [PATCH 53/61] Update dependencies --- app/build.gradle | 11 ++++++----- app/src/main/res/layout/activity_main_content.xml | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 0b8281060..e36d27826 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -75,7 +75,7 @@ dependencies { implementation "${bindingAdapter}:${vBAdapt}" implementation "${bindingAdapter}-recyclerview:${vBAdapt}" - def vMarkwon = '4.1.1' + def vMarkwon = '4.1.2' implementation "io.noties.markwon:core:${vMarkwon}" implementation "io.noties.markwon:html:${vMarkwon}" implementation "io.noties.markwon:image:${vMarkwon}" @@ -112,7 +112,7 @@ dependencies { replacedBy('com.github.topjohnwu:room-runtime') } } - def vRoom = "2.2.0" + def vRoom = "2.2.1" implementation "com.github.topjohnwu:room-runtime:${vRoom}" kapt "androidx.room:room-compiler:${vRoom}" @@ -123,11 +123,12 @@ dependencies { implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0-alpha03' implementation 'androidx.preference:preference:1.1.0' - implementation 'androidx.recyclerview:recyclerview:1.0.0' + implementation 'androidx.recyclerview:recyclerview:1.1.0-rc01' + implementation 'androidx.fragment:fragment-ktx:1.2.0-rc01' implementation 'androidx.cardview:cardview:1.0.0' implementation 'androidx.work:work-runtime:2.2.0' - implementation 'androidx.transition:transition:1.2.0' + implementation 'androidx.transition:transition:1.3.0-rc01' implementation 'androidx.multidex:multidex:2.0.1' implementation 'androidx.core:core-ktx:1.1.0' - implementation 'com.google.android.material:material:1.1.0-beta01' + implementation 'com.google.android.material:material:1.2.0-alpha01' } diff --git a/app/src/main/res/layout/activity_main_content.xml b/app/src/main/res/layout/activity_main_content.xml index b2b8363df..ab5775c0d 100644 --- a/app/src/main/res/layout/activity_main_content.xml +++ b/app/src/main/res/layout/activity_main_content.xml @@ -32,7 +32,7 @@ - Date: Sun, 27 Oct 2019 02:03:37 +0300 Subject: [PATCH 54/61] Update Ukrainian translation --- app/src/main/res/values-uk/strings.xml | 10 +++++++--- stub/src/main/res/values-uk/strings.xml | 2 ++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 017bd043a..2a3d700fc 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -109,8 +109,8 @@ Не вдалося приховати Magisk Manager. Не знайдено програм для відкриття посилання. Попередження - Видалення виконано - Відновити образи + Повне видалення + Відновити розділи Відновлення… Відновлення завершено! Немає резервної копії оригінального boot образу @@ -143,13 +143,17 @@ Бета реліз Власний Вставте власний URL - Режим ядра Magisk + Режим Magisk Core Увімкнути тільки можливості ядра. MagiskSU i Magisk Hide залишуться увімкненими, проте ніякі модулі не будуть завантажені. Приховати Magisk від різних форм виявлень. Позасистемні хости Підтримка позасистемних хостів для програм блокування реклами. Додано модуль позасистемних хостів + Введіть бажане ім\'я застосунку + Нове ім\'я + Застосунок буде перезібрано з цим ім\'ям + Неправильний формат Програми і ADB Програми ADB diff --git a/stub/src/main/res/values-uk/strings.xml b/stub/src/main/res/values-uk/strings.xml index 3d6f7ed57..d5e7bd16f 100644 --- a/stub/src/main/res/values-uk/strings.xml +++ b/stub/src/main/res/values-uk/strings.xml @@ -1,7 +1,9 @@ + Ні, дякую Так OK Оновіть Magisk Manager для завершення встановлення. Завантажити і встановити? Будь ласка, підключіться до Інтернету! Потрібно оновити Magisk Manager. + Завантаження From 9628700a2fd9d9a8daeead3bd029b6e2e94984ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mevl=C3=BCt=20TOP=C3=87U?= Date: Fri, 25 Oct 2019 15:24:17 +0300 Subject: [PATCH 55/61] Update Turkish language Hi, Merge please Thanks --- app/src/main/res/values-tr/strings.xml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 12046de21..0a9d2d273 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -150,6 +150,10 @@ Reklam engelleme uygulamaları için sistemsiz host desteği Sistemsiz host modülü eklendi + İstediğiniz uygulama adını yazın + Yeni ad + Uygulama bu ad ile yeniden paketlenecek + Geçersiz format Uygulamalar ve ADB Sadece uygulamalar Sadece ADB @@ -188,7 +192,7 @@ Her bir kök oturumunun kendi izole ad alanı olacaktır Android 8.0 ve üzerinde desteklenmiyor Parmak izi ayarlanmadı veya cihaz desteği yok - Klasör oluşturma hatası. Depolama kök dizininden erişilebilir olmalı ve bir dosya olmamalıdır. + Klasör oluşturma hatası. Depolama kök dizininden erişilebilir olmalı ve bir dosya olmamalıdır. Yetkili Kullanıcı İsteği From 7693024c299d4f4ae264637579bf000c41a440b1 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sat, 26 Oct 2019 19:23:57 -0400 Subject: [PATCH 56/61] Replace general resources with platform --- .../java/com/topjohnwu/magisk/ui/SplashActivity.kt | 2 +- .../com/topjohnwu/magisk/ui/home/HomeFragment.kt | 4 ++-- .../topjohnwu/magisk/ui/settings/SettingsFragment.kt | 12 ++++++------ .../magisk/ui/superuser/SuperuserViewModel.kt | 6 +++--- .../java/com/topjohnwu/magisk/view/MarkDownWindow.kt | 2 +- .../topjohnwu/magisk/view/dialogs/EnvFixDialog.kt | 4 ++-- .../magisk/view/dialogs/FingerprintAuthDialog.kt | 2 +- .../magisk/view/dialogs/InstallMethodDialog.kt | 4 ++-- app/src/main/res/values-ar/strings.xml | 5 ----- app/src/main/res/values-az/strings.xml | 5 ----- app/src/main/res/values-bg/strings.xml | 5 ----- app/src/main/res/values-ca/strings.xml | 5 ----- app/src/main/res/values-cs/strings.xml | 5 ----- app/src/main/res/values-de/strings.xml | 5 ----- app/src/main/res/values-el/strings.xml | 5 ----- app/src/main/res/values-es/strings.xml | 5 ----- app/src/main/res/values-et/strings.xml | 5 ----- app/src/main/res/values-fr/strings.xml | 5 ----- app/src/main/res/values-hi/strings.xml | 5 ----- app/src/main/res/values-hr/strings.xml | 4 ---- app/src/main/res/values-in/strings.xml | 5 ----- app/src/main/res/values-it/strings.xml | 5 ----- app/src/main/res/values-ja/strings.xml | 5 ----- app/src/main/res/values-ko/strings.xml | 5 ----- app/src/main/res/values-lt/strings.xml | 5 ----- app/src/main/res/values-mk/strings.xml | 5 ----- app/src/main/res/values-nb/strings.xml | 5 ----- app/src/main/res/values-nl/strings.xml | 5 ----- app/src/main/res/values-pl/strings.xml | 5 ----- app/src/main/res/values-pt-rBR/strings.xml | 5 ----- app/src/main/res/values-pt-rPT/strings.xml | 4 ---- app/src/main/res/values-ro/strings.xml | 5 ----- app/src/main/res/values-ru/strings.xml | 5 ----- app/src/main/res/values-sk/strings.xml | 5 ----- app/src/main/res/values-sr/strings.xml | 4 ---- app/src/main/res/values-sv/strings.xml | 4 ---- app/src/main/res/values-th/strings.xml | 5 ----- app/src/main/res/values-tr/strings.xml | 5 ----- app/src/main/res/values-uk/strings.xml | 5 ----- app/src/main/res/values-vi/strings.xml | 5 ----- app/src/main/res/values-zh-rCN/strings.xml | 5 ----- app/src/main/res/values-zh-rTW/strings.xml | 5 ----- app/src/main/res/values/strings.xml | 5 ----- .../java/com/topjohnwu/magisk/DownloadActivity.java | 6 +++--- stub/src/main/res/values-ar/strings.xml | 6 +----- stub/src/main/res/values-az/strings.xml | 3 --- stub/src/main/res/values-bg/strings.xml | 3 --- stub/src/main/res/values-ca/strings.xml | 5 +---- stub/src/main/res/values-cs/strings.xml | 6 +----- stub/src/main/res/values-de/strings.xml | 3 --- stub/src/main/res/values-el/strings.xml | 6 +----- stub/src/main/res/values-es/strings.xml | 3 --- stub/src/main/res/values-et/strings.xml | 5 +---- stub/src/main/res/values-fr/strings.xml | 3 --- stub/src/main/res/values-hi/strings.xml | 3 --- stub/src/main/res/values-hr/strings.xml | 6 +----- stub/src/main/res/values-in/strings.xml | 3 --- stub/src/main/res/values-it/strings.xml | 3 --- stub/src/main/res/values-ja/strings.xml | 6 +----- stub/src/main/res/values-ko/strings.xml | 3 --- stub/src/main/res/values-lt/strings.xml | 3 --- stub/src/main/res/values-mk/strings.xml | 3 --- stub/src/main/res/values-nb/strings.xml | 3 --- stub/src/main/res/values-nl/strings.xml | 6 +----- stub/src/main/res/values-pl/strings.xml | 3 --- stub/src/main/res/values-pt-rBR/strings.xml | 6 +----- stub/src/main/res/values-pt-rPT/strings.xml | 6 +----- stub/src/main/res/values-ro/strings.xml | 3 --- stub/src/main/res/values-ru/strings.xml | 3 --- stub/src/main/res/values-sk/strings.xml | 3 --- stub/src/main/res/values-sr/strings.xml | 6 +----- stub/src/main/res/values-sv/strings.xml | 6 +----- stub/src/main/res/values-th/strings.xml | 6 +----- stub/src/main/res/values-tr/strings.xml | 3 --- stub/src/main/res/values-uk/strings.xml | 3 --- stub/src/main/res/values-vi/strings.xml | 6 +----- stub/src/main/res/values-zh-rCN/strings.xml | 3 --- stub/src/main/res/values-zh-rTW/strings.xml | 3 --- stub/src/main/res/values/strings.xml | 3 --- 79 files changed, 35 insertions(+), 323 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/SplashActivity.kt b/app/src/main/java/com/topjohnwu/magisk/ui/SplashActivity.kt index f0316b7fe..879d0ae65 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/SplashActivity.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/SplashActivity.kt @@ -25,7 +25,7 @@ open class SplashActivity : Activity() { AlertDialog.Builder(this) .setTitle(R.string.unsupport_magisk_title) .setMessage(R.string.unsupport_magisk_message) - .setNegativeButton(R.string.ok, null) + .setNegativeButton(android.R.string.ok, null) .setOnDismissListener { finish() } .show() } else { diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeFragment.kt b/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeFragment.kt index 2d2b2161c..d9cd0df8b 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeFragment.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeFragment.kt @@ -87,8 +87,8 @@ class HomeFragment : BaseFragment(), .setTitle(R.string.proprietary_title) .setMessage(R.string.proprietary_notice) .setCancelable(false) - .setPositiveButton(R.string.yes) { _, _ -> download() } - .setNegativeButton(R.string.no_thanks) { _, _ -> viewModel.finishSafetyNetCheck(-2) } + .setPositiveButton(android.R.string.yes) { _, _ -> download() } + .setNegativeButton(android.R.string.no) { _, _ -> viewModel.finishSafetyNetCheck(-2) } .show() } diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt b/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt index 10c1059cf..81fba3fff 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt @@ -295,8 +295,8 @@ class SettingsFragment : BasePreferenceFragment() { AlertDialog.Builder(requireActivity()) .setTitle(R.string.settings_update_custom) .setView(v) - .setPositiveButton(R.string.ok) { _, _ -> onSuccess(url.text.toString()) } - .setNegativeButton(R.string.close) { _, _ -> onCancel() } + .setPositiveButton(android.R.string.ok) { _, _ -> onSuccess(url.text.toString()) } + .setNegativeButton(android.R.string.cancel) { _, _ -> onCancel() } .setOnCancelListener { onCancel() } .show() } @@ -320,11 +320,11 @@ class SettingsFragment : BasePreferenceFragment() { AlertDialog.Builder(requireActivity()) .setTitle(R.string.settings_download_path_title) .setView(binding.root) - .setPositiveButton(R.string.ok) { _, _ -> + .setPositiveButton(android.R.string.ok) { _, _ -> Utils.ensureDownloadPath(data.text.value)?.let { onSuccess(data.text.value) } ?: Utils.toast(R.string.settings_download_path_error, Toast.LENGTH_SHORT) } - .setNegativeButton(R.string.close, null) + .setNegativeButton(android.R.string.cancel, null) .show() } @@ -339,12 +339,12 @@ class SettingsFragment : BasePreferenceFragment() { AlertDialog.Builder(requireActivity()) .setTitle(R.string.settings_app_name) .setView(view.root) - .setPositiveButton(R.string.ok) { _, _ -> + .setPositiveButton(android.R.string.ok) { _, _ -> if (view.dialogNameInput.error.isNullOrBlank()) { onSuccess(data.name.value) } } - .setNegativeButton(R.string.close, null) + .setNegativeButton(android.R.string.cancel, null) .show() } diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/superuser/SuperuserViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/superuser/SuperuserViewModel.kt index adbae5577..aa0bcfee4 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/superuser/SuperuserViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/superuser/SuperuserViewModel.kt @@ -84,8 +84,8 @@ class SuperuserViewModel( CustomAlertDialog(this) .setTitle(R.string.su_revoke_title) .setMessage(getString(R.string.su_revoke_msg, item.item.appName)) - .setPositiveButton(R.string.yes) { _, _ -> updateState() } - .setNegativeButton(R.string.no_thanks, null) + .setPositiveButton(android.R.string.yes) { _, _ -> updateState() } + .setNegativeButton(android.R.string.no, null) .setCancelable(true) .show() } @@ -144,4 +144,4 @@ class SuperuserViewModel( private fun deletePolicy(policy: MagiskPolicy) = policyDB.delete(policy.uid).andThen(Single.just(policy)) -} \ No newline at end of file +} diff --git a/app/src/main/java/com/topjohnwu/magisk/view/MarkDownWindow.kt b/app/src/main/java/com/topjohnwu/magisk/view/MarkDownWindow.kt index 071913a63..d5b844b92 100644 --- a/app/src/main/java/com/topjohnwu/magisk/view/MarkDownWindow.kt +++ b/app/src/main/java/com/topjohnwu/magisk/view/MarkDownWindow.kt @@ -48,7 +48,7 @@ object MarkDownWindow : KoinComponent { AlertDialog.Builder(activity) .setTitle(title) .setView(mv) - .setNegativeButton(R.string.close) { dialog, _ -> dialog.dismiss() } + .setNegativeButton(android.R.string.cancel) { dialog, _ -> dialog.dismiss() } .show() } } diff --git a/app/src/main/java/com/topjohnwu/magisk/view/dialogs/EnvFixDialog.kt b/app/src/main/java/com/topjohnwu/magisk/view/dialogs/EnvFixDialog.kt index 8eb37107b..12d8b81a2 100644 --- a/app/src/main/java/com/topjohnwu/magisk/view/dialogs/EnvFixDialog.kt +++ b/app/src/main/java/com/topjohnwu/magisk/view/dialogs/EnvFixDialog.kt @@ -23,7 +23,7 @@ class EnvFixDialog(activity: Activity) : CustomAlertDialog(activity) { setTitle(R.string.env_fix_title) setMessage(R.string.env_fix_msg) setCancelable(true) - setPositiveButton(R.string.yes) { _, _ -> + setPositiveButton(android.R.string.yes) { _, _ -> val pd = ProgressDialog.show(activity, activity.getString(R.string.setup_title), activity.getString(R.string.setup_msg)) @@ -46,6 +46,6 @@ class EnvFixDialog(activity: Activity) : CustomAlertDialog(activity) { } }.exec() } - setNegativeButton(R.string.no_thanks, null) + setNegativeButton(android.R.string.no, null) } } diff --git a/app/src/main/java/com/topjohnwu/magisk/view/dialogs/FingerprintAuthDialog.kt b/app/src/main/java/com/topjohnwu/magisk/view/dialogs/FingerprintAuthDialog.kt index e11b5a6bf..a27d599de 100644 --- a/app/src/main/java/com/topjohnwu/magisk/view/dialogs/FingerprintAuthDialog.kt +++ b/app/src/main/java/com/topjohnwu/magisk/view/dialogs/FingerprintAuthDialog.kt @@ -31,7 +31,7 @@ class FingerprintAuthDialog(activity: Activity, private val callback: () -> Unit binding.message.compoundDrawablePadding = Utils.dpInPx(20) binding.message.gravity = Gravity.CENTER setMessage(R.string.auth_fingerprint) - setNegativeButton(R.string.close) { _, _ -> + setNegativeButton(android.R.string.cancel) { _, _ -> helper?.cancel() failureCallback?.invoke() } diff --git a/app/src/main/java/com/topjohnwu/magisk/view/dialogs/InstallMethodDialog.kt b/app/src/main/java/com/topjohnwu/magisk/view/dialogs/InstallMethodDialog.kt index 4d0e0c09a..6e1e812c1 100644 --- a/app/src/main/java/com/topjohnwu/magisk/view/dialogs/InstallMethodDialog.kt +++ b/app/src/main/java/com/topjohnwu/magisk/view/dialogs/InstallMethodDialog.kt @@ -62,12 +62,12 @@ internal class InstallMethodDialog(activity: BaseActivity<*, *>, options: List + .setPositiveButton(android.R.string.yes) { _, _ -> DownloadService(activity) { subject = DownloadSubject.Magisk(Configuration.Flash.Secondary) } } - .setNegativeButton(R.string.no_thanks, null) + .setNegativeButton(android.R.string.no, null) .show() } } diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 1ed6f8f6e..a7be4c183 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -89,10 +89,6 @@ إعادة التشغيل خلال خمس ثواني… - لا شكراً - نعم - موافق - إغلاق تثبيت %1$s هل تريد تثبيت %1$s ? التنزيل @@ -187,7 +183,6 @@ تستخدم كافة جلسات العمل للروت مساحة الاسم ذات التركيب العامة سترث جلسات العمل للروت مساحة الأسماء لطالبيها سيكون لكل جلسة عمل للروت مساحة اسم معزولة خاصة بها - لا يدعم إصدار الأندرويد +8.0 لم تُعين بصمات الأصابع أو لا يوجد قارئ بصمات خطأ عند إنشاء مجلد. عليه أن يكون سهلا الوصول إليه من خلال مجلد التخزين للروت و ألا يكون ملفا. diff --git a/app/src/main/res/values-az/strings.xml b/app/src/main/res/values-az/strings.xml index 4fdb0b851..d8ae0ac98 100644 --- a/app/src/main/res/values-az/strings.xml +++ b/app/src/main/res/values-az/strings.xml @@ -75,10 +75,6 @@ Magisk Manager Yeniləməsi Var! - Yox, sağolun - Bəli - OK - Qapat %1$s faylını yüklə %1$s faylını indi yükləmək istəyirsiniz? Yüklə @@ -173,7 +169,6 @@ Bütün root sessyaları qlobal qoşma namespace\'dən istifadə edir. Root sessyaları soruşulan namespace\'ləri birindən digərinə keçirəcək. Hər bir root sessyasının ayrılmış namespace\'i olacaq. - Android 8.0+\'da dəstəklənmir. Barmaq izi təyin edilməyib ya da dəstəklənmir. diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml index 002f1a957..10c8b3378 100644 --- a/app/src/main/res/values-bg/strings.xml +++ b/app/src/main/res/values-bg/strings.xml @@ -61,10 +61,6 @@ Списък с промени - Не, благодаря. - Да - OK - Затваряне Инсталиране на %1$s Желаете ли да инсталирате %1$s сега? Изтегляне @@ -165,7 +161,6 @@ Всички сесии с руут достъп използват глобалното именно пространство. Всички сесии с руут достъп наследяват именното пространство на запитващото приложение. Всички сесии с руут достъп имат собствени именни пространства. - Не поддържа Android 8.0+. Не са добавени пръстови отпечатъци или устройството не поддържа тази функция. diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index d3076996b..02b5cc495 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -87,10 +87,6 @@ Reinici en 5 segons… - No, gràcies - - Ok - Tancar Instal·lar %1$s Vols instal·lar %1$s ara? Baixar @@ -185,7 +181,6 @@ Totes les sessions d\'arrel utilitzen el suport Namespace Global Les sessions d\'arrel heretaran les peticiones Namespace Totes les sessions d\'arrel tindran la seva pròpia Namespace - No es compatible amb Android 8.0+ No s\'han establert empremtes dactilars o no existeix el suport del dispositiu Error al crear la carpeta. El directori ha de ser accesible desde el directori arrel i no pot ser un arxiu. diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 1059e8bc5..7f9d1abfc 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -84,10 +84,6 @@ Restartování za 5 sekund… - Ne, díky - Ano - OK - Zavřít Instalovat %1$s Chcete nyní nainstalovat %1$s? Stáhnout @@ -178,7 +174,6 @@ Všechny relace root používají globální připojení jmenného prostoru. Kořenové relace dědí jmenný prostor žadatele. Každá relace root bude mít svůj vlastní izolovaný jmenný prostor. - Nepodporuje Android 8.0+. Nebyly nastaveny žádné otisky prstů ani žádná podpora zařízení. diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index e2eb35a26..4a954d4c2 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -84,10 +84,6 @@ Neustart in 5 Sekunden… - Nein danke - Ja - OK - Schließen Installiere %1$s Möchtest du %1$s installieren? Herunterladen @@ -180,7 +176,6 @@ Alle Root-Sitzungen benutzen den global angelegten Namespace Root-Sitzungen erben den Namespace des Abfragenden Jede Root-Sitzung hat ihren isolierten Namespace - Android 8.0+ wird nicht unterstützt Keine Fingerabdrücke gespeichert oder keine Geräteunterstützung diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index b81fb8d5f..38311bb25 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -62,10 +62,6 @@ Καταγραφή αλλαγών εφαρμογής - Όχι ευχαριστώ - Ναι - OK - Κλείσιμο Εγκατάσταση %1$s Θέλετε να εγκαταστήσετε το %1$s τώρα; Λήψη @@ -147,7 +143,6 @@ Όλες οι συνεδρίες root χρησιμοποιούν τον καθολικό χώρο oνομάτων προσάρτησης Οι συνεδρίες root θα κληρονομούν το χώρο ονομάτων του αιτούντα τους Κάθε συνεδρία root θα έχει το δικό της απομονωμένο χώρο ονομάτων - Δεν υποστηρίζεται Android 8.0+ Αίτημα υπερχρήστη diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 8788c1c55..547e88569 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -86,10 +86,6 @@ Reiniciando en 5 segundos… - No gracias - - Aceptar - Cerrar Instalar %1$s ¿Quieres instalar %1$s ahora? Descargar @@ -183,7 +179,6 @@ Todas las sesiones de root utilizan el soporte Global Namespace Las sesiones de root heredarán las peticiones Namespace Cada sesión root tendrá su propia Namespace - No es compatible con Android 8.0+ No se establecieron huellas dactilares o no existe soporte del dispositivo Error al crear la carpeta. Debe ser accesible desde el directorio raíz de almacenamiento y no debe ser un archivo. diff --git a/app/src/main/res/values-et/strings.xml b/app/src/main/res/values-et/strings.xml index 403d400bd..4effbee81 100644 --- a/app/src/main/res/values-et/strings.xml +++ b/app/src/main/res/values-et/strings.xml @@ -88,10 +88,6 @@ Taaskäivitamine 5 sekundi pärast… - Tänan ei - Jah - OK - Sulge Installi %1$s Kas soovid kohe installida %1$s? Allalaadimine @@ -186,7 +182,6 @@ Kõik juurkasutaja sessioonid kasutavad globaalset monteerimise nimeruumi. Juurkasutaja sessioonid võtavad üle selle taotleja nimeruumi. Iga juurkasutaja sessioon saab oma isoleeritud nimeruumi. - Ei toeta Androidi versiooni 8.0+. Sõrmejälgi pole määratud või seade pole toetatud. Faili loomisel esines viga. See peab olema ligipääsetav mäluruumi juurkaustast ning ei tohi olla fail. diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index dfad5ac62..2fcb32888 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -88,10 +88,6 @@ Redémarrage dans 5 secondes… - Non merci - Oui - OK - Fermer Installer %1$s Voulez‐vous installer %1$s maintenant ? Télécharger @@ -186,7 +182,6 @@ Toutes les sessions super‐utilisateur utilisent l’espace de noms global du montage. Les sessions super‐utilisateur hériteront de l’espace de noms de leur demandeur. Chaque session super‐utilisateur aura son propre espace de noms isolé. - Android 8.0 et supérieurs ne sont pas pris en charge. Aucune empreinte digitale n’a été définie ou le lecteur d’empreinte n’est pas pris en charge. Erreur lors de la création du dossier. Il doit être accessible depuis le répertoire racine du stockage et ne doit pas être un fichier. diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index a7818a6ab..759d5dd33 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -88,10 +88,6 @@ 5 सेकंड में रिबूट हो रहा है … - नहीं शुक्रिया - हां - ठीक - बंद करें %1$s को स्थापित करें क्या आप %1$s को स्थापित करना चाहते हैं ? डाउनलोड @@ -186,7 +182,6 @@ सभी रूट सत्र वैश्विक माउंट नेमस्पेस का उपयोग करते हैं. रूट सत्रों को उनके अनुरोधकर्ताओं के नेमस्पेस विरासत में मिलेंगे. प्रत्येक रूट सत्र का अपना अलग नेमस्पेस होगा. - Android 8.0+ का समर्थन नहीं करता है. कोई फ़िंगरप्रिंट नहीं सेट किया गया या डिवाइस का समर्थन नहीं है. फोल्डर बनाने में त्रुटि. यह स्टोरेज रूट डायरेक्टरी से एक्सेस होना चाहिए और फाइल नहीं होना चाहिए. diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml index d67260c55..964a0d98a 100644 --- a/app/src/main/res/values-hr/strings.xml +++ b/app/src/main/res/values-hr/strings.xml @@ -55,10 +55,6 @@ Popis izmjena aplikacije - Ne hvala - Da - OK - Zatvori Instaliraj %1$s Da li želite instalirati %1$s sada? Preuzmi diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index fc32437ae..361e0e09f 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -86,10 +86,6 @@ Me-reboot dalam 5 detik… - Tidak, terima kasih - Ya - OK - Tutup Pasang %1$s Apakah Anda ingin memasang %1$s sekarang? Unduh @@ -184,7 +180,6 @@ Semua sesi root menggunakan mount ruang nama global. Sesi root akan mewarisi ruang nama peminta mereka. Setiap sesi root akan memiliki ruang nama tersendiri. - Tidak mendukung Android 8.0+. Tidak ada sidik jari diatur atau tidak ada dukungan perangkat. Kesalahan membuat folder. Folder harus dapat diakses dari direktori penyimpanan root dan bukan merupakan file. diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index add53ea18..7d20c8d46 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -86,10 +86,6 @@ Riavvio fra 5 secondi… - No, grazie - - OK - Chiudi Installazione di %1$s Vuoi installare %1$s? Download @@ -184,7 +180,6 @@ Tutte le sessioni di root erediteranno il namespace globale. Le sessioni di root erediteranno il namespace del loro richiedente. Ogni sessione di root avrà il suo namespace isolato. - Non è supportato da Android 8.0+. Non è presente alcuna impronta o il dispositivo non è supportato. Errore durante la creazione della cartella. Deve essere accessibile dalla radice della memoria di archiviazione e non essere un file. diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 952f2c56a..61faf6ea1 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -72,10 +72,6 @@ Magisk Managerの更新があります! - いいえ - はい - OK - 閉じる %1$s をインストール %1$s をインストールしますか? ダウンロード @@ -172,7 +168,6 @@ すべてのrootセッションがグローバル名前空間を使用します rootセッションはリクエスト者の名前空間を継承します rootセッション毎に分離された名前空間を使用します - Android 8.0以降では対応していません 指紋が登録されていないか、お使いの端末でサポートされていません。 diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index c3f376cdb..395760601 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -83,10 +83,6 @@ 원시 이미지 (*.img) 또는 오딘 tar 파일 (*.tar) 선택 - 아니오, 괜찮습니다 - - 확인 - 닫기 %1$s 설치 정말 %1$s을(를) 설치하시겠습니까? 다운로드 @@ -179,7 +175,6 @@ 모든 루트 세션이 전역 마운트 이름공간을 사용합니다. 루트 세션은 요청자의 이름공간을 상속합니다. 각각의 루트 세션은 자신만의 독립된 이름공간을 사용합니다. - 안드로이드 8.0 이상 버전에서 사용할 수 없습니다. 지문이 등록되지 않았거나 기기가 지문 인식을 지원하지 않습니다. diff --git a/app/src/main/res/values-lt/strings.xml b/app/src/main/res/values-lt/strings.xml index 915783032..4484d78a6 100644 --- a/app/src/main/res/values-lt/strings.xml +++ b/app/src/main/res/values-lt/strings.xml @@ -61,10 +61,6 @@ Pakeitimų sąrašas - Ačiū, nereikia - Taip - Gerai - Uždaryti Instaliuoti %1$s Ar jūs norite instaliuoti %1$s? Atsisiųsti @@ -159,7 +155,6 @@ Visos root sesijos naudoja globalią vardų sritį Root sesijos paveldi jos išprašytojo/s vardų sritį Kiekviena root sesija turi savo izoliuotą vardų sritį - Įrenginiai su Android 8.0+ nepalaiko šio nustatymo Jūsų įrenginyje nebuvo surasta pirštų antspaudų arba jūsų įrenginys neturi pirštų antspaudų skaitytuvo diff --git a/app/src/main/res/values-mk/strings.xml b/app/src/main/res/values-mk/strings.xml index ca2e43e31..c891083a7 100644 --- a/app/src/main/res/values-mk/strings.xml +++ b/app/src/main/res/values-mk/strings.xml @@ -84,10 +84,6 @@ Рестартирање за 5 секунди… - Не, благодарам - Да - ОК - Затвори Инсталирај %1$s Дали сакате да го инсталирате %1$s сега? Преземи @@ -178,7 +174,6 @@ Сите рут сесии го користат глобалниот именски простор. Рут сесиите ќе го наследат именскиот простор на нивниот барател. Секоја рут сесија ќе има свој изолиран именски простор. - Не е поддржано на Android 8.0+. Нема регистрирано отпечатоци од прсти или уредот не ја поддржува оваа функција. diff --git a/app/src/main/res/values-nb/strings.xml b/app/src/main/res/values-nb/strings.xml index f5fd61aad..c8d884ccf 100644 --- a/app/src/main/res/values-nb/strings.xml +++ b/app/src/main/res/values-nb/strings.xml @@ -69,10 +69,6 @@ En Magisk Manager-oppdatering er tilgjengelig! - Nei takk - Ja - OK - Lukk Installer %1$s Vil du installere %1$s nå? Last ned @@ -169,7 +165,6 @@ Alle root-økter benytter det altdekkende monteringsnavnefeltet. Root-økter vil arve forespørrerens navnefelt. Hver root-økt vil ha sitt eget isolerte navnefelt. - Støtter ikke Android ≥8.0. Ingen fingeravtrykk ble gitt, eller så støttes det ikke av enheten. diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 96913c937..2d00fb929 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -62,10 +62,6 @@ App\'s changelog - Nee bedankt - Ja - Oké - Sluiten %1$s installeren Zeker weten %1$s installeren? Downloaden @@ -154,7 +150,6 @@ Alle rootsessies gebruiken de globale naamruimte Rootsessies verkrijgen de verzoeker\'s naamruimte Iedere rootsessie heeft een eigen geïsoleerde naamruimte - Ondersteunt geen Android 8.0+ Geen vingerafdrukken ingesteld, of geen apparaatondersteuning diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 44d0c23f7..a96a201e1 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -87,10 +87,6 @@ Ponowne uruchomienie za 5 sekund… - Nie dziękuję - Tak - OK - Zamknij Instaluj %1$s Czy chcesz zainstalować %1$s ? Pobierz @@ -185,7 +181,6 @@ Wszystkie sesje root za pomocą globalnej przestrzeni montowań nazw Sesje Root będzie dziedziczyć prośby i nazwy W każdej sesji root będzie miał własną odosobnioną nazwę - Brak wsparcia dla Androida 8.0+ Nie ustawiono żadnych odcisków palców lub brak obsługi urządzenia Błąd podczas tworzenia folderu. Musi być dostępny z głównego katalogu pamięci i nie może być plikiem. diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 5b64e423a..b69f2f4fe 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -63,10 +63,6 @@ Registro de mudanças - Não - Sim - OK - Fechar Instalar %1$s Instalar %1$s agora? Baixar @@ -156,7 +152,6 @@ Todas as sessões root usam montagem de espaço de nome global As sessões root herdarão espaço de nome de seu solicitante Cada sessão root terá seu próprio espaço de nome isolado - Não suporta Android 8.0+ Nenhuma impressão digital foi definida ou o dispostivo não tem suporte diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml index 7c4d4082d..0f3a0da64 100644 --- a/app/src/main/res/values-pt-rPT/strings.xml +++ b/app/src/main/res/values-pt-rPT/strings.xml @@ -53,10 +53,6 @@ Lista de alterações da aplicação - Não, Obrigado - Sim - OK - Fechar Instalar %1$s Deseja instalar%1$s agora? Transferir diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index 95f256e05..6e6a8e423 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -87,10 +87,6 @@ Repornire în 5 secunde… - Nu, mulțumesc - Da - Ok - Închide Instalează %1$s Vrei să instalezi acum %1$s? Descarcă @@ -185,7 +181,6 @@ Toate sesiunile de root folosesc spațiul de nume global. Sesiunile de root vor moșteni spațiul de nume al solicitantului. Fiecare sesiune de root va avea propriul spațiu de nume izolat. - Nu suportă Android 8.0+. Nu au fost setate amprente sau scannerul de amprentă lipsește. Eroare la crearea dosarului. Acesta trebuie să fie accesibil din directorul rădăcină al stocării și nu trebuie să fie un fișier. diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index d46e7b3ea..154e81018 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -88,10 +88,6 @@ Перезагрузка через 5 секунд… - Нет - Да - OK - Закрыть Установка %1$s Установить %1$s ? Скачать @@ -186,7 +182,6 @@ Сессии суперпользователя используют общее пространство имён Сессии суперпользователя наследуют пространство имён запрашивающего Сессии суперпользователя используют изолированные пространства имён - Не поддерживается в Android 8.0+ Не поддерживается устройством или не заданы отпечатки Ошибка создания папки. Она должна быть доступна из корневой директории хранилища и не должна быть файлом. diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml index 95d507eaa..9d62740bf 100644 --- a/app/src/main/res/values-sk/strings.xml +++ b/app/src/main/res/values-sk/strings.xml @@ -72,10 +72,6 @@ Je dostupná aktualizácia Magisk Manager! - Nie, ďakujem - Áno - OK - Zavrieť Nainštalovať %1$s Chcete teraz nainštalovať %1$s? Stiahnuť @@ -170,7 +166,6 @@ Všetky relácie root použijú globálne mount namespace Relácie root zdedia namespace od požadovateľa Každá relácia root bude mať vlastný izolovaný namespace - Nepodporuje Android 8.0+ Neboli odoslané žiadne odtlačky prsta alebo ich zariadenie nepodporuje diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index 6f5ba4c8d..337589fba 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -55,10 +55,6 @@ Дневник промена апликације - Не хвала - Да - ОК - Затвори Инсталирај %1$s Да ли желите да инсталирате %1$s? Преузми diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 309337b0c..2ce35d2a9 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -53,10 +53,6 @@ Ändringslogg - Nej tack - Ja - OK - Stäng Installera %1$s Vill du installera %1$s ? Ladda ner diff --git a/app/src/main/res/values-th/strings.xml b/app/src/main/res/values-th/strings.xml index d62cafddd..066df9c69 100644 --- a/app/src/main/res/values-th/strings.xml +++ b/app/src/main/res/values-th/strings.xml @@ -69,10 +69,6 @@ มีการอัพเดต Magisk Manager! - ไม่, ขอบคุณ - ใช่ - โอเค - ปิด ติดตั้ง %1$s ต้องการติดตั้ง %1$s ตอนนี้หรือไม่? ดาวน์โหลด @@ -169,7 +165,6 @@ All root sessions use the global mount namespace. Root sessions will inherit their requester\'s namespace. Each root session will have its own isolated namespace. - ไม่รองรับ Android 8.0 ขึ้นไป ไม่มีลายนิ้วมือหรืออุปกรณ์แสกน diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 0a9d2d273..bc574a0b8 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -88,10 +88,6 @@ 5 saniye içinde yeniden başlatılacak... - Hayır, teşekkürler - Evet - Tamam - Kapat %1$s yükle %1$s yüklensin mi? İndir @@ -190,7 +186,6 @@ Tüm kök oturumları genel bağlama ad alanını kullanır Kök oturumları, istekte bulunanın ad alanını devralır Her bir kök oturumunun kendi izole ad alanı olacaktır - Android 8.0 ve üzerinde desteklenmiyor Parmak izi ayarlanmadı veya cihaz desteği yok Klasör oluşturma hatası. Depolama kök dizininden erişilebilir olmalı ve bir dosya olmamalıdır. diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 2a3d700fc..4a3f86992 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -88,10 +88,6 @@ Перезавантаження через 5 секунд… - Ні, дякую - Так - OK - Закрити Встановити %1$s Бажаєте встановити %1$s ? Завантажити @@ -190,7 +186,6 @@ Всі сеанси Суперкористувача використовують глобальний простір імен. Сеанси Суперкористувача наслідують простір імен запитувача. Кожнен сеанс Суперкористувача має власний ізольований простір імен. - Не працює на Android 8.0+. Немає відбитків пальця або пристрій не підтримується. Помилка створення папки. Вона повинна бути доступна з кореневої директорії сховища і не повинна бути файлом. diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index 73ffc17c9..1b9cef3be 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -61,10 +61,6 @@ Nhật ký thay đổi của ứng dụng - Không, cảm ơn - - OK - Đóng Cài đặt %1$s Bạn muốn cài đặt %1$s ? Tải xuống @@ -162,7 +158,6 @@ Tất cả các phiên root sử dụng không gian tên gắn kết chung. Các phiên root sẽ kế thừa không gian tên của người yêu cầu. Mỗi phiên root sẽ có không gian tên riêng biệt. - Không hỗ trợ Android 8.0+. Không có dấu vân tay nào được thiết lập hoặc thiết bị không hỗ trợ. diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index b5dc25982..e52a41ad6 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -88,10 +88,6 @@ 5 秒后重启 - 不,谢谢 - - - 关闭 安装 %1$s 是否安装 %1$s ? 下载 @@ -190,7 +186,6 @@ 所有的 ROOT 会话使用全局挂载命名空间 ROOT 会话继承原程序的命名空间 每一个 ROOT 会话使用自己独立的命名空间 - 不支持 Android 8.0+ 没有设置指纹或设备不支持 创建文件夹出错。路径需要位于内部存储空间,并且不能有同名文件。 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 5b66650a9..7e092939d 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -84,10 +84,6 @@ 將在 5 秒後重新啟動… - 不,謝謝 - - - 關閉 安裝 %1$s 即將安裝 %1$s 下載 @@ -180,7 +176,6 @@ 所有 Root 工作階段皆使用全域 Namespace 所有 Root 工作階段皆繼承原程式 Namespace 所有 Root 工作階段個別擁有獨立 Namespace - 不支援 Android 8.0 及更新版本 未設定指紋或無指紋辨識器 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 664976811..d4eca1d44 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -88,10 +88,6 @@ Rebooting in 5 seconds… - No thanks - Yes - OK - Close Install %1$s Do you want to install %1$s now? Download @@ -190,7 +186,6 @@ All root sessions use the global mount namespace. Root sessions will inherit their requester\'s namespace. Each root session will have its own isolated namespace. - Does not support Android 8.0+. No fingerprints were set or no device support. Error creating folder. It must be accessible from storage root directory and must not be a file. diff --git a/stub/src/main/java/com/topjohnwu/magisk/DownloadActivity.java b/stub/src/main/java/com/topjohnwu/magisk/DownloadActivity.java index dfad034d5..141ebacd3 100644 --- a/stub/src/main/java/com/topjohnwu/magisk/DownloadActivity.java +++ b/stub/src/main/java/com/topjohnwu/magisk/DownloadActivity.java @@ -68,7 +68,7 @@ public class DownloadActivity extends Activity { .setCancelable(false) .setTitle(R.string.app_name) .setMessage(R.string.no_internet_msg) - .setNegativeButton(R.string.ok, (d, w) -> finish()) + .setNegativeButton(android.R.string.ok, (d, w) -> finish()) .show(); } } @@ -84,8 +84,8 @@ public class DownloadActivity extends Activity { .setCancelable(false) .setTitle(R.string.app_name) .setMessage(R.string.upgrade_msg) - .setPositiveButton(R.string.yes, (d, w) -> dlAPK()) - .setNegativeButton(R.string.no_thanks, (d, w) -> finish()) + .setPositiveButton(android.R.string.yes, (d, w) -> dlAPK()) + .setNegativeButton(android.R.string.no, (d, w) -> finish()) .show(); } catch (JSONException e) { finish(); diff --git a/stub/src/main/res/values-ar/strings.xml b/stub/src/main/res/values-ar/strings.xml index 6e7deae89..7abc06d3b 100644 --- a/stub/src/main/res/values-ar/strings.xml +++ b/stub/src/main/res/values-ar/strings.xml @@ -1,5 +1 @@ - - لا شكراً - نعم - موافق - + diff --git a/stub/src/main/res/values-az/strings.xml b/stub/src/main/res/values-az/strings.xml index b0d32921f..f8d446377 100644 --- a/stub/src/main/res/values-az/strings.xml +++ b/stub/src/main/res/values-az/strings.xml @@ -1,7 +1,4 @@ Qurmanı sonlandırmaq üçün full Magisk Manager`ə yüksəldin. Yüklənib qurulsun? Lütfən internetə qoşulun! Full Magisk Manager\'ə yüksəltmə lazımidir. - Yox, sağolun - Bəli - OK diff --git a/stub/src/main/res/values-bg/strings.xml b/stub/src/main/res/values-bg/strings.xml index 1421eb6b0..09255da5e 100644 --- a/stub/src/main/res/values-bg/strings.xml +++ b/stub/src/main/res/values-bg/strings.xml @@ -1,7 +1,4 @@ - Не, благодаря. - Да - OK Надградете до пълната версия на Magisk Manager, за да довършите първоначалната настройка. Изтегляне и инсталиране сега? Моля да се свържете към работеща интернет мрежа, защото надграждането до пълната версия на Magisk Manager е задължително. diff --git a/stub/src/main/res/values-ca/strings.xml b/stub/src/main/res/values-ca/strings.xml index 5f51d0659..80b7c163a 100644 --- a/stub/src/main/res/values-ca/strings.xml +++ b/stub/src/main/res/values-ca/strings.xml @@ -1,7 +1,4 @@ - - No, gràcies - - Ok + Fes una actualització total de Magisk Manager per finalitzar l\'instalació. Descarregar i instalar? Si us plau, connecta\'t a internet! Es necessari fer una actualització total de Magisk Manager. diff --git a/stub/src/main/res/values-cs/strings.xml b/stub/src/main/res/values-cs/strings.xml index 0aa2702ab..7abc06d3b 100644 --- a/stub/src/main/res/values-cs/strings.xml +++ b/stub/src/main/res/values-cs/strings.xml @@ -1,5 +1 @@ - - Ne, díky - Ano - OK - + diff --git a/stub/src/main/res/values-de/strings.xml b/stub/src/main/res/values-de/strings.xml index 426a03351..45488872f 100644 --- a/stub/src/main/res/values-de/strings.xml +++ b/stub/src/main/res/values-de/strings.xml @@ -1,7 +1,4 @@ - Nein danke - Ja - OK Upgrade zum vollständigen Magisk Manager, um das Setup abzuschließen. Herunterladen und installieren? Bitte eine Verbindung mit dem Internet herstellen! Upgrade zum vollständigen Magisk Manager ist erforderlich. diff --git a/stub/src/main/res/values-el/strings.xml b/stub/src/main/res/values-el/strings.xml index bd0c41ae2..7abc06d3b 100644 --- a/stub/src/main/res/values-el/strings.xml +++ b/stub/src/main/res/values-el/strings.xml @@ -1,5 +1 @@ - - Όχι ευχαριστώ - Ναι - OK - + diff --git a/stub/src/main/res/values-es/strings.xml b/stub/src/main/res/values-es/strings.xml index 8904fdf32..5d1d2fd19 100644 --- a/stub/src/main/res/values-es/strings.xml +++ b/stub/src/main/res/values-es/strings.xml @@ -1,7 +1,4 @@ - No gracias - - Aceptar Actualizar a la Ver. Completa de Magisk Manager para finalizar la instalación. Descargar e instalar? ¡Por favor conectarse a Internet! Se requiere actualizar a la Ver. Completa de Magisk Manager diff --git a/stub/src/main/res/values-et/strings.xml b/stub/src/main/res/values-et/strings.xml index 355de0266..ec72c8a82 100644 --- a/stub/src/main/res/values-et/strings.xml +++ b/stub/src/main/res/values-et/strings.xml @@ -1,7 +1,4 @@ - Tänan ei - Jah - OK Täienda seadistuse lõpetamiseks Magisk Manager\'i täisversioonile. Kas laadid alla ja installid? Palun ühendu Internetti! Nõutud on Magisk Manager\'i täisversioonile täiendamine. - \ No newline at end of file + diff --git a/stub/src/main/res/values-fr/strings.xml b/stub/src/main/res/values-fr/strings.xml index a088cabc4..dc928c8e9 100644 --- a/stub/src/main/res/values-fr/strings.xml +++ b/stub/src/main/res/values-fr/strings.xml @@ -1,8 +1,5 @@ - Non merci - Oui - OK Mettre à jour vers la version complête de Magisk Manager pour finir l\'installation. Télécharger et installer? Veuillez vous connecter à Internet! Une mise à niveau complête vers le Gestionnaire Magisk est requise. diff --git a/stub/src/main/res/values-hi/strings.xml b/stub/src/main/res/values-hi/strings.xml index 7b29600b5..7328bb697 100644 --- a/stub/src/main/res/values-hi/strings.xml +++ b/stub/src/main/res/values-hi/strings.xml @@ -1,8 +1,5 @@ - नहीं शुक्रिया - हां - ठीक सेटअप को पूरा करने के लिए पूर्ण Magisk Manager में अपग्रेड करें. डाउनलोड करके स्थापित करें ? कृपया इन्टरनेट से जुड़िये! पूर्ण Magisk Manager के उन्नयन की आवश्यकता है. diff --git a/stub/src/main/res/values-hr/strings.xml b/stub/src/main/res/values-hr/strings.xml index 919a11b57..7abc06d3b 100644 --- a/stub/src/main/res/values-hr/strings.xml +++ b/stub/src/main/res/values-hr/strings.xml @@ -1,5 +1 @@ - - Ne hvala - Da - OK - \ No newline at end of file + diff --git a/stub/src/main/res/values-in/strings.xml b/stub/src/main/res/values-in/strings.xml index 6bc1ef7f8..ec38f4ab0 100644 --- a/stub/src/main/res/values-in/strings.xml +++ b/stub/src/main/res/values-in/strings.xml @@ -1,7 +1,4 @@ - Tidak, terima kasih - Ya - OK Tingkatkan ke Magisk Manager versi penuh untuk menyelesaikan penyiapan. Unduh dan pasang? Harap menyambungkan ke Internet! Peningkatan ke Magisk Manager versi penuh diperlukan. diff --git a/stub/src/main/res/values-it/strings.xml b/stub/src/main/res/values-it/strings.xml index 0c8c96c0e..81add81af 100644 --- a/stub/src/main/res/values-it/strings.xml +++ b/stub/src/main/res/values-it/strings.xml @@ -1,7 +1,4 @@ - No, grazie - - OK Aggiorna alla versione completa di Magisk Manager per completare l\'installazione. Vuoi procedere al download e all\'installazione? Controlla la connessione a Internet! È necessaria per l\'aggiornamento di Magisk Manager. diff --git a/stub/src/main/res/values-ja/strings.xml b/stub/src/main/res/values-ja/strings.xml index 66c34dc33..7abc06d3b 100644 --- a/stub/src/main/res/values-ja/strings.xml +++ b/stub/src/main/res/values-ja/strings.xml @@ -1,5 +1 @@ - - いいえ - はい - OK - \ No newline at end of file + diff --git a/stub/src/main/res/values-ko/strings.xml b/stub/src/main/res/values-ko/strings.xml index a47c15d35..5b79aa155 100644 --- a/stub/src/main/res/values-ko/strings.xml +++ b/stub/src/main/res/values-ko/strings.xml @@ -1,7 +1,4 @@ - 아니오, 괜찮습니다 - - 확인 완전한 Magisk Manager로 업데이트하여 설치를 마치십시오. 다운로드하고 설치하시겠습니까? 인터넷에 연결해 주시기 바랍니다! 완전한 Magisk Manager로 업데이트 해야 합니다. diff --git a/stub/src/main/res/values-lt/strings.xml b/stub/src/main/res/values-lt/strings.xml index 2c5179804..db2eb98b0 100644 --- a/stub/src/main/res/values-lt/strings.xml +++ b/stub/src/main/res/values-lt/strings.xml @@ -1,7 +1,4 @@ - Ačiū, nereikia - Taip - Gerai Atsinaujinkite į pilną Magisk Manager versiją, kad baigtumėte pasiruošimą. Atsisiųsti ir instaliuoti? Prašome prisijungti prie interneto! Atsinaujinimas į pilną Magisk Manager versiją yra privalomas. diff --git a/stub/src/main/res/values-mk/strings.xml b/stub/src/main/res/values-mk/strings.xml index c1870cde9..32664f06e 100644 --- a/stub/src/main/res/values-mk/strings.xml +++ b/stub/src/main/res/values-mk/strings.xml @@ -1,7 +1,4 @@ - Не, благодарам - Да - ОК Надградете до целосната верзија на Magisk Manager за да го завршите поставувањето. Преземете и инсталирајте? Ве молиме поврзете се на интернет бидејќи е потребна надградба на целосната верзија на Magisk Manager. diff --git a/stub/src/main/res/values-nb/strings.xml b/stub/src/main/res/values-nb/strings.xml index 954aec658..2d9139952 100644 --- a/stub/src/main/res/values-nb/strings.xml +++ b/stub/src/main/res/values-nb/strings.xml @@ -1,8 +1,5 @@ - Nei takk - Ja - OK Oppgrader til den komplette versjonen av Magisk Manager for å fullføre oppsettet. Vil du laste ned og installere? Vennligst koble deg på internettet! Å oppgradere til den komplette versjonen av Magisk Manager er påkrevd. diff --git a/stub/src/main/res/values-nl/strings.xml b/stub/src/main/res/values-nl/strings.xml index d6812f1e1..7abc06d3b 100644 --- a/stub/src/main/res/values-nl/strings.xml +++ b/stub/src/main/res/values-nl/strings.xml @@ -1,5 +1 @@ - - Nee bedankt - Ja - Oké - + diff --git a/stub/src/main/res/values-pl/strings.xml b/stub/src/main/res/values-pl/strings.xml index d38b3c55a..c166e4125 100644 --- a/stub/src/main/res/values-pl/strings.xml +++ b/stub/src/main/res/values-pl/strings.xml @@ -1,7 +1,4 @@ - Nie dziękuję - Tak - OK Przejdź na pełną wersję programu Magisk Manager, aby ukończyć konfigurację. Ściągnąć i zainstalować? Połącz się z Internetem! Wymagana jest aktualizacja do pełnego programu Magisk Manager. diff --git a/stub/src/main/res/values-pt-rBR/strings.xml b/stub/src/main/res/values-pt-rBR/strings.xml index 9d4f3eafd..7abc06d3b 100644 --- a/stub/src/main/res/values-pt-rBR/strings.xml +++ b/stub/src/main/res/values-pt-rBR/strings.xml @@ -1,5 +1 @@ - - Não - Sim - OK - + diff --git a/stub/src/main/res/values-pt-rPT/strings.xml b/stub/src/main/res/values-pt-rPT/strings.xml index 6850a7943..7abc06d3b 100644 --- a/stub/src/main/res/values-pt-rPT/strings.xml +++ b/stub/src/main/res/values-pt-rPT/strings.xml @@ -1,5 +1 @@ - - Não, Obrigado - Sim - OK - + diff --git a/stub/src/main/res/values-ro/strings.xml b/stub/src/main/res/values-ro/strings.xml index 0e70bed77..c3f0469c9 100644 --- a/stub/src/main/res/values-ro/strings.xml +++ b/stub/src/main/res/values-ro/strings.xml @@ -1,7 +1,4 @@ - Nu, mulțumesc - Da - Ok Treci la versiunea completă Magisk Manager pentru a finaliza configurarea. Descarci și instalezi? Te rugăm să te conectezi la internet! Este necesară actualizarea la versiunea completă Magisk Manager. diff --git a/stub/src/main/res/values-ru/strings.xml b/stub/src/main/res/values-ru/strings.xml index 4bb584099..6df6adc83 100644 --- a/stub/src/main/res/values-ru/strings.xml +++ b/stub/src/main/res/values-ru/strings.xml @@ -1,7 +1,4 @@ - Нет - Да - OK Обновите Magisk Manager для завершения установки. Загрузить и установить? Пожалуйста, подключитесь к интернету! Требуется обновление Magisk Manager. diff --git a/stub/src/main/res/values-sk/strings.xml b/stub/src/main/res/values-sk/strings.xml index 794ee0eff..d123d58b7 100644 --- a/stub/src/main/res/values-sk/strings.xml +++ b/stub/src/main/res/values-sk/strings.xml @@ -1,7 +1,4 @@ - Nie, ďakujem - Áno - OK Pre dokončenie inštalácie sa vyžaduje upgrade Magisk Managera. Stiahnuť a nainštalovať? Pripojte sa na internet! Upgrade Magisk Managera je potrebný. diff --git a/stub/src/main/res/values-sr/strings.xml b/stub/src/main/res/values-sr/strings.xml index 2e568e78b..7abc06d3b 100644 --- a/stub/src/main/res/values-sr/strings.xml +++ b/stub/src/main/res/values-sr/strings.xml @@ -1,5 +1 @@ - - Не хвала - Да - ОК - + diff --git a/stub/src/main/res/values-sv/strings.xml b/stub/src/main/res/values-sv/strings.xml index 57e72dd52..7abc06d3b 100644 --- a/stub/src/main/res/values-sv/strings.xml +++ b/stub/src/main/res/values-sv/strings.xml @@ -1,5 +1 @@ - - Nej tack - Ja - OK - + diff --git a/stub/src/main/res/values-th/strings.xml b/stub/src/main/res/values-th/strings.xml index 78f4e50cb..3ea04e700 100644 --- a/stub/src/main/res/values-th/strings.xml +++ b/stub/src/main/res/values-th/strings.xml @@ -1,6 +1,2 @@ - - ไม่, ขอบคุณ - ใช่ - โอเค - \ No newline at end of file + diff --git a/stub/src/main/res/values-tr/strings.xml b/stub/src/main/res/values-tr/strings.xml index 24ae0185a..95b9bbe82 100644 --- a/stub/src/main/res/values-tr/strings.xml +++ b/stub/src/main/res/values-tr/strings.xml @@ -1,7 +1,4 @@ - Hayır, teşekkürler - Evet - Tamam Kurulumu tamamlamak için tam Magisk Manager\'a yükseltin. İndirip yüklensin mi? Lütfen internete bağlanın! Tam Magisk Manager\'a yükseltmek gerekiyor. diff --git a/stub/src/main/res/values-uk/strings.xml b/stub/src/main/res/values-uk/strings.xml index d5e7bd16f..9d6dfb76e 100644 --- a/stub/src/main/res/values-uk/strings.xml +++ b/stub/src/main/res/values-uk/strings.xml @@ -1,8 +1,5 @@ - Ні, дякую - Так - OK Оновіть Magisk Manager для завершення встановлення. Завантажити і встановити? Будь ласка, підключіться до Інтернету! Потрібно оновити Magisk Manager. Завантаження diff --git a/stub/src/main/res/values-vi/strings.xml b/stub/src/main/res/values-vi/strings.xml index 18e8582b4..7abc06d3b 100644 --- a/stub/src/main/res/values-vi/strings.xml +++ b/stub/src/main/res/values-vi/strings.xml @@ -1,5 +1 @@ - - Không, cảm ơn - - OK - + diff --git a/stub/src/main/res/values-zh-rCN/strings.xml b/stub/src/main/res/values-zh-rCN/strings.xml index 32d2d1d81..9c6d9763b 100644 --- a/stub/src/main/res/values-zh-rCN/strings.xml +++ b/stub/src/main/res/values-zh-rCN/strings.xml @@ -1,7 +1,4 @@ - 不,谢谢 - - 需要升级到完整的 Magisk Manager 来完成安装。 现在下载? 请连接到互联网! 这是升级到完整 Magisk Manager 所必需的。 正在下载 diff --git a/stub/src/main/res/values-zh-rTW/strings.xml b/stub/src/main/res/values-zh-rTW/strings.xml index c330fec82..84bb1988f 100644 --- a/stub/src/main/res/values-zh-rTW/strings.xml +++ b/stub/src/main/res/values-zh-rTW/strings.xml @@ -1,7 +1,4 @@ - 不,謝謝 - - 需要升級到完整版 Magisk Manager。是否下載並安裝? 請連上網路!升級到完整版 Magisk Manager 是必須的。 diff --git a/stub/src/main/res/values/strings.xml b/stub/src/main/res/values/strings.xml index 75117a28c..3b6ec0284 100644 --- a/stub/src/main/res/values/strings.xml +++ b/stub/src/main/res/values/strings.xml @@ -1,8 +1,5 @@ - No thanks - Yes - OK Upgrade to full Magisk Manager to finish the setup. Download and install? Please connect to the Internet! Upgrading to full Magisk Manager is required. Downloading From 31153e4366edf396e02cb691eee1d185b5ced1ad Mon Sep 17 00:00:00 2001 From: Nathan Muccino Date: Wed, 23 Oct 2019 18:05:21 -0400 Subject: [PATCH 57/61] Minor grammatical changes The plural form of the words 'documentation' and 'following' are used very rarely if ever and I don't believe that they should be used in this particular context. --- docs/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/README.md b/docs/README.md index 5f1763509..6d1732db5 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,4 +1,4 @@ -# Magisk Documentations +# Magisk Documentation (Updated on 2019.9.19) - [Installation](install.md) @@ -6,7 +6,7 @@ - [OTA Installation](tutorials.md#ota-installation) - [Best Practices for MagiskHide](tutorials.md#best-practices-for-magiskhide) -The followings are for developers +The following sections are for developers - [Magisk Details](details.md) - [Magisk Tools](tools.md) From ee447bc4cef0febcb5067ac328a45549cc3203f6 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sat, 26 Oct 2019 21:11:32 -0400 Subject: [PATCH 58/61] Improve Keygen yet again --- .../java/com/topjohnwu/magisk/utils/Keygen.kt | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/Keygen.kt b/app/src/main/java/com/topjohnwu/magisk/utils/Keygen.kt index bdd2b7f4a..1ba0dc982 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Keygen.kt +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Keygen.kt @@ -15,7 +15,6 @@ import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder import org.koin.core.context.GlobalContext import org.koin.core.context.startKoin import timber.log.Timber -import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream import java.math.BigInteger import java.security.KeyPairGenerator @@ -37,15 +36,14 @@ class Keygen: CertKeyProvider { companion object { private const val ALIAS = "magisk" - private val PASSWORD = "magisk".toCharArray() + private val PASSWORD get() = "magisk".toCharArray() private const val TESTKEY_CERT = "61ed377e85d386a8dfee6b864bd85b0bfaa5af81" - private const val DNAME = "CN=Android, OU=Android, O=Google Inc., L=Mountain View, ST=California, C=US" + private const val DNAME = "C=US,ST=California,L=Mountain View,O=Google Inc.,OU=Android,CN=Android" + private const val BASE64_FLAG = Base64.NO_PADDING or Base64.NO_WRAP } - private val start get() = Calendar.getInstance() - private val end get() = Calendar.getInstance().apply { - add(Calendar.YEAR, 20) - } + private val start = Calendar.getInstance() + private val end = Calendar.getInstance().apply { add(Calendar.YEAR, 30) } override val cert get() = provider.cert override val key get() = provider.key @@ -104,9 +102,7 @@ class Keygen: CertKeyProvider { if (raw.isEmpty()) { ks.load(null) } else { - GZIPInputStream(ByteArrayInputStream( - Base64.decode(raw, Base64.NO_PADDING or Base64.NO_WRAP) - )).use { + GZIPInputStream(Base64.decode(raw, BASE64_FLAG).inputStream()).use { ks.load(it, PASSWORD) } } @@ -116,20 +112,20 @@ class Keygen: CertKeyProvider { return ks // Generate new private key and certificate - val kp = KeyPairGenerator.getInstance("RSA").apply { initialize(2048) }.genKeyPair() + val kp = KeyPairGenerator.getInstance("RSA").apply { initialize(4096) }.genKeyPair() val dname = X500Name(DNAME) - val builder = JcaX509v3CertificateBuilder(dname, - BigInteger.valueOf(start.timeInMillis), start.time, end.time, dname, kp.public) + val builder = JcaX509v3CertificateBuilder(dname, BigInteger(160, Random()), + start.time, end.time, dname, kp.public) val signer = JcaContentSignerBuilder("SHA256WithRSA").build(kp.private) val cert = JcaX509CertificateConverter().getCertificate(builder.build(signer)) // Store them into keystore ks.setKeyEntry(ALIAS, kp.private, PASSWORD, arrayOf(cert)) val bytes = ByteArrayOutputStream() - GZIPOutputStream(Base64OutputStream(bytes, Base64.NO_PADDING or Base64.NO_WRAP)).use { + GZIPOutputStream(Base64OutputStream(bytes, BASE64_FLAG)).use { ks.store(it, PASSWORD) } - Config.keyStoreRaw = bytes.toString() + Config.keyStoreRaw = bytes.toString("UTF-8") return ks } From 321d11c2c676aff54f9acf1b21243755f333fd3d Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Mon, 28 Oct 2019 01:15:27 -0400 Subject: [PATCH 59/61] Move Mapping class --- .../topjohnwu/magisk/DelegateApplication.java | 1 + .../magisk/DelegateComponentFactory.java | 1 + .../magisk/{ => obfuscate}/Mapping.java | 19 ++++++++++--------- 3 files changed, 12 insertions(+), 9 deletions(-) rename stub/src/main/java/com/topjohnwu/magisk/{ => obfuscate}/Mapping.java (68%) diff --git a/stub/src/main/java/com/topjohnwu/magisk/DelegateApplication.java b/stub/src/main/java/com/topjohnwu/magisk/DelegateApplication.java index 817d4da40..a19a400a1 100644 --- a/stub/src/main/java/com/topjohnwu/magisk/DelegateApplication.java +++ b/stub/src/main/java/com/topjohnwu/magisk/DelegateApplication.java @@ -9,6 +9,7 @@ import android.content.res.Configuration; import android.os.Build; import android.util.Log; +import com.topjohnwu.magisk.obfuscate.Mapping; import com.topjohnwu.magisk.utils.DynamicClassLoader; import java.io.File; diff --git a/stub/src/main/java/com/topjohnwu/magisk/DelegateComponentFactory.java b/stub/src/main/java/com/topjohnwu/magisk/DelegateComponentFactory.java index 89874c93f..c62806aad 100644 --- a/stub/src/main/java/com/topjohnwu/magisk/DelegateComponentFactory.java +++ b/stub/src/main/java/com/topjohnwu/magisk/DelegateComponentFactory.java @@ -14,6 +14,7 @@ import com.topjohnwu.magisk.dummy.DummyActivity; import com.topjohnwu.magisk.dummy.DummyProvider; import com.topjohnwu.magisk.dummy.DummyReceiver; import com.topjohnwu.magisk.dummy.DummyService; +import com.topjohnwu.magisk.obfuscate.Mapping; import static com.topjohnwu.magisk.DownloadActivity.TAG; diff --git a/stub/src/main/java/com/topjohnwu/magisk/Mapping.java b/stub/src/main/java/com/topjohnwu/magisk/obfuscate/Mapping.java similarity index 68% rename from stub/src/main/java/com/topjohnwu/magisk/Mapping.java rename to stub/src/main/java/com/topjohnwu/magisk/obfuscate/Mapping.java index b069c145d..65e7eec82 100644 --- a/stub/src/main/java/com/topjohnwu/magisk/Mapping.java +++ b/stub/src/main/java/com/topjohnwu/magisk/obfuscate/Mapping.java @@ -1,15 +1,16 @@ -package com.topjohnwu.magisk; +package com.topjohnwu.magisk.obfuscate; import java.util.HashMap; import java.util.Map; import static com.topjohnwu.magisk.DynAPK.*; +import static com.topjohnwu.magisk.R.drawable.*; -class Mapping { +public class Mapping { private static Map map = new HashMap<>(); // This mapping will be sent into the guest app - static Data data = new Data(); + public static Data data = new Data(); static { map.put(a.z.class.getName(), "a.c"); @@ -25,15 +26,15 @@ class Mapping { data.componentMap.put(e.getValue(), e.getKey()); } int[] res = new int[5]; - res[NOTIFICATION] = R.drawable.ic_magisk_outline; - res[SUPERUSER] = R.drawable.sc_superuser; - res[MAGISKHIDE] = R.drawable.sc_magiskhide; - res[DOWNLOAD] = R.drawable.sc_cloud_download; - res[MODULES] = R.drawable.sc_extension; + res[NOTIFICATION] = ic_magisk_outline; + res[SUPERUSER] = sc_superuser; + res[MAGISKHIDE] = sc_magiskhide; + res[DOWNLOAD] = sc_cloud_download; + res[MODULES] = sc_extension; data.resourceMap = res; } - static String get(String name) { + public static String get(String name) { String n = map.get(name); return n != null ? n : name; } From f7aa451591c8576dc508e4a029fea10cc5be96a7 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Tue, 29 Oct 2019 07:36:50 -0400 Subject: [PATCH 60/61] Update strings --- app/src/main/res/values-ca/strings.xml | 33 ++++---- app/src/main/res/values-ru/strings.xml | 78 ++++++++++--------- app/src/main/res/values/strings.xml | 42 +++++----- .../topjohnwu/magisk/DelegateApplication.java | 6 +- .../magisk/DelegateComponentFactory.java | 9 --- .../topjohnwu/magisk/DownloadActivity.java | 30 +++---- .../topjohnwu/magisk/obfuscate/RawData.java | 38 +++++++++ stub/src/main/res/values-ca/strings.xml | 2 + stub/src/main/res/values-ru/strings.xml | 1 + stub/src/main/res/values/misc.xml | 4 - 10 files changed, 141 insertions(+), 102 deletions(-) create mode 100644 stub/src/main/java/com/topjohnwu/magisk/obfuscate/RawData.java delete mode 100644 stub/src/main/res/values/misc.xml diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index 02b5cc495..76edbd704 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -24,6 +24,7 @@ Configuració avançada Mantenir el xifrat forçat Mantenir AVB 2.0/dm-verity + Mode de Recuperació Instal·lada: %1$s Última: %1$s Desinstal·lar @@ -75,12 +76,12 @@ Actualització de Magisk Manager disponible! - Prem per descarregar i instalar. - Descarrega només el ZIP + Premi per baixar i instalar. + Únicament baixa el ZIP Instal·lació directa (Recomanat) Instal·la a la ranura inactiva (Després d\'una OTA) El teu dispositiu serà FORÇAT a arrancar en l\'actual ranura inactiva després del reinici!\nUtilitza aquesta opció NOMÉS quan l\'OTA s\'hagi fet.\nContinuar? - Sel·lecciona mètode + Sel·lecciona un mètode Instal·lació addicional Sel·lecciona i arranja un arxiu Sel·lecciona una imatge crua (*.img) o un ODIN tarfile (*.tar) @@ -109,23 +110,23 @@ Restaurant… Restauració feta! La còpia de seguretat de Stock no existeix! - Descarrega codi propietari - Magisk Manager és codi lliure i no conté codi de l\'API de SafetyNet, ja que és codi propietari de Google.\n\nPot permetre que Magisk Manager descarregui una extensió que conté el GoogleApiClient per poder fer la comprobació de SafetyNet? + Baixar codi propietari + Magisk Manager és codi lliure i no conté codi de l\'API de SafetyNet, ja que és codi propietari de Google.\n\nPot permetre que Magisk Manager baixi una extensió que conté el GoogleApiClient per poder fer la comprobació de SafetyNet? Instal·lació fallida. Es requereix instal·lació addicional - El teu dispositiu necessita instal·lació addicional per Magisk per funcionar correctament. Es descarregarà el ZIP d\'instal·lació de Magisk , vol procedir a l\'instalació ara? + El teu dispositiu necessita instal·lació addicional per Magisk per funcionar correctament. Es baixarà el ZIP d\'instal·lació de Magisk , vol procedir a l\'instalació ara? S\'està executant la configuració de l\'entorn… General - Tema obscur - Habilitar el tema obscur - Directori de descàrrega + Tema fosc + Habilitar el tema fosc + Directori de baixades Els arxius es desaràn a %1$s Netejar memòria cau del repositori Neteja l\'informació en memòria cau per als repositoris en línia, força a l\'aplicació a actualitzar-se en línia. Amagar Magisk Manager - Re-empaquetar Magisk Manager amb un nom de paquet a l\'atzar + Reempaquetar Magisk Manager amb un nom de paquet a l\'atzar Restaurar Magisk Manager Restaura Magisk Manager amb el nom de paquet original Idioma @@ -145,6 +146,10 @@ Suport per aplicacions tipus Adblock fora de la partició del sistema Agregat el mòdul Systemless Hosts + Escriu el nom desitjat per l\'App + Nou nom + Es refarà l\'App amb aquest nom + Format invàl·lid Aplicacions y ADB Només aplicacions Només ADB @@ -160,8 +165,8 @@ Temps de petició Notificació de superusuari %1$d segons - Re-autenticació - Demanar permisos de superusuari novament si una aplicació es actualitzada o reinstal·lada + Demanar després d\'una actualització + Demanar permisos de superusuari novament si una aplicació és actualitzada o reinstal·lada Autenticació per Empremta Dactilar Utilitza el sensor d\'Empremta Dactilar per permetre les sol·licituds de superusuari Autenticar Emprempta Digital @@ -173,7 +178,7 @@ Només l\'administrador té accés d\'arrel Només l\'administrador pot supervisar l\'acces d\'arrel y rebre sol·licituds d\'altres usuaris Tots els usuaris tenen separades les seves pròpies regles d\'arrel - + Muntar Namespace Namespace Global Heretar Namespace @@ -215,7 +220,7 @@ PID: %1$d UID de l\'objectiu: %1$d Ordre: %1$s - + Mostra apps del sistema diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 154e81018..be293523f 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -18,18 +18,18 @@ Проверка статуса SafetyNet… Результат проверки SafetyNet Ошибка SafetyNet API - Некорректный ответ. + Некорректный ответ Magisk актуален Magisk Manager актуален Расширенные опции - Сохранить принудительное шифрование - Сохранить AVB 2.0/dm-verity - Режим Recovery - Установлена: %1$s - Последняя: %1$s + Не отключать шифрование /data + Не отключать AVB 2.0/dm-verity + Режим установки в recovery + Установлен: %1$s + Последний: %1$s Удаление Удаление Magisk - Все модули будут отключены/удалены. Root-права будут удалены. Шифрование будет активировано. + Все модули будут отключены/удалены!\nRoot-права будут удалены!\nШифрование будет активировано! Обновить (Активирован режим Magisk Core) @@ -76,14 +76,14 @@ Доступно обновление Magisk Manager! - Нажмите, чтобы загрузить и установить. - Загрузка установочного ZIP + Нажмите, чтобы загрузить и установить + Только загрузка ZIP Прямая установка (Рекомендуется) - Установка в неактивный слот (После OTA) - Ваше устройство будет принудительно перезагружено в неактивный слот!\nИспользуйте эту опцию только при установке OTA.\nПродолжить? + Установка во второй слот (OTA) + Ваше устройство будет принудительно перезагружено в неактивный (противоположный) слот!\nИспользуйте эту опцию только при интеграции после OTA.\nПродолжить? Выбор способа Дополнительная установка - Выбрать и пропатчить файл + Вручную пропатчить образ Выберите файл образа (*.img) или архив ODIN (*.tar) Перезагрузка через 5 секунд… @@ -92,7 +92,7 @@ Установить %1$s ? Скачать Перезагрузка - Для применения настроек перезагрузите устройство. + Для применения настроек перезагрузите устройство О версии Кэш репозитория очищен @@ -101,9 +101,9 @@ Прошивка… Завершено! Ошибка - Маскировка Magisk Manager… + Скрытие Magisk Manager… Не удалось пересобрать Magisk Manager - Не найдено приложений для открытия ссылки. + Не найдено приложений для открытия ссылки Предупреждение Полное удаление Восстановить разделы @@ -111,8 +111,8 @@ Восстановление завершено! Резервная копия отсутствует! Загрузка SafetyNet - Magisk Manager — свободно распространяемый продукт, он не содержит собственный код SafetyNet API от Google.\n\nРазрешить Magisk Manager загрузить расширение для проверки SafetyNet? (содержит GoogleApiClient) - Ошибка установки. + Magisk Manager — проект с открытым исходным кодом и не содержит проприетарный код SafetyNet API от Google.\n\nРазрешить Magisk Manager загрузить расширение для проверки SafetyNet? (содержит GoogleApiClient) + Ошибка установки Требуется дополнительная установка Вашему устройству требуется дополнительная установка Magisk для корректной работы. Будет загружен установочный ZIP Magisk, продолжить? Настройка рабочей среды… @@ -120,32 +120,36 @@ Основные Тёмная тема - Включить тёмное оформление. + Включить тёмное оформление Папка загрузки Файлы будут загружаться в %1$s Очистка кэша репозитория - Очистить кэш репозитория. Будет загружен заново. - Маскировка Magisk Manager - Пересобрать Magisk Manager со случайным именем пакета. + Очистить кэш репозитория. Будет загружен заново + Скрытие Magisk Manager + Пересобрать Magisk Manager со случайным названием и именем пакета Восстановление Magisk Manager - Восстановить Magisk Manager с исходным именем пакета. + Восстановить Magisk Manager с исходным названием и именем пакета Язык По умолчанию (Системный) Настройки обновлений Проверка обновлений - Периодически проверять наличие обновлений в фоновом режиме. + Периодически проверять наличие обновлений в фоновом режиме Источник обновлений Стабильный канал Beta канал Сторонний канал Укажите ссылку Magisk Core - Активировать только основные возможности. Модули не будут загружены. MagiskSU и Magisk Hide останутся активными. - Скрыть Magisk от различных обнаружений. + Активировать только основные возможности. Модули не будут загружены. MagiskSU и Magisk Hide останутся активными + Скрывать Magisk от различных обнаружений Внесистемные хосты - Поддержка внесистемных хостов для приложений, блокирующих рекламу. + Поддержка внесистемных хостов для приложений, блокирующих рекламу Добавлен модуль внесистемных хостов + Укажите имя приложения + Новое имя + Приложение будет пересобрано с этим именем + Некорректный формат Приложения и ADB Только приложения Только ADB @@ -162,18 +166,18 @@ Уведомления суперпользователя %1$d секунд Повторная аутентификация - Повторный запрос прав суперпользователя после обновления приложений. + Повторный запрос прав суперпользователя после обновления приложений Биометрическая аутентификация - Использовать сканер отпечатков пальцев для запросов прав суперпользователя. - Аутентифицировать отпечаток пальца + Использовать сканер отпечатков пальцев для запросов прав суперпользователя + Подтвердите отпечаток пальца Многопользовательский режим Только владелец Регулировка владельцем Правила пользователей - Только владелец имеет Root-доступ. - Только владелец управляет Root-доступом и обрабатывает запросы. - Каждый пользователь имеет свои собственные правила Root-доступа. + Только владелец имеет Root-доступ + Только владелец управляет Root-доступом и обрабатывает запросы + Каждый пользователь имеет свои собственные правила Root-доступа Настройка пространств имён Общее пространство имён @@ -187,12 +191,12 @@ Запрос прав суперпользователя - Отказать + Запретить Запрос - Предоставить - Предоставить полный доступ к устройству.\nЕсли не уверены - отклоните данное действие! + Разрешить + Разрешить полный доступ к устройству?\nЕсли не уверены - отклоните данное действие! Навсегда - Сейчас + Единожды 10 мин. 20 мин. 30 мин. @@ -218,6 +222,6 @@ Команда: %1$s - Показать системные приложения + Системные приложения diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d4eca1d44..ca53b8223 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -18,7 +18,7 @@ Checking SafetyNet status… SafetyNet Check Success SafetyNet API Error - The response is invalid. + The response is invalid Magisk is up to date Magisk Manager is up to date Advanced Settings @@ -29,7 +29,7 @@ Latest: %1$s Uninstall Uninstall Magisk - All modules will be disabled/removed. Root will be removed, and your data potentially encrypted if not already. + All modules will be disabled/removed!\nRoot will be removed!\nYour data potentially encrypted if not already! Update (Core only mode enabled) @@ -76,7 +76,7 @@ Magisk Manager Update Available! - Press to download and install. + Press to download and install Download Zip Only Direct Install (Recommended) Install to Inactive Slot (After OTA) @@ -92,7 +92,7 @@ Do you want to install %1$s now? Download Reboot - Reboot to apply settings. + Reboot to apply settings Release notes Repo cache cleared @@ -103,7 +103,7 @@ Failed Hiding Magisk Manager… Hide Magisk Manager failed. - No application found to open the link. + No application found to open the link Warning Complete Uninstall Restore Images @@ -112,7 +112,7 @@ Stock backup does not exist! Download Proprietary Code Magisk Manager is FOSS and doesn\'t contain Google\'s proprietary SafetyNet API code.\n\nWill you allow Magisk Manager to download an extension (contains GoogleApiClient) for SafetyNet checks? - Setup failed. + Setup failed Requires Additional Setup Your device needs additional setup for Magisk to work properly. It will download the Magisk setup zip, do you want to proceed now? Running environment setup… @@ -120,30 +120,30 @@ General Dark Theme - Enable dark theme. + Enable dark theme Download path Files will be saved to %1$s Clear Repo Cache - Clear the cached information for online repos. This forces the app to refresh online. + Clear the cached information for online repos. This forces the app to refresh online Hide Magisk Manager - Repackage Magisk Manager with random package name. + Repackage Magisk Manager with random package and app names Restore Magisk Manager - Restore Magisk Manager with original package + Restore Magisk Manager with original package and app names Language (System Default) Update Settings Check Updates - Periodically check for updates in the background. + Periodically check for updates in the background Update Channel Stable Beta Custom Insert a custom URL Magisk Core Only Mode - Enable only core features. MagiskSU and MagiskHide will still be enabled, but no modules will be loaded. - Hide Magisk from various forms of detection. + Enable only core features. MagiskSU and MagiskHide will still be enabled, but no modules will be loaded + Hide Magisk from various forms of detection Systemless hosts - Systemless hosts support for Adblock apps. + Systemless hosts support for Adblock apps Added systemless hosts module Type desired app name @@ -175,18 +175,18 @@ Device Owner Only Device Owner Managed User-Independent - Only owner has root access. - Only owner can manage root access and receive request prompts. - Each user has his/her own separate root rules. + Only owner has root access + Only owner can manage root access and receive request prompts + Each user has his/her own separate root rules Mount Namespace Mode Global Namespace Inherit Namespace Isolated Namespace - All root sessions use the global mount namespace. - Root sessions will inherit their requester\'s namespace. - Each root session will have its own isolated namespace. - No fingerprints were set or no device support. + All root sessions use the global mount namespace + Root sessions will inherit their requester\'s namespace + Each root session will have its own isolated namespace + No fingerprints were set or no device support Error creating folder. It must be accessible from storage root directory and must not be a file. diff --git a/stub/src/main/java/com/topjohnwu/magisk/DelegateApplication.java b/stub/src/main/java/com/topjohnwu/magisk/DelegateApplication.java index a19a400a1..c338c0658 100644 --- a/stub/src/main/java/com/topjohnwu/magisk/DelegateApplication.java +++ b/stub/src/main/java/com/topjohnwu/magisk/DelegateApplication.java @@ -15,8 +15,6 @@ import com.topjohnwu.magisk.utils.DynamicClassLoader; import java.io.File; import java.lang.reflect.Method; -import static com.topjohnwu.magisk.DownloadActivity.TAG; - public class DelegateApplication extends Application { static File MANAGER_APK; @@ -36,7 +34,7 @@ public class DelegateApplication extends Application { if (Build.VERSION.SDK_INT >= 28) { setUpDynAPK(); } else { - MANAGER_APK = new File(base.getCacheDir(), "manager.apk"); + MANAGER_APK = new File(base.getCacheDir(), "app.apk"); } } @@ -72,7 +70,7 @@ public class DelegateApplication extends Application { factory.delegate = (AppComponentFactory) df; factory.loader = cl; } catch (Exception e) { - Log.e(TAG, "dyn load", e); + Log.e(getClass().getSimpleName(), "", e); MANAGER_APK.delete(); } } diff --git a/stub/src/main/java/com/topjohnwu/magisk/DelegateComponentFactory.java b/stub/src/main/java/com/topjohnwu/magisk/DelegateComponentFactory.java index c62806aad..f21839c52 100644 --- a/stub/src/main/java/com/topjohnwu/magisk/DelegateComponentFactory.java +++ b/stub/src/main/java/com/topjohnwu/magisk/DelegateComponentFactory.java @@ -8,7 +8,6 @@ import android.app.Service; import android.content.BroadcastReceiver; import android.content.ContentProvider; import android.content.Intent; -import android.util.Log; import com.topjohnwu.magisk.dummy.DummyActivity; import com.topjohnwu.magisk.dummy.DummyProvider; @@ -16,8 +15,6 @@ import com.topjohnwu.magisk.dummy.DummyReceiver; import com.topjohnwu.magisk.dummy.DummyService; import com.topjohnwu.magisk.obfuscate.Mapping; -import static com.topjohnwu.magisk.DownloadActivity.TAG; - @SuppressLint("NewApi") public class DelegateComponentFactory extends AppComponentFactory { @@ -27,14 +24,12 @@ public class DelegateComponentFactory extends AppComponentFactory { @Override public Application instantiateApplication(ClassLoader cl, String className) { if (loader == null) loader = cl; - Log.d(TAG, className); return new DelegateApplication(this); } @Override public Activity instantiateActivity(ClassLoader cl, String className, Intent intent) throws ClassNotFoundException, IllegalAccessException, InstantiationException { - Log.d(TAG, className); if (delegate != null) return delegate.instantiateActivity(loader, Mapping.get(className), intent); return create(className, DummyActivity.class); @@ -43,7 +38,6 @@ public class DelegateComponentFactory extends AppComponentFactory { @Override public BroadcastReceiver instantiateReceiver(ClassLoader cl, String className, Intent intent) throws ClassNotFoundException, IllegalAccessException, InstantiationException { - Log.d(TAG, className); if (delegate != null) return delegate.instantiateReceiver(loader, Mapping.get(className), intent); return create(className, DummyReceiver.class); @@ -52,7 +46,6 @@ public class DelegateComponentFactory extends AppComponentFactory { @Override public Service instantiateService(ClassLoader cl, String className, Intent intent) throws ClassNotFoundException, IllegalAccessException, InstantiationException { - Log.d(TAG, className); if (delegate != null) return delegate.instantiateService(loader, Mapping.get(className), intent); return create(className, DummyService.class); @@ -61,7 +54,6 @@ public class DelegateComponentFactory extends AppComponentFactory { @Override public ContentProvider instantiateProvider(ClassLoader cl, String className) throws ClassNotFoundException, IllegalAccessException, InstantiationException { - Log.d(TAG, className); if (loader == null) loader = cl; if (delegate != null) return delegate.instantiateProvider(loader, Mapping.get(className)); @@ -73,7 +65,6 @@ public class DelegateComponentFactory extends AppComponentFactory { */ private T create(String name, Class dummy) throws InstantiationException, IllegalAccessException { - Log.d(TAG, "create " + name); try { return (T) loader.loadClass(name).newInstance(); } catch (IllegalAccessException | InstantiationException | ClassNotFoundException ignored) { diff --git a/stub/src/main/java/com/topjohnwu/magisk/DownloadActivity.java b/stub/src/main/java/com/topjohnwu/magisk/DownloadActivity.java index 141ebacd3..38e1e9c5e 100644 --- a/stub/src/main/java/com/topjohnwu/magisk/DownloadActivity.java +++ b/stub/src/main/java/com/topjohnwu/magisk/DownloadActivity.java @@ -11,31 +11,33 @@ import android.util.Log; import com.topjohnwu.magisk.net.ErrorHandler; import com.topjohnwu.magisk.net.Networking; import com.topjohnwu.magisk.net.ResponseListener; +import com.topjohnwu.magisk.obfuscate.RawData; import com.topjohnwu.magisk.utils.APKInstall; import org.json.JSONException; import org.json.JSONObject; +import static android.R.string.no; +import static android.R.string.ok; +import static android.R.string.yes; import static com.topjohnwu.magisk.DelegateApplication.MANAGER_APK; public class DownloadActivity extends Activity { - static final String TAG = "MMStub"; private static final String URL = BuildConfig.DEV_CHANNEL != null ? BuildConfig.DEV_CHANNEL : - "https://raw.githubusercontent.com/topjohnwu/magisk_files/" + - (BuildConfig.DEBUG ? "canary/debug.json" : "master/stable.json"); + RawData.urlBase() + (BuildConfig.DEBUG ? RawData.canary() : RawData.stable()); private String apkLink; private ErrorHandler err = (conn, e) -> { - Log.e(TAG, "network error", e); + Log.e(getClass().getSimpleName(), "", e); finish(); }; private void showDialog() { ProgressDialog.show(this, - getString(R.string.dling), - getString(R.string.dling) + " " + getString(R.string.app_name), + RawData.dling(), + RawData.dling() + " " + RawData.appName(), true); } @@ -58,7 +60,9 @@ public class DownloadActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + RawData.res = getResources(); Networking.init(this); + if (Networking.checkNetworkStatus(this)) { Networking.get(URL) .setErrorHandler(err) @@ -66,9 +70,9 @@ public class DownloadActivity extends Activity { } else { new AlertDialog.Builder(this) .setCancelable(false) - .setTitle(R.string.app_name) - .setMessage(R.string.no_internet_msg) - .setNegativeButton(android.R.string.ok, (d, w) -> finish()) + .setTitle(RawData.appName()) + .setMessage(RawData.no_internet_msg()) + .setNegativeButton(ok, (d, w) -> finish()) .show(); } } @@ -82,10 +86,10 @@ public class DownloadActivity extends Activity { apkLink = manager.getString("link"); new AlertDialog.Builder(DownloadActivity.this) .setCancelable(false) - .setTitle(R.string.app_name) - .setMessage(R.string.upgrade_msg) - .setPositiveButton(android.R.string.yes, (d, w) -> dlAPK()) - .setNegativeButton(android.R.string.no, (d, w) -> finish()) + .setTitle(RawData.appName()) + .setMessage(RawData.upgrade_msg()) + .setPositiveButton(yes, (d, w) -> dlAPK()) + .setNegativeButton(no, (d, w) -> finish()) .show(); } catch (JSONException e) { finish(); diff --git a/stub/src/main/java/com/topjohnwu/magisk/obfuscate/RawData.java b/stub/src/main/java/com/topjohnwu/magisk/obfuscate/RawData.java new file mode 100644 index 000000000..da3dabd4e --- /dev/null +++ b/stub/src/main/java/com/topjohnwu/magisk/obfuscate/RawData.java @@ -0,0 +1,38 @@ +package com.topjohnwu.magisk.obfuscate; + +import android.content.res.Resources; + +import com.topjohnwu.magisk.R; + +public class RawData { + + public static Resources res; + + public static String appName() { + return "Magisk Manager"; + } + + public static String urlBase() { + return "https://raw.githubusercontent.com/topjohnwu/magisk_files/"; + } + + public static String canary() { + return "canary/debug.json"; + } + + public static String stable() { + return "master/stable.json"; + } + + public static String no_internet_msg() { + return res.getString(R.string.no_internet_msg); + } + + public static String upgrade_msg() { + return res.getString(R.string.upgrade_msg); + } + + public static String dling() { + return res.getString(R.string.dling); + } +} diff --git a/stub/src/main/res/values-ca/strings.xml b/stub/src/main/res/values-ca/strings.xml index 80b7c163a..23de839a9 100644 --- a/stub/src/main/res/values-ca/strings.xml +++ b/stub/src/main/res/values-ca/strings.xml @@ -1,4 +1,6 @@ + Fes una actualització total de Magisk Manager per finalitzar l\'instalació. Descarregar i instalar? Si us plau, connecta\'t a internet! Es necessari fer una actualització total de Magisk Manager. + Baixant diff --git a/stub/src/main/res/values-ru/strings.xml b/stub/src/main/res/values-ru/strings.xml index 6df6adc83..71e5245ef 100644 --- a/stub/src/main/res/values-ru/strings.xml +++ b/stub/src/main/res/values-ru/strings.xml @@ -1,4 +1,5 @@ Обновите Magisk Manager для завершения установки. Загрузить и установить? Пожалуйста, подключитесь к интернету! Требуется обновление Magisk Manager. + Загрузка diff --git a/stub/src/main/res/values/misc.xml b/stub/src/main/res/values/misc.xml deleted file mode 100644 index f60a4b322..000000000 --- a/stub/src/main/res/values/misc.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - Magisk Manager - From 5e87483f3424cbbbf532d7ab1fbb1804433e5b60 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Tue, 29 Oct 2019 07:37:19 -0400 Subject: [PATCH 61/61] Move addAssetPath to shared --- app/src/main/java/com/topjohnwu/magisk/Hacks.kt | 6 +----- shared/src/main/java/com/topjohnwu/magisk/DynAPK.java | 11 +++++++++++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/Hacks.kt b/app/src/main/java/com/topjohnwu/magisk/Hacks.kt index f0b2380ab..0245f9591 100644 --- a/app/src/main/java/com/topjohnwu/magisk/Hacks.kt +++ b/app/src/main/java/com/topjohnwu/magisk/Hacks.kt @@ -27,12 +27,8 @@ import com.topjohnwu.magisk.utils.currentLocale import com.topjohnwu.magisk.utils.defaultLocale import java.util.* -private val addAssetPath by lazy { - AssetManager::class.java.getMethod("addAssetPath", String::class.java) -} - fun AssetManager.addAssetPath(path: String) { - addAssetPath.invoke(this, path) + DynAPK.addAssetPath(this, path) } fun Context.wrap(global: Boolean = true): Context diff --git a/shared/src/main/java/com/topjohnwu/magisk/DynAPK.java b/shared/src/main/java/com/topjohnwu/magisk/DynAPK.java index 28be1d9e7..8dc790c81 100644 --- a/shared/src/main/java/com/topjohnwu/magisk/DynAPK.java +++ b/shared/src/main/java/com/topjohnwu/magisk/DynAPK.java @@ -1,8 +1,10 @@ package com.topjohnwu.magisk; import android.content.Context; +import android.content.res.AssetManager; import java.io.File; +import java.lang.reflect.Method; import java.util.Map; import static android.os.Build.VERSION.SDK_INT; @@ -24,6 +26,7 @@ public class DynAPK { public static final int MAGISKHIDE = 4; private static File dynDir; + private static Method addAssetPath; private static File getDynDir(Context c) { if (dynDir == null) { @@ -62,6 +65,14 @@ public class DynAPK { return arr; } + public static void addAssetPath(AssetManager asset, String path) { + try { + if (addAssetPath == null) + addAssetPath = AssetManager.class.getMethod("addAssetPath", String.class); + addAssetPath.invoke(asset, path); + } catch (Exception ignored) {} + } + public static class Data { public int version; public Map componentMap;