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