[Android] Crash reporter: include the crash logcat as well and allow forcing a crash

Nicolas Pomepuy git at videolan.org
Thu Sep 23 11:01:20 UTC 2021


vlc-android | branch: master | Nicolas Pomepuy <nicolas at videolabs.io> | Thu Sep 23 11:25:37 2021 +0200| [d01b401a63584d543bf32ade9c09301bce0fd61a] | committer: Nicolas Pomepuy

Crash reporter: include the crash logcat as well and allow forcing a crash

> https://code.videolan.org/videolan/vlc-android/commit/d01b401a63584d543bf32ade9c09301bce0fd61a
---

 .../org/videolan/resources/util/VLCCrashHandler.kt | 150 ++++++++++++---------
 .../src/org/videolan/vlc/PlaybackService.kt        |   2 +
 .../src/org/videolan/vlc/gui/SendCrashActivity.kt  |   2 +-
 3 files changed, 90 insertions(+), 64 deletions(-)

diff --git a/application/resources/src/main/java/org/videolan/resources/util/VLCCrashHandler.kt b/application/resources/src/main/java/org/videolan/resources/util/VLCCrashHandler.kt
index 05f016ca6..22a3b5ad6 100644
--- a/application/resources/src/main/java/org/videolan/resources/util/VLCCrashHandler.kt
+++ b/application/resources/src/main/java/org/videolan/resources/util/VLCCrashHandler.kt
@@ -38,76 +38,100 @@ class VLCCrashHandler : UncaughtExceptionHandler {
     private val defaultUEH: UncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler()
 
     override fun uncaughtException(thread: Thread, ex: Throwable) {
-
-        val result = StringWriter()
-        val printWriter = PrintWriter(result)
-
-        // Inject some info about android version and the device, since google can't provide them in the developer console
-        val trace = ex.stackTrace
-        val trace2 = arrayOfNulls<StackTraceElement>(trace.size + 3)
-        System.arraycopy(trace, 0, trace2, 0, trace.size)
-        trace2[trace.size + 0] = StackTraceElement("Android", "MODEL", android.os.Build.MODEL, -1)
-        trace2[trace.size + 1] = StackTraceElement("Android", "VERSION", android.os.Build.VERSION.RELEASE, -1)
-        trace2[trace.size + 2] = StackTraceElement("Android", "FINGERPRINT", android.os.Build.FINGERPRINT, -1)
-        ex.stackTrace = trace2
-
-        ex.printStackTrace(printWriter)
-        val stacktrace = result.toString()
-        printWriter.close()
-        Log.e(TAG, stacktrace)
-
-        // Save the log on SD card if available
-        if (Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED) {
-            writeLog(stacktrace, AppContextProvider.appContext.getExternalFilesDir(null)!!.absolutePath + "/vlc_crash")
-            writeLogcat(AppContextProvider.appContext.getExternalFilesDir(null)!!.absolutePath + "/vlc_logcat")
-        }
-
-        defaultUEH.uncaughtException(thread, ex)
+        defaultUEH.uncaughtException(thread, saveLog(ex))
     }
 
-
-    private fun writeLog(log: String, name: String) {
-        val timestamp = DateFormat.format("yyyyMMdd_kkmmss", System.currentTimeMillis())
-        val filename = name + "_" + timestamp + ".log"
-
-        val stream: FileOutputStream
-        try {
-            stream = FileOutputStream(filename)
-        } catch (e: FileNotFoundException) {
-            e.printStackTrace()
-            return
+    companion object {
+        /**
+         * Saves a [Throwable] stack trace in a crash file after having some useful info appended.
+         * Also save a logcat file besides it
+         * /!\ Will trigger the crash reporter in beta!
+         * It's called by the [UncaughtExceptionHandler] but is useful in case we want to workaround a crash
+         * but still get the trace in the crash reporter
+         *
+         * @param ex: the [Throwable] to log
+         * @return the [Throwable] with versions appended
+         */
+        fun saveLog(ex: Throwable):Throwable {
+            val result = StringWriter()
+            val printWriter = PrintWriter(result)
+
+            // Inject some info about android version and the device, since google can't provide them in the developer console
+            val trace = ex.stackTrace
+            val trace2 = arrayOfNulls<StackTraceElement>(trace.size + 3)
+            System.arraycopy(trace, 0, trace2, 0, trace.size)
+            trace2[trace.size + 0] = StackTraceElement("Android", "MODEL", android.os.Build.MODEL, -1)
+            trace2[trace.size + 1] = StackTraceElement("Android", "VERSION", android.os.Build.VERSION.RELEASE, -1)
+            trace2[trace.size + 2] = StackTraceElement("Android", "FINGERPRINT", android.os.Build.FINGERPRINT, -1)
+            ex.stackTrace = trace2
+
+            ex.printStackTrace(printWriter)
+            val stacktrace = result.toString()
+            printWriter.close()
+            Log.e(TAG, stacktrace)
+
+            // Save the log on SD card if available
+            if (Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED) {
+                writeLog(stacktrace, AppContextProvider.appContext.getExternalFilesDir(null)!!.absolutePath + "/vlc_crash")
+                writeLogcat(AppContextProvider.appContext.getExternalFilesDir(null)!!.absolutePath + "/vlc_logcat")
+            }
+            return ex
         }
 
-        val output = OutputStreamWriter(stream)
-        val bw = BufferedWriter(output)
-
-        val version = try {
-            val pInfo: PackageInfo = AppContextProvider.appContext.packageManager.getPackageInfo(AppContextProvider.appContext.getPackageName(), 0)
-             pInfo.versionName
-        } catch (e: PackageManager.NameNotFoundException) {
-            e.printStackTrace()
+        /**
+         * Writes a log in a file
+         *
+         * @param log: the log string to write
+         * @param name: the file name to write into
+         */
+        private fun writeLog(log: String, name: String) {
+            val timestamp = DateFormat.format("yyyyMMdd_kkmmss", System.currentTimeMillis())
+            val filename = name + "_" + timestamp + ".log"
+
+            val stream: FileOutputStream
+            try {
+                stream = FileOutputStream(filename)
+            } catch (e: FileNotFoundException) {
+                e.printStackTrace()
+                return
+            }
+
+            val output = OutputStreamWriter(stream)
+            val bw = BufferedWriter(output)
+
+            val version = try {
+                val pInfo: PackageInfo = AppContextProvider.appContext.packageManager.getPackageInfo(AppContextProvider.appContext.getPackageName(), 0)
+                pInfo.versionName
+            } catch (e: PackageManager.NameNotFoundException) {
+                e.printStackTrace()
+            }
+
+            try {
+                bw.write("App version: $version\r\n")
+                bw.write(log)
+                bw.newLine()
+            } catch (e: IOException) {
+                e.printStackTrace()
+            } finally {
+                CloseableUtils.close(bw)
+                CloseableUtils.close(output)
+            }
         }
 
-        try {
-            bw.write("App version: $version\r\n")
-            bw.write(log)
-            bw.newLine()
-        } catch (e: IOException) {
-            e.printStackTrace()
-        } finally {
-            CloseableUtils.close(bw)
-            CloseableUtils.close(output)
-        }
-    }
+        /**
+         * Write the current log in a file
+         *
+         * @param name: the file name to use to save the logcat
+         */
+        private fun writeLogcat(name: String) {
+            val timestamp = DateFormat.format("yyyyMMdd_kkmmss", System.currentTimeMillis())
+            val filename = name + "_" + timestamp + ".log"
+            try {
+                Logcat.writeLogcat(filename)
+            } catch (e: IOException) {
+                Log.e(TAG, "Cannot write logcat to disk")
+            }
 
-    private fun writeLogcat(name: String) {
-        val timestamp = DateFormat.format("yyyyMMdd_kkmmss", System.currentTimeMillis())
-        val filename = name + "_" + timestamp + ".log"
-        try {
-            Logcat.writeLogcat(filename)
-        } catch (e: IOException) {
-            Log.e(TAG, "Cannot write logcat to disk")
         }
-
     }
 }
diff --git a/application/vlc-android/src/org/videolan/vlc/PlaybackService.kt b/application/vlc-android/src/org/videolan/vlc/PlaybackService.kt
index a91f3eee1..307a29b93 100644
--- a/application/vlc-android/src/org/videolan/vlc/PlaybackService.kt
+++ b/application/vlc-android/src/org/videolan/vlc/PlaybackService.kt
@@ -66,6 +66,7 @@ import org.videolan.libvlc.util.AndroidUtil
 import org.videolan.medialibrary.interfaces.Medialibrary
 import org.videolan.medialibrary.interfaces.media.MediaWrapper
 import org.videolan.resources.*
+import org.videolan.resources.util.VLCCrashHandler
 import org.videolan.resources.util.getFromMl
 import org.videolan.resources.util.launchForeground
 import org.videolan.tools.*
@@ -1188,6 +1189,7 @@ class PlaybackService : MediaBrowserServiceCompat(), LifecycleOwner {
                     }
                 } catch (e: java.lang.NullPointerException) {
                     Log.e("PlaybackService", "Caught NullPointerException", e)
+                    VLCCrashHandler.saveLog(e)
                 }
             }
             artworkToUriCache.clear()
diff --git a/application/vlc-android/src/org/videolan/vlc/gui/SendCrashActivity.kt b/application/vlc-android/src/org/videolan/vlc/gui/SendCrashActivity.kt
index d1059c7a9..e0b1bb735 100644
--- a/application/vlc-android/src/org/videolan/vlc/gui/SendCrashActivity.kt
+++ b/application/vlc-android/src/org/videolan/vlc/gui/SendCrashActivity.kt
@@ -99,7 +99,7 @@ class SendCrashActivity : AppCompatActivity(), DebugLogService.Client.Callback {
                 try {
                     val folder = AppContextProvider.appContext.getExternalFilesDir(null)?.absolutePath
                     File(folder).listFiles().forEach {
-                        if (it.isFile && it.name.contains("crash")) filesToAdd.add(it.path)
+                        if (it.isFile && (it.name.contains("crash") || it.name.contains("logcat"))) filesToAdd.add(it.path)
                     }
                 } catch (exception: IOException) {
 



More information about the Android mailing list