1
mirror of https://github.com/topjohnwu/Magisk synced 2025-10-29 07:20:52 +01:00

Compare commits

...

238 Commits

Author SHA1 Message Date
topjohnwu
c0f2164bc5 Magisk v22.1 release notes 2021-04-09 02:50:41 -07:00
Wang Han
f6e4a27fdd Don't export $API when initializing shell
* This becomes meanless after 9c0e189.
2021-04-09 01:47:52 -07:00
topjohnwu
257ceb99f7 SDK < 21 is EOL 2021-04-09 01:40:08 -07:00
topjohnwu
706d53065b Rename TransitiveText 2021-04-09 01:32:37 -07:00
topjohnwu
0f95a7babe Do not hold resources in SuperuserViewModel 2021-04-09 01:00:26 -07:00
topjohnwu
7cb2806878 Release new canary build 2021-04-06 04:13:41 -07:00
topjohnwu
9c0e18975c Fallback to getprop when reading system props
Close #4153
2021-04-06 03:56:49 -07:00
Shaka Huang
3da318b48e Fix random return value of faccessat() in x86
faccessat() should return 0 when success, but it returns random number with errno == 0 in x86 platform.

It’s a side effect of commit bf80b08b5f when magisk binaries ‘corretly’ linked with library of API16 .. lol

Co-authored-by: John Wu <topjohnwu@gmail.com>
2021-04-04 03:04:09 -07:00
Shaka Huang
dfe1f2c108 Call freecon() when fgetfilecon() succeeds 2021-04-04 01:58:59 -07:00
Thomas Bertels
f42a87b51a Fix spelling in French translation 2021-03-29 09:15:23 -07:00
ahmouse15
ab25857176 Update docs to use the Magisk Manager's revised name 2021-03-29 09:14:21 -07:00
topjohnwu
7da36079c1 Always delete existing ro props at setprop
Close #4113
2021-03-29 04:16:18 -07:00
topjohnwu
2bef967af1 Make systemproperties more match AOSP 2021-03-29 03:46:07 -07:00
topjohnwu
7e4194418a Update libcxx 2021-03-28 04:55:56 -07:00
topjohnwu
aa02057895 Do not use -f flag for readlink
Close #4104, fix #4098
2021-03-28 04:47:13 -07:00
topjohnwu
fb8dc07599 Release new canary build 2021-03-25 02:09:51 -07:00
topjohnwu
66e30a7723 Build libc++ ourselves 2021-03-25 01:00:10 -07:00
vvb2060
0298ab99c4 Update AGP 2021-03-24 04:43:45 -07:00
vvb2060
d11358671e Fix isolated process display 2021-03-24 04:43:45 -07:00
vvb2060
8b5cb4c7b0 Fix #3735 2021-03-24 04:43:45 -07:00
vvb2060
aad52ae743 Fix UID removed action 2021-03-24 04:43:45 -07:00
vvb2060
8ddab84745 Don't auto hide microG
close #3559
2021-03-24 04:43:45 -07:00
vvb2060
6865652125 Fix process name in MagiskHide
close #3997
2021-03-24 04:43:45 -07:00
topjohnwu
ed4d0867e8 Make sure navigation happens on main thread
Fix #4044
2021-03-24 03:23:11 -07:00
Kazuki H
1c71e02454 Update Japanese translations 2021-03-24 03:10:21 -07:00
Matthew Mirvish
f332e87cab Ensure the installer knows the API version when running from addon.d 2021-03-24 03:08:59 -07:00
osm0sis
023dbc6cb5 scripts: fix empty module cleanup
- should be sufficient for all basic modules, see https://github.com/topjohnwu/Magisk/issues/3119#issuecomment-704000783 for ideas for fixing it further on the daemon module-processing side

Fixes #3119
2021-03-24 03:06:57 -07:00
osm0sis
4dd3f55407 App: add versionCode to magisk_patched.img filenames 2021-03-24 03:06:57 -07:00
osm0sis
7b9a71c9af scripts: improve boot_patch 64bit detection
- use existing api_level_arch_detect function

Fixes #3961
2021-03-24 03:06:57 -07:00
osm0sis
901d22cdfa scripts: add boot_patch unpack error catching
- failure to unpack wasn't being caught so boot_patch would continue to build a new cpio out of nothing and attempt to repack it (identified in #4049)
2021-03-24 03:06:57 -07:00
osm0sis
93e1266ee7 scripts: fix find_boot_image using wrong partition list on non-slot
- revert logic changes introduced by ec8fffe61c which break find_boot_image on NAND devices and any others using non-standard naming supported by the A-only device boot partition name list
- despite being accepted equivalents in modern shells -n does not work on Android in some shell/env scenarios where ! -z always does
2021-03-24 03:06:57 -07:00
osm0sis
0a4e7eea41 scripts: clean up remaining Manager references 2021-03-24 03:06:57 -07:00
Shaka Huang
e3801d6965 Fix overflow
`totalsize` might be a big (invalid) number so instead of checking the end address we check the size of the image.

Fix #4049
2021-03-24 03:02:46 -07:00
topjohnwu
336f1687c1 Be more careful with signals
Fix #4040
2021-03-18 03:28:02 -07:00
topjohnwu
d4e2f2df6e Release new canary build 2021-03-16 05:47:29 -07:00
topjohnwu
f152b4c26e Make LiveData nullable 2021-03-16 05:34:54 -07:00
topjohnwu
bd935b0553 Cleanup fragment navigations 2021-03-16 04:58:02 -07:00
topjohnwu
a9b3b7a359 Update dependencies 2021-03-16 03:44:25 -07:00
vvb2060
7a007b342a Correct comment
For file-based encryption, /data/adb is always required to encrypt
https://android.googlesource.com/platform/system/extras/+/refs/tags/android-7.0.0_r36/ext4_utils/ext4_crypt_init_extensions.cpp
68258e8444%5E%21/
2021-03-13 21:10:02 -08:00
vvb2060
0783f3d5b6 Fix mount rules dir
close #4006
2021-03-13 21:10:02 -08:00
Rikka
afe3c2bc1b Fix "rm_rf" in build.py on Windows
prebuilt/windows-x86_64/bin/libpython2.7.dll
prebuilt/windows-x86_64/lib/python2.7/config/libpython2.7.dll.a

These two files in NDK has read-only attribute on Windows, remove these files with Python will get "WindowsError: [Error 5] Access is denied". It will finally make "build.py ndk" unable to remove the "magisk" folder.

This commit add a onerror callback for "shutil.rmtree" which clear the "read-only" attribute and retry.
2021-03-13 17:51:39 -08:00
topjohnwu
82f8948fd4 Separate setting log functions and starting log daemon 2021-03-13 17:50:48 -08:00
Shaka Huang
b9cdc755d1 Returned fds[0] in socketpair() might be STDOUT
* There will be garbage output when executing `su` (#4016)
* Failed to check root status and showing N/A in status (#4005)

Signed-off-by: Shaka Huang <shakalaca@gmail.com>
2021-03-13 17:50:48 -08:00
topjohnwu
a6f81c66e5 Bypass stdio 2021-03-13 16:17:28 -08:00
topjohnwu
1ff45ac5f5 Proper pattern matching
Fix #3998
2021-03-09 04:08:34 -08:00
Alexandru Scurtu
48bde7375f uninstaller: consistency improvements
since there's no more "Magisk Manager"
2021-03-09 03:05:47 -08:00
topjohnwu
0601fa3b3d Release new canary build 2021-03-09 02:59:07 -08:00
vvb2060
d0d3c8dbfd Disable blank issues 2021-03-09 02:51:20 -08:00
vvb2060
8057de1973 Auto close issues 2021-03-09 02:51:20 -08:00
topjohnwu
43c1105d62 Use dedicated thread for writing logfile 2021-03-09 02:40:12 -08:00
topjohnwu
6adf516b30 Release new canary build 2021-03-07 04:39:47 -08:00
topjohnwu
bf80b08b5f Fix build script 2021-03-07 04:34:06 -08:00
topjohnwu
3e0b1df46d Update README 2021-03-07 04:12:32 -08:00
topjohnwu
84811c80b6 Release new canary build 2021-03-07 02:51:10 -08:00
LLZN
45e0df9c57 Update strings.xml 2021-03-07 01:56:02 -08:00
vvb2060
bc51ce7c7b Fix reboot menu 2021-03-07 01:55:19 -08:00
vvb2060
b693d13b93 Proper implementation of cgroup migration
https://www.kernel.org/doc/Documentation/admin-guide/cgroup-v1/cgroups.rst
https://www.kernel.org/doc/Documentation/admin-guide/cgroup-v2.rst
2021-03-07 01:55:19 -08:00
topjohnwu
39982d57ef Fix logging implementation
- Block signals in logging routine (fix #3976)
- Prevent possible deadlock after fork (stdio locks internally)
  by creating a new FILE pointer per logging call (thread/stack local)
2021-03-06 13:55:30 -08:00
topjohnwu
15e27e54fb Migrate to new endpoints 2021-03-05 05:09:25 -08:00
topjohnwu
851404205b Update NDK to r21e 2021-03-02 23:18:44 -08:00
topjohnwu
117ae71025 Use custom class instead of std::map 2021-03-02 23:16:10 -08:00
topjohnwu
027ec70262 Patch AVB structures
Disable vbmeta verification in flags
2021-03-02 20:37:37 -08:00
topjohnwu
55fdee4d65 Use memmem for searching byte patterns 2021-02-28 14:37:12 -08:00
topjohnwu
0d42f937dd Refactor magiskboot 2021-02-28 14:37:12 -08:00
vvb2060
ac8372dd26 Add cgroup2 path
https://android-review.googlesource.com/c/platform/system/core/+/1585101
2021-02-26 21:36:58 -08:00
vvb2060
5e56a6bbee Fix isolated process name before Android 10 2021-02-26 21:36:58 -08:00
etmatrix
3c6c409df0 Fix #3916 2021-02-25 21:25:21 -08:00
vvb2060
d05408c89f Delete outdated policies when refresh 2021-02-25 20:08:42 -08:00
vvb2060
ee0ec3fbfa Use UID_REMOVED action for multi-user and shared user id compatibility 2021-02-25 20:08:42 -08:00
vvb2060
122a73e086 Always show hidden apps 2021-02-25 20:08:42 -08:00
omerakgoz34
29a9b18c4c Update Turkish translation 2021-02-25 19:56:05 -08:00
孟武.尼德霍格.龍
1561272109 更新繁體中文
更新並改善繁體中文的翻譯
2021-02-25 19:55:25 -08:00
Ilya Kushnir
3e61ab0d25 Update RU strings 2021-02-25 19:54:58 -08:00
Francesco Saltori
a49dc6ccb7 Update Italian translation 2021-02-25 19:54:21 -08:00
topjohnwu
60f3d62f00 Proper synchronization 2021-02-24 02:50:55 -08:00
topjohnwu
e613855a4f Do not check PXA header signatures
Fix #3876
2021-02-24 02:27:42 -08:00
sn-o-w
22662d7e03 Update Romanian 2021-02-24 02:08:46 -08:00
Arbri çoçka
6e7e5be1a2 Update values-sq 2021-02-24 02:06:42 -08:00
vvb2060
8b2ab778c9 Fix show canary channel on stable build 2021-02-24 02:06:20 -08:00
vvb2060
35f3766ecf Update zh-rCN translation 2021-02-24 02:05:33 -08:00
Rom
995304dabb Update French translation 2021-02-24 02:05:16 -08:00
topjohnwu
803982a271 Prevent multiple installation sessions running in parallel 2021-02-24 01:45:10 -08:00
topjohnwu
9164bf22c2 Update terminology 2021-02-23 23:56:58 -08:00
topjohnwu
911a576893 Publish new canary build 2021-02-23 04:36:49 -08:00
topjohnwu
79ee85c0f9 Update README 2021-02-23 04:22:32 -08:00
topjohnwu
483dbcdc40 Release v22.0 2021-02-23 04:09:26 -08:00
topjohnwu
a1096b5bf0 Do not run pm install on main thread 2021-02-23 04:09:13 -08:00
Chris Renshaw
5ac0e64edb Update guides.md for system_ext 2021-02-23 03:27:36 -08:00
Lishoo
60b2624607 Update polish translations
Add missing strings
2021-02-23 03:26:47 -08:00
topjohnwu
d2e2847b03 Fix stub 2021-02-23 03:24:51 -08:00
topjohnwu
b9669f54f7 Update docs 2021-02-23 03:06:00 -08:00
topjohnwu
8c7bd77d33 Do not wrap twice 2021-02-23 01:49:15 -08:00
Shaka Huang
ba1ce16b8b Fix error in pure 64-bit environment
In Android S preview, there’s no 32-bit libraries in x86_64 system image for emulator.

Signed-off-by: Shaka Huang <shakalaca@gmail.com>
2021-02-22 03:28:54 -08:00
topjohnwu
68090943f4 Several changes
- Change error message strings
- Move non-root stub error to SplashActivity
- Skip shell init in non-root stub
2021-02-22 03:28:19 -08:00
vvb2060
a4fb1297b0 Fix crash in pure 64-bit devices 2021-02-22 03:08:51 -08:00
vvb2060
860a05abf2 Simplify UpdateChannel 2021-02-22 03:08:51 -08:00
vvb2060
8bb2f356c0 Allow offline restore app 2021-02-22 03:08:51 -08:00
vvb2060
4950020635 Prevent dot in the first position again 2021-02-22 03:08:51 -08:00
vvb2060
0a6140c6eb Try install with root first 2021-02-22 03:08:51 -08:00
vvb2060
bba2ac8817 Add unsupport env check 2021-02-22 03:08:51 -08:00
topjohnwu
331b1f542f Use standard Android APIs for install and launch 2021-02-20 20:12:35 -08:00
topjohnwu
ccb55205e6 Fix pre 21 support 2021-02-20 03:38:39 -08:00
topjohnwu
9cc91b30b3 Fix #3871 2021-02-20 02:49:43 -08:00
grmasa
e836caf31e Update Greek translation 2021-02-20 01:51:39 -08:00
Lishoo
beaa1e5be2 Add missing strings and small updates. 2021-02-20 01:51:02 -08:00
Lishoo
ea545bae26 Update polish translations 2021-02-20 01:50:44 -08:00
topjohnwu
1c9ec2df45 Publish new canary build 2021-02-14 13:43:24 -08:00
vvb2060
b76c80e2ce Fix apex path 2021-02-14 13:37:38 -08:00
topjohnwu
236990f4a3 Fix stub app crashing 2021-02-14 13:37:13 -08:00
topjohnwu
1ed32df20d Publish new canary build 2021-02-13 17:26:53 -08:00
topjohnwu
8476eb9f4b Avoid patching vendor_boot.img 2021-02-13 17:15:04 -08:00
JoanVC100
735af7843b Add new ca-strings 2021-02-13 17:09:46 -08:00
MC Naveen
ded73e958b Added Tamil Translation 2021-02-13 17:09:28 -08:00
Ooggle
6dcb84d4f4 French translation of newest commit 2021-02-13 17:08:53 -08:00
topjohnwu
501bc9f438 Restore init from backup rather than symlink
Because of course Samsung don't follow AOSP norms.
I mean, why would they?
2021-02-13 16:43:06 -08:00
topjohnwu
f88e812b63 Move behavior to XML 2021-02-13 15:26:32 -08:00
Tornike Khintibidze
be6386c410 Updated Georgian translation 2021-02-12 03:59:35 -08:00
Didgeridoohan
2af4fd17c4 Minor fixes and changes to Swedish transaltions 2021-02-12 03:59:07 -08:00
Mikael Bjurström
f870418bd0 Update Swedish translation 2021-02-12 00:07:40 -08:00
vvb2060
00659e4795 Hide OTA option on virtual A/B devices 2021-02-12 00:07:15 -08:00
Jose Manuel Estrada-Nora Muñoz
cdda10207e Spanish strings 2021-02-11 23:32:24 -08:00
Ilya Kushnir
701700279f Update RU strings 2021-02-11 23:32:04 -08:00
alex26052005
a9d804724a Update strings.xml
Updated German language
2021-02-11 23:31:04 -08:00
DanGLES3
e033a9ab47 Update Portugues Brazilian translation 2021-02-11 23:30:35 -08:00
kubalav
059e5fb8aa Update Slovak translation 2021-02-11 23:28:49 -08:00
vvb2060
a78f255928 Update zh-rCN translation 2021-02-11 23:25:24 -08:00
AndroPlus
1d10e69288 Update Japanese translation 2021-02-11 23:23:36 -08:00
topjohnwu
63590d379c Update hide icon strategy 2021-02-11 22:38:41 -08:00
topjohnwu
5f63e88984 Hide icons when things don't fit 2021-02-11 05:08:40 -08:00
topjohnwu
75584e2b19 App string resources overhaul 2021-02-11 02:34:27 -08:00
vvb2060
1426ee2ebd Fix Android build version sdk in script 2021-02-10 22:22:50 -08:00
topjohnwu
b6643b7bfc Publish new canary build 2021-02-07 21:39:00 -08:00
Hen Ry
721dfdf553 Added translation of new strings 2021-02-07 17:42:33 -08:00
topjohnwu
2963747d14 Fix LZ4_LG format decompression
Fix #3802, fix #3722, fix #3770, fix #3635, fix #3787, close #3812
2021-02-07 17:40:59 -08:00
topjohnwu
e7350d5041 Fix unable to patch images when app is hidden 2021-02-07 06:42:06 -08:00
topjohnwu
f37e8f4ca8 Fix boot image patching 2021-02-07 01:54:08 -08:00
topjohnwu
594c2accc0 Update dependencies 2021-02-05 04:41:01 -08:00
topjohnwu
7acfac6a91 Publish new canary build 2021-01-30 12:54:51 -08:00
Laz M
0646f48e14 [README] Warn users that the official website is github
Google puts a number of cheeky looking websites in the results for Magisk.

I only found out they were unofficial is though issue #3435. This deserves to be shown more prominently.
2021-01-30 11:59:39 -08:00
tzagim
37565fd067 Fix TYPOs 2021-01-30 11:58:43 -08:00
vvb2060
26b2e7dc5d Care version code changes 2021-01-30 11:58:10 -08:00
vvb2060
c3313623e4 Fix release build 2021-01-30 11:58:10 -08:00
topjohnwu
2089223690 Fix #3785 2021-01-30 11:51:15 -08:00
topjohnwu
52e1b84d41 Symlink pre API 21 2021-01-30 01:12:49 -08:00
topjohnwu
8794141b7f Support super old emulators 2021-01-30 00:56:16 -08:00
topjohnwu
f6126dd20e Support Shortcuts pre API 26
Close #3778
2021-01-29 23:16:09 -08:00
topjohnwu
18acfda99b Remove Windows NDK symlink
https://github.com/actions/virtual-environments/pull/2343
2021-01-29 05:43:41 -08:00
topjohnwu
bec5edca84 Avoiding using shell I/O 2021-01-29 05:15:22 -08:00
topjohnwu
6fb20b3ee5 Proper proguard rules 2021-01-27 04:56:39 -08:00
topjohnwu
eaf4d8064b Also download to external storage 2021-01-27 04:09:07 -08:00
topjohnwu
2a5f5b1bba Workaround zip extraction bug on older devices 2021-01-27 03:00:09 -08:00
topjohnwu
c538a77937 Tweak build configs and scripts 2021-01-27 02:36:32 -08:00
sominn
aa9e7b1ed1 Update strings.xml
CS string update
2021-01-27 01:00:10 -08:00
Arbri çoçka
a3066eddab Fix string in values-sq 2021-01-27 00:59:49 -08:00
Arbri çoçka
d1729fa787 Fix string in values-sq 2021-01-27 00:59:49 -08:00
vvb2060
93961dde2c Fix version on continuous build 2021-01-27 00:54:11 -08:00
topjohnwu
1024e68eb6 Remove class mapping in full APK 2021-01-26 07:27:35 -08:00
topjohnwu
6ae2c9387d Use stub APK hiding method for Android 5.0+
At the same time, disable app hiding on devices lower than 5.0
to simplify the logic in the app. By doing so, a hidden app always
implies running as stub.
2021-01-26 07:27:35 -08:00
topjohnwu
fba83e2330 Support stub APK loading down to Android 5.0 2021-01-26 07:27:35 -08:00
topjohnwu
f1295cb7d6 Fix root on Android 7.0 and lower 2021-01-26 02:16:11 -08:00
topjohnwu
dc61dfbde6 Cache update check results 2021-01-25 04:13:08 -08:00
topjohnwu
21466426da Some code cleanup 2021-01-25 03:44:38 -08:00
topjohnwu
3f0136362b Move nand flash handling into boot_patch.sh 2021-01-25 03:37:41 -08:00
topjohnwu
e92d77bbec Some optimizations 2021-01-25 03:02:43 -08:00
topjohnwu
07bd36c94b Fix patching files
Fix #3765
2021-01-25 02:24:12 -08:00
topjohnwu
b1dbbdef12 Remove unneeded busybox redirection 2021-01-25 00:23:42 -08:00
topjohnwu
3e479726ec Fix legacy rootfs devices 2021-01-25 00:19:10 -08:00
vvb2060
4cc41eccb3 Skip download notes when loading notes url 2021-01-24 21:02:51 -08:00
vvb2060
8f08ae59ac Fix permission 2021-01-24 21:02:43 -08:00
vvb2060
e8d4e492d6 Fix CHANGELOG_URL 2021-01-24 21:02:37 -08:00
topjohnwu
b8090a8e18 Ensure cwd is writable in module scripts
Close #3763
2021-01-24 20:58:30 -08:00
topjohnwu
c609a01e55 Proper shortcut name 2021-01-24 08:00:17 -08:00
Wagg13
c97fb385cd New update values-pt-rBR
update brazilian strings.xml
2021-01-24 07:36:07 -08:00
LLZN
da6c57750e correction czech translat
change and fix some strings after trying a new version of the application (v8.0.6)
2021-01-24 07:35:49 -08:00
topjohnwu
6951d926f7 Rename app name to just Magisk 2021-01-24 07:35:00 -08:00
topjohnwu
6623195bd5 Cleanup scripts 2021-01-24 07:24:13 -08:00
topjohnwu
ec31bb9a82 Rename scripts 2021-01-24 07:18:14 -08:00
vvb2060
8618cc383a Fix install modules
Fix #3759
2021-01-24 07:03:19 -08:00
vvb2060
4b01e3a3c7 Cleanup more kotlin stuffs 2021-01-24 07:03:06 -08:00
vvb2060
7f748c23c1 Use Java debugger 2021-01-24 07:02:44 -08:00
vvb2060
963d248cc7 Rename apk to be uninstaller 2021-01-24 07:02:36 -08:00
topjohnwu
657056e636 Cache changelog files 2021-01-24 06:55:43 -08:00
topjohnwu
9d5efea66e Remove ManagerJson
Everything is now Magisk
2021-01-24 05:14:46 -08:00
topjohnwu
658d74e026 Update home fragment 2021-01-24 00:02:49 -08:00
vvb2060
5113f6d375 Fix stop magiskhide 2021-01-23 18:13:15 -08:00
vvb2060
96405c26d0 writeTo has closed InputStream 2021-01-23 18:12:19 -08:00
vvb2060
4ea5f34bf3 Remove unused action 2021-01-23 18:11:08 -08:00
vvb2060
dbd13a2019 Clean code 2021-01-23 18:10:26 -08:00
vvb2060
06773235da Fix Windows build 2021-01-23 18:06:01 -08:00
vvb2060
e57556a8af Use ro.kernel.qemu to check emulator 2021-01-23 18:05:38 -08:00
vvb2060
b54b78c29d Fix prevent dot in the first position 2021-01-23 17:31:18 -08:00
vvb2060
317336f771 Add isolated processes log 2021-01-23 17:31:11 -08:00
topjohnwu
b4e52f6135 Better development workflow 2021-01-23 16:50:55 -08:00
topjohnwu
f2ca042915 Fix script for handling .apex files 2021-01-23 16:09:30 -08:00
topjohnwu
1060dd2906 Random refactoring 2021-01-23 13:26:28 -08:00
topjohnwu
2e0f7a82fa More complete stub sources 2021-01-22 20:45:37 -08:00
topjohnwu
5798536559 Remove unnecessary hacks 2021-01-22 20:25:37 -08:00
topjohnwu
ab9a83c82f Bump target SDK to 30 2021-01-22 05:03:33 -08:00
topjohnwu
c87fdbea0f Fix erroneous stream close 2021-01-22 03:07:39 -08:00
topjohnwu
ec8fffe61c Merge Magisk install zip into Magisk Manager
Distribute Magisk directly with Magisk Manager APK. The APK will
contain all required binaries and scripts for installation and
uninstallation. App versions will now align with Magisk releases.

Extra effort is spent to make the APK itself also a flashable zip that
can be used in custom recoveries, so those still prefer to install
Magisk with recoveries will not be affected with this change.

As a bonus, this makes the whole installation and uninstallation
process 100% offline. The existing Magisk Manager was not really
functional without an Internet connection, as the installation process
was highly tied to zips hosted on the server.

An additional bonus: since all binaries are now shipped as "native
libraries" of the APK, we can finally bump the target SDK version
higher than 28. The target SDK version was stuck at 28 for a long time
because newer SELinux restricts running executables from internal
storage. More details can be found here: https://github.com/termux/termux-app/issues/1072
The target SDK bump will be addressed in a future commit.

Co-authored with @vvb2060
2021-01-22 02:29:54 -08:00
topjohnwu
61d52991f1 Update BusyBox 2021-01-21 00:35:22 -08:00
topjohnwu
9100186dce Make emulator direct install env fix 2021-01-18 13:32:10 -08:00
topjohnwu
d2bc2cfcf8 Install both 32 and 64 bit binaries 2021-01-18 12:37:08 -08:00
topjohnwu
5a71998b4e Stop embedding magisk in magiskinit 2021-01-18 04:25:26 -08:00
topjohnwu
42278f12ff Fix typo in init daemon 2021-01-18 04:13:54 -08:00
topjohnwu
f5593e051c Update README 2021-01-17 06:19:56 -08:00
topjohnwu
a27e30cf54 Update release notes 2021-01-17 06:08:15 -08:00
topjohnwu
79140c7636 Proper xxread and xwrite implementation 2021-01-17 01:42:45 -08:00
topjohnwu
1f4c595cd3 Revert to old su -c behavior 2021-01-16 23:59:31 -08:00
topjohnwu
b5b62e03af Fix copySepolicyRules logic 2021-01-16 21:45:45 -08:00
topjohnwu
67e2a4720e Fix xxread false negatives
Fix #3710
2021-01-16 21:43:53 -08:00
topjohnwu
f5c2d72429 Also log pid and tid 2021-01-16 16:10:47 -08:00
topjohnwu
2f5331ab48 Update README 2021-01-16 05:02:39 -08:00
topjohnwu
7f8257152f Add v21.3 release notes 2021-01-16 04:55:44 -08:00
topjohnwu
0cd80f2556 Update app changelog 2021-01-16 04:42:14 -08:00
rydwhelchel
1717387876 Grammatical changes to the install docs 2021-01-15 21:32:29 -08:00
Mspy1
109363ebf6 Fixed typo 2021-01-15 21:31:58 -08:00
LLZN
716c4fa386 new update values-cs
update czech strings.xml
2021-01-15 21:31:17 -08:00
Arbri çoçka
9a09b4eb20 fix strings-sq 2021-01-15 21:29:53 -08:00
Rikka
95a5b57265 Remove "Flashing" overlay
Fix #3579, fix #3250
2021-01-15 21:28:59 -08:00
topjohnwu
13fbf397d1 Isolated processes might still be hide-able 2021-01-15 20:22:49 -08:00
vvb2060
20be99ec8a Restore mistakenly deleted codes 2021-01-15 19:59:55 -08:00
topjohnwu
04c53c3578 Legacy SAR: use a simpler method to detect is_two_stage 2021-01-15 02:44:40 -08:00
topjohnwu
51bc27a869 Avoid F2FS like a plague 2021-01-15 02:24:11 -08:00
topjohnwu
71b083794c Maintain global mount list 2021-01-14 21:14:54 -08:00
topjohnwu
b100d0c503 Revert DTB fstab changes 2021-01-14 19:48:00 -08:00
topjohnwu
76061296c9 Let MagiskBoot handle dtb fstab patching 2021-01-14 06:20:12 -08:00
topjohnwu
bb303d2da1 Remove old unused code 2021-01-14 05:59:53 -08:00
topjohnwu
c91c070343 Re-enable DTB table rebuilding 2021-01-14 05:45:05 -08:00
topjohnwu
aec06a6f61 Get proper total image size 2021-01-14 03:55:27 -08:00
topjohnwu
e8ba671fc2 Guard all injection features behind a global flag 2021-01-13 20:07:23 -08:00
topjohnwu
1860e5d133 Dynamically find libselinux.so path 2021-01-13 19:41:57 -08:00
topjohnwu
f2cb3c38fe Update mmap implementation
Always map memory as writable, but private when read-only
2021-01-12 22:50:55 -08:00
topjohnwu
9a28dd4f6e Implement MagiskHide through code injection 2021-01-12 03:28:00 -08:00
topjohnwu
d2acd59ea8 Minor code refactoring 2021-01-12 00:07:48 -08:00
topjohnwu
79dfdb29e7 Minor tweaks for patching tar files 2021-01-11 19:47:36 -08:00
topjohnwu
eb21c8b42e Code cleanups 2021-01-11 02:19:10 -08:00
topjohnwu
541bb53553 Update links in README 2021-01-10 20:36:58 -08:00
317 changed files with 5545 additions and 5201 deletions

View File

@@ -7,15 +7,17 @@ assignees: ''
---
<!--
## READ BEFORE OPENING ISSUES
All bug reports require you to **USE CANARY BUILDS**. Please include the version name and version code in the bug report.
If you experience a bootloop, attach a `dmesg` (kernel logs) when the device refuse to boot. This may very likely require a custom kernel on some devices as `last_kmsg` or `pstore ramoops` are usually not enabled by default. In addition, please also upload the result of `cat /proc/mounts` when your device is working correctly **WITHOUT ROOT**.
If you experience issues during installation, in recovery, upload the recovery logs, or in Magisk Manager, upload the install logs. Please also upload the `boot.img` or `recovery.img` that you are using for patching.
If you experience issues during installation, in recovery, upload the recovery logs, or in Magisk, upload the install logs. Please also upload the `boot.img` or `recovery.img` that you are using for patching.
If you experience a crash of Magisk Manager, dump the full `logcat` **when the crash happens**. **DO NOT** upload `magisk.log`.
If you experience a crash of Magisk app, dump the full `logcat` **when the crash happens**.
If you experience other issues related to Magisk, upload `magisk.log`, and preferably also include a boot `logcat` (start dumping `logcat` when the device boots up)
@@ -26,3 +28,10 @@ If you experience other issues related to Magisk, upload `magisk.log`, and prefe
**DO NOT** report issues if you have any modules installed.
Without following the rules above, your issue will be closed without explanation.
-->
Device:
Android version:
Magisk version name:
Magisk version code:

6
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,6 @@
blank_issues_enabled: false
contact_links:
- name: XDA Community Support
url: https://forum.xda-developers.com/f/magisk.5903/
about: Please ask and answer questions here.

View File

@@ -43,12 +43,8 @@ jobs:
- name: Set up GitHub env (Windows)
if: runner.os == 'Windows'
run: |
$oldAndroidPath = $env:ANDROID_SDK_ROOT
$sdk_root = "C:\Android"
New-Item -Path $sdk_root -ItemType SymbolicLink -Value $oldAndroidPath
$ndk_ver = Select-String -Path "gradle.properties" -Pattern "^magisk.fullNdkVersion=" | % { $_ -replace ".*=" }
echo "ANDROID_SDK_ROOT=$sdk_root" >> $env:GITHUB_ENV
echo "ANDROID_HOME=$sdk_root" >> $env:GITHUB_ENV
echo "ANDROID_SDK_ROOT=$env:ANDROID_SDK_ROOT" >> $env:GITHUB_ENV
echo "MAGISK_NDK_VERSION=$ndk_ver" >> $env:GITHUB_ENV
echo "GRADLE_OPTS=-Dorg.gradle.daemon=false" >> $env:GITHUB_ENV

26
.github/workflows/issues.yml vendored Normal file
View File

@@ -0,0 +1,26 @@
name: Check Issues
on:
issues:
types: [opened]
jobs:
check:
runs-on: ubuntu-latest
steps:
- name: Check out
uses: actions/checkout@v2
- name: Read latest version code
run: |
ver=$(sed -n 's/^magisk.versionCode=//p' gradle.properties)
echo MAGISK_VERSION_CODE=$ver >> $GITHUB_ENV
- if: contains(github.event.issue.body, format('Magisk version code{0} ', ':')) != true
id: close
name: Close Issue(template)
uses: peter-evans/close-issue@v1
with:
comment: This issue is being automatically closed because it does not follow the issue template.
- if: steps.close.conclusion == 'skipped' && contains(github.event.issue.body, format('Magisk version code{0} {1}', ':', env.MAGISK_VERSION_CODE)) != true
name: Close Issue(latest canary)
uses: peter-evans/close-issue@v1
with:
comment: This issue is being automatically closed because latest canary Magisk version code is ${{ env.MAGISK_VERSION_CODE }}.

3
.gitmodules vendored
View File

@@ -28,6 +28,9 @@
[submodule "xhook"]
path = native/jni/external/xhook
url = https://github.com/iqiyi/xHook.git
[submodule "libcxx"]
path = native/jni/external/libcxx
url = https://github.com/topjohnwu/libcxx.git
[submodule "termux-elf-cleaner"]
path = tools/termux-elf-cleaner
url = https://github.com/termux/termux-elf-cleaner.git

View File

@@ -1,7 +1,6 @@
![](docs/images/logo.png)
![ZIP Downloads](https://img.shields.io/badge/dynamic/json?color=blue&label=ZIP%20Downloads&query=magisk&url=https%3A%2F%2Fraw.githubusercontent.com%2Ftopjohnwu%2Fmagisk_files%2Fcount%2Fcount.json&cacheSeconds=1800)
![APK Downloads](https://img.shields.io/badge/dynamic/json?color=green&label=APK%20Downloads&query=manager&url=https%3A%2F%2Fraw.githubusercontent.com%2Ftopjohnwu%2Fmagisk_files%2Fcount%2Fcount.json&cacheSeconds=1800)
[![Downloads](https://img.shields.io/badge/dynamic/json?color=green&label=Downloads&query=totalString&url=https%3A%2F%2Fraw.githubusercontent.com%2Ftopjohnwu%2Fmagisk-files%2Fcount%2Fcount.json&cacheSeconds=1800)](https://raw.githubusercontent.com/topjohnwu/magisk-files/count/count.json)
## Introduction
@@ -15,11 +14,11 @@ Here are some feature highlights:
## Downloads
[![](https://img.shields.io/badge/Magisk%20Manager-v8.0.4-green)](https://github.com/topjohnwu/Magisk/releases/download/manager-v8.0.4/MagiskManager-v8.0.4.apk)
[![](https://img.shields.io/badge/Magisk%20Manager-Canary-red)](https://raw.githubusercontent.com/topjohnwu/magisk_files/canary/app-debug.apk)
<br>
[![](https://img.shields.io/badge/Magisk-v20.4-blue)](https://github.com/topjohnwu/Magisk/releases/tag/v20.4)
[![](https://img.shields.io/badge/Magisk%20Beta-v21.2-blue)](https://github.com/topjohnwu/Magisk/releases/tag/v21.2)
Please note that the only source of official Magisk information and downloads is [Github](https://github.com/topjohnwu/Magisk/). Beware of any other websites.
[![](https://img.shields.io/badge/Magisk-v22.0-blue)](https://github.com/topjohnwu/Magisk/releases/tag/v22.0)
[![](https://img.shields.io/badge/Magisk%20Beta-v22.0-blue)](https://github.com/topjohnwu/Magisk/releases/tag/v22.0)
[![](https://img.shields.io/badge/Magisk-Canary-red)](https://raw.githubusercontent.com/topjohnwu/magisk-files/canary/app-debug.apk)
## Useful Links
@@ -34,17 +33,14 @@ Here are some feature highlights:
- Android 4.4+: All core features available
- Android 6.0+: Guaranteed MagiskHide support
- Android 7.0+: Full MagiskHide protection
- Android 9.0+: Magisk Manager stealth mode
## Bug Reports
Canary Channels are cutting edge builds for those adventurous. To access canary builds, install the Canary Magisk Manager, switch to the Canary Channel in settings and upgrade.
**Only bug reports from Canary builds will be accepted.**
For installation issues, upload both boot image and install logs.<br>
For Magisk issues, upload boot logcat or dmesg.<br>
For Magisk Manager crashes, record and upload the logcat when the crash occurs.
For Magisk app crashes, record and upload the logcat when the crash occurs.
## Building and Development
@@ -60,13 +56,13 @@ For Magisk Manager crashes, record and upload the logcat when the crash occurs.
- Run `./build.py ndk` to let the script download and install NDK for you
- To start building, run `build.py` to see your options. \
For each action, use `-h` to access help (e.g. `./build.py all -h`)
- To start development, open the project in Android Studio. Both app (Kotlin/Java) and native (C++/C) source code can be properly developed using the IDE, but *always* use `build.py` for building.
- To start development, open the project with Android Studio. The IDE can be used for both app (Kotlin/Java) and native (C++/C) sources.
- Optionally, set custom configs with `config.prop`. A sample `config.prop.sample` is provided.
- To sign APKs and zips with your own private keys, set signing configs in `config.prop`. For more info, check [Google's Documentation](https://developer.android.com/studio/publish/app-signing.html#generate-key).
## Translation Contributions
Default string resources for Magisk Manager and its stub APK are located here:
Default string resources for the Magisk app and its stub APK are located here:
- `app/src/main/res/values/strings.xml`
- `stub/src/main/res/values/strings.xml`

5
app/.gitignore vendored
View File

@@ -6,6 +6,7 @@
app/release
*.hprof
.externalNativeBuild/
public.certificate.x509.pem
private.key.pk8
*.apk
src/main/assets
src/main/jniLibs
src/main/resources

View File

@@ -1,3 +1,4 @@
import org.apache.tools.ant.filters.FixCrLfFilter
import java.io.PrintStream
plugins {
@@ -22,8 +23,9 @@ android {
applicationId = "com.topjohnwu.magisk"
vectorDrawables.useSupportLibrary = true
multiDexEnabled = true
versionName = Config.appVersion
versionCode = Config.appVersionCode
versionName = Config.version
versionCode = Config.versionCode
ndk.abiFilters("armeabi-v7a", "arm64-v8a", "x86", "x86_64")
javaCompileOptions.annotationProcessorOptions.arguments(
mapOf("room.incremental" to "true")
@@ -51,13 +53,14 @@ android {
}
packagingOptions {
exclude("/META-INF/**")
exclude("/META-INF/*")
exclude("/org/bouncycastle/**")
exclude("/kotlin/**")
exclude("/kotlinx/**")
exclude("/okhttp3/**")
exclude("/*.txt")
exclude("/*.bin")
doNotStrip("**/*.so")
}
kotlinOptions {
@@ -65,10 +68,83 @@ android {
}
}
tasks["preBuild"]?.dependsOn(tasks.register("copyUtils", Copy::class) {
from(rootProject.file("scripts/util_functions.sh"))
into("src/main/res/raw")
})
val syncLibs by tasks.registering(Sync::class) {
into("src/main/jniLibs")
into("armeabi-v7a") {
from(rootProject.file("native/out/armeabi-v7a")) {
include("busybox", "magiskboot", "magiskinit", "magisk")
rename { if (it == "magisk") "libmagisk32.so" else "lib$it.so" }
}
from(rootProject.file("native/out/arm64-v8a")) {
include("magisk")
rename { if (it == "magisk") "libmagisk64.so" else "lib$it.so" }
}
}
into("x86") {
from(rootProject.file("native/out/x86")) {
include("busybox", "magiskboot", "magiskinit", "magisk")
rename { if (it == "magisk") "libmagisk32.so" else "lib$it.so" }
}
from(rootProject.file("native/out/x86_64")) {
include("magisk")
rename { if (it == "magisk") "libmagisk64.so" else "lib$it.so" }
}
}
onlyIf {
if (inputs.sourceFiles.files.size != 10)
throw StopExecutionException("Please build binaries first! (./build.py binary)")
true
}
}
val createStubLibs by tasks.registering {
dependsOn(syncLibs)
doLast {
val arm64 = project.file("src/main/jniLibs/arm64-v8a/libstub.so")
arm64.parentFile.mkdirs()
arm64.createNewFile()
val x64 = project.file("src/main/jniLibs/x86_64/libstub.so")
x64.parentFile.mkdirs()
x64.createNewFile()
}
}
val syncAssets by tasks.registering(Sync::class) {
dependsOn(createStubLibs)
inputs.property("version", Config.version)
inputs.property("versionCode", Config.versionCode)
into("src/main/assets")
from(rootProject.file("scripts")) {
include("util_functions.sh", "boot_patch.sh", "uninstaller.sh", "addon.d.sh")
}
into("chromeos") {
from(rootProject.file("tools/futility"))
from(rootProject.file("tools/keys")) {
include("kernel_data_key.vbprivk", "kernel.keyblock")
}
}
filesMatching("**/util_functions.sh") {
filter {
it.replace("#MAGISK_VERSION_STUB",
"MAGISK_VER='${Config.version}'\n" +
"MAGISK_VER_CODE=${Config.versionCode}")
}
filter<FixCrLfFilter>("eol" to FixCrLfFilter.CrLf.newInstance("lf"))
}
}
val syncResources by tasks.registering(Sync::class) {
dependsOn(syncAssets)
into("src/main/resources/META-INF/com/google/android")
from(rootProject.file("scripts/update_binary.sh")) {
rename { "update-binary" }
}
from(rootProject.file("scripts/flash_script.sh")) {
rename { "updater-script" }
}
}
tasks["preBuild"]?.dependsOn(syncResources)
android.applicationVariants.all {
val keysDir = rootProject.file("tools/keys")
@@ -125,13 +201,13 @@ dependencies {
implementation("${bindingAdapter}:${vBAdapt}")
implementation("${bindingAdapter}-recyclerview:${vBAdapt}")
val vMarkwon = "4.6.0"
val vMarkwon = "4.6.2"
implementation("io.noties.markwon:core:${vMarkwon}")
implementation("io.noties.markwon:html:${vMarkwon}")
implementation("io.noties.markwon:image:${vMarkwon}")
implementation("com.caverock:androidsvg:1.4")
val vLibsu = "3.0.2"
val vLibsu = "3.1.1"
implementation("com.github.topjohnwu.libsu:core:${vLibsu}")
implementation("com.github.topjohnwu.libsu:io:${vLibsu}")
@@ -158,7 +234,7 @@ dependencies {
implementation("com.squareup.moshi:moshi:${vMoshi}")
kapt("com.squareup.moshi:moshi-kotlin-codegen:${vMoshi}")
val vRoom = "2.3.0-alpha04"
val vRoom = "2.3.0-beta03"
implementation("androidx.room:room-runtime:${vRoom}")
implementation("androidx.room:room-ktx:${vRoom}")
kapt("androidx.room:room-compiler:${vRoom}")
@@ -167,17 +243,16 @@ dependencies {
implementation("androidx.navigation:navigation-fragment-ktx:${vNav}")
implementation("androidx.navigation:navigation-ui-ktx:${vNav}")
implementation("androidx.biometric:biometric:1.0.1")
implementation("androidx.biometric:biometric:1.1.0")
implementation("androidx.constraintlayout:constraintlayout:2.0.4")
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
implementation("androidx.browser:browser:1.3.0")
implementation("androidx.preference:preference:1.1.1")
implementation("androidx.recyclerview:recyclerview:1.1.0")
implementation("androidx.fragment:fragment-ktx:1.2.5")
implementation("androidx.work:work-runtime-ktx:2.4.0")
implementation("androidx.transition:transition:1.3.1")
implementation("androidx.fragment:fragment-ktx:1.3.1")
implementation("androidx.work:work-runtime-ktx:2.5.0")
implementation("androidx.transition:transition:1.4.0")
implementation("androidx.multidex:multidex:2.0.1")
implementation("androidx.core:core-ktx:1.3.2")
implementation("androidx.localbroadcastmanager:localbroadcastmanager:1.0.0")
implementation("com.google.android.material:material:1.2.1")
implementation("com.google.android.material:material:1.3.0")
}

View File

@@ -18,16 +18,10 @@
# Kotlin
-assumenosideeffects class kotlin.jvm.internal.Intrinsics {
public static void checkExpressionValueIsNotNull(...);
public static void checkNotNullExpressionValue(...);
public static void checkReturnedValueIsNotNull(...);
public static void checkFieldIsNotNull(...);
public static void checkParameterIsNotNull(...);
public static void check*(...);
public static void throw*(...);
}
# Stubs
-keep class a.* { *; }
# Snet
-keepclassmembers class com.topjohnwu.magisk.ui.safetynet.SafetyNetHelper { *; }
-keep,allowobfuscation interface com.topjohnwu.magisk.ui.safetynet.SafetyNetHelper$Callback
@@ -35,14 +29,17 @@
void onResponse(org.json.JSONObject);
}
# Stub
-keep class com.topjohnwu.magisk.core.App { <init>(java.lang.Object); }
# Strip Timber verbose and debug logging
-assumenosideeffects class timber.log.Timber.Tree {
-assumenosideeffects class timber.log.Timber$Tree {
public void v(**);
public void d(**);
}
# Excessive obfuscation
-repackageclasses
-repackageclasses 'a'
-allowaccessmodification
# QOL

View File

@@ -1,17 +1,27 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.topjohnwu.shared">
package="com.topjohnwu.shared"
android:installLocation="internalOnly">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="29"
tools:ignore="ScopedStorage" />
<uses-permission
android:name="android.permission.QUERY_ALL_PACKAGES"
tools:ignore="QueryAllPackagesPermission" />
<application
android:label="Magisk Manager"
android:installLocation="internalOnly"
android:usesCleartextTraffic="true"
android:allowBackup="false"
android:label="Magisk"
android:requestLegacyExternalStorage="true"
android:supportsRtl="true"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
tools:ignore="UnusedAttribute">
</application>
android:usesCleartextTraffic="true"
tools:ignore="UnusedAttribute" />
</manifest>

View File

@@ -1,7 +1,10 @@
package com.topjohnwu.magisk.utils;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.os.Build;
@@ -10,20 +13,36 @@ import com.topjohnwu.magisk.FileProvider;
import java.io.File;
public class APKInstall {
public static Intent installIntent(Context c, File apk) {
Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (Build.VERSION.SDK_INT >= 24) {
intent.setData(FileProvider.getUriForFile(c, c.getPackageName() + ".provider", apk));
} else {
//noinspection ResultOfMethodCallIgnored SetWorldReadable
apk.setReadable(true, false);
intent.setData(Uri.fromFile(apk));
}
return intent;
}
public static void install(Context c, File apk) {
c.startActivity(installIntent(c, apk));
}
public static Intent installIntent(Context c, File apk) {
Intent install = new Intent(Intent.ACTION_INSTALL_PACKAGE);
install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
install.setData(FileProvider.getUriForFile(c, c.getPackageName() + ".provider", apk));
} else {
apk.setReadable(true, false);
install.setData(Uri.fromFile(apk));
}
return install;
public static void registerInstallReceiver(Context c, BroadcastReceiver r) {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
filter.addAction(Intent.ACTION_PACKAGE_ADDED);
filter.addDataScheme("package");
c.getApplicationContext().registerReceiver(r, filter);
}
public static void installHideResult(Activity c, File apk) {
Intent intent = installIntent(c, apk);
intent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
c.startActivityForResult(intent, 0); // Ignore result, use install receiver
}
}

View File

@@ -3,21 +3,19 @@
xmlns:tools="http://schemas.android.com/tools"
package="com.topjohnwu.magisk">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="29" />
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
<application
android:name=".core.App"
android:extractNativeLibs="true"
android:icon="@drawable/ic_launcher"
android:name="a.e"
android:allowBackup="false"
android:multiArch="true"
tools:ignore="UnusedAttribute,GoogleAppIndexingWarning">
<!-- Splash -->
<activity
android:name="a.c"
android:name=".core.SplashActivity"
android:exported="true"
android:theme="@style/SplashTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -30,48 +28,47 @@
</activity>
<!-- Main -->
<activity android:name="a.b" />
<activity android:name=".ui.MainActivity" />
<!-- Superuser -->
<activity
android:name="a.m"
android:name=".ui.surequest.SuRequestActivity"
android:directBootAware="true"
android:excludeFromRecents="true"
android:exported="false"
tools:ignore="AppLinkUrlError">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<!-- Receiver -->
<receiver
android:name="a.h"
android:directBootAware="true">
android:name=".core.Receiver"
android:directBootAware="true"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.REBOOT" />
<action android:name="android.intent.action.LOCALE_CHANGED" />
<action android:name="android.intent.action.UID_REMOVED" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.PACKAGE_REPLACED" />
<action android:name="android.intent.action.PACKAGE_FULLY_REMOVED" />
<data android:scheme="package" />
</intent-filter>
</receiver>
<!-- DownloadService -->
<service android:name="a.j" />
<service android:name=".core.download.DownloadService" />
<!-- FileProvider -->
<provider
android:name="a.p"
android:name=".core.Provider"
android:authorities="${applicationId}.provider"
android:directBootAware="true"
android:exported="false"
android:grantUriPermissions="true">
</provider>
android:grantUriPermissions="true" />
<!-- Hardcode GMS version -->
<meta-data
@@ -82,16 +79,12 @@
<provider
android:name="androidx.work.impl.WorkManagerInitializer"
android:authorities="${applicationId}.workmanager-init"
tools:node="remove" />
tools:node="remove"
tools:ignore="ExportedContentProvider" />
<!-- We don't invalidate Room -->
<service
android:name="androidx.room.MultiInstanceInvalidationService"
tools:node="remove"/>
<!-- We don't use Device Credentials -->
<activity
android:name="androidx.biometric.DeviceCredentialHandlerActivity"
tools:node="remove" />
</application>

View File

@@ -1,32 +0,0 @@
@file:JvmName("a")
package a
import com.topjohnwu.magisk.core.App
import com.topjohnwu.magisk.core.Provider
import com.topjohnwu.magisk.core.Receiver
import com.topjohnwu.magisk.core.SplashActivity
import com.topjohnwu.magisk.core.download.DownloadService
import com.topjohnwu.magisk.ui.MainActivity
import com.topjohnwu.magisk.ui.surequest.SuRequestActivity
import com.topjohnwu.signing.SignBoot
fun main(args: Array<String>) {
SignBoot.main(args)
}
class b : MainActivity()
class c : SplashActivity()
class e : App {
constructor() : super()
constructor(o: Any) : super(o)
}
class h : Receiver()
class j : DownloadService()
class m : SuRequestActivity()
class p : Provider()

View File

@@ -10,7 +10,6 @@ import androidx.appcompat.app.AppCompatDelegate
import androidx.core.content.res.use
import androidx.databinding.DataBindingUtil
import androidx.databinding.ViewDataBinding
import androidx.lifecycle.MutableLiveData
import androidx.navigation.NavController
import androidx.navigation.NavDirections
import androidx.navigation.fragment.NavHostFragment
@@ -28,7 +27,7 @@ abstract class BaseUIActivity<VM : BaseViewModel, Binding : ViewDataBinding> :
protected open val themeRes: Int = Theme.selected.themeRes
private val navHostFragment by lazy {
supportFragmentManager.findFragmentById(navHost) as? NavHostFragment
supportFragmentManager.findFragmentById(navHostId) as? NavHostFragment
}
private val topFragment get() = navHostFragment?.childFragmentManager?.fragments?.getOrNull(0)
protected val currentFragment get() = topFragment as? BaseUIFragment<*, *>
@@ -36,7 +35,7 @@ abstract class BaseUIActivity<VM : BaseViewModel, Binding : ViewDataBinding> :
override val viewRoot: View get() = binding.root
open val navigation: NavController? get() = navHostFragment?.navController
open val navHost: Int = 0
open val navHostId: Int = 0
open val snackbarView get() = binding.root
init {
@@ -58,14 +57,6 @@ abstract class BaseUIActivity<VM : BaseViewModel, Binding : ViewDataBinding> :
.use { it.getDrawable(0) }
.also { window.setBackgroundDrawable(it) }
directionsDispatcher.observe(this) {
it?.navigate()
// we don't want the directions to be re-dispatched, so we preemptively set them to null
if (it != null) {
directionsDispatcher.value = null
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window?.decorView?.let {
it.systemUiVisibility = (it.systemUiVisibility
@@ -127,14 +118,4 @@ abstract class BaseUIActivity<VM : BaseViewModel, Binding : ViewDataBinding> :
fun NavDirections.navigate() {
navigation?.navigate(this)
}
companion object {
private val directionsDispatcher = MutableLiveData<NavDirections?>()
fun postDirections(navDirections: NavDirections) =
directionsDispatcher.postValue(navDirections)
}
}

View File

@@ -5,7 +5,6 @@ import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.graphics.Insets
import androidx.databinding.DataBindingUtil
import androidx.databinding.OnRebindCallback
import androidx.databinding.ViewDataBinding
@@ -41,6 +40,11 @@ abstract class BaseUIFragment<VM : BaseViewModel, Binding : ViewDataBinding> :
return binding.root
}
override fun onStart() {
super.onStart()
activity.supportActionBar?.subtitle = null
}
override fun onEventDispatched(event: ViewEvent) = when(event) {
is ContextExecutor -> event(requireContext())
is ActivityExecutor -> event(activity)

View File

@@ -1,7 +1,6 @@
package com.topjohnwu.magisk.arch
import android.Manifest
import android.os.Build
import androidx.annotation.CallSuper
import androidx.core.graphics.Insets
import androidx.databinding.Bindable
@@ -107,7 +106,7 @@ abstract class BaseViewModel(
_viewEvents.postValue(this)
}
fun NavDirections.publish() {
fun NavDirections.navigate() {
_viewEvents.postValue(NavigationEvent(this))
}

View File

@@ -10,8 +10,9 @@ import androidx.multidex.MultiDex
import androidx.work.WorkManager
import com.topjohnwu.magisk.BuildConfig
import com.topjohnwu.magisk.DynAPK
import com.topjohnwu.magisk.core.utils.AppShellInit
import com.topjohnwu.magisk.core.utils.BusyBoxInit
import com.topjohnwu.magisk.core.utils.IODispatcherExecutor
import com.topjohnwu.magisk.core.utils.RootInit
import com.topjohnwu.magisk.core.utils.updateConfig
import com.topjohnwu.magisk.di.koinModules
import com.topjohnwu.magisk.ktx.unwrap
@@ -19,6 +20,7 @@ import com.topjohnwu.superuser.Shell
import org.koin.android.ext.koin.androidContext
import org.koin.core.context.startKoin
import timber.log.Timber
import java.io.File
import kotlin.system.exitProcess
open class App() : Application() {
@@ -31,7 +33,7 @@ open class App() : Application() {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
Shell.setDefaultBuilder(Shell.Builder.create()
.setFlags(Shell.FLAG_MOUNT_MASTER)
.setInitializers(RootInit::class.java)
.setInitializers(BusyBoxInit::class.java, AppShellInit::class.java)
.setTimeout(2))
Shell.EXECUTOR = IODispatcherExecutor()
@@ -61,12 +63,18 @@ open class App() : Application() {
val wrapped = impl.wrap()
super.attachBaseContext(wrapped)
val info = base.applicationInfo
val libDir = runCatching {
info.javaClass.getDeclaredField("secondaryNativeLibraryDir").get(info) as String?
}.getOrNull() ?: info.nativeLibraryDir
Const.NATIVE_LIB_DIR = File(libDir)
// Normal startup
startKoin {
androidContext(wrapped)
modules(koinModules)
}
ResMgr.init(impl)
AssetHack.init(impl)
app.registerActivityLifecycleCallbacks(ForegroundTracker)
WorkManager.initialize(impl.wrapJob(), androidx.work.Configuration.Builder().build())
}

View File

@@ -1,41 +1,52 @@
package com.topjohnwu.magisk.core
import android.os.Build
import android.os.Process
import com.topjohnwu.magisk.BuildConfig
import java.io.File
@Suppress("DEPRECATION")
object Const {
val CPU_ABI: String
val CPU_ABI_32: String
init {
if (Build.VERSION.SDK_INT >= 21) {
CPU_ABI = Build.SUPPORTED_ABIS[0]
CPU_ABI_32 = Build.SUPPORTED_32_BIT_ABIS.firstOrNull() ?: CPU_ABI
} else {
CPU_ABI = Build.CPU_ABI
CPU_ABI_32 = CPU_ABI
}
}
// Paths
lateinit var MAGISKTMP: String
lateinit var NATIVE_LIB_DIR: File
val MAGISK_PATH get() = "$MAGISKTMP/modules"
const val TMP_FOLDER_PATH = "/dev/tmp"
const val TMPDIR = "/dev/tmp"
const val MAGISK_LOG = "/cache/magisk.log"
// Versions
const val SNET_EXT_VER = 15
const val SNET_REVISION = "18ab78817087c337ae0edd1ecac38aec49217880"
const val BOOTCTL_REVISION = "18ab78817087c337ae0edd1ecac38aec49217880"
const val SNET_REVISION = "22.0"
const val BOOTCTL_REVISION = "22.0"
// Misc
val USER_ID = Process.myUid() / 100000
object Version {
const val MIN_VERSION = "v19.0"
const val MIN_VERCODE = 19000
const val MIN_VERSION = "v20.4"
const val MIN_VERCODE = 20400
fun atLeast_20_2() = Info.env.magiskVersionCode >= 20200 || isCanary()
fun atLeast_20_4() = Info.env.magiskVersionCode >= 20400 || isCanary()
fun atLeast_21_0() = Info.env.magiskVersionCode >= 21000 || isCanary()
fun atLeast_21_2() = Info.env.magiskVersionCode >= 21200 || isCanary()
fun isCanary() = Info.env.magiskVersionCode % 100 != 0
}
object ID {
const val FETCH_ZIP = 2
const val SELECT_FILE = 3
const val MAX_ACTIVITY_RESULT = 10
// notifications
const val MAGISK_UPDATE_NOTIFICATION_ID = 4
const val APK_UPDATE_NOTIFICATION_ID = 5
const val UPDATE_NOTIFICATION_CHANNEL = "update"
const val PROGRESS_NOTIFICATION_CHANNEL = "progress"
@@ -46,9 +57,13 @@ object Const {
const val PATREON_URL = "https://www.patreon.com/topjohnwu"
const val SOURCE_CODE_URL = "https://github.com/topjohnwu/Magisk"
val CHANGELOG_URL = if (BuildConfig.VERSION_CODE % 100 != 0) Info.remote.magisk.note
else "https://topjohnwu.github.io/Magisk/releases/${BuildConfig.VERSION_CODE}.md"
const val GITHUB_RAW_URL = "https://raw.githubusercontent.com/"
const val GITHUB_API_URL = "https://api.github.com/"
const val GITHUB_PAGE_URL = "https://topjohnwu.github.io/magisk_files/"
const val GITHUB_PAGE_URL = "https://topjohnwu.github.io/magisk-files/"
const val GITHUB_OLD_PAGE_URL = "https://topjohnwu.github.io/magisk_files/"
const val JS_DELIVR_URL = "https://cdn.jsdelivr.net/gh/"
const val OFFICIAL_REPO = "https://magisk-modules-repo.github.io/submission/modules.json"
}

View File

@@ -14,44 +14,38 @@ import android.content.Intent
import android.content.res.AssetManager
import android.content.res.Configuration
import android.content.res.Resources
import android.util.DisplayMetrics
import androidx.annotation.RequiresApi
import com.topjohnwu.magisk.DynAPK
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.download.DownloadService
import com.topjohnwu.magisk.core.utils.refreshLocale
import com.topjohnwu.magisk.core.utils.updateConfig
import com.topjohnwu.magisk.ktx.forceGetDeclaredField
import com.topjohnwu.magisk.ui.MainActivity
import com.topjohnwu.magisk.ui.surequest.SuRequestActivity
fun AssetManager.addAssetPath(path: String) {
DynAPK.addAssetPath(this, path)
}
fun Context.wrap(global: Boolean = true): Context =
if (global) GlobalResContext(this) else ResContext(this)
fun Context.wrap(inject: Boolean = false): Context =
if (inject) ReInjectedContext(this) else InjectedContext(this)
fun Context.wrapJob(): Context = object : GlobalResContext(this) {
fun Context.wrapJob(): Context = object : InjectedContext(this) {
override fun getApplicationContext(): Context {
return this
}
override fun getApplicationContext() = 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)
return super.getSystemService(name).let {
when {
!isRunningAsStub -> it
name == JOB_SCHEDULER_SERVICE -> JobSchedulerWrapper(it as JobScheduler)
else -> it
}
}
}
}
fun Class<*>.cmp(pkg: String): ComponentName {
val name = ClassMap[this].name
return ComponentName(pkg, Info.stub?.classToComponent?.get(name) ?: name)
}
fun Class<*>.cmp(pkg: String) =
ComponentName(pkg, Info.stub?.classToComponent?.get(name) ?: name)
inline fun <reified T> Activity.redirect() = Intent(intent)
.setComponent(T::class.java.cmp(packageName))
@@ -59,34 +53,27 @@ inline fun <reified T> Activity.redirect() = Intent(intent)
inline fun <reified T> Context.intent() = Intent().setComponent(T::class.java.cmp(packageName))
private open class GlobalResContext(base: Context) : ContextWrapper(base) {
open val mRes: Resources get() = ResMgr.resource
override fun getResources(): Resources {
return mRes
}
override fun getClassLoader(): ClassLoader {
return javaClass.classLoader!!
}
private open class InjectedContext(base: Context) : ContextWrapper(base) {
open val res: Resources get() = AssetHack.resource
override fun getAssets(): AssetManager = res.assets
override fun getResources() = res
override fun getClassLoader() = javaClass.classLoader!!
override fun createConfigurationContext(config: Configuration): Context {
return ResContext(super.createConfigurationContext(config))
return super.createConfigurationContext(config).wrap(true)
}
}
private class ResContext(base: Context) : GlobalResContext(base) {
override val mRes by lazy { base.resources.patch() }
private class ReInjectedContext(base: Context) : InjectedContext(base) {
override val res by lazy { base.resources.patch() }
private fun Resources.patch(): Resources {
updateConfig()
if (isRunningAsStub)
assets.addAssetPath(ResMgr.apk)
assets.addAssetPath(AssetHack.apk)
return this
}
}
object ResMgr {
object AssetHack {
lateinit var resource: Resources
lateinit var apk: String
@@ -101,62 +88,39 @@ object ResMgr {
apk = context.packageResourcePath
}
}
fun newResource(): Resources {
val asset = AssetManager::class.java.newInstance()
asset.addAssetPath(apk)
val config = Configuration(resource.configuration)
val metrics = DisplayMetrics()
metrics.setTo(resource.displayMetrics)
return Resources(asset, metrics, config)
}
}
@RequiresApi(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<JobInfo> {
return base.allPendingJobs
}
override fun getPendingJob(jobId: Int): JobInfo? {
return base.getPendingJob(jobId)
}
override fun schedule(job: JobInfo) = base.schedule(job.patch())
override fun enqueue(job: JobInfo, work: JobWorkItem) = base.enqueue(job.patch(), work)
override fun cancel(jobId: Int) = base.cancel(jobId)
override fun cancelAll() = base.cancelAll()
override fun getAllPendingJobs(): List<JobInfo> = base.allPendingJobs
override fun getPendingJob(jobId: Int) = base.getPendingJob(jobId)
private fun JobInfo.patch(): JobInfo {
// We need to swap out the service of JobInfo
val name = service.className
val component = ComponentName(
service.packageName,
Info.stubChk.classToComponent[name] ?: name
)
// Swap out the service of JobInfo
val component = service.run {
ComponentName(packageName,
Info.stub?.classToComponent?.get(className) ?: className)
}
javaClass.getDeclaredField("service").apply {
isAccessible = true
}.set(this, component)
javaClass.forceGetDeclaredField("service")?.set(this, component)
return this
}
}
private object ClassMap {
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,
Receiver::class.java to a.h::class.java,
DownloadService::class.java to a.j::class.java,
SuRequestActivity::class.java to a.m::class.java
)
operator fun get(c: Class<*>) = map.getOrElse(c) { c }
}
// Keep a reference to these resources to prevent it from
// being removed when running "remove unused resources"
val shouldKeepResources = listOf(

View File

@@ -1,41 +1,45 @@
package com.topjohnwu.magisk.core
import android.os.Build
import androidx.databinding.ObservableBoolean
import com.topjohnwu.magisk.DynAPK
import com.topjohnwu.magisk.core.model.UpdateInfo
import com.topjohnwu.magisk.core.utils.net.NetworkObserver
import com.topjohnwu.magisk.data.repository.NetworkService
import com.topjohnwu.magisk.ktx.get
import com.topjohnwu.magisk.utils.CachedValue
import com.topjohnwu.magisk.ktx.getProperty
import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.ShellUtils.fastCmd
import com.topjohnwu.superuser.internal.UiThreadHandler
import java.io.FileInputStream
import java.io.File
import java.io.IOException
import java.util.*
val isRunningAsStub get() = Info.stub != null
object Info {
val envRef = CachedValue { loadState() }
@JvmStatic val env by envRef
var stub: DynAPK.Data? = null
val stubChk: DynAPK.Data
get() = stub as DynAPK.Data
var remote = UpdateInfo()
val EMPTY_REMOTE = UpdateInfo()
var remote = EMPTY_REMOTE
suspend fun getRemote(svc: NetworkService): UpdateInfo? {
return if (remote === EMPTY_REMOTE) {
svc.fetchUpdate()?.apply { remote = this }
} else remote
}
// Device state
var crypto = ""
@JvmStatic var isSAR = false
@JvmStatic var isAB = false
@JvmStatic val env by lazy { loadState() }
@JvmField var isSAR = false
@JvmField var isAB = false
@JvmField val isVirtualAB = getProperty("ro.virtual_ab.enabled", "false") == "true"
@JvmStatic val isFDE get() = crypto == "block"
@JvmStatic var ramdisk = false
@JvmStatic var hasGMS = true
@JvmStatic var isPixel = false
@JvmStatic val cryptoText get() = crypto.capitalize(Locale.US)
@JvmField var ramdisk = false
@JvmField var hasGMS = true
@JvmField val isPixel = Build.BRAND == "google"
@JvmField val isEmulator = getProperty("ro.kernel.qemu", "0") == "1"
var crypto = ""
var noDataExec = false
val isConnected by lazy {
ObservableBoolean(false).also { field ->
@@ -47,14 +51,12 @@ object Info {
val isNewReboot by lazy {
try {
FileInputStream("/proc/sys/kernel/random/boot_id").bufferedReader().use {
val id = it.readLine()
if (id != Config.bootId) {
Config.bootId = id
true
} else {
false
}
val id = File("/proc/sys/kernel/random/boot_id").readText()
if (id != Config.bootId) {
Config.bootId = id
true
} else {
false
}
} catch (e: IOException) {
false
@@ -64,7 +66,7 @@ object Info {
private fun loadState() = Env(
fastCmd("magisk -v").split(":".toRegex())[0],
runCatching { fastCmd("magisk -V").toInt() }.getOrDefault(-1),
Shell.su("magiskhide --status").exec().isSuccess
Shell.su("magiskhide status").exec().isSuccess
)
class Env(
@@ -73,8 +75,8 @@ object Info {
hide: Boolean = false
) {
val magiskHide get() = Config.magiskHide
val magiskVersionCode = when (code) {
in Int.MIN_VALUE..Const.Version.MIN_VERCODE -> -1
val magiskVersionCode = when {
code < Const.Version.MIN_VERCODE -> -1
else -> if (Shell.rootAccess()) code else -1
}
val isUnsupported = code > 0 && code < Const.Version.MIN_VERCODE

View File

@@ -1,10 +1,10 @@
package com.topjohnwu.magisk.core
import android.annotation.SuppressLint
import android.content.ContextWrapper
import android.content.Intent
import com.topjohnwu.magisk.core.base.BaseReceiver
import com.topjohnwu.magisk.core.magiskdb.PolicyDao
import com.topjohnwu.magisk.core.su.SuCallbackHandler
import com.topjohnwu.magisk.view.Shortcuts
import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.GlobalScope
@@ -15,30 +15,33 @@ open class Receiver : BaseReceiver() {
private val policyDB: PolicyDao by inject()
private fun getPkg(intent: Intent): String {
return intent.data?.encodedSchemeSpecificPart.orEmpty()
@SuppressLint("InlinedApi")
private fun getPkg(intent: Intent): String? {
val pkg = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME)
return pkg ?: intent.data?.schemeSpecificPart
}
private fun getUid(intent: Intent): Int? {
val uid = intent.getIntExtra(Intent.EXTRA_UID, -1)
return if (uid == -1) null else uid
}
override fun onReceive(context: ContextWrapper, intent: Intent?) {
intent ?: return
fun rmPolicy(pkg: String) = GlobalScope.launch {
policyDB.delete(pkg)
fun rmPolicy(uid: Int) = GlobalScope.launch {
policyDB.delete(uid)
}
when (intent.action ?: return) {
Intent.ACTION_REBOOT -> {
SuCallbackHandler(context, intent.getStringExtra("action"), intent.extras)
}
Intent.ACTION_PACKAGE_REPLACED -> {
// This will only work pre-O
if (Config.suReAuth)
rmPolicy(getPkg(intent))
getUid(intent)?.let { rmPolicy(it) }
}
Intent.ACTION_PACKAGE_FULLY_REMOVED -> {
val pkg = getPkg(intent)
rmPolicy(pkg)
Shell.su("magiskhide --rm $pkg").submit()
Intent.ACTION_UID_REMOVED -> {
getUid(intent)?.let { rmPolicy(it) }
getPkg(intent)?.let { Shell.su("magiskhide rm $it").submit() }
}
Intent.ACTION_LOCALE_CHANGED -> Shortcuts.setupDynamic(context)
}

View File

@@ -1,32 +1,30 @@
package com.topjohnwu.magisk.core
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import com.topjohnwu.magisk.BuildConfig.APPLICATION_ID
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.base.BaseActivity
import com.topjohnwu.magisk.core.tasks.HideAPK
import com.topjohnwu.magisk.data.repository.NetworkService
import com.topjohnwu.magisk.ktx.get
import com.topjohnwu.magisk.ui.MainActivity
import com.topjohnwu.magisk.view.MagiskDialog
import com.topjohnwu.magisk.view.Notifications
import com.topjohnwu.magisk.view.Shortcuts
import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.util.concurrent.CountDownLatch
open class SplashActivity : Activity() {
open class SplashActivity : BaseActivity() {
override fun attachBaseContext(base: Context) {
super.attachBaseContext(base.wrap())
}
private val latch = CountDownLatch(1)
override fun onCreate(savedInstanceState: Bundle?) {
setTheme(R.style.SplashTheme)
super.onCreate(savedInstanceState)
GlobalScope.launch(Dispatchers.IO) {
initAndStart()
}
// Pre-initialize root shell
Shell.getShell(null) { initAndStart() }
}
private fun handleRepackage(pkg: String?) {
@@ -40,13 +38,26 @@ open class SplashActivity : Activity() {
if (Config.suManager.isNotEmpty())
Config.suManager = ""
pkg ?: return
Shell.su("(pm uninstall $pkg)& >/dev/null 2>&1").exec()
if (!Shell.su("(pm uninstall $pkg)& >/dev/null 2>&1").exec().isSuccess)
uninstallApp(pkg)
}
}
private fun initAndStart() {
// Pre-initialize root shell
Shell.getShell()
if (isRunningAsStub && !Shell.rootAccess()) {
runOnUiThread {
MagiskDialog(this)
.applyTitle(R.string.unsupport_nonroot_stub_title)
.applyMessage(R.string.unsupport_nonroot_stub_msg)
.applyButton(MagiskDialog.ButtonType.POSITIVE) {
titleRes = R.string.install
onClick { HideAPK.restore(this@SplashActivity) }
}
.cancellable(false)
.reveal()
}
return
}
val prevPkg = intent.getStringExtra(Const.Key.PREV_PKG)
@@ -60,11 +71,21 @@ open class SplashActivity : Activity() {
get<NetworkService>()
DONE = true
redirect<MainActivity>().also { startActivity(it) }
startActivity(redirect<MainActivity>())
finish()
}
@Suppress("DEPRECATION")
private fun uninstallApp(pkg: String) {
val uri = Uri.Builder().scheme("package").opaquePart(pkg).build()
val intent = Intent(Intent.ACTION_UNINSTALL_PACKAGE, uri)
intent.putExtra(Intent.EXTRA_RETURN_RESULT, true)
startActivityForResult(intent) { _, _ ->
latch.countDown()
}
latch.await()
}
companion object {
var DONE = false
}

View File

@@ -1,13 +1,11 @@
package com.topjohnwu.magisk.core
import android.annotation.SuppressLint
import android.content.Context
import androidx.work.*
import com.topjohnwu.magisk.BuildConfig
import com.topjohnwu.magisk.data.repository.NetworkService
import com.topjohnwu.magisk.view.Notifications
import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.koin.core.KoinComponent
import org.koin.core.inject
import java.util.concurrent.TimeUnit
@@ -18,20 +16,15 @@ class UpdateCheckService(context: Context, workerParams: WorkerParameters)
private val svc: NetworkService by inject()
override suspend fun doWork(): Result {
// Make sure shell initializer was ran
withContext(Dispatchers.IO) {
Shell.getShell()
}
return svc.fetchUpdate()?.let {
if (BuildConfig.VERSION_CODE < it.app.versionCode)
return svc.fetchUpdate()?.run {
if (Info.env.isActive && BuildConfig.VERSION_CODE < magisk.versionCode)
Notifications.managerUpdate(applicationContext)
else if (Info.env.isActive && Info.env.magiskVersionCode < it.magisk.versionCode)
Notifications.magiskUpdate(applicationContext)
Result.success()
} ?: Result.failure()
}
companion object {
@SuppressLint("NewApi")
fun schedule(context: Context) {
if (Config.checkUpdate) {
val constraints = Constraints.Builder()

View File

@@ -14,7 +14,6 @@ import androidx.collection.SparseArrayCompat
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.utils.currentLocale
import com.topjohnwu.magisk.core.wrap
import com.topjohnwu.magisk.ktx.set
@@ -26,6 +25,13 @@ typealias ActivityResultCallback = BaseActivity.(Int, Intent?) -> Unit
abstract class BaseActivity : AppCompatActivity() {
private val resultCallbacks by lazy { SparseArrayCompat<ActivityResultCallback>() }
private val newRequestCode: Int get() {
var requestCode: Int
do {
requestCode = Random.nextInt(0, 1 shl 15)
} while (resultCallbacks.containsKey(requestCode))
return requestCode
}
override fun applyOverrideConfiguration(config: Configuration?) {
// Force applying our preferred local
@@ -34,7 +40,7 @@ abstract class BaseActivity : AppCompatActivity() {
}
override fun attachBaseContext(base: Context) {
super.attachBaseContext(base.wrap(false))
super.attachBaseContext(base.wrap(true))
}
fun withPermission(permission: String, builder: PermissionRequestBuilder.() -> Unit) {
@@ -49,10 +55,7 @@ abstract class BaseActivity : AppCompatActivity() {
if (ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED) {
request.onSuccess()
} else {
var requestCode: Int
do {
requestCode = Random.nextInt(Const.ID.MAX_ACTIVITY_RESULT + 1, 1 shl 15)
} while (resultCallbacks.containsKey(requestCode))
val requestCode = newRequestCode
resultCallbacks[requestCode] = { result, _ ->
if (result > 0)
request.onSuccess()
@@ -92,7 +95,8 @@ abstract class BaseActivity : AppCompatActivity() {
}
}
fun startActivityForResult(intent: Intent, requestCode: Int, callback: ActivityResultCallback) {
fun startActivityForResult(intent: Intent, callback: ActivityResultCallback) {
val requestCode = newRequestCode
resultCallbacks[requestCode] = callback
try {
startActivityForResult(intent, requestCode)

View File

@@ -1,31 +0,0 @@
package com.topjohnwu.magisk.core.download
import android.net.Uri
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
sealed class Action : Parcelable {
sealed class Flash : Action() {
@Parcelize
object Primary : Flash()
@Parcelize
object Secondary : Flash()
}
@Parcelize
object Download : Action()
@Parcelize
object Uninstall : Action()
@Parcelize
object EnvFix : Action()
@Parcelize
data class Patch(val fileUri: Uri) : Action()
}

View File

@@ -8,11 +8,8 @@ import androidx.lifecycle.MutableLiveData
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.ForegroundTracker
import com.topjohnwu.magisk.core.base.BaseService
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.checkSum
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
import com.topjohnwu.magisk.core.utils.ProgressInputStream
import com.topjohnwu.magisk.data.repository.NetworkService
import com.topjohnwu.magisk.ktx.withStreams
import com.topjohnwu.magisk.view.Notifications
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -69,18 +66,11 @@ abstract class BaseDownloader : BaseService(), KoinComponent {
// -- Download logic
private suspend fun Subject.startDownload() {
val skip = this is Subject.Magisk && file.checkSum("MD5", magisk.md5)
if (!skip) {
val stream = service.fetchFile(url).toProgressStream(this)
when (this) {
is Subject.Module -> // Download and process on-the-fly
stream.toModule(file, service.fetchInstaller().byteStream())
else -> {
withStreams(stream, file.outputStream()) { it, out -> it.copyTo(out) }
if (this is Subject.Manager)
handleAPK(this)
}
}
val stream = service.fetchFile(url).toProgressStream(this)
when (this) {
is Subject.Module -> // Download and process on-the-fly
stream.toModule(file, service.fetchInstaller().byteStream())
is Subject.Manager -> handleAPK(this, stream)
}
val newId = notifyFinish(this)
if (ForegroundTracker.hasForeground)
@@ -187,7 +177,7 @@ abstract class BaseDownloader : BaseService(), KoinComponent {
companion object : KoinComponent {
const val ACTION_KEY = "download_action"
private val progressBroadcast = MutableLiveData<Pair<Float, Subject>>()
private val progressBroadcast = MutableLiveData<Pair<Float, Subject>?>()
fun observeProgress(owner: LifecycleOwner, callback: (Float, Subject) -> Unit) {
progressBroadcast.value = null

View File

@@ -1,46 +1,38 @@
package com.topjohnwu.magisk.core.download
import android.annotation.SuppressLint
import android.app.Notification
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.os.Build
import androidx.core.net.toFile
import com.topjohnwu.magisk.core.download.Action.*
import com.topjohnwu.magisk.core.download.Action.Flash.Secondary
import com.topjohnwu.magisk.core.download.Subject.*
import com.topjohnwu.magisk.arch.BaseUIActivity
import com.topjohnwu.magisk.core.ForegroundTracker
import com.topjohnwu.magisk.core.download.Action.Flash
import com.topjohnwu.magisk.core.download.Subject.Manager
import com.topjohnwu.magisk.core.download.Subject.Module
import com.topjohnwu.magisk.core.intent
import com.topjohnwu.magisk.core.tasks.EnvFixTask
import com.topjohnwu.magisk.ui.flash.FlashFragment
import com.topjohnwu.magisk.utils.APKInstall
import com.topjohnwu.superuser.internal.UiThreadHandler
import kotlin.random.Random.Default.nextInt
@SuppressLint("Registered")
open class DownloadService : BaseDownloader() {
private val context get() = this
override suspend fun onFinish(subject: Subject, id: Int) = when (subject) {
is Magisk -> subject.onFinish(id)
is Module -> subject.onFinish(id)
is Manager -> subject.onFinish(id)
}
private suspend fun Magisk.onFinish(id: Int) = when (val action = action) {
Uninstall -> FlashFragment.uninstall(file, id)
EnvFix -> {
remove(id)
EnvFixTask(file).exec()
Unit
}
is Patch -> FlashFragment.patch(file, action.fileUri, id)
is Flash -> FlashFragment.flash(file, action is Secondary, id)
else -> Unit
}
private fun Module.onFinish(id: Int) = when (action) {
is Flash -> FlashFragment.install(file, id)
Flash -> {
UiThreadHandler.run {
(ForegroundTracker.foreground as? BaseUIActivity<*, *>)
?.navigation?.navigate(FlashFragment.install(file, id))
}
}
else -> Unit
}
@@ -53,22 +45,13 @@ open class DownloadService : BaseDownloader() {
override fun Notification.Builder.setIntent(subject: Subject)
= when (subject) {
is Magisk -> setIntent(subject)
is Module -> setIntent(subject)
is Manager -> setIntent(subject)
}
private fun Notification.Builder.setIntent(subject: Magisk)
= when (val action = subject.action) {
Uninstall -> setContentIntent(FlashFragment.uninstallIntent(context, subject.file))
is Flash -> setContentIntent(FlashFragment.flashIntent(context, subject.file, action is Secondary))
is Patch -> setContentIntent(FlashFragment.patchIntent(context, subject.file, action.fileUri))
else -> setContentIntent(Intent())
}
private fun Notification.Builder.setIntent(subject: Module)
= when (subject.action) {
is Flash -> setContentIntent(FlashFragment.installIntent(context, subject.file))
Flash -> setContentIntent(FlashFragment.installIntent(context, subject.file))
else -> setContentIntent(Intent())
}

View File

@@ -2,19 +2,22 @@ package com.topjohnwu.magisk.core.download
import android.content.Context
import androidx.core.net.toFile
import com.topjohnwu.magisk.BuildConfig
import com.topjohnwu.magisk.DynAPK
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.isRunningAsStub
import com.topjohnwu.magisk.core.tasks.HideAPK
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
import com.topjohnwu.magisk.ktx.relaunchApp
import com.topjohnwu.magisk.ktx.withStreams
import com.topjohnwu.magisk.ktx.writeTo
import java.io.File
import java.io.InputStream
import java.io.OutputStream
private fun Context.patch(apk: File) {
val patched = File(apk.parent, "patched.apk")
HideAPK.patch(this, apk.path, patched.path, packageName, applicationInfo.nonLocalizedLabel)
HideAPK.patch(this, apk, patched, packageName, applicationInfo.nonLocalizedLabel)
apk.delete()
patched.renameTo(apk)
}
@@ -22,30 +25,51 @@ private fun Context.patch(apk: File) {
private fun BaseDownloader.notifyHide(id: Int) {
update(id) {
it.setProgress(0, 0, true)
.setContentTitle(getString(R.string.hide_manager_title))
.setContentTitle(getString(R.string.hide_app_title))
.setContentText("")
}
}
suspend fun BaseDownloader.handleAPK(subject: Subject.Manager) {
val apk = subject.file.toFile()
val id = subject.notifyID()
private class DupOutputStream(
private val o1: OutputStream,
private val o2: OutputStream
) : OutputStream() {
override fun write(b: Int) {
o1.write(b)
o2.write(b)
}
override fun write(b: ByteArray?, off: Int, len: Int) {
o1.write(b, off, len)
o2.write(b, off, len)
}
override fun close() {
o1.close()
o2.close()
}
}
suspend fun BaseDownloader.handleAPK(subject: Subject.Manager, stream: InputStream) {
fun write(output: OutputStream) {
val ext = subject.externalFile.outputStream()
val o = DupOutputStream(ext, output)
withStreams(stream, o) { src, out -> src.copyTo(out) }
}
if (isRunningAsStub) {
// Move to upgrade location
apk.copyTo(DynAPK.update(this), overwrite = true)
apk.delete()
if (Info.stubChk.version < subject.stub.versionCode) {
notifyHide(id)
val apk = subject.file.toFile()
val id = subject.notifyID()
write(DynAPK.update(this).outputStream())
if (Info.stub!!.version < subject.stub.versionCode) {
// Also upgrade stub
service.fetchFile(subject.stub.link).byteStream().use { it.writeTo(apk) }
notifyHide(id)
service.fetchFile(subject.stub.link).byteStream().writeTo(apk)
patch(apk)
} else {
// Simply relaunch the app
stopSelf()
relaunchApp(this)
}
} else if (packageName != BuildConfig.APPLICATION_ID) {
notifyHide(id)
patch(apk)
} else {
write(subject.file.outputStream())
}
}

View File

@@ -1,8 +1,9 @@
package com.topjohnwu.magisk.core.download
import android.net.Uri
import com.topjohnwu.magisk.ktx.withStreams
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
import com.topjohnwu.magisk.ktx.forEach
import com.topjohnwu.magisk.ktx.withStreams
import java.io.InputStream
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream
@@ -25,8 +26,7 @@ fun InputStream.toModule(file: Uri, installer: InputStream) {
zout.write("#MAGISK\n".toByteArray(charset("UTF-8")))
var off = -1
var entry: ZipEntry? = zin.nextEntry
while (entry != null) {
zin.forEach { entry ->
if (off < 0) {
off = entry.name.indexOf('/') + 1
}
@@ -38,8 +38,6 @@ fun InputStream.toModule(file: Uri, installer: InputStream) {
zin.copyTo(zout)
}
}
entry = zin.nextEntry
}
}
}

View File

@@ -6,7 +6,6 @@ import android.os.Parcelable
import androidx.core.net.toUri
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.model.MagiskJson
import com.topjohnwu.magisk.core.model.ManagerJson
import com.topjohnwu.magisk.core.model.StubJson
import com.topjohnwu.magisk.core.model.module.OnlineModule
import com.topjohnwu.magisk.core.utils.MediaStoreUtils
@@ -40,70 +39,26 @@ sealed class Subject : Parcelable {
@Parcelize
class Manager(
private val app: ManagerJson = Info.remote.app,
private val json: MagiskJson = Info.remote.magisk,
val stub: StubJson = Info.remote.stub
) : Subject() {
override val action get() = Action.Download
override val title: String get() = "MagiskManager-${app.version}(${app.versionCode})"
override val url: String get() = app.link
override val title: String get() = "Magisk-${json.version}(${json.versionCode})"
override val url: String get() = json.link
@IgnoredOnParcel
override val file by lazy {
cachedFile("manager.apk")
}
val externalFile get() = MediaStoreUtils.getFile("$title.apk").uri
}
abstract class Magisk : Subject() {
val magisk: MagiskJson = Info.remote.magisk
@Parcelize
private class Internal(
override val action: Action
) : Magisk() {
override val url: String get() = magisk.link
override val title: String get() = "Magisk-${magisk.version}(${magisk.versionCode})"
@IgnoredOnParcel
override val file by lazy {
cachedFile("magisk.zip")
}
}
@Parcelize
private class Uninstall : Magisk() {
override val action get() = Action.Uninstall
override val url: String get() = Info.remote.uninstaller.link
override val title: String get() = "uninstall.zip"
@IgnoredOnParcel
override val file by lazy {
cachedFile(title)
}
}
@Parcelize
private class Download : Magisk() {
override val action get() = Action.Download
override val url: String get() = magisk.link
override val title: String get() = "Magisk-${magisk.version}(${magisk.versionCode}).zip"
@IgnoredOnParcel
override val file by lazy {
MediaStoreUtils.getFile(title).uri
}
}
companion object {
operator fun invoke(config: Action) = when (config) {
Action.Download -> Download()
Action.Uninstall -> Uninstall()
Action.EnvFix, is Action.Flash, is Action.Patch -> Internal(config)
}
}
}
}
sealed class Action : Parcelable {
@Parcelize
object Flash : Action()
@Parcelize
object Download : Action()
}

View File

@@ -31,12 +31,6 @@ class PolicyDao(
}
}.commit()
suspend fun delete(packageName: String) = buildQuery<Delete> {
condition {
equals("package_name", packageName)
}
}.commit()
suspend fun delete(uid: Int) = buildQuery<Delete> {
condition {
equals("uid", uid)

View File

@@ -6,29 +6,13 @@ import kotlinx.parcelize.Parcelize
@JsonClass(generateAdapter = true)
data class UpdateInfo(
val app: ManagerJson = ManagerJson(),
val uninstaller: UninstallerJson = UninstallerJson(),
val magisk: MagiskJson = MagiskJson(),
val stub: StubJson = StubJson()
)
@JsonClass(generateAdapter = true)
data class UninstallerJson(
val link: String = ""
)
@JsonClass(generateAdapter = true)
data class MagiskJson(
val version: String = "",
val versionCode: Int = -1,
val link: String = "",
val note: String = "",
val md5: String = ""
)
@Parcelize
@JsonClass(generateAdapter = true)
data class ManagerJson(
data class MagiskJson(
val version: String = "",
val versionCode: Int = -1,
val link: String = "",

Some files were not shown because too many files have changed in this diff Show More