Skip to content

Commit db9c280

Browse files
committed
save file extra data to file instead of global data, to avoid mutex.
we should use shared memory, but it is only support in platform >=26
1 parent 13cafd7 commit db9c280

File tree

2 files changed

+184
-77
lines changed

2 files changed

+184
-77
lines changed

bootstrap.cpp

Lines changed: 29 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,7 @@
1010
#include "xhook/xhook.h"
1111
#include "com_unity3d_hookplayer_Boostrap.h"
1212
#include "mymap32.h"
13-
14-
struct GlobalData
15-
{
16-
/*std::map<int, FILE*>*/MyMap32 g_fd_to_file;
17-
/*std::map<FILE*, ShadowZip*>*/MyMap32 g_file_to_shadowzip;
18-
PthreadRwMutex g_file_to_shadowzip_mutex;
19-
};
20-
#define g_global_data (LeakSingleton<GlobalData, 0>::instance())
13+
#include "file_mapping.h"
2114

2215

2316
static inline char * dupstr(const char* const str)
@@ -40,9 +33,6 @@ std::string get_apk_path(const std::string& bundle_id);
4033
__attribute__ ((visibility ("default")))
4134
JNIEXPORT int JNICALL Java_com_unity3d_hookplayer_Boostrap_init(JNIEnv * jenv, jclass cls)
4235
{
43-
LeakSingleton<GlobalData, 0>::init();
44-
g_global_data->g_fd_to_file.init(4096, 4096, "fd_to_file");
45-
g_global_data->g_file_to_shadowzip.init(8192, 8192, "file_to_shadowzip");
4636
return bootstrap();
4737
}
4838

@@ -81,7 +71,7 @@ JNIEXPORT char* JNICALL Java_com_unity3d_hookplayer_Boostrap_getAbi(JNIEnv * jen
8171
return dupstr(TARGET_ARCH_ABI);
8272
}*/
8373

84-
static char* g_use_data_path = NULL;
74+
char* g_use_data_path = NULL;
8575
__attribute__ ((visibility ("default")))
8676
JNIEXPORT int JNICALL Java_com_unity3d_hookplayer_Boostrap_useDataDir(JNIEnv * jenv, jclass cls, jstring data_path_str, jstring apk_path_str)
8777
{
@@ -444,22 +434,14 @@ static int my_stat(const char *path, struct stat *file_stat)
444434

445435
static ShadowZip* get_cached_shadowzip(FILE *stream)
446436
{
447-
PthreadReadGuard(g_global_data->g_file_to_shadowzip_mutex);
448-
ShadowZip* shadow_zip = NULL;
449-
g_global_data->g_file_to_shadowzip.find((intptr_t)stream, (intptr_t&)shadow_zip);
450-
return shadow_zip;
437+
FileExtraData* file_extra_data = get_file_mapping(stream);
438+
return file_extra_data == NULL ? NULL : file_extra_data->shadow_zip;
451439
}
452440

453441
static ShadowZip* get_cached_shadowzip(int fd)
454442
{
455-
PthreadReadGuard(g_global_data->g_file_to_shadowzip_mutex);
456-
FILE * stream = NULL;
457-
g_global_data->g_fd_to_file.find((intptr_t)fd, (intptr_t&)stream);
458-
if (stream == NULL){return NULL;}
459-
460-
ShadowZip* shadow_zip = NULL;
461-
g_global_data->g_file_to_shadowzip.find((intptr_t)stream, (intptr_t&)shadow_zip);
462-
return shadow_zip;
443+
FileExtraData* file_extra_data = get_file_mapping(fd);
444+
return file_extra_data == NULL ? NULL : file_extra_data->shadow_zip;
463445
}
464446

465447
typedef FILE *(* FOpenType)(const char *path, const char *mode);
@@ -485,10 +467,9 @@ static FILE *my_fopen(const char *path, const char *mode)
485467
return fopen(path, mode);
486468
}
487469

488-
MY_LOG("shadow apk in fopen: %s, fd:0x%08x, file*: 0x%08llx", path, fileno(fp), (unsigned long long)fp);
489-
PthreadWriteGuard(g_global_data->g_file_to_shadowzip_mutex);
490-
g_global_data->g_file_to_shadowzip.set((intptr_t)fp, (intptr_t)shadow_zip);
491-
return fp;
470+
FileExtraData* file_extra_data = save_file_mapping(shadow_zip);
471+
MY_LOG("shadow apk in fopen: %s, fd:0x%08x, file*: 0x%08llx", path, file_extra_data->fd, (unsigned long long)file_extra_data->file);
472+
return file_extra_data->file;
492473
}
493474

494475
MY_METHOD("not apk([%s],[%s])", path, mode);
@@ -561,26 +542,15 @@ static int my_fclose(FILE* stream)
561542
{
562543
MY_METHOD("my_fclose: file*: 0x%08llx", (unsigned long long)stream);
563544

564-
ShadowZip* shadow_zip = NULL;
565-
{
566-
PthreadWriteGuard(g_global_data->g_file_to_shadowzip_mutex);
567-
if (g_global_data->g_file_to_shadowzip.find((intptr_t)stream, (intptr_t &)shadow_zip))
568-
{
569-
g_global_data->g_file_to_shadowzip.del((intptr_t)stream);
570-
571-
int fd = fileno(stream);
572-
MY_METHOD("my_fclose: fd: 0x%08x, file*: 0x%08llx", fd, (unsigned long long)stream);
573-
g_global_data->g_fd_to_file.del((intptr_t)fd);
574-
}
575-
545+
FileExtraData* file_extra_data = get_file_mapping(stream);
546+
if (file_extra_data != NULL)
547+
{
548+
clean_mapping_data(file_extra_data);
549+
return 0;
576550
}
577-
578-
if (shadow_zip == NULL){
579-
return fclose(stream);
580-
}else{
581-
int ret = shadow_zip->fclose(stream);
582-
delete shadow_zip;
583-
return ret;
551+
else
552+
{
553+
return fclose(stream);
584554
}
585555
}
586556

@@ -633,13 +603,10 @@ static int my_open(const char *path, int flags, ...)
633603
MY_METHOD("open(rollback): %s -> fd:0x%08x", path, ret);
634604
return ret;
635605
}
636-
int fd = fileno(fp);
637606

638-
MY_LOG("shadow apk: %s, fd:0x%08x, file*: 0x%08llx", path, fd, (unsigned long long)fp);
639-
PthreadWriteGuard(g_global_data->g_file_to_shadowzip_mutex);
640-
g_global_data->g_fd_to_file.set((intptr_t)fd, (intptr_t)fp);
641-
g_global_data->g_file_to_shadowzip.set((intptr_t)fp, (intptr_t)shadow_zip);
642-
return fd;
607+
FileExtraData* file_extra_data = save_file_mapping(shadow_zip);
608+
MY_LOG("shadow apk in open: %s, fd:0x%08x, file*: 0x%08llx", path, file_extra_data->fd, (unsigned long long)file_extra_data->file);
609+
return file_extra_data->fd;
643610
}
644611

645612
int ret = has_mode ? open(path, flags, mode) : open(path, flags);
@@ -668,8 +635,7 @@ typedef off_t (*LseekType)(int fd, off_t offset, int whence);
668635
off_t my_lseek(int fd, off_t offset, int whence)
669636
{
670637
MY_METHOD("lseek: 0x%08x, offset: 0x%08lx, whence: %d", fd, offset, whence);
671-
672-
638+
673639
off_t ret = 0;
674640
ShadowZip* shadow_zip = get_cached_shadowzip(fd);
675641
if (shadow_zip == NULL){
@@ -704,29 +670,15 @@ static int my_close(int fd)
704670
{
705671
MY_METHOD("my_close: 0x%08x", fd);
706672

707-
708-
ShadowZip* shadow_zip = NULL;
673+
FileExtraData* file_extra_data = get_file_mapping(fd);
674+
if (file_extra_data != NULL)
709675
{
710-
PthreadWriteGuard(g_global_data->g_file_to_shadowzip_mutex);
711-
FILE* stream = NULL;
712-
if(g_global_data->g_fd_to_file.find((intptr_t)fd, (intptr_t &)stream))
713-
{
714-
g_global_data->g_fd_to_file.del((intptr_t)fd);
715-
716-
MY_METHOD("my_close: fd: 0x%08x, file*: 0x%08llx", fd, (unsigned long long)stream);
717-
if (g_global_data->g_file_to_shadowzip.find((intptr_t)stream, (intptr_t &)shadow_zip))
718-
{
719-
g_global_data->g_file_to_shadowzip.del((intptr_t)stream);
720-
}
721-
}
676+
clean_mapping_data(file_extra_data);
677+
return 0;
722678
}
723-
724-
if (shadow_zip == NULL){
725-
return close(fd);
726-
}else{
727-
int ret = shadow_zip->fclose((FILE*)(size_t)fd);
728-
delete shadow_zip;
729-
return ret;
679+
else
680+
{
681+
return close(fd);
730682
}
731683
}
732684

@@ -870,7 +822,7 @@ static int bootstrap()
870822

871823
if (use_patch){
872824
MY_INFO("bootstrap running %s with apk_path:%s", TARGET_ARCH_ABI, g_apk_file_path);
873-
bool success = (0 == ShadowZip::init(g_use_data_path, g_apk_file_path)) && (0 == init_hook(bundle_id)) && (0 == init_art_hook());
825+
bool success = (0 == ShadowZip::init(g_use_data_path, g_apk_file_path)) && (0 == init_hook(bundle_id)) && (0 == init_file_mapping_data());
874826
if (success)
875827
{
876828
static void *handle = dlopen(patch_il2cpp_path.c_str(), RTLD_NOW);

file_mapping.h

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
#ifndef FILE_MAPPLE_H
2+
#define FILE_MAPPLE_H
3+
4+
#include <string.h>
5+
#include <sys/types.h>
6+
#include <sys/stat.h>
7+
#include <fcntl.h>
8+
#include <dirent.h>
9+
#include <errno.h>
10+
#include "log.h"
11+
12+
#include <vector>
13+
#include <string>
14+
15+
extern char* g_use_data_path;
16+
17+
const uint64_t MY_MAGIC_NUM = 0x1983546019835460;
18+
struct FileExtraData
19+
{
20+
uint64_t magic_num;
21+
FileExtraData* self;
22+
ShadowZip* shadow_zip;
23+
FILE* file;
24+
int fd;
25+
};
26+
27+
28+
// we should use memfd, but it is not supported in older android
29+
static int init_file_mapping_data()
30+
{
31+
char fds_dir[512] = {0};
32+
snprintf(fds_dir, sizeof(fds_dir), "%s/rt_fd_mappings", g_use_data_path);
33+
MY_INFO("init_file_mapping_data %s with apk_path:%s", TARGET_ARCH_ABI, fds_dir);
34+
35+
//create dir if not exist
36+
DIR* dir = opendir(fds_dir);
37+
if (dir == NULL)
38+
{
39+
if (errno == ENOENT)
40+
{
41+
mkdir(fds_dir, 0700);
42+
dir = opendir(fds_dir);
43+
}
44+
else
45+
{
46+
MY_ERROR("open %s failed! errno:%d", fds_dir, errno);
47+
return -1;
48+
}
49+
}
50+
51+
//delete all files under the dir
52+
if (dir == NULL){
53+
MY_ERROR("open %s failed! errno:%d", fds_dir, errno);
54+
return -1;
55+
}
56+
57+
struct dirent *ent = NULL;
58+
std::vector<std::string> fd_files;
59+
while((ent = readdir(dir)) != NULL) {
60+
if(ent->d_type & DT_REG) {
61+
std::string fd_file = std::string(fds_dir) + "/" + ent->d_name;
62+
fd_files.push_back(fd_file);
63+
}
64+
}
65+
closedir(dir);
66+
67+
for(int i = 0; i < fd_files.size(); i++)
68+
{
69+
std::string& fd_file = fd_files[i];
70+
if (0 != unlink(fd_file.c_str()))
71+
{
72+
MY_METHOD("delete fd file:[%s], ret:%d", fd_file.c_str(), errno);
73+
return -1;
74+
}
75+
MY_METHOD("delete fd file:[%s]", fd_file.c_str());
76+
}
77+
return 0;
78+
}
79+
80+
static FileExtraData* save_file_mapping(ShadowZip* shadow_zip)
81+
{
82+
FileExtraData* file_extra_data = new FileExtraData();
83+
file_extra_data->magic_num = MY_MAGIC_NUM;
84+
file_extra_data->self = file_extra_data;
85+
file_extra_data->shadow_zip = shadow_zip;
86+
87+
char save_path[512] = {0};
88+
snprintf(save_path, sizeof(save_path), "%s/rt_fd_mappings/%08llx", g_use_data_path, (unsigned long long)file_extra_data);
89+
file_extra_data->file = ::fopen(save_path, "wb+");
90+
if (file_extra_data->file == NULL)
91+
{
92+
MY_ERROR("open save path:%s failed! errno:%d", save_path, errno);
93+
_exit(-1);
94+
}
95+
file_extra_data->fd = fileno(file_extra_data->file);
96+
97+
fwrite((void*)file_extra_data, 1, sizeof(FileExtraData), file_extra_data->file);
98+
fflush(file_extra_data->file);
99+
fseek(file_extra_data->file, 0, SEEK_SET);
100+
101+
MY_METHOD("FileExtraData saved to %s. fd:0x%08x, file*: 0x%08llx", save_path, file_extra_data->fd, (unsigned long long)file_extra_data->file);
102+
return file_extra_data;
103+
}
104+
105+
static FileExtraData* get_file_mapping(int fd)
106+
{
107+
off_t pos = lseek(fd, 0, SEEK_CUR);
108+
if (pos != 0){return NULL;}
109+
110+
lseek(fd, 0, SEEK_SET);
111+
FileExtraData file_extra_data_copy;
112+
int read_cnt = read(fd, (void*)&file_extra_data_copy, sizeof(FileExtraData));
113+
lseek(fd, 0, SEEK_SET);
114+
115+
//validate
116+
if (read_cnt != sizeof(FileExtraData)){ return NULL; }
117+
if (file_extra_data_copy.magic_num != MY_MAGIC_NUM) { return NULL; }
118+
if (file_extra_data_copy.fd != fd) { return NULL; }
119+
120+
return file_extra_data_copy.self;
121+
}
122+
123+
static FileExtraData* get_file_mapping(FILE* file)
124+
{
125+
off_t pos = ftell(file);
126+
if (pos != 0){return NULL;}
127+
128+
fseek(file, 0, SEEK_SET);
129+
FileExtraData file_extra_data_copy;
130+
int read_cnt = fread((void*)&file_extra_data_copy, 1, sizeof(FileExtraData), file);
131+
fseek(file, 0, SEEK_SET);
132+
133+
//validate
134+
if (read_cnt != sizeof(FileExtraData)){ return NULL; }
135+
if (file_extra_data_copy.magic_num != MY_MAGIC_NUM) { return NULL; }
136+
if (file_extra_data_copy.file != file) { return NULL; }
137+
138+
return file_extra_data_copy.self;
139+
}
140+
141+
static void clean_mapping_data(FileExtraData* file_extra_data)
142+
{
143+
char save_path[512] = {0};
144+
snprintf(save_path, sizeof(save_path), "%s/rt_fd_mappings/%08llx", g_use_data_path, (unsigned long long)file_extra_data->self);
145+
unlink(save_path);
146+
147+
fclose(file_extra_data->file);
148+
delete file_extra_data->shadow_zip;
149+
MY_METHOD("FileExtraData deleted %s. fd:0x%08x, file*: 0x%08llx", save_path, file_extra_data->fd, (unsigned long long)file_extra_data->file);
150+
151+
delete file_extra_data->self;
152+
}
153+
154+
155+
#endif

0 commit comments

Comments
 (0)