@@ -98,7 +98,6 @@ struct ZygiskContext {
9898 ~ZygiskContext ();
9999
100100 /* Zygisksu changed: Load module fds */
101- bool load_modules_only ();
102101 void run_modules_pre ();
103102 void run_modules_post ();
104103 DCL_PRE_POST (fork)
@@ -696,7 +695,7 @@ void ZygiskContext::fork_post() {
696695 g_ctx = nullptr ;
697696}
698697
699- bool ZygiskContext:: load_modules_only () {
698+ bool load_modules_only () {
700699 struct zygisk_modules ms;
701700 if (rezygiskd_read_modules (&ms) == false ) {
702701 LOGE (" Failed to read modules from zygiskd" );
@@ -738,14 +737,33 @@ bool ZygiskContext::load_modules_only() {
738737 zygisk_modules[zygisk_module_length].handle = handle;
739738 zygisk_modules[zygisk_module_length].zygisk_module_entry = (void (*)(void *, void *))entry;
740739
740+ zygisk_modules[zygisk_module_length].base = solist_get_base (entry);
741+ zygisk_modules[zygisk_module_length].size = solist_get_size (entry);
742+
743+ zygisk_modules[zygisk_module_length].deconstructors = solist_get_deconstructors (entry);
744+ zygisk_modules[zygisk_module_length].gap = solist_get_gap_info (entry);
745+
746+ LOGD (" Loaded module [%s]. Entry: %p, Base: %p, Size: %zu, Deconstructors: fini_func=%p, fini_array=%p (size: %zu), Gap: %p (size: %zu)" ,
747+ lib_path,
748+ entry,
749+ zygisk_modules[zygisk_module_length].base ,
750+ zygisk_modules[zygisk_module_length].size ,
751+ zygisk_modules[zygisk_module_length].deconstructors .fini_func ,
752+ zygisk_modules[zygisk_module_length].deconstructors .fini_array ,
753+ zygisk_modules[zygisk_module_length].deconstructors .fini_array_size ,
754+ zygisk_modules[zygisk_module_length].gap .start ,
755+ zygisk_modules[zygisk_module_length].gap .size );
756+
741757 zygisk_modules[zygisk_module_length].unload = false ;
742758
743- zygisk_module_length++;
759+ /* INFO: Early removal to avoid gaps in solist */
760+ solist_drop_so_path (entry, false );
744761
745- /* INFO: The module will call register module function, so by then, it must be fully registered. */
746- rezygisk_module_call_on_load (&zygisk_modules[zygisk_module_length - 1 ], env);
762+ zygisk_module_length++;
747763 }
748764
765+ solist_reset_counters (zygisk_module_length, zygisk_module_length);
766+
749767 free_modules (&ms);
750768
751769 return true ;
@@ -754,6 +772,8 @@ bool ZygiskContext::load_modules_only() {
754772/* Zygisksu changed: Load module fds */
755773void ZygiskContext::run_modules_pre () {
756774 for (size_t i = 0 ; i < zygisk_module_length; i++) {
775+ rezygisk_module_call_on_load (&zygisk_modules[i], env);
776+
757777 if (flags[APP_SPECIALIZE]) rezygisk_module_call_pre_app_specialize (&zygisk_modules[i], args.app );
758778 else if (flags[SERVER_FORK_AND_SPECIALIZE]) rezygisk_module_call_pre_server_specialize (&zygisk_modules[i], args.server );
759779 }
@@ -771,24 +791,28 @@ void ZygiskContext::run_modules_post() {
771791
772792 /* INFO: If module is unloaded by dlclose, there's no need to
773793 hide it from soinfo manually. */
774- if (m->unload && dlclose (m->handle ) == 0 ) modules_unloaded++;
775- else if (m->unload ) {
776- PLOGE (" Failed to unload module %zu" , i);
777- } else {
778- bool has_dropped = solist_drop_so_path ((void *)m->zygisk_module_entry , false );
779- if (!has_dropped) continue ;
794+ if (m->unload ) {
795+ /* INFO: Deconstructors are called in the inverted order, and following fini array then fini
796+ function order. It must not change. */
797+ for (size_t j = m->deconstructors .fini_array_size ; j > 0 ; j--) {
798+ void (*destructor)(void ) = m->deconstructors .fini_array [j - 1 ];
799+ if (destructor) {
800+ LOGD (" Calling destructor %p for module %p" , (void *)destructor, (void *)m->zygisk_module_entry );
801+
802+ destructor ();
803+ }
804+ }
805+
806+ if (m->deconstructors .fini_func ) m->deconstructors .fini_func ();
780807
781- LOGD (" Dropped solist record for %p" , (void *)m->zygisk_module_entry );
808+ solist_unload_lib (&m->gap , m->base , m->size );
809+
810+ modules_unloaded++;
782811 }
783812 }
784813
785- if (zygisk_module_length > 0 ) {
814+ if (zygisk_module_length > 0 )
786815 LOGD (" Modules unloaded: %zu/%zu" , modules_unloaded, zygisk_module_length);
787-
788- solist_reset_counters (zygisk_module_length, modules_unloaded);
789-
790- LOGD (" Returned global counters to their original values" );
791- }
792816}
793817
794818/* Zygisksu changed: Load module fds */
@@ -936,11 +960,6 @@ void ZygiskContext::nativeForkSystemServer_pre() {
936960 LOGV (" pre forkSystemServer" );
937961 flags[SERVER_FORK_AND_SPECIALIZE] = true ;
938962
939- if (!modules_loaded) {
940- load_modules_only ();
941- modules_loaded = true ;
942- }
943-
944963 fork_pre ();
945964 if (!is_child ())
946965 return ;
@@ -1140,6 +1159,13 @@ static void hook_unloader() {
11401159 }
11411160
11421161 lsplt_free_maps (map_infos);
1162+
1163+ /* INFO: Load modules early on (before system server fork) to spread through all Zygotes */
1164+ if (!modules_loaded) {
1165+ if (!load_modules_only ()) {
1166+ LOGE (" Failed to load modules in hook_unloader" );
1167+ } else modules_loaded = true ;
1168+ }
11431169}
11441170
11451171static void unhook_functions () {
0 commit comments