1 // Copyright 2003 Dolphin Emulator Project
2 // Licensed under GPLv2+
3 // Refer to the license.txt file included.
4 
5 #include <EGL/egl.h>
6 #include <UICommon/GameFile.h>
7 #include <android/log.h>
8 #include <android/native_window_jni.h>
9 #include <cinttypes>
10 #include <cstdio>
11 #include <cstdlib>
12 #include <jni.h>
13 #include <memory>
14 #include <mutex>
15 #include <optional>
16 #include <string>
17 #include <thread>
18 #include <utility>
19 
20 #include "Common/AndroidAnalytics.h"
21 #include "Common/Assert.h"
22 #include "Common/CPUDetect.h"
23 #include "Common/CommonPaths.h"
24 #include "Common/CommonTypes.h"
25 #include "Common/Event.h"
26 #include "Common/FileUtil.h"
27 #include "Common/IniFile.h"
28 #include "Common/Logging/LogManager.h"
29 #include "Common/MsgHandler.h"
30 #include "Common/ScopeGuard.h"
31 #include "Common/Version.h"
32 #include "Common/WindowSystemInfo.h"
33 
34 #include "Core/Analytics.h"
35 #include "Core/Boot/Boot.h"
36 #include "Core/BootManager.h"
37 #include "Core/ConfigLoaders/GameConfigLoader.h"
38 #include "Core/ConfigManager.h"
39 #include "Core/Core.h"
40 #include "Core/HW/DVD/DVDInterface.h"
41 #include "Core/HW/Wiimote.h"
42 #include "Core/HW/WiimoteReal/WiimoteReal.h"
43 #include "Core/Host.h"
44 #include "Core/PowerPC/JitInterface.h"
45 #include "Core/PowerPC/PowerPC.h"
46 #include "Core/PowerPC/Profiler.h"
47 #include "Core/State.h"
48 #include "Core/WiiUtils.h"
49 
50 #include "DiscIO/Blob.h"
51 #include "DiscIO/Enums.h"
52 #include "DiscIO/ScrubbedBlob.h"
53 #include "DiscIO/Volume.h"
54 
55 #include "InputCommon/ControllerInterface/Android/Android.h"
56 #include "InputCommon/ControllerInterface/Touch/ButtonManager.h"
57 #include "InputCommon/GCAdapter.h"
58 
59 #include "UICommon/UICommon.h"
60 
61 #include "VideoCommon/OnScreenDisplay.h"
62 #include "VideoCommon/RenderBase.h"
63 #include "VideoCommon/VideoBackendBase.h"
64 
65 #include "../../Core/Common/WindowSystemInfo.h"
66 #include "jni/AndroidCommon/AndroidCommon.h"
67 #include "jni/AndroidCommon/IDCache.h"
68 
69 namespace
70 {
71 constexpr char DOLPHIN_TAG[] = "DolphinEmuNative";
72 
73 ANativeWindow* s_surf;
74 IniFile s_ini;
75 
76 // The Core only supports using a single Host thread.
77 // If multiple threads want to call host functions then they need to queue
78 // sequentially for access.
79 std::mutex s_host_identity_lock;
80 Common::Event s_update_main_frame_event;
81 Common::Event s_emulation_end_event;
82 bool s_have_wm_user_stop = false;
83 }  // Anonymous namespace
84 
UpdatePointer()85 void UpdatePointer()
86 {
87   // Update touch pointer
88   JNIEnv* env = IDCache::GetEnvForThread();
89   env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(), IDCache::GetUpdateTouchPointer());
90 }
91 
Host_NotifyMapLoaded()92 void Host_NotifyMapLoaded()
93 {
94 }
Host_RefreshDSPDebuggerWindow()95 void Host_RefreshDSPDebuggerWindow()
96 {
97 }
Host_UIBlocksControllerState()98 bool Host_UIBlocksControllerState()
99 {
100   return false;
101 }
102 
Host_Message(HostMessageID id)103 void Host_Message(HostMessageID id)
104 {
105   if (id == HostMessageID::WMUserJobDispatch)
106   {
107     s_update_main_frame_event.Set();
108   }
109   else if (id == HostMessageID::WMUserStop)
110   {
111     s_have_wm_user_stop = true;
112     if (Core::IsRunning())
113       Core::QueueHostJob(&Core::Stop);
114   }
115 }
116 
Host_UpdateTitle(const std::string & title)117 void Host_UpdateTitle(const std::string& title)
118 {
119   __android_log_write(ANDROID_LOG_INFO, DOLPHIN_TAG, title.c_str());
120 }
121 
Host_UpdateDisasmDialog()122 void Host_UpdateDisasmDialog()
123 {
124 }
125 
Host_UpdateMainFrame()126 void Host_UpdateMainFrame()
127 {
128 }
129 
Host_RequestRenderWindowSize(int width,int height)130 void Host_RequestRenderWindowSize(int width, int height)
131 {
132   std::thread jnicall(UpdatePointer);
133   jnicall.join();
134 }
135 
Host_RendererHasFocus()136 bool Host_RendererHasFocus()
137 {
138   return true;
139 }
140 
Host_RendererIsFullscreen()141 bool Host_RendererIsFullscreen()
142 {
143   return false;
144 }
145 
Host_YieldToUI()146 void Host_YieldToUI()
147 {
148 }
149 
Host_TitleChanged()150 void Host_TitleChanged()
151 {
152 }
153 
MsgAlert(const char * caption,const char * text,bool yes_no,Common::MsgType)154 static bool MsgAlert(const char* caption, const char* text, bool yes_no, Common::MsgType /*style*/)
155 {
156   JNIEnv* env = IDCache::GetEnvForThread();
157 
158   // Execute the Java method.
159   jboolean result = env->CallStaticBooleanMethod(
160       IDCache::GetNativeLibraryClass(), IDCache::GetDisplayAlertMsg(), ToJString(env, caption),
161       ToJString(env, text), yes_no ? JNI_TRUE : JNI_FALSE);
162 
163   return result != JNI_FALSE;
164 }
165 
ReportSend(const std::string & endpoint,const std::string & report)166 static void ReportSend(const std::string& endpoint, const std::string& report)
167 {
168   JNIEnv* env = IDCache::GetEnvForThread();
169 
170   jbyteArray output_array = env->NewByteArray(report.size());
171   jbyte* output = env->GetByteArrayElements(output_array, nullptr);
172   memcpy(output, report.data(), report.size());
173   env->ReleaseByteArrayElements(output_array, output, 0);
174   env->CallStaticVoidMethod(IDCache::GetAnalyticsClass(), IDCache::GetSendAnalyticsReport(),
175                             ToJString(env, endpoint), output_array);
176 }
177 
GetAnalyticValue(const std::string & key)178 static std::string GetAnalyticValue(const std::string& key)
179 {
180   JNIEnv* env = IDCache::GetEnvForThread();
181 
182   auto value = reinterpret_cast<jstring>(env->CallStaticObjectMethod(
183       IDCache::GetAnalyticsClass(), IDCache::GetAnalyticsValue(), ToJString(env, key)));
184 
185   std::string stdvalue = GetJString(env, value);
186 
187   return stdvalue;
188 }
189 
190 #ifdef __cplusplus
191 extern "C" {
192 #endif
193 
194 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_UnPauseEmulation(JNIEnv* env,
195                                                                                      jobject obj);
196 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_PauseEmulation(JNIEnv* env,
197                                                                                    jobject obj);
198 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_StopEmulation(JNIEnv* env,
199                                                                                   jobject obj);
200 JNIEXPORT void JNICALL
201 Java_org_dolphinemu_dolphinemu_NativeLibrary_WaitUntilDoneBooting(JNIEnv* env, jobject obj);
202 JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_IsRunning(JNIEnv* env,
203                                                                                   jobject obj);
204 JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_onGamePadEvent(
205     JNIEnv* env, jobject obj, jstring jDevice, jint Button, jint Action);
206 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_onGamePadMoveEvent(
207     JNIEnv* env, jobject obj, jstring jDevice, jint Axis, jfloat Value);
208 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetMotionSensorsEnabled(
209     JNIEnv* env, jobject obj, jboolean accelerometer_enabled, jboolean gyroscope_enabled);
210 JNIEXPORT double JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetInputRadiusAtAngle(
211     JNIEnv* env, jobject obj, int emu_pad_id, int stick, double angle);
212 JNIEXPORT jstring JNICALL
213 Java_org_dolphinemu_dolphinemu_NativeLibrary_GetVersionString(JNIEnv* env, jobject obj);
214 JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetGitRevision(JNIEnv* env,
215                                                                                       jobject obj);
216 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SaveScreenShot(JNIEnv* env,
217                                                                                    jobject obj);
218 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_eglBindAPI(JNIEnv* env,
219                                                                                jobject obj,
220                                                                                jint api);
221 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetFilename(JNIEnv* env,
222                                                                                 jobject obj,
223                                                                                 jstring jFile);
224 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SaveState(JNIEnv* env,
225                                                                               jobject obj,
226                                                                               jint slot,
227                                                                               jboolean wait);
228 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SaveStateAs(JNIEnv* env,
229                                                                                 jobject obj,
230                                                                                 jstring path,
231                                                                                 jboolean wait);
232 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_LoadState(JNIEnv* env,
233                                                                               jobject obj,
234                                                                               jint slot);
235 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_LoadStateAs(JNIEnv* env,
236                                                                                 jobject obj,
237                                                                                 jstring path);
238 JNIEXPORT void JNICALL
239 Java_org_dolphinemu_dolphinemu_utils_DirectoryInitialization_CreateUserDirectories(JNIEnv* env,
240                                                                                    jobject obj);
241 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetUserDirectory(
242     JNIEnv* env, jobject obj, jstring jDirectory);
243 JNIEXPORT jstring JNICALL
244 Java_org_dolphinemu_dolphinemu_NativeLibrary_GetUserDirectory(JNIEnv* env, jobject obj);
245 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetCacheDirectory(
246     JNIEnv* env, jobject obj, jstring jDirectory);
247 JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_DefaultCPUCore(JNIEnv* env,
248                                                                                    jobject obj);
249 JNIEXPORT jstring JNICALL
250 Java_org_dolphinemu_dolphinemu_NativeLibrary_GetDefaultGraphicsBackendName(JNIEnv* env,
251                                                                            jobject obj);
252 JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetMaxLogLevel(JNIEnv* env,
253                                                                                    jobject obj);
254 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetProfiling(JNIEnv* env,
255                                                                                  jobject obj,
256                                                                                  jboolean enable);
257 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Initialize(JNIEnv* env,
258                                                                                jobject obj);
259 JNIEXPORT void JNICALL
260 Java_org_dolphinemu_dolphinemu_NativeLibrary_ReportStartToAnalytics(JNIEnv* env, jobject obj);
261 JNIEXPORT void JNICALL
262 Java_org_dolphinemu_dolphinemu_NativeLibrary_WriteProfileResults(JNIEnv* env, jobject obj);
263 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Run__Ljava_lang_String_2(
264     JNIEnv* env, jobject obj, jstring jFile);
265 JNIEXPORT void JNICALL
266 Java_org_dolphinemu_dolphinemu_NativeLibrary_Run__Ljava_lang_String_2Ljava_lang_String_2Z(
267     JNIEnv* env, jobject obj, jstring jFile, jstring jSavestate, jboolean jDeleteSavestate);
268 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceChanged(JNIEnv* env,
269                                                                                    jobject obj,
270                                                                                    jobject surf);
271 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceDestroyed(JNIEnv* env,
272                                                                                      jobject obj);
273 
Java_org_dolphinemu_dolphinemu_NativeLibrary_UnPauseEmulation(JNIEnv * env,jobject obj)274 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_UnPauseEmulation(JNIEnv* env,
275                                                                                      jobject obj)
276 {
277   std::lock_guard<std::mutex> guard(s_host_identity_lock);
278   Core::SetState(Core::State::Running);
279 }
Java_org_dolphinemu_dolphinemu_NativeLibrary_PauseEmulation(JNIEnv * env,jobject obj)280 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_PauseEmulation(JNIEnv* env,
281                                                                                    jobject obj)
282 {
283   std::lock_guard<std::mutex> guard(s_host_identity_lock);
284   Core::SetState(Core::State::Paused);
285 }
286 
Java_org_dolphinemu_dolphinemu_NativeLibrary_StopEmulation(JNIEnv * env,jobject obj)287 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_StopEmulation(JNIEnv* env,
288                                                                                   jobject obj)
289 {
290   {
291     std::lock_guard<std::mutex> guard(s_host_identity_lock);
292     s_emulation_end_event.Reset();
293     Core::Stop();
294 
295     // Kick the waiting event
296     s_update_main_frame_event.Set();
297   }
298 
299   // Wait for shutdown, to avoid accessing the config at the same time as the shutdown code
300   s_emulation_end_event.Wait();
301 }
302 
303 JNIEXPORT void JNICALL
Java_org_dolphinemu_dolphinemu_NativeLibrary_WaitUntilDoneBooting(JNIEnv * env,jobject obj)304 Java_org_dolphinemu_dolphinemu_NativeLibrary_WaitUntilDoneBooting(JNIEnv* env, jobject obj)
305 {
306   Core::WaitUntilDoneBooting();
307 }
308 
Java_org_dolphinemu_dolphinemu_NativeLibrary_IsRunning(JNIEnv * env,jobject obj)309 JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_IsRunning(JNIEnv* env,
310                                                                                   jobject obj)
311 {
312   return Core::IsRunning();
313 }
314 
315 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_ChangeDisc(JNIEnv* env,
316                                                                                jobject obj,
317                                                                                jstring jFile);
318 
Java_org_dolphinemu_dolphinemu_NativeLibrary_onGamePadEvent(JNIEnv * env,jobject obj,jstring jDevice,jint Button,jint Action)319 JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_onGamePadEvent(
320     JNIEnv* env, jobject obj, jstring jDevice, jint Button, jint Action)
321 {
322   return ButtonManager::GamepadEvent(GetJString(env, jDevice), Button, Action);
323 }
324 
Java_org_dolphinemu_dolphinemu_NativeLibrary_onGamePadMoveEvent(JNIEnv * env,jobject obj,jstring jDevice,jint Axis,jfloat Value)325 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_onGamePadMoveEvent(
326     JNIEnv* env, jobject obj, jstring jDevice, jint Axis, jfloat Value)
327 {
328   ButtonManager::GamepadAxisEvent(GetJString(env, jDevice), Axis, Value);
329 }
330 
Java_org_dolphinemu_dolphinemu_NativeLibrary_SetMotionSensorsEnabled(JNIEnv * env,jobject obj,jboolean accelerometer_enabled,jboolean gyroscope_enabled)331 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetMotionSensorsEnabled(
332     JNIEnv* env, jobject obj, jboolean accelerometer_enabled, jboolean gyroscope_enabled)
333 {
334   ciface::Android::SetMotionSensorsEnabled(accelerometer_enabled, gyroscope_enabled);
335 }
336 
Java_org_dolphinemu_dolphinemu_NativeLibrary_GetInputRadiusAtAngle(JNIEnv * env,jobject obj,int emu_pad_id,int stick,double angle)337 JNIEXPORT double JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetInputRadiusAtAngle(
338     JNIEnv* env, jobject obj, int emu_pad_id, int stick, double angle)
339 {
340   const auto casted_stick = static_cast<ButtonManager::ButtonType>(stick);
341   return ButtonManager::GetInputRadiusAtAngle(emu_pad_id, casted_stick, angle);
342 }
343 
Java_org_dolphinemu_dolphinemu_NativeLibrary_GetVersionString(JNIEnv * env,jobject obj)344 JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetVersionString(JNIEnv* env,
345                                                                                         jobject obj)
346 {
347   return ToJString(env, Common::scm_rev_str);
348 }
349 
Java_org_dolphinemu_dolphinemu_NativeLibrary_GetGitRevision(JNIEnv * env,jobject obj)350 JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetGitRevision(JNIEnv* env,
351                                                                                       jobject obj)
352 {
353   return ToJString(env, Common::scm_rev_git_str);
354 }
355 
Java_org_dolphinemu_dolphinemu_NativeLibrary_SaveScreenShot(JNIEnv * env,jobject obj)356 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SaveScreenShot(JNIEnv* env,
357                                                                                    jobject obj)
358 {
359   std::lock_guard<std::mutex> guard(s_host_identity_lock);
360   Core::SaveScreenShot();
361 }
362 
Java_org_dolphinemu_dolphinemu_NativeLibrary_eglBindAPI(JNIEnv * env,jobject obj,jint api)363 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_eglBindAPI(JNIEnv* env,
364                                                                                jobject obj,
365                                                                                jint api)
366 {
367   eglBindAPI(api);
368 }
369 
Java_org_dolphinemu_dolphinemu_NativeLibrary_SaveState(JNIEnv * env,jobject obj,jint slot,jboolean wait)370 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SaveState(JNIEnv* env,
371                                                                               jobject obj,
372                                                                               jint slot,
373                                                                               jboolean wait)
374 {
375   std::lock_guard<std::mutex> guard(s_host_identity_lock);
376   State::Save(slot, wait);
377 }
378 
Java_org_dolphinemu_dolphinemu_NativeLibrary_SaveStateAs(JNIEnv * env,jobject obj,jstring path,jboolean wait)379 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SaveStateAs(JNIEnv* env,
380                                                                                 jobject obj,
381                                                                                 jstring path,
382                                                                                 jboolean wait)
383 {
384   std::lock_guard<std::mutex> guard(s_host_identity_lock);
385   State::SaveAs(GetJString(env, path), wait);
386 }
387 
Java_org_dolphinemu_dolphinemu_NativeLibrary_LoadState(JNIEnv * env,jobject obj,jint slot)388 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_LoadState(JNIEnv* env,
389                                                                               jobject obj,
390                                                                               jint slot)
391 {
392   std::lock_guard<std::mutex> guard(s_host_identity_lock);
393   State::Load(slot);
394 }
395 
Java_org_dolphinemu_dolphinemu_NativeLibrary_LoadStateAs(JNIEnv * env,jobject obj,jstring path)396 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_LoadStateAs(JNIEnv* env,
397                                                                                 jobject obj,
398                                                                                 jstring path)
399 {
400   std::lock_guard<std::mutex> guard(s_host_identity_lock);
401   State::LoadAs(GetJString(env, path));
402 }
403 
Java_org_dolphinemu_dolphinemu_utils_DirectoryInitialization_SetSysDirectory(JNIEnv * env,jobject obj,jstring jPath)404 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_utils_DirectoryInitialization_SetSysDirectory(
405     JNIEnv* env, jobject obj, jstring jPath)
406 {
407   const std::string path = GetJString(env, jPath);
408   File::SetSysDirectory(path);
409 }
410 
411 JNIEXPORT void JNICALL
Java_org_dolphinemu_dolphinemu_utils_DirectoryInitialization_CreateUserDirectories(JNIEnv * env,jobject obj)412 Java_org_dolphinemu_dolphinemu_utils_DirectoryInitialization_CreateUserDirectories(JNIEnv* env,
413                                                                                    jobject obj)
414 {
415   UICommon::CreateDirectories();
416 }
417 
Java_org_dolphinemu_dolphinemu_NativeLibrary_SetUserDirectory(JNIEnv * env,jobject obj,jstring jDirectory)418 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetUserDirectory(
419     JNIEnv* env, jobject obj, jstring jDirectory)
420 {
421   std::lock_guard<std::mutex> guard(s_host_identity_lock);
422   UICommon::SetUserDirectory(GetJString(env, jDirectory));
423 }
424 
Java_org_dolphinemu_dolphinemu_NativeLibrary_GetUserDirectory(JNIEnv * env,jobject obj)425 JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetUserDirectory(JNIEnv* env,
426                                                                                         jobject obj)
427 {
428   return ToJString(env, File::GetUserPath(D_USER_IDX));
429 }
430 
Java_org_dolphinemu_dolphinemu_NativeLibrary_SetCacheDirectory(JNIEnv * env,jobject obj,jstring jDirectory)431 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetCacheDirectory(
432     JNIEnv* env, jobject obj, jstring jDirectory)
433 {
434   std::lock_guard<std::mutex> guard(s_host_identity_lock);
435   File::SetUserPath(D_CACHE_IDX, GetJString(env, jDirectory) + DIR_SEP);
436 }
437 
Java_org_dolphinemu_dolphinemu_NativeLibrary_DefaultCPUCore(JNIEnv * env,jobject obj)438 JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_DefaultCPUCore(JNIEnv* env,
439                                                                                    jobject obj)
440 {
441   return static_cast<jint>(PowerPC::DefaultCPUCore());
442 }
443 
444 JNIEXPORT jstring JNICALL
Java_org_dolphinemu_dolphinemu_NativeLibrary_GetDefaultGraphicsBackendName(JNIEnv * env,jobject obj)445 Java_org_dolphinemu_dolphinemu_NativeLibrary_GetDefaultGraphicsBackendName(JNIEnv* env, jobject obj)
446 {
447   return ToJString(env, VideoBackendBase::GetDefaultBackendName());
448 }
449 
Java_org_dolphinemu_dolphinemu_NativeLibrary_GetMaxLogLevel(JNIEnv * env,jobject obj)450 JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetMaxLogLevel(JNIEnv* env,
451                                                                                    jobject obj)
452 {
453   return static_cast<jint>(MAX_LOGLEVEL);
454 }
455 
Java_org_dolphinemu_dolphinemu_NativeLibrary_SetProfiling(JNIEnv * env,jobject obj,jboolean enable)456 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetProfiling(JNIEnv* env,
457                                                                                  jobject obj,
458                                                                                  jboolean enable)
459 {
460   std::lock_guard<std::mutex> guard(s_host_identity_lock);
461   Core::SetState(Core::State::Paused);
462   JitInterface::ClearCache();
463   JitInterface::SetProfilingState(enable ? JitInterface::ProfilingState::Enabled :
464                                            JitInterface::ProfilingState::Disabled);
465   Core::SetState(Core::State::Running);
466 }
467 
Java_org_dolphinemu_dolphinemu_NativeLibrary_WriteProfileResults(JNIEnv * env,jobject obj)468 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_WriteProfileResults(JNIEnv* env,
469                                                                                         jobject obj)
470 {
471   std::lock_guard<std::mutex> guard(s_host_identity_lock);
472   std::string filename = File::GetUserPath(D_DUMP_IDX) + "Debug/profiler.txt";
473   File::CreateFullPath(filename);
474   JitInterface::WriteProfileResults(filename);
475 }
476 
477 // Surface Handling
Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceChanged(JNIEnv * env,jobject obj,jobject surf)478 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceChanged(JNIEnv* env,
479                                                                                    jobject obj,
480                                                                                    jobject surf)
481 {
482   s_surf = ANativeWindow_fromSurface(env, surf);
483   if (s_surf == nullptr)
484     __android_log_print(ANDROID_LOG_ERROR, DOLPHIN_TAG, "Error: Surface is null.");
485 
486   if (g_renderer)
487     g_renderer->ChangeSurface(s_surf);
488 }
489 
Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceDestroyed(JNIEnv * env,jobject obj)490 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceDestroyed(JNIEnv* env,
491                                                                                      jobject obj)
492 {
493   if (g_renderer)
494     g_renderer->ChangeSurface(nullptr);
495 
496   if (s_surf)
497   {
498     ANativeWindow_release(s_surf);
499     s_surf = nullptr;
500   }
501 }
502 
503 JNIEXPORT jfloat JNICALL
Java_org_dolphinemu_dolphinemu_NativeLibrary_GetGameAspectRatio(JNIEnv * env,jobject obj)504 Java_org_dolphinemu_dolphinemu_NativeLibrary_GetGameAspectRatio(JNIEnv* env, jobject obj)
505 {
506   return g_renderer->CalculateDrawAspectRatio();
507 }
508 
Java_org_dolphinemu_dolphinemu_NativeLibrary_RefreshWiimotes(JNIEnv * env,jobject obj)509 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_RefreshWiimotes(JNIEnv* env,
510                                                                                     jobject obj)
511 {
512   std::lock_guard<std::mutex> guard(s_host_identity_lock);
513   WiimoteReal::Refresh();
514 }
515 
Java_org_dolphinemu_dolphinemu_NativeLibrary_ReloadWiimoteConfig(JNIEnv * env,jobject obj)516 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_ReloadWiimoteConfig(JNIEnv* env,
517                                                                                         jobject obj)
518 {
519   WiimoteReal::LoadSettings();
520   Wiimote::LoadConfig();
521 }
522 
Java_org_dolphinemu_dolphinemu_NativeLibrary_ReloadConfig(JNIEnv * env,jobject obj)523 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_ReloadConfig(JNIEnv* env,
524                                                                                  jobject obj)
525 {
526   SConfig::GetInstance().LoadSettings();
527 }
528 
529 JNIEXPORT void JNICALL
Java_org_dolphinemu_dolphinemu_NativeLibrary_UpdateGCAdapterScanThread(JNIEnv * env,jobject obj)530 Java_org_dolphinemu_dolphinemu_NativeLibrary_UpdateGCAdapterScanThread(JNIEnv* env, jobject obj)
531 {
532   if (GCAdapter::UseAdapter())
533   {
534     GCAdapter::StartScanThread();
535   }
536   else
537   {
538     GCAdapter::StopScanThread();
539   }
540 }
541 
Java_org_dolphinemu_dolphinemu_NativeLibrary_Initialize(JNIEnv * env,jobject obj)542 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Initialize(JNIEnv* env,
543                                                                                jobject obj)
544 {
545   Common::RegisterMsgAlertHandler(&MsgAlert);
546   Common::AndroidSetReportHandler(&ReportSend);
547   DolphinAnalytics::AndroidSetGetValFunc(&GetAnalyticValue);
548   UICommon::Init();
549 }
550 
551 JNIEXPORT void JNICALL
Java_org_dolphinemu_dolphinemu_NativeLibrary_ReportStartToAnalytics(JNIEnv * env,jobject obj)552 Java_org_dolphinemu_dolphinemu_NativeLibrary_ReportStartToAnalytics(JNIEnv* env, jobject obj)
553 {
554   DolphinAnalytics::Instance().ReportDolphinStart(GetAnalyticValue("DEVICE_TYPE"));
555 }
556 
557 // Returns the scale factor for imgui rendering.
558 // Based on the scaledDensity of the device's display metrics.
GetRenderSurfaceScale(JNIEnv * env)559 static float GetRenderSurfaceScale(JNIEnv* env)
560 {
561   jclass native_library_class = env->FindClass("org/dolphinemu/dolphinemu/NativeLibrary");
562   jmethodID get_render_surface_scale_method =
563       env->GetStaticMethodID(native_library_class, "getRenderSurfaceScale", "()F");
564   return env->CallStaticFloatMethod(native_library_class, get_render_surface_scale_method);
565 }
566 
Run(JNIEnv * env,const std::vector<std::string> & paths,const std::optional<std::string> & savestate_path={},bool delete_savestate=false)567 static void Run(JNIEnv* env, const std::vector<std::string>& paths,
568                 const std::optional<std::string>& savestate_path = {},
569                 bool delete_savestate = false)
570 {
571   ASSERT(!paths.empty());
572   __android_log_print(ANDROID_LOG_INFO, DOLPHIN_TAG, "Running : %s", paths[0].c_str());
573 
574   std::unique_lock<std::mutex> guard(s_host_identity_lock);
575 
576   WiimoteReal::InitAdapterClass();
577 
578   // No use running the loop when booting fails
579   s_have_wm_user_stop = false;
580   std::unique_ptr<BootParameters> boot = BootParameters::GenerateFromFile(paths, savestate_path);
581   boot->delete_savestate = delete_savestate;
582   WindowSystemInfo wsi(WindowSystemType::Android, nullptr, s_surf, s_surf);
583   wsi.render_surface_scale = GetRenderSurfaceScale(env);
584   if (BootManager::BootCore(std::move(boot), wsi))
585   {
586     ButtonManager::Init(SConfig::GetInstance().GetGameID());
587     static constexpr int TIMEOUT = 10000;
588     static constexpr int WAIT_STEP = 25;
589     int time_waited = 0;
590     // A Core::CORE_ERROR state would be helpful here.
591     while (!Core::IsRunning() && time_waited < TIMEOUT && !s_have_wm_user_stop)
592     {
593       std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_STEP));
594       time_waited += WAIT_STEP;
595     }
596     while (Core::IsRunning())
597     {
598       guard.unlock();
599       s_update_main_frame_event.Wait();
600       guard.lock();
601       Core::HostDispatchJobs();
602     }
603   }
604 
605   Core::Shutdown();
606   ButtonManager::Shutdown();
607   guard.unlock();
608 
609   if (s_surf)
610   {
611     ANativeWindow_release(s_surf);
612     s_surf = nullptr;
613   }
614 
615   s_emulation_end_event.Set();
616 }
617 
Java_org_dolphinemu_dolphinemu_NativeLibrary_Run___3Ljava_lang_String_2(JNIEnv * env,jobject obj,jobjectArray jPaths)618 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Run___3Ljava_lang_String_2(
619     JNIEnv* env, jobject obj, jobjectArray jPaths)
620 {
621   Run(env, JStringArrayToVector(env, jPaths));
622 }
623 
624 JNIEXPORT void JNICALL
Java_org_dolphinemu_dolphinemu_NativeLibrary_Run___3Ljava_lang_String_2Ljava_lang_String_2Z(JNIEnv * env,jobject obj,jobjectArray jPaths,jstring jSavestate,jboolean jDeleteSavestate)625 Java_org_dolphinemu_dolphinemu_NativeLibrary_Run___3Ljava_lang_String_2Ljava_lang_String_2Z(
626     JNIEnv* env, jobject obj, jobjectArray jPaths, jstring jSavestate, jboolean jDeleteSavestate)
627 {
628   Run(env, JStringArrayToVector(env, jPaths), GetJString(env, jSavestate), jDeleteSavestate);
629 }
630 
Java_org_dolphinemu_dolphinemu_NativeLibrary_ChangeDisc(JNIEnv * env,jobject obj,jstring jFile)631 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_ChangeDisc(JNIEnv* env,
632                                                                                jobject obj,
633                                                                                jstring jFile)
634 {
635   const std::string path = GetJString(env, jFile);
636   __android_log_print(ANDROID_LOG_INFO, DOLPHIN_TAG, "Change Disc: %s", path.c_str());
637   Core::RunAsCPUThread([&path] { DVDInterface::ChangeDisc(path); });
638 }
639 
Java_org_dolphinemu_dolphinemu_NativeLibrary_GetLogTypeNames(JNIEnv * env,jobject obj)640 JNIEXPORT jobject JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetLogTypeNames(JNIEnv* env,
641                                                                                        jobject obj)
642 {
643   std::map<std::string, std::string> map = Common::Log::LogManager::GetInstance()->GetLogTypes();
644 
645   auto map_size = static_cast<jsize>(map.size());
646   jobject linked_hash_map =
647       env->NewObject(IDCache::GetLinkedHashMapClass(), IDCache::GetLinkedHashMapInit(), map_size);
648   for (const auto& entry : map)
649   {
650     env->CallObjectMethod(linked_hash_map, IDCache::GetLinkedHashMapPut(),
651                           ToJString(env, entry.first), ToJString(env, entry.second));
652   }
653   return linked_hash_map;
654 }
655 
Java_org_dolphinemu_dolphinemu_NativeLibrary_ReloadLoggerConfig(JNIEnv * env,jobject obj)656 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_ReloadLoggerConfig(JNIEnv* env,
657                                                                                        jobject obj)
658 {
659   Common::Log::LogManager::Init();
660 }
661 
Java_org_dolphinemu_dolphinemu_NativeLibrary_InstallWAD(JNIEnv * env,jobject obj,jstring jFile)662 JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_InstallWAD(JNIEnv* env,
663                                                                                    jobject obj,
664                                                                                    jstring jFile)
665 {
666   const std::string path = GetJString(env, jFile);
667   return static_cast<jboolean>(WiiUtils::InstallWAD(path));
668 }
669 
Java_org_dolphinemu_dolphinemu_NativeLibrary_ConvertDiscImage(JNIEnv * env,jobject obj,jstring jInPath,jstring jOutPath,jint jPlatform,jint jFormat,jint jBlockSize,jint jCompression,jint jCompressionLevel,jboolean jScrub,jobject jCallback)670 JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_ConvertDiscImage(
671     JNIEnv* env, jobject obj, jstring jInPath, jstring jOutPath, jint jPlatform, jint jFormat,
672     jint jBlockSize, jint jCompression, jint jCompressionLevel, jboolean jScrub, jobject jCallback)
673 {
674   const std::string in_path = GetJString(env, jInPath);
675   const std::string out_path = GetJString(env, jOutPath);
676   const DiscIO::Platform platform = static_cast<DiscIO::Platform>(jPlatform);
677   const DiscIO::BlobType format = static_cast<DiscIO::BlobType>(jFormat);
678   const DiscIO::WIARVZCompressionType compression =
679       static_cast<DiscIO::WIARVZCompressionType>(jCompression);
680   const bool scrub = static_cast<bool>(jScrub);
681 
682   std::unique_ptr<DiscIO::BlobReader> blob_reader;
683   if (scrub)
684     blob_reader = DiscIO::ScrubbedBlob::Create(in_path);
685   else
686     blob_reader = DiscIO::CreateBlobReader(in_path);
687 
688   if (!blob_reader)
689     return static_cast<jboolean>(false);
690 
691   jobject jCallbackGlobal = env->NewGlobalRef(jCallback);
692   Common::ScopeGuard scope_guard([jCallbackGlobal, env] { env->DeleteGlobalRef(jCallbackGlobal); });
693 
694   const auto callback = [&jCallbackGlobal](const std::string& text, float completion) {
695     JNIEnv* env = IDCache::GetEnvForThread();
696     return static_cast<bool>(env->CallBooleanMethod(
697         jCallbackGlobal, IDCache::GetCompressCallbackRun(), ToJString(env, text), completion));
698   };
699 
700   bool success = false;
701 
702   switch (format)
703   {
704   case DiscIO::BlobType::PLAIN:
705     success = DiscIO::ConvertToPlain(blob_reader.get(), in_path, out_path, callback);
706     break;
707 
708   case DiscIO::BlobType::GCZ:
709     success =
710         DiscIO::ConvertToGCZ(blob_reader.get(), in_path, out_path,
711                              platform == DiscIO::Platform::WiiDisc ? 1 : 0, jBlockSize, callback);
712     break;
713 
714   case DiscIO::BlobType::WIA:
715   case DiscIO::BlobType::RVZ:
716     success = DiscIO::ConvertToWIAOrRVZ(blob_reader.get(), in_path, out_path,
717                                         format == DiscIO::BlobType::RVZ, compression,
718                                         jCompressionLevel, jBlockSize, callback);
719     break;
720 
721   default:
722     ASSERT(false);
723     break;
724   }
725 
726   return static_cast<jboolean>(success);
727 }
728 
Java_org_dolphinemu_dolphinemu_NativeLibrary_FormatSize(JNIEnv * env,jobject obj,jlong bytes,jint decimals)729 JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_FormatSize(JNIEnv* env,
730                                                                                   jobject obj,
731                                                                                   jlong bytes,
732                                                                                   jint decimals)
733 {
734   return ToJString(env, UICommon::FormatSize(bytes, decimals));
735 }
736 
Java_org_dolphinemu_dolphinemu_NativeLibrary_SetObscuredPixelsLeft(JNIEnv * env,jobject obj,jint width)737 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetObscuredPixelsLeft(
738     JNIEnv* env, jobject obj, jint width)
739 {
740   OSD::SetObscuredPixelsLeft(width);
741 }
742 
Java_org_dolphinemu_dolphinemu_NativeLibrary_SetObscuredPixelsTop(JNIEnv * env,jobject obj,jint height)743 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetObscuredPixelsTop(
744     JNIEnv* env, jobject obj, jint height)
745 {
746   OSD::SetObscuredPixelsTop(height);
747 }
748 
749 #ifdef __cplusplus
750 }
751 #endif
752