diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 89db45c95b..8fb0dea2f6 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -208,10 +208,6 @@ android:host="*" android:pathPrefix="@string/path_rx_bridge" android:scheme="wear" /> - { + rxPath -> { aapsLogger.debug(LTag.WEAR, "onMessageReceived rxPath: ${String(messageEvent.data)}") val command = EventData.deserialize(String(messageEvent.data)) rxBus.send(command.also { it.sourceNodeId = messageEvent.sourceNodeId }) } - - exceptionPath -> logWearException(messageEvent) } } } - private fun logWearException(messageEvent: MessageEvent) { - aapsLogger.debug(LTag.WEAR, "logWearException") - val map = DataMap.fromByteArray(messageEvent.data) - val bis = ByteArrayInputStream(map.getByteArray("exception")) - try { - val ois = ObjectInputStream(bis) - fabricPrivacy.getInstance().apply { - setCustomKey("wear_exception", true) - setCustomKey("wear_board", map.getString("board") ?: "unknown") - setCustomKey("wear_fingerprint", map.getString("fingerprint") ?: "unknown") - setCustomKey("wear_sdk", map.getString("sdk") ?: "unknown") - setCustomKey("wear_model", map.getString("model") ?: "unknown") - setCustomKey("wear_manufacturer", map.getString("manufacturer") ?: "unknown") - setCustomKey("wear_product", map.getString("product") ?: "unknown") - } - fabricPrivacy.logException(ois.readObject() as Throwable) - } catch (e: IOException) { - e.printStackTrace() - } catch (e: ClassNotFoundException) { - e.printStackTrace() - } - } - private var transcriptionNodeId: String? = null private fun updateTranscriptionCapability() { diff --git a/core/src/main/java/info/nightscout/androidaps/utils/FabricPrivacy.kt b/core/src/main/java/info/nightscout/androidaps/utils/FabricPrivacy.kt index 7ec112ce9f..46a8813120 100644 --- a/core/src/main/java/info/nightscout/androidaps/utils/FabricPrivacy.kt +++ b/core/src/main/java/info/nightscout/androidaps/utils/FabricPrivacy.kt @@ -10,6 +10,10 @@ import info.nightscout.androidaps.core.R import info.nightscout.shared.logging.AAPSLogger import info.nightscout.shared.logging.LTag import info.nightscout.shared.sharedPreferences.SP +import info.nightscout.shared.weardata.EventData +import java.io.ByteArrayInputStream +import java.io.IOException +import java.io.ObjectInputStream import javax.inject.Inject import javax.inject.Singleton @@ -77,13 +81,9 @@ class FabricPrivacy @Inject constructor( } } - fun getInstance(): FirebaseCrashlytics { - return FirebaseCrashlytics.getInstance() - } - // Crashlytics log message fun logMessage(message: String) { - aapsLogger.info(LTag.CORE,"Crashlytics log message: $message") + aapsLogger.info(LTag.CORE, "Crashlytics log message: $message") FirebaseCrashlytics.getInstance().log(message) } @@ -96,4 +96,31 @@ class FabricPrivacy @Inject constructor( fun fabricEnabled(): Boolean { return sp.getBoolean(R.string.key_enable_fabric, true) } -} \ No newline at end of file + + fun logWearException(wearException: EventData.WearException) { + aapsLogger.debug(LTag.WEAR, "logWearException") + FirebaseCrashlytics.getInstance().apply { + setCustomKey("wear_exception", true) + setCustomKey("wear_board", wearException.board) + setCustomKey("wear_fingerprint", wearException.fingerprint) + setCustomKey("wear_sdk", wearException.sdk) + setCustomKey("wear_model", wearException.model) + setCustomKey("wear_manufacturer", wearException.manufacturer) + setCustomKey("wear_product", wearException.product) + } + logException(byteArrayToThrowable(wearException.exception)) + } + + private fun byteArrayToThrowable(wearExceptionData: ByteArray): Throwable { + val bis = ByteArrayInputStream(wearExceptionData) + try { + val ois = ObjectInputStream(bis) + return ois.readObject() as Throwable + } catch (e: IOException) { + e.printStackTrace() + } catch (e: ClassNotFoundException) { + e.printStackTrace() + } + return IllegalArgumentException("Wear Exception could not be de-serialized") + } +} diff --git a/shared/src/main/java/info/nightscout/shared/weardata/EventData.kt b/shared/src/main/java/info/nightscout/shared/weardata/EventData.kt index c2d38b1d4d..6d78a1cd3e 100644 --- a/shared/src/main/java/info/nightscout/shared/weardata/EventData.kt +++ b/shared/src/main/java/info/nightscout/shared/weardata/EventData.kt @@ -25,6 +25,18 @@ sealed class EventData : Event() { @Serializable data class ActionPong(val timeStamp: Long, val apiLevel: Int) : EventData() + @Serializable + data class WearException( + val timeStamp: Long, + val exception: ByteArray, + val board: String, + val fingerprint: String, + val sdk: String, + val model: String, + val manufacturer: String, + val product: String + ) : EventData() + @Serializable data class Error(val timeStamp: Long) : EventData() // ignored @@ -134,9 +146,9 @@ sealed class EventData : Event() { override fun equals(other: Any?): Boolean = when { - other !is SingleBg -> false + other !is SingleBg -> false color != other.color -> false - else -> timeStamp == other.timeStamp + else -> timeStamp == other.timeStamp } override fun hashCode(): Int { diff --git a/shared/src/main/res/values/wear_paths.xml b/shared/src/main/res/values/wear_paths.xml index defc5544a9..36d7325849 100644 --- a/shared/src/main/res/values/wear_paths.xml +++ b/shared/src/main/res/values/wear_paths.xml @@ -1,5 +1,4 @@ /rx_bridge - /wear_error - + \ No newline at end of file diff --git a/wear/src/main/AndroidManifest.xml b/wear/src/main/AndroidManifest.xml index dba8a05295..3d10810e37 100644 --- a/wear/src/main/AndroidManifest.xml +++ b/wear/src/main/AndroidManifest.xml @@ -537,8 +537,6 @@ android:resource="@drawable/quick_wizard_tile_preview" /> - - + Log.d("WEAR", "uncaughtException :" + ex.message) + + // Pass the exception to the bus which will send the data upstream to your Smartphone/Tablet + val wearException = EventData.WearException( + timeStamp = System.currentTimeMillis(), + exception = exceptionToByteArray(ex), + board = Build.BOARD, + sdk = Build.VERSION.SDK_INT.toString(), + fingerprint = Build.FINGERPRINT, + model = Build.MODEL, + manufacturer = Build.MANUFACTURER, + product = Build.PRODUCT + ) + rxBus.send(EventWearToMobile(wearException)) + + // Let the default UncaughtExceptionHandler take it from here + mDefaultUEH?.uncaughtException(thread, ex) + } + + fun register() { + mDefaultUEH = Thread.getDefaultUncaughtExceptionHandler() + Thread.setDefaultUncaughtExceptionHandler(mWearUEH) + } + + private fun exceptionToByteArray(ex: Throwable): ByteArray { + ex.stackTrace // Make sure the stacktrace gets built up + val bos = ByteArrayOutputStream() + var oos: ObjectOutputStream? = null + try { + oos = ObjectOutputStream(bos) + oos.writeObject(ex) + return bos.toByteArray() + + } catch (e: IOException) { + e.printStackTrace() + } finally { + try { + oos?.close() + } catch (exx: IOException) { + // Ignore close exception + } + try { + bos.close() + } catch (exx: IOException) { + // Ignore close exception + } + } + return byteArrayOf() + } + +} diff --git a/wear/src/main/java/info/nightscout/androidaps/comm/ExceptionService.kt b/wear/src/main/java/info/nightscout/androidaps/comm/ExceptionService.kt deleted file mode 100644 index cc9964f142..0000000000 --- a/wear/src/main/java/info/nightscout/androidaps/comm/ExceptionService.kt +++ /dev/null @@ -1,110 +0,0 @@ -package info.nightscout.androidaps.comm - -import android.app.IntentService -import android.content.Context -import android.content.Intent -import android.os.Build -import android.os.Handler -import android.os.HandlerThread -import android.util.Log -import com.google.android.gms.tasks.Tasks -import com.google.android.gms.wearable.CapabilityClient -import com.google.android.gms.wearable.CapabilityInfo -import com.google.android.gms.wearable.DataMap -import com.google.android.gms.wearable.Node -import com.google.android.gms.wearable.Wearable -import info.nightscout.androidaps.R -import java.io.ByteArrayOutputStream -import java.io.IOException -import java.io.ObjectOutputStream - -class ExceptionService : IntentService(ExceptionService::class.simpleName) { - - private val messageClient by lazy { Wearable.getMessageClient(this) } - private val capabilityClient by lazy { Wearable.getCapabilityClient(this) } - private var handler = Handler(HandlerThread(this::class.simpleName + "Handler").also { it.start() }.looper) - private val exceptionPath get() = getString(R.string.path_log_exception) - private var transcriptionNodeId: String? = null - - override fun onCreate() { - super.onCreate() - - handler.post { updateTranscriptionCapability() } - } - - private fun updateTranscriptionCapability() { - val capabilityInfo: CapabilityInfo = Tasks.await( - capabilityClient.getCapability(DataLayerListenerServiceWear.PHONE_CAPABILITY, CapabilityClient.FILTER_REACHABLE) - ) - Log.d("WEAR", "Nodes: ${capabilityInfo.nodes.joinToString(", ") { it.displayName + "(" + it.id + ")" }}") - pickBestNodeId(capabilityInfo.nodes)?.let { transcriptionNodeId = it } - Log.d("WEAR", "Selected node: $transcriptionNodeId") - } - - // Find a nearby node or pick one arbitrarily - private fun pickBestNodeId(nodes: Set): String? = - nodes.firstOrNull { it.isNearby }?.id ?: nodes.firstOrNull()?.id - - private fun sendMessage(path: String, data: ByteArray) { - transcriptionNodeId?.also { nodeId -> - messageClient - .sendMessage(nodeId, path, data).apply { - addOnSuccessListener { } - addOnFailureListener { - Log.d("WEAR", "sendMessage: $path failure") - } - } - } - } - - override fun onHandleIntent(intent: Intent?) { - Log.d("WEAR", "onHandleIntent: ErrorService $intent") - - val bos = ByteArrayOutputStream() - var oos: ObjectOutputStream? = null - try { - oos = ObjectOutputStream(bos) - oos.writeObject(intent?.getSerializableExtra("exception")) - val exceptionData = bos.toByteArray() - val dataMap = DataMap() - - dataMap.putString("board", Build.BOARD) - dataMap.putString("sdk", Build.VERSION.SDK_INT.toString()) - dataMap.putString("fingerprint", Build.FINGERPRINT) - dataMap.putString("model", Build.MODEL) - dataMap.putString("manufacturer", Build.MANUFACTURER) - dataMap.putString("product", Build.PRODUCT) - dataMap.putByteArray("exception", exceptionData) - - handler.post { - sendMessage(exceptionPath, dataMap.toByteArray()) - } - } catch (e: IOException) { - e.printStackTrace() - } finally { - try { - oos?.close() - } catch (exx: IOException) { - // ignore close exception - } - try { - bos.close() - } catch (exx: IOException) { - // ignore close exception - } - } - } - - init { - setIntentRedelivery(true) - } - - companion object { - fun reportException(context: Context, ex: Throwable?) { - val errorIntent = Intent(context, ExceptionService::class.java) - errorIntent.putExtra("exception", ex) - context.startService(errorIntent) - } - } - -} diff --git a/wear/src/main/java/info/nightscout/androidaps/comm/ExceptionWear.kt b/wear/src/main/java/info/nightscout/androidaps/comm/ExceptionWear.kt deleted file mode 100644 index 1bbc18ab8b..0000000000 --- a/wear/src/main/java/info/nightscout/androidaps/comm/ExceptionWear.kt +++ /dev/null @@ -1,23 +0,0 @@ -package info.nightscout.androidaps.comm - -import android.content.Context -import android.util.Log - -class ExceptionWear(private val context: Context) { - - private var mDefaultUEH: Thread.UncaughtExceptionHandler? = null - - private val mWearUEH = Thread.UncaughtExceptionHandler { thread, ex -> - Log.d("WEAR", "uncaughtException :" + ex.message) - // Pass the exception to a Service which will send the data upstream to your Smartphone/Tablet - ExceptionService.reportException(context, ex) - // Let the default UncaughtExceptionHandler take it from here - mDefaultUEH?.uncaughtException(thread, ex) - } - - init { - mDefaultUEH = Thread.getDefaultUncaughtExceptionHandler() - Thread.setDefaultUncaughtExceptionHandler(mWearUEH) - } - -}