11use crate :: consts:: { MODULEMNT , MODULEROOT , MODULEUPGRADE , WORKERDIR } ;
22use crate :: daemon:: MagiskD ;
3- use crate :: ffi:: { ModuleInfo , exec_script, get_magisk_tmp, get_zygisk_lib_name, load_prop_file} ;
3+ use crate :: ffi:: {
4+ ModuleInfo , exec_module_scripts, exec_script, get_magisk_tmp, get_zygisk_lib_name,
5+ load_prop_file, set_zygisk_prop,
6+ } ;
47use crate :: mount:: setup_module_mount;
58use base:: {
69 DirEntry , Directory , FsPathBuilder , LibcReturn , LoggedResult , OsResultStatic , ResultExt ,
710 Utf8CStr , Utf8CStrBuf , Utf8CString , WalkResult , clone_attr, cstr, debug, error, info, libc,
8- warn,
11+ raw_cstr , warn,
912} ;
1013use libc:: { AT_REMOVEDIR , MS_RDONLY , O_CLOEXEC , O_CREAT , O_RDONLY } ;
1114use std:: collections:: BTreeMap ;
12- use std:: os:: fd:: AsRawFd ;
15+ use std:: os:: fd:: { AsRawFd , IntoRawFd } ;
1316use std:: path:: { Component , Path } ;
17+ use std:: ptr;
18+ use std:: sync:: atomic:: Ordering ;
1419
1520const MAGISK_BIN_INJECT_PARTITIONS : [ & Utf8CStr ; 4 ] = [
1621 cstr ! ( "/system/" ) ,
@@ -698,7 +703,7 @@ fn upgrade_modules() -> LoggedResult<()> {
698703 Ok ( ( ) )
699704}
700705
701- fn for_each_module ( func : impl Fn ( & DirEntry ) -> LoggedResult < ( ) > ) -> LoggedResult < ( ) > {
706+ fn for_each_module ( mut func : impl FnMut ( & DirEntry ) -> LoggedResult < ( ) > ) -> LoggedResult < ( ) > {
702707 let mut root = Directory :: open ( cstr ! ( MODULEROOT ) ) ?;
703708 while let Some ( ref e) = root. read ( ) ? {
704709 if e. is_dir ( ) && e. name ( ) != ".core" {
@@ -717,28 +722,161 @@ pub fn disable_modules() {
717722 . log_ok ( ) ;
718723}
719724
725+ fn run_uninstall_script ( module_name : & Utf8CStr ) {
726+ let script = cstr:: buf:: default ( )
727+ . join_path ( MODULEROOT )
728+ . join_path ( module_name)
729+ . join_path ( "uninstall.sh" ) ;
730+ exec_script ( & script) ;
731+ }
732+
720733pub fn remove_modules ( ) {
721734 for_each_module ( |e| {
722735 let dir = e. open_as_dir ( ) ?;
723736 if dir. contains_path ( cstr ! ( "uninstall.sh" ) ) {
724- let script = cstr:: buf:: default ( )
725- . join_path ( MODULEROOT )
726- . join_path ( e. name ( ) )
727- . join_path ( "uninstall.sh" ) ;
728- exec_script ( & script) ;
737+ run_uninstall_script ( e. name ( ) ) ;
729738 }
730739 Ok ( ( ) )
731740 } )
732741 . log_ok ( ) ;
733742 cstr ! ( MODULEROOT ) . remove_all ( ) . log_ok ( ) ;
734743}
735744
745+ fn collect_modules ( zygisk_enabled : bool , open_zygisk : bool ) -> Vec < ModuleInfo > {
746+ let mut modules = Vec :: new ( ) ;
747+
748+ #[ allow( unused_mut) ] // It's possible that z32 and z64 are unused
749+ for_each_module ( |e| {
750+ let name = e. name ( ) ;
751+ let dir = e. open_as_dir ( ) ?;
752+ if dir. contains_path ( cstr ! ( "remove" ) ) {
753+ info ! ( "{name}: remove" ) ;
754+ if dir. contains_path ( cstr ! ( "uninstall.sh" ) ) {
755+ run_uninstall_script ( name) ;
756+ }
757+ dir. remove_all ( ) ?;
758+ e. unlink ( ) ?;
759+ return Ok ( ( ) ) ;
760+ }
761+ dir. unlink_at ( cstr ! ( "update" ) , 0 ) . ok ( ) ;
762+ if dir. contains_path ( cstr ! ( "disable" ) ) {
763+ return Ok ( ( ) ) ;
764+ }
765+
766+ let mut z32 = -1 ;
767+ let mut z64 = -1 ;
768+
769+ let is_zygisk = dir. contains_path ( cstr ! ( "zygisk" ) ) ;
770+
771+ if zygisk_enabled {
772+ // Riru and its modules are not compatible with zygisk
773+ if name == "riru-core" || dir. contains_path ( cstr ! ( "riru" ) ) {
774+ return Ok ( ( ) ) ;
775+ }
776+
777+ fn open_fd_safe ( dir : & Directory , name : & Utf8CStr ) -> i32 {
778+ dir. open_as_file_at ( name, O_RDONLY | O_CLOEXEC , 0 )
779+ . log ( )
780+ . map ( IntoRawFd :: into_raw_fd)
781+ . unwrap_or ( -1 )
782+ }
783+
784+ if open_zygisk && is_zygisk {
785+ #[ cfg( target_arch = "arm" ) ]
786+ {
787+ z32 = open_fd_safe ( & dir, cstr ! ( "zygisk/armeabi-v7a.so" ) ) ;
788+ }
789+ #[ cfg( target_arch = "aarch64" ) ]
790+ {
791+ z32 = open_fd_safe ( & dir, cstr ! ( "zygisk/armeabi-v7a.so" ) ) ;
792+ z64 = open_fd_safe ( & dir, cstr ! ( "zygisk/arm64-v8a.so" ) ) ;
793+ }
794+ #[ cfg( target_arch = "x86" ) ]
795+ {
796+ z32 = open_fd_safe ( & dir, cstr ! ( "zygisk/x86.so" ) ) ;
797+ }
798+ #[ cfg( target_arch = "x86_64" ) ]
799+ {
800+ z32 = open_fd_safe ( & dir, cstr ! ( "zygisk/x86.so" ) ) ;
801+ z64 = open_fd_safe ( & dir, cstr ! ( "zygisk/x86_64.so" ) ) ;
802+ }
803+ #[ cfg( target_arch = "riscv64" ) ]
804+ {
805+ z64 = open_fd_safe ( & dir, cstr ! ( "zygisk/riscv64.so" ) ) ;
806+ }
807+ dir. unlink_at ( cstr ! ( "zygisk/unloaded" ) , 0 ) . ok ( ) ;
808+ }
809+ } else {
810+ // Ignore zygisk modules when zygisk is not enabled
811+ if is_zygisk {
812+ info ! ( "{name}: ignore" ) ;
813+ return Ok ( ( ) ) ;
814+ }
815+ }
816+ modules. push ( ModuleInfo {
817+ name : name. to_string ( ) ,
818+ z32,
819+ z64,
820+ } ) ;
821+ Ok ( ( ) )
822+ } )
823+ . log_ok ( ) ;
824+
825+ if zygisk_enabled && open_zygisk {
826+ let mut use_memfd = true ;
827+ let mut convert_to_memfd = |fd : i32 | -> i32 {
828+ if fd < 0 {
829+ return fd;
830+ }
831+ if use_memfd {
832+ let memfd = unsafe {
833+ libc:: syscall (
834+ libc:: SYS_memfd_create ,
835+ raw_cstr ! ( "jit-cache" ) ,
836+ libc:: MFD_CLOEXEC ,
837+ ) as i32
838+ } ;
839+ if memfd >= 0 {
840+ unsafe {
841+ if libc:: sendfile ( memfd, fd, ptr:: null_mut ( ) , i32:: MAX as usize ) < 0 {
842+ libc:: close ( memfd) ;
843+ } else {
844+ libc:: close ( fd) ;
845+ return memfd;
846+ }
847+ }
848+ }
849+ // Some error occurred, don't try again
850+ use_memfd = false ;
851+ }
852+ fd
853+ } ;
854+
855+ modules. iter_mut ( ) . for_each ( |m| {
856+ m. z32 = convert_to_memfd ( m. z32 ) ;
857+ m. z64 = convert_to_memfd ( m. z64 ) ;
858+ } ) ;
859+ }
860+
861+ modules
862+ }
863+
736864impl MagiskD {
737865 pub fn handle_modules ( & self ) {
738866 setup_module_mount ( ) ;
739867 upgrade_modules ( ) . ok ( ) ;
740- let modules = self . load_modules ( ) ;
741- apply_modules ( self . zygisk_enabled ( ) , & modules) ;
868+
869+ let zygisk = self . zygisk_enabled . load ( Ordering :: Acquire ) ;
870+ let modules = collect_modules ( zygisk, false ) ;
871+ exec_module_scripts ( cstr ! ( "post-fs-data" ) , & modules) ;
872+
873+ // Recollect modules (module scripts could remove itself)
874+ let modules = collect_modules ( zygisk, true ) ;
875+ if zygisk {
876+ set_zygisk_prop ( ) ;
877+ }
878+ apply_modules ( zygisk, & modules) ;
879+
742880 self . module_list . set ( modules) . ok ( ) ;
743881 }
744882}
0 commit comments