Android: Fix race condition in displayAlertMsg

It was possible for sAlertMessageLock.notify() to be called before
sAlertMessageLock.wait(), causing Dolphin to deadlock. In particular,
this was guaranteed to happen if displayAlertMsg was called from the UI
thread while the emulation activity is being destroyed, because
runOnUiThread runs the passed-in anonymous function immediately when
called from the UI thread.

By replacing Object.wait/Object.notify with Semaphore.acquire/
Semaphore.release, it no longer matters what order the methods are
called in.
This commit is contained in:
JosJuice 2024-04-05 22:40:24 +02:00
parent 4312840a4b
commit 9ca9d073df
1 changed files with 8 additions and 13 deletions

View File

@ -21,6 +21,7 @@ import org.dolphinemu.dolphinemu.utils.Log;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.concurrent.Semaphore;
/** /**
* Class which contains methods that interact * Class which contains methods that interact
@ -28,7 +29,7 @@ import java.util.LinkedHashMap;
*/ */
public final class NativeLibrary public final class NativeLibrary
{ {
private static final Object sAlertMessageLock = new Object(); private static final Semaphore sAlertMessageSemaphore = new Semaphore(0);
private static boolean sIsShowingAlertMessage = false; private static boolean sIsShowingAlertMessage = false;
private static WeakReference<EmulationActivity> sEmulationActivity = new WeakReference<>(null); private static WeakReference<EmulationActivity> sEmulationActivity = new WeakReference<>(null);
@ -492,15 +493,12 @@ public final class NativeLibrary
}); });
// Wait for the lock to notify that it is complete. // Wait for the lock to notify that it is complete.
synchronized (sAlertMessageLock) try
{
sAlertMessageSemaphore.acquire();
}
catch (InterruptedException ignored)
{ {
try
{
sAlertMessageLock.wait();
}
catch (Exception ignored)
{
}
} }
if (yesNo) if (yesNo)
@ -520,10 +518,7 @@ public final class NativeLibrary
public static void NotifyAlertMessageLock() public static void NotifyAlertMessageLock()
{ {
synchronized (sAlertMessageLock) sAlertMessageSemaphore.release();
{
sAlertMessageLock.notify();
}
} }
public static void setEmulationActivity(EmulationActivity emulationActivity) public static void setEmulationActivity(EmulationActivity emulationActivity)