1 // Copyright 2018 Dolphin Emulator Project
2 // Licensed under GPLv2+
3 // Refer to the license.txt file included.
4 
5 #include "jni/AndroidCommon/IDCache.h"
6 
7 #include <jni.h>
8 
9 static constexpr jint JNI_VERSION = JNI_VERSION_1_6;
10 
11 static JavaVM* s_java_vm;
12 
13 static jclass s_native_library_class;
14 static jmethodID s_display_alert_msg;
15 static jmethodID s_do_rumble;
16 static jmethodID s_get_update_touch_pointer;
17 
18 static jclass s_game_file_class;
19 static jfieldID s_game_file_pointer;
20 static jmethodID s_game_file_constructor;
21 
22 static jclass s_game_file_cache_class;
23 static jfieldID s_game_file_cache_pointer;
24 
25 static jclass s_analytics_class;
26 static jmethodID s_send_analytics_report;
27 static jmethodID s_get_analytics_value;
28 
29 static jclass s_linked_hash_map_class;
30 static jmethodID s_linked_hash_map_init;
31 static jmethodID s_linked_hash_map_put;
32 
33 static jclass s_ini_file_class;
34 static jfieldID s_ini_file_pointer;
35 static jclass s_ini_file_section_class;
36 static jfieldID s_ini_file_section_pointer;
37 static jmethodID s_ini_file_section_constructor;
38 
39 static jclass s_compress_cb_class;
40 static jmethodID s_compress_cb_run;
41 
42 static jclass s_content_handler_class;
43 static jmethodID s_content_handler_open_fd;
44 static jmethodID s_content_handler_delete;
45 
46 namespace IDCache
47 {
GetEnvForThread()48 JNIEnv* GetEnvForThread()
49 {
50   thread_local static struct OwnedEnv
51   {
52     OwnedEnv()
53     {
54       status = s_java_vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
55       if (status == JNI_EDETACHED)
56         s_java_vm->AttachCurrentThread(&env, nullptr);
57     }
58 
59     ~OwnedEnv()
60     {
61       if (status == JNI_EDETACHED)
62         s_java_vm->DetachCurrentThread();
63     }
64 
65     int status;
66     JNIEnv* env = nullptr;
67   } owned;
68   return owned.env;
69 }
70 
GetNativeLibraryClass()71 jclass GetNativeLibraryClass()
72 {
73   return s_native_library_class;
74 }
75 
GetDisplayAlertMsg()76 jmethodID GetDisplayAlertMsg()
77 {
78   return s_display_alert_msg;
79 }
80 
GetDoRumble()81 jmethodID GetDoRumble()
82 {
83   return s_do_rumble;
84 }
85 
GetUpdateTouchPointer()86 jmethodID GetUpdateTouchPointer()
87 {
88   return s_get_update_touch_pointer;
89 }
90 
GetAnalyticsClass()91 jclass GetAnalyticsClass()
92 {
93   return s_analytics_class;
94 }
95 
GetSendAnalyticsReport()96 jmethodID GetSendAnalyticsReport()
97 {
98   return s_send_analytics_report;
99 }
100 
GetAnalyticsValue()101 jmethodID GetAnalyticsValue()
102 {
103   return s_get_analytics_value;
104 }
105 
GetGameFileClass()106 jclass GetGameFileClass()
107 {
108   return s_game_file_class;
109 }
110 
GetGameFilePointer()111 jfieldID GetGameFilePointer()
112 {
113   return s_game_file_pointer;
114 }
115 
GetGameFileConstructor()116 jmethodID GetGameFileConstructor()
117 {
118   return s_game_file_constructor;
119 }
120 
GetGameFileCacheClass()121 jclass GetGameFileCacheClass()
122 {
123   return s_game_file_cache_class;
124 }
125 
GetGameFileCachePointer()126 jfieldID GetGameFileCachePointer()
127 {
128   return s_game_file_cache_pointer;
129 }
130 
GetLinkedHashMapClass()131 jclass GetLinkedHashMapClass()
132 {
133   return s_linked_hash_map_class;
134 }
135 
GetLinkedHashMapInit()136 jmethodID GetLinkedHashMapInit()
137 {
138   return s_linked_hash_map_init;
139 }
140 
GetLinkedHashMapPut()141 jmethodID GetLinkedHashMapPut()
142 {
143   return s_linked_hash_map_put;
144 }
145 
GetIniFileClass()146 jclass GetIniFileClass()
147 {
148   return s_ini_file_class;
149 }
150 
GetIniFilePointer()151 jfieldID GetIniFilePointer()
152 {
153   return s_ini_file_pointer;
154 }
155 
GetIniFileSectionClass()156 jclass GetIniFileSectionClass()
157 {
158   return s_ini_file_section_class;
159 }
160 
GetIniFileSectionPointer()161 jfieldID GetIniFileSectionPointer()
162 {
163   return s_ini_file_section_pointer;
164 }
165 
GetIniFileSectionConstructor()166 jmethodID GetIniFileSectionConstructor()
167 {
168   return s_ini_file_section_constructor;
169 }
170 
GetCompressCallbackClass()171 jclass GetCompressCallbackClass()
172 {
173   return s_compress_cb_class;
174 }
175 
GetCompressCallbackRun()176 jmethodID GetCompressCallbackRun()
177 {
178   return s_compress_cb_run;
179 }
180 
GetContentHandlerClass()181 jclass GetContentHandlerClass()
182 {
183   return s_content_handler_class;
184 }
185 
GetContentHandlerOpenFd()186 jmethodID GetContentHandlerOpenFd()
187 {
188   return s_content_handler_open_fd;
189 }
190 
GetContentHandlerDelete()191 jmethodID GetContentHandlerDelete()
192 {
193   return s_content_handler_delete;
194 }
195 
196 }  // namespace IDCache
197 
198 #ifdef __cplusplus
199 extern "C" {
200 #endif
201 
JNI_OnLoad(JavaVM * vm,void * reserved)202 jint JNI_OnLoad(JavaVM* vm, void* reserved)
203 {
204   s_java_vm = vm;
205 
206   JNIEnv* env;
207   if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION) != JNI_OK)
208     return JNI_ERR;
209 
210   const jclass native_library_class = env->FindClass("org/dolphinemu/dolphinemu/NativeLibrary");
211   s_native_library_class = reinterpret_cast<jclass>(env->NewGlobalRef(native_library_class));
212   s_display_alert_msg = env->GetStaticMethodID(s_native_library_class, "displayAlertMsg",
213                                                "(Ljava/lang/String;Ljava/lang/String;Z)Z");
214   s_do_rumble = env->GetStaticMethodID(s_native_library_class, "rumble", "(ID)V");
215   s_get_update_touch_pointer =
216       env->GetStaticMethodID(s_native_library_class, "updateTouchPointer", "()V");
217   env->DeleteLocalRef(native_library_class);
218 
219   const jclass game_file_class = env->FindClass("org/dolphinemu/dolphinemu/model/GameFile");
220   s_game_file_class = reinterpret_cast<jclass>(env->NewGlobalRef(game_file_class));
221   s_game_file_pointer = env->GetFieldID(game_file_class, "mPointer", "J");
222   s_game_file_constructor = env->GetMethodID(game_file_class, "<init>", "(J)V");
223   env->DeleteLocalRef(game_file_class);
224 
225   const jclass game_file_cache_class =
226       env->FindClass("org/dolphinemu/dolphinemu/model/GameFileCache");
227   s_game_file_cache_class = reinterpret_cast<jclass>(env->NewGlobalRef(game_file_cache_class));
228   s_game_file_cache_pointer = env->GetFieldID(game_file_cache_class, "mPointer", "J");
229   env->DeleteLocalRef(game_file_cache_class);
230 
231   const jclass analytics_class = env->FindClass("org/dolphinemu/dolphinemu/utils/Analytics");
232   s_analytics_class = reinterpret_cast<jclass>(env->NewGlobalRef(analytics_class));
233   s_send_analytics_report =
234       env->GetStaticMethodID(s_analytics_class, "sendReport", "(Ljava/lang/String;[B)V");
235   s_get_analytics_value = env->GetStaticMethodID(s_analytics_class, "getValue",
236                                                  "(Ljava/lang/String;)Ljava/lang/String;");
237   env->DeleteLocalRef(analytics_class);
238 
239   const jclass ini_file_class = env->FindClass("org/dolphinemu/dolphinemu/utils/IniFile");
240   s_ini_file_class = reinterpret_cast<jclass>(env->NewGlobalRef(ini_file_class));
241   s_ini_file_pointer = env->GetFieldID(ini_file_class, "mPointer", "J");
242   env->DeleteLocalRef(ini_file_class);
243 
244   const jclass ini_file_section_class =
245       env->FindClass("org/dolphinemu/dolphinemu/utils/IniFile$Section");
246   s_ini_file_section_class = reinterpret_cast<jclass>(env->NewGlobalRef(ini_file_section_class));
247   s_ini_file_section_pointer = env->GetFieldID(ini_file_section_class, "mPointer", "J");
248   s_ini_file_section_constructor = env->GetMethodID(
249       ini_file_section_class, "<init>", "(Lorg/dolphinemu/dolphinemu/utils/IniFile;J)V");
250   env->DeleteLocalRef(ini_file_section_class);
251 
252   const jclass map_class = env->FindClass("java/util/LinkedHashMap");
253   s_linked_hash_map_class = reinterpret_cast<jclass>(env->NewGlobalRef(map_class));
254   s_linked_hash_map_init = env->GetMethodID(s_linked_hash_map_class, "<init>", "(I)V");
255   s_linked_hash_map_put = env->GetMethodID(
256       s_linked_hash_map_class, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
257 
258   const jclass compress_cb_class =
259       env->FindClass("org/dolphinemu/dolphinemu/utils/CompressCallback");
260   s_compress_cb_class = reinterpret_cast<jclass>(env->NewGlobalRef(compress_cb_class));
261   s_compress_cb_run = env->GetMethodID(s_compress_cb_class, "run", "(Ljava/lang/String;F)Z");
262 
263   const jclass content_handler_class =
264       env->FindClass("org/dolphinemu/dolphinemu/utils/ContentHandler");
265   s_content_handler_class = reinterpret_cast<jclass>(env->NewGlobalRef(content_handler_class));
266   s_content_handler_open_fd = env->GetStaticMethodID(s_content_handler_class, "openFd",
267                                                      "(Ljava/lang/String;Ljava/lang/String;)I");
268   s_content_handler_delete =
269       env->GetStaticMethodID(s_content_handler_class, "delete", "(Ljava/lang/String;)Z");
270 
271   return JNI_VERSION;
272 }
273 
JNI_OnUnload(JavaVM * vm,void * reserved)274 void JNI_OnUnload(JavaVM* vm, void* reserved)
275 {
276   JNIEnv* env;
277   if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION) != JNI_OK)
278     return;
279 
280   env->DeleteGlobalRef(s_native_library_class);
281   env->DeleteGlobalRef(s_game_file_class);
282   env->DeleteGlobalRef(s_game_file_cache_class);
283   env->DeleteGlobalRef(s_analytics_class);
284   env->DeleteGlobalRef(s_linked_hash_map_class);
285   env->DeleteGlobalRef(s_ini_file_class);
286   env->DeleteGlobalRef(s_ini_file_section_class);
287   env->DeleteGlobalRef(s_compress_cb_class);
288   env->DeleteGlobalRef(s_content_handler_class);
289 }
290 
291 #ifdef __cplusplus
292 }
293 #endif
294