diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DlgDelegate.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DlgDelegate.java
index 0c9e325d4..8a1ebac0f 100644
--- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DlgDelegate.java
+++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DlgDelegate.java
@@ -51,6 +51,7 @@ public class DlgDelegate {
DWNLD_LOC_DICT,
NEW_GAME_DFLT_NAME,
SEND_EMAIL,
+ WRITE_LOG_DB,
CLEAR_LOG_DB,
// BoardDelegate
diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/GamesListDelegate.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/GamesListDelegate.java
index 7f5fdf688..ce6da0e3e 100644
--- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/GamesListDelegate.java
+++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/GamesListDelegate.java
@@ -1385,6 +1385,25 @@ public class GamesListDelegate extends ListDelegateBase
Utils.emailAuthor( m_activity );
break;
+ case WRITE_LOG_DB:
+ final File logLoc = Log.dumpStored();
+ post( new Runnable() {
+ @Override
+ public void run() {
+ String dumpMsg;
+ if ( null == logLoc ) {
+ dumpMsg = LocUtils.getString( m_activity,
+ R.string.logstore_notdumped );
+ } else {
+ dumpMsg = LocUtils
+ .getString( m_activity, R.string.logstore_dumped_fmt,
+ logLoc.getPath() );
+ }
+ makeOkOnlyBuilder( dumpMsg ).show();
+ }
+ } );
+ break;
+
case CLEAR_LOG_DB:
int nDumped = Log.clearStored();
Utils.showToast( m_activity, R.string.logstore_cleared_fmt, nDumped );
@@ -1687,13 +1706,8 @@ public class GamesListDelegate extends ListDelegateBase
.show();
break;
case R.id.games_menu_dumpLogStorage:
- File logLoc = Log.dumpStored();
- if ( null != logLoc ) {
- String dumpMsg = LocUtils
- .getString( m_activity, R.string.logstore_dumped_fmt,
- logLoc.getPath() );
- makeOkOnlyBuilder( dumpMsg ).show();
- }
+ Perms23.tryGetPerms( this, Perm.STORAGE, null,
+ Action.WRITE_LOG_DB );
break;
default:
@@ -1907,6 +1921,7 @@ public class GamesListDelegate extends ListDelegateBase
} else {
dropSels = true; // will select the new game instead
post( new Runnable() {
+ @Override
public void run() {
Activity self = m_activity;
byte[] stream =
diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/Log.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/Log.java
index 1def66a8c..146e280f6 100644
--- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/Log.java
+++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/Log.java
@@ -42,9 +42,11 @@ public class Log {
private static final boolean LOGGING_ENABLED
= BuildConfig.DEBUG || !BuildConfig.IS_TAGGED_BUILD;
private static final boolean ERROR_LOGGING_ENABLED = true;
- private static final String LOGS_DB_NAME = "logs_db";
+ private static final String LOGS_DB_NAME = "xwlogs_db";
private static final String LOGS_TABLE_NAME = "logs";
private static final String COL_ENTRY = "entry";
+ private static final String COL_THREAD = "tid";
+ private static final String COL_PID = "pid";
private static final String COL_ROWID = "rowid";
private static final String COL_TAG = "tag";
private static final String COL_LEVEL = "level";
@@ -188,10 +190,10 @@ public class Log {
return s_dbHelper;
}
- // Called from jni
+ // Called from jni. Keep name and signature in sync with what's in
+ // passToJava() in andutils.c
public static void store( String tag, String msg )
{
- llog( "store(%s) called from jni", msg );
store( LOG_LEVEL.DEBUG, tag, msg );
}
@@ -220,6 +222,8 @@ public class Log {
String query = "CREATE TABLE " + LOGS_TABLE_NAME + "("
+ COL_ROWID + " INTEGER PRIMARY KEY AUTOINCREMENT"
+ "," + COL_ENTRY + " TEXT"
+ + "," + COL_THREAD + " INTEGER"
+ + "," + COL_PID + " INTEGER"
+ "," + COL_TAG + " TEXT"
+ "," + COL_LEVEL + " INTEGER(2)"
+ ");";
@@ -238,8 +242,11 @@ public class Log {
void store( LOG_LEVEL level, String tag, String msg )
{
+ long tid = Thread.currentThread().getId();
+
ContentValues values = new ContentValues();
values.put( COL_ENTRY, msg );
+ values.put( COL_THREAD, tid );
values.put( COL_TAG, tag );
values.put( COL_LEVEL, level.ordinal() );
long res = getWritableDatabase().insert( LOGS_TABLE_NAME, null, values );
@@ -247,14 +254,15 @@ public class Log {
File dumpToFile()
{
- File storage = Environment.getExternalStorageDirectory();
- File db = new File( storage, LOGS_DB_NAME );
+ File dir = Environment.getExternalStorageDirectory();
+ dir = new File( dir, Environment.DIRECTORY_DOWNLOADS );
+ File db = new File( dir, LOGS_DB_NAME + ".txt" );
try {
OutputStream os = new FileOutputStream( db );
OutputStreamWriter osw = new OutputStreamWriter(os);
- String[] columns = { COL_ENTRY, COL_TAG };
+ String[] columns = { COL_ENTRY, COL_TAG, COL_THREAD };
String selection = null;
String orderBy = COL_ROWID;
Cursor cursor = getReadableDatabase().query( LOGS_TABLE_NAME, columns,
@@ -263,17 +271,22 @@ public class Log {
llog( "dumpToFile(): got %d results", cursor.getCount() );
int indx0 = cursor.getColumnIndex( columns[0] );
int indx1 = cursor.getColumnIndex( columns[1] );
+ int indx2 = cursor.getColumnIndex( columns[2] );
while ( cursor.moveToNext() ) {
String data = cursor.getString(indx0);
String tag = cursor.getString(indx1);
- osw.write( tag );
- osw.write( ":" );
- osw.write(data);
- osw.write( "\n" );
+ long tid = cursor.getLong(indx2);
+ StringBuilder builder = new StringBuilder()
+ .append(tid).append(":")
+ .append(tag).append(":")
+ .append(data).append("\n")
+ ;
+ osw.write( builder.toString() );
}
osw.close();
} catch ( IOException ioe ) {
llog( "dumpToFile(): ioe: %s", ioe );
+ db = null;
}
return db;
}
diff --git a/xwords4/android/app/src/main/res/values/strings.xml b/xwords4/android/app/src/main/res/values/strings.xml
index 69a88dedb..ba05ded9f 100644
--- a/xwords4/android/app/src/main/res/values/strings.xml
+++ b/xwords4/android/app/src/main/res/values/strings.xml
@@ -2530,6 +2530,8 @@
Write stored logs to file
Logs written to file %1$s
+
+ Unable to write logs
%1$d log entries deleted
diff --git a/xwords4/android/jni/andutils.c b/xwords4/android/jni/andutils.c
index 14c785dbb..272787f9d 100644
--- a/xwords4/android/jni/andutils.c
+++ b/xwords4/android/jni/andutils.c
@@ -768,43 +768,25 @@ deleteLocalRefs( JNIEnv* env, ... )
}
#ifdef DEBUG
-static int g_log_count = 0;
-static pthread_mutex_t g_log_count_lock = PTHREAD_MUTEX_INITIALIZER;
/* A bunch of threads are generating log statements. */
static void
passToJava( const char* tag, const char* msg )
{
- if ( 1 ) {
- pthread_mutex_lock( &g_log_count_lock );
- int lockCount = ++g_log_count;
- RAW_LOG( "lockCount: %d", lockCount );
- pthread_mutex_unlock( &g_log_count_lock );
+ JNIEnv* env = waitEnvFromGlobals();
+ if ( !!env ) {
+ jstring jtag = (*env)->NewStringUTF( env, tag );
+ jstring jbuf = (*env)->NewStringUTF( env, msg );
+ jclass clazz = (*env)->FindClass( env, PKG_PATH("Log") );
+ XP_ASSERT( !!clazz );
+ jmethodID mid = (*env)->GetStaticMethodID( env, clazz, "store",
+ "(Ljava/lang/String;Ljava/lang/String;)V" );
+ (*env)->CallStaticVoidMethod( env, clazz, mid, jtag, jbuf );
+ deleteLocalRefs( env, clazz, jtag, jbuf, DELETE_NO_REF );
- /* Now pass into Log.java for possible writing to DB */
- if ( 1 == lockCount ) {
- JNIEnv* env = waitEnvFromGlobals();
- if ( !!env ) {
- jstring jtag = (*env)->NewStringUTF( env, tag );
- jstring jbuf = (*env)->NewStringUTF( env, msg );
- jclass clazz = (*env)->FindClass( env, PKG_PATH("Log") );
- XP_ASSERT( !!clazz );
- jmethodID mid = (*env)->GetStaticMethodID( env, clazz, "store",
- "(Ljava/lang/String;Ljava/lang/String;)V" );
- (*env)->CallStaticVoidMethod( env, clazz, mid, jtag, jbuf );
- deleteLocalRefs( env, clazz, jtag, jbuf, DELETE_NO_REF );
-
- releaseEnvFromGlobals( env );
- } else {
- RAW_LOG( "env is NULL; dropping" );
- }
- } else {
- RAW_LOG( "recursing! Skipping msg %s", msg );
- }
-
- pthread_mutex_lock( &g_log_count_lock );
- --g_log_count;
- pthread_mutex_unlock( &g_log_count_lock );
+ releaseEnvFromGlobals( env );
+ } else {
+ RAW_LOG( "env is NULL; dropping" );
}
}
diff --git a/xwords4/android/jni/andutils.h b/xwords4/android/jni/andutils.h
index a2cc306b8..07b14b38e 100644
--- a/xwords4/android/jni/andutils.h
+++ b/xwords4/android/jni/andutils.h
@@ -113,7 +113,11 @@ JNIEnv* waitEnvFromGlobals();
void releaseEnvFromGlobals( JNIEnv* env );
void raw_log( const char* func, const char* fmt, ... );
-#define RAW_LOG(...) raw_log( __func__, __VA_ARGS__ )
+#ifdef DEBUG
+# define RAW_LOG(...) raw_log( __func__, __VA_ARGS__ )
+#else
+# define RAW_LOG(...)
+#endif
# define DELETE_NO_REF ((jobject)-1) /* terminates above varargs list */
#endif