synchronize read and write of files, fixing a race condition between

BoardActivity shutdown (save) and GamesList refresh (open) that
resulted in zero-length byte array being passed into the jni.  It's
now possible for the list to win the race and display old data, so a
better solution would be to check-out the file in such a way that the
list couldn't read it until it was update, but at least now we won't
crash.
This commit is contained in:
Andy2 2010-07-30 17:40:46 -07:00
parent d07d90761f
commit 13596f8538
2 changed files with 18 additions and 29 deletions

View file

@ -62,13 +62,13 @@ public class GameListAdapter extends XWListAdapter {
public Object getItem( int position ) public Object getItem( int position )
{ {
String path = GameUtils.gamesList(m_context)[position]; final String path = GameUtils.gamesList(m_context)[position];
View layout = m_viewsCache.get( path ); View layout = m_viewsCache.get( path );
if ( null == layout ) { if ( null == layout ) {
Utils.logf( "creating new list elem for %s", path ); Utils.logf( "creating new list elem for %s", path );
layout = m_factory.inflate( m_layoutId, null ); layout = m_factory.inflate( m_layoutId, null );
byte[] stream = open( path ); byte[] stream = GameUtils.savedGame( m_context, path );
if ( null != stream ) { if ( null != stream ) {
CurGameInfo gi = new CurGameInfo( m_context ); CurGameInfo gi = new CurGameInfo( m_context );
XwJNI.gi_from_stream( gi, stream ); XwJNI.gi_from_stream( gi, stream );
@ -103,24 +103,6 @@ public class GameListAdapter extends XWListAdapter {
return (View)getItem( position ); return (View)getItem( position );
} }
private byte[] open( String file )
{
byte[] stream = null;
try {
FileInputStream in = m_context.openFileInput( file );
int len = in.available();
stream = new byte[len];
in.read( stream, 0, len );
in.close();
} catch ( java.io.FileNotFoundException ex ) {
Utils.logf( "got FileNotFoundException: " + ex.toString() );
} catch ( java.io.IOException ex ) {
Utils.logf( "got IOException: " + ex.toString() );
}
return stream;
}
public void inval( String key ) public void inval( String key )
{ {
m_viewsCache.remove( key ); m_viewsCache.remove( key );

View file

@ -31,15 +31,19 @@ import org.eehouse.android.xw4.jni.*;
public class GameUtils { public class GameUtils {
private static Object s_syncObj = new Object();
public static byte[] savedGame( Context context, String path ) public static byte[] savedGame( Context context, String path )
{ {
byte[] stream = null; byte[] stream = null;
try { try {
synchronized( s_syncObj ) {
FileInputStream in = context.openFileInput( path ); FileInputStream in = context.openFileInput( path );
int len = in.available(); int len = in.available();
stream = new byte[len]; stream = new byte[len];
in.read( stream, 0, len ); in.read( stream, 0, len );
in.close(); in.close();
}
} catch ( java.io.FileNotFoundException fnf ) { } catch ( java.io.FileNotFoundException fnf ) {
Utils.logf( fnf.toString() ); Utils.logf( fnf.toString() );
stream = null; stream = null;
@ -109,6 +113,7 @@ public class GameUtils {
public static void deleteGame( Context context, String path ) public static void deleteGame( Context context, String path )
{ {
// does this need to be synchronized?
context.deleteFile( path ); context.deleteFile( path );
DBUtils.saveSummary( path, null ); DBUtils.saveSummary( path, null );
} }
@ -147,10 +152,12 @@ public class GameUtils {
public static void saveGame( Context context, byte[] bytes, String path ) public static void saveGame( Context context, byte[] bytes, String path )
{ {
try { try {
FileOutputStream out = context.openFileOutput( path, synchronized( s_syncObj ) {
Context.MODE_PRIVATE ); FileOutputStream out =
context.openFileOutput( path, Context.MODE_PRIVATE );
out.write( bytes ); out.write( bytes );
out.close(); out.close();
}
} catch ( java.io.IOException ex ) { } catch ( java.io.IOException ex ) {
Utils.logf( "got IOException: " + ex.toString() ); Utils.logf( "got IOException: " + ex.toString() );
} }