Skip to content
Permalink
Browse files

Android: Fix race condition in AppLinkActivity

  • Loading branch information...
JosJuice committed Jun 16, 2019
1 parent c34388f commit e4ef2193e0512878517d20ccedfcef3d712488c3
@@ -1,5 +1,7 @@
package org.dolphinemu.dolphinemu.activities;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
@@ -26,6 +28,7 @@

private AppLinkHelper.PlayAction playAction;
private DirectoryStateReceiver directoryStateReceiver;
private BroadcastReceiver gameFileCacheReceiver;

@Override
protected void onCreate(Bundle savedInstanceState)
@@ -63,16 +66,19 @@ protected void onCreate(Bundle savedInstanceState)
*/
private void initResources()
{
IntentFilter statusIntentFilter = new IntentFilter(
IntentFilter directoryStateIntentFilter = new IntentFilter(
DirectoryInitialization.BROADCAST_ACTION);

IntentFilter gameFileCacheIntentFilter = new IntentFilter(
GameFileCacheService.BROADCAST_ACTION);

directoryStateReceiver =
new DirectoryStateReceiver(directoryInitializationState ->
{
if (directoryInitializationState ==
DirectoryInitialization.DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED)
{
play(playAction);
tryPlay(playAction);
}
else if (directoryInitializationState ==
DirectoryInitialization.DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED)
@@ -88,10 +94,23 @@ else if (directoryInitializationState ==
}
});

// Registers the DirectoryStateReceiver and its intent filters
LocalBroadcastManager.getInstance(this).registerReceiver(
directoryStateReceiver,
statusIntentFilter);
gameFileCacheReceiver =
new BroadcastReceiver()
{
@Override
public void onReceive(Context context, Intent intent)
{
if (DirectoryInitialization.areDolphinDirectoriesReady())
{
tryPlay(playAction);
}
}
};

LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(this);
broadcastManager.registerReceiver(directoryStateReceiver, directoryStateIntentFilter);
broadcastManager.registerReceiver(gameFileCacheReceiver, gameFileCacheIntentFilter);

DirectoryInitialization.start(this);
GameFileCacheService.startLoad(this);
}
@@ -107,17 +126,31 @@ private void browse()
finish();
}

private void tryPlay(AppLinkHelper.PlayAction action)
{
// TODO: This approach of getting the game from the game file cache without rescanning
// the library means that we can fail to launch games if the cache file has been deleted.

GameFile game = GameFileCacheService.getGameFileByGameId(action.getGameId());

// If game == null and the load isn't done, wait for the next GameFileCacheService broadcast.
// If game == null and the load is done, call play with a null game, making us exit in failure.
if (game != null || GameFileCacheService.hasLoadedCache())
{
play(action, game);
}
}

/**
* Action if program(game) is selected
*/
private void play(AppLinkHelper.PlayAction action)
private void play(AppLinkHelper.PlayAction action, GameFile game)
{
Log.d(TAG, "Playing game "
+ action.getGameId()
+ " from channel "
+ action.getChannelId());

GameFile game = GameFileCacheService.getGameFileByGameId(action.getGameId());
if (game == null)
Log.e(TAG, "Invalid Game: " + action.getGameId());
else
@@ -13,6 +13,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;

/**
@@ -27,6 +28,8 @@

private static GameFileCache gameFileCache = null;
private static AtomicReference<GameFile[]> gameFiles = new AtomicReference<>(new GameFile[]{});
private static AtomicBoolean hasLoadedCache = new AtomicBoolean(false);
private static AtomicBoolean hasScannedLibrary = new AtomicBoolean(false);

public GameFileCacheService()
{
@@ -81,6 +84,16 @@ public static GameFile findSecondDisc(GameFile game)
return matchWithoutRevision;
}

public static boolean hasLoadedCache()
{
return hasLoadedCache.get();
}

public static boolean hasScannedLibrary()
{
return hasScannedLibrary.get();
}

private static void startService(Context context, String action)
{
Intent intent = new Intent(context, GameFileCacheService.class);
@@ -130,6 +143,8 @@ protected void onHandleIntent(Intent intent)
gameFileCache = temp;
gameFileCache.load();
updateGameFileArray();
hasLoadedCache.set(true);
sendBroadcast();
}
}

@@ -138,10 +153,11 @@ protected void onHandleIntent(Intent intent)
{
synchronized (gameFileCache)
{
if (gameFileCache.scanLibrary(this))
{
boolean changed = gameFileCache.scanLibrary(this);
if (changed)
updateGameFileArray();
}
hasScannedLibrary.set(true);
sendBroadcast();
}
}
}
@@ -151,6 +167,10 @@ private void updateGameFileArray()
GameFile[] gameFilesTemp = gameFileCache.getAllGames();
Arrays.sort(gameFilesTemp, (lhs, rhs) -> lhs.getTitle().compareToIgnoreCase(rhs.getTitle()));
gameFiles.set(gameFilesTemp);
}

private void sendBroadcast()
{
LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(BROADCAST_ACTION));
}
}

0 comments on commit e4ef219

Please sign in to comment.
You can’t perform that action at this time.