Merge pull request #1910 from Andries-Smit/feat/wear-crashlytics

Feat Wear OS Crashlytics
This commit is contained in:
Milos Kozak 2022-07-14 08:00:33 +02:00 committed by GitHub
commit 2368300505
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 141 additions and 13 deletions

View file

@ -271,6 +271,13 @@ class DataHandlerMobile @Inject constructor(
aapsLogger.debug(LTag.WEAR, "SnoozeAlert received $it from ${it.sourceNodeId}")
alarmSoundServiceHelper.stopService(context, "Muted from wear")
}, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventData.WearException::class.java)
.observeOn(aapsSchedulers.io)
.subscribe({
aapsLogger.debug(LTag.WEAR, "WearException received $it from ${it.sourceNodeId}")
fabricPrivacy.logWearException(it)
}, fabricPrivacy::logException)
}
private fun handleTddStatus() {

View file

@ -8,18 +8,13 @@ import dagger.android.AndroidInjection
import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.events.EventMobileToWear
import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.androidaps.interfaces.Config
import info.nightscout.androidaps.interfaces.IobCobCalculator
import info.nightscout.androidaps.interfaces.Loop
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.*
import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus
import info.nightscout.androidaps.plugins.general.wear.WearPlugin
import info.nightscout.androidaps.plugins.general.wear.events.EventWearUpdateGui
import info.nightscout.androidaps.receivers.ReceiverStatusStore
import info.nightscout.androidaps.utils.DefaultValueHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.wizard.QuickWizard
@ -116,7 +111,7 @@ class DataLayerListenerServiceMobile : WearableListenerService() {
if (wearPlugin.isEnabled()) {
when (messageEvent.path) {
rxPath -> {
aapsLogger.debug(LTag.WEAR, "onMessageReceived: ${String(messageEvent.data)}")
aapsLogger.debug(LTag.WEAR, "onMessageReceived rxPath: ${String(messageEvent.data)}")
val command = EventData.deserialize(String(messageEvent.data))
rxBus.send(command.also { it.sourceNodeId = messageEvent.sourceNodeId })
}
@ -203,4 +198,4 @@ class DataLayerListenerServiceMobile : WearableListenerService() {
const val WEAR_CAPABILITY = "androidaps_wear"
}
}
}

View file

@ -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
@ -79,7 +83,7 @@ class FabricPrivacy @Inject constructor(
// 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)
}
@ -92,4 +96,31 @@ class FabricPrivacy @Inject constructor(
fun fabricEnabled(): Boolean {
return sp.getBoolean(R.string.key_enable_fabric, true)
}
}
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")
}
}

View file

@ -25,6 +25,29 @@ 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() {
override fun equals(other: Any?): Boolean =
when (other) {
!is WearException -> false
else -> timeStamp == other.timeStamp && fingerprint == other.fingerprint
}
override fun hashCode(): Int {
return Objects.hash(timeStamp, fingerprint)
}
}
@Serializable
data class Error(val timeStamp: Long) : EventData() // ignored

View file

@ -9,6 +9,7 @@ import dagger.android.AndroidInjector
import dagger.android.DaggerApplication
import info.nightscout.androidaps.comm.DataHandlerWear
import info.nightscout.androidaps.comm.DataLayerListenerServiceWear
import info.nightscout.androidaps.comm.ExceptionHandlerWear
import info.nightscout.androidaps.di.DaggerWearComponent
import info.nightscout.androidaps.events.EventWearPreferenceChange
import info.nightscout.androidaps.plugins.bus.RxBus
@ -21,13 +22,14 @@ class Aaps : DaggerApplication(), OnSharedPreferenceChangeListener {
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var rxBus: RxBus
@Inject lateinit var dataHandlerWear: DataHandlerWear // instantiate only
@Inject lateinit var exceptionHandlerWear: ExceptionHandlerWear
override fun onCreate() {
super.onCreate()
exceptionHandlerWear.register()
aapsLogger.debug(LTag.WEAR, "onCreate")
PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this)
startService(Intent(this, DataLayerListenerServiceWear::class.java))
}
override fun applicationInjector(): AndroidInjector<out DaggerApplication> =
@ -37,8 +39,8 @@ class Aaps : DaggerApplication(), OnSharedPreferenceChangeListener {
.build()
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
// we trigger update on Complications
// We trigger update on Complications
LocalBroadcastManager.getInstance(this).sendBroadcast(Intent(DataLayerListenerServiceWear.INTENT_NEW_DATA))
rxBus.send(EventWearPreferenceChange(key))
}
}
}

View file

@ -0,0 +1,70 @@
package info.nightscout.androidaps.comm
import android.os.Build
import android.util.Log
import info.nightscout.androidaps.events.EventWearToMobile
import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.shared.weardata.EventData
import java.io.ByteArrayOutputStream
import java.io.IOException
import java.io.ObjectOutputStream
import javax.inject.Inject
class ExceptionHandlerWear @Inject constructor(
private val rxBus: RxBus,
) {
private var mDefaultUEH: Thread.UncaughtExceptionHandler? = null
private val mWearUEH = Thread.UncaughtExceptionHandler { thread, ex ->
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()
}
}