Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • justJanne/QuasselDroid-ng
1 result
Select Git revision
Show changes
Commits on Source (2)
Showing
with 32 additions and 514 deletions
......@@ -317,7 +317,8 @@
android:name="de.kuschku.quasseldroid.service.QuasselService"
android:description="@string/connection_service_description"
android:exported="false"
android:label="@string/connection_service_title" />
android:label="@string/connection_service_title"
android:foregroundServiceType="remoteMessaging" />
</application>
</manifest>
......@@ -90,7 +90,7 @@ class CrashAdapter : ListAdapter<Pair<Report?, Uri>, CrashAdapter.CrashViewHolde
this.item = item
this.uri = uri
binding.crashTime.text = item?.environment?.crashTime?.let {
binding.crashTime.text = item?.timestamp?.let {
dateTimeFormatter.format(Instant.ofEpochMilli(it).atZone(ZoneId.systemDefault()))
} ?: "null"
binding.versionName.text = item?.application?.versionName ?: "null"
......
......@@ -75,7 +75,7 @@ class CrashFragment : DaggerFragment() {
FileProvider.getUriForFile(context, "${BuildConfig.APPLICATION_ID}.fileprovider", it)
)
}
.sortedByDescending { it.first?.environment?.crashTime }
.sortedByDescending { it.first?.timestamp }
activity?.runOnUiThread {
this.adapter?.submitList(list)
......
......@@ -24,7 +24,6 @@ import android.os.Build
import de.kuschku.malheur.CrashContext
import de.kuschku.malheur.config.AppConfig
import de.kuschku.malheur.data.AppInfo
import de.kuschku.malheur.util.reflectionCollectConstants
class AppCollector(private val application: Application) : Collector<AppInfo, AppConfig> {
override fun collect(context: CrashContext, config: AppConfig) = AppInfo(
......@@ -39,20 +38,13 @@ class AppCollector(private val application: Application) : Collector<AppInfo, Ap
application.packageManager.getPackageInfo(application.packageName, 0).versionCode.toLong()
}
},
buildConfig = collectIf(config.buildConfig) {
reflectionCollectConstants(
context.buildConfig ?: getBuildConfigClass(application.packageName)
)
},
installationSource = collectIf(config.installationSource) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
application.packageManager.getInstallSourceInfo(application.packageName).originatingPackageName
} else {
@Suppress("DEPRECATION")
application.packageManager.getInstallerPackageName(application.packageName)
}
)
private fun getBuildConfigClass(packageName: String) = try {
Class.forName("$packageName.BuildConfig")
} catch (e: ClassNotFoundException) {
null
}
)
}
/*
* Quasseldroid - Quassel client for Android
*
* Copyright (c) 2020 Janne Mareike Koschinski
* Copyright (c) 2020 The Quassel Project
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.malheur.collectors
import android.annotation.SuppressLint
import android.app.Application
import android.content.res.Configuration
import android.util.SparseArray
import de.kuschku.malheur.CrashContext
import java.lang.reflect.Field
import java.lang.reflect.Modifier
class ConfigurationCollector(private val application: Application) :
Collector<Map<String, Any?>, Boolean> {
private val configValueInfo = mutableMapOf<String, SparseArray<String>>()
private val configurationFields = listOf(
FieldDefinition(
fieldName = "screenHeightDp"
),
FieldDefinition(
fieldName = "screenWidthDp"
),
FieldDefinition(
fieldName = "smallestScreenWidthDp"
),
FieldDefinition(
fieldName = "navigation",
enumPrefix = "NAVIGATION"
),
FieldDefinition(
fieldName = "navigationHidden",
enumPrefix = "NAVIGATIONHIDDEN"
),
FieldDefinition(
fieldName = "orientation",
enumPrefix = "ORIENTATION"
),
FieldDefinition(
fieldName = "screenLayout",
enumPrefix = "SCREENLAYOUT",
isFlag = true
),
FieldDefinition(
fieldName = "touchscreen",
enumPrefix = "TOUCHSCREEN"
),
FieldDefinition(
fieldName = "uiMode",
enumPrefix = "UI_MODE",
isFlag = true
)
)
init {
val configurationFieldPrefixes = configurationFields.map(FieldDefinition::enumPrefix)
Configuration::class.java.declaredFields.filter {
Modifier.isStatic(it.modifiers)
}.filter {
it.type == Int::class.java
}.filterNot {
it.name.endsWith("_MASK")
}.forEach { field ->
val group = configurationFieldPrefixes.find { field.name.startsWith(it + "_") }
if (group != null) {
val value = field.name.substring(group.length + 1)
configValueInfo.getOrPut(group, ::SparseArray).put(field.getInt(null), value)
}
}
}
@SuppressLint("PrivateApi")
override fun collect(context: CrashContext,
config: Boolean) = configurationFields.mapNotNull { info ->
val field: Field? = Configuration::class.java.getDeclaredField(info.fieldName)
field?.let {
Pair(info, it)
}
}.filter { (_, field) ->
!Modifier.isStatic(field.modifiers)
}.map { (info, field) ->
val groupInfo = configValueInfo[info.enumPrefix]
if (groupInfo != null) {
val value = field.getInt(application.resources.configuration)
if (info.isFlag) {
info.fieldName to (0 until groupInfo.size()).map { idx ->
groupInfo.keyAt(idx) to groupInfo.valueAt(idx)
}.filter { (key, _) ->
value and key != 0
}.map { (_, value) ->
value
}.toList()
} else {
val valueConstant = groupInfo[value]
if (valueConstant == null) {
info.fieldName to value
} else {
info.fieldName to valueConstant
}
}
} else {
val value = field.getInt(application.resources.configuration)
info.fieldName to value
}
}.toMap()
class FieldDefinition(
val fieldName: String,
val enumPrefix: String? = null,
val isFlag: Boolean = false
)
}
/*
* Quasseldroid - Quassel client for Android
*
* Copyright (c) 2020 Janne Mareike Koschinski
* Copyright (c) 2020 The Quassel Project
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.malheur.collectors
import android.app.Application
import android.os.Build
import de.kuschku.malheur.CrashContext
import de.kuschku.malheur.config.DeviceConfig
import de.kuschku.malheur.data.DeviceInfo
import de.kuschku.malheur.util.reflectionCollectConstants
import java.io.File
class DeviceCollector(private val application: Application) : Collector<DeviceInfo, DeviceConfig> {
private val displayCollector = DisplayCollector(application)
override fun collect(context: CrashContext, config: DeviceConfig): DeviceInfo {
return DeviceInfo(
build = collectIf(config.build) {
reflectionCollectConstants(Build::class.java)
},
version = collectIf(config.version) {
reflectionCollectConstants(Build.VERSION::class.java)
},
processor = collectIf(config.processor) {
readProcInfo()
},
display = displayCollector.collectIf(context, config.display)
)
}
private fun readProcInfo() = File("/proc/cpuinfo")
.bufferedReader(Charsets.UTF_8)
.lineSequence()
.map { line -> line.split(":") }
.filter { split -> split.size == 2 }
.map { (key, value) -> key.trim() to value.trim() }
.filter { (key, _) -> key == "Hardware" }
.map { (_, value) -> value }
.firstOrNull()
}
/*
* Quasseldroid - Quassel client for Android
*
* Copyright (c) 2020 Janne Mareike Koschinski
* Copyright (c) 2020 The Quassel Project
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.malheur.collectors
import android.app.Application
import android.content.Context
import android.graphics.Point
import android.os.Build
import android.util.SparseArray
import android.view.Display
import android.view.WindowManager
import androidx.annotation.RequiresApi
import de.kuschku.malheur.CrashContext
import de.kuschku.malheur.data.DisplayInfo
import de.kuschku.malheur.data.MetricsInfo
import de.kuschku.malheur.util.getMetrics
import java.lang.reflect.Modifier
class DisplayCollector(application: Application) :
Collector<DisplayInfo, Boolean> {
private val windowManager = application.getSystemService(
Context.WINDOW_SERVICE
) as WindowManager
@Suppress("DEPRECATION")
override fun collect(context: CrashContext, config: Boolean): DisplayInfo {
val display = windowManager.defaultDisplay
val hdrCapabilities = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val capabilitiesEnum = getHdrCapabilitiesEnum()
display.hdrCapabilities.supportedHdrTypes.map(capabilitiesEnum::get)
} else {
null
}
val size = Point().also {
display.getRealSize(it)
}
return DisplayInfo(
width = size.x,
height = size.y,
refreshRate = display.refreshRate,
hdr = hdrCapabilities,
isWideGamut = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
display.isWideColorGamut
} else {
null
},
metrics = MetricsInfo(display.getMetrics())
)
}
@RequiresApi(Build.VERSION_CODES.N)
private fun getHdrCapabilitiesEnum(): SparseArray<String> {
val hdrCapabilityEnums = SparseArray<String>()
Display.HdrCapabilities::class.java.declaredFields.filter {
Modifier.isStatic(it.modifiers)
}.filter {
it.name.startsWith("HDR_TYPE_")
}.filter {
it.type == Int::class.java
}.forEach {
try {
val value = it.getInt(null)
hdrCapabilityEnums.put(value, it.name.substring("HDR_TYPE_".length))
} catch (e: IllegalAccessException) {
}
}
return hdrCapabilityEnums
}
}
/*
* Quasseldroid - Quassel client for Android
*
* Copyright (c) 2020 Janne Mareike Koschinski
* Copyright (c) 2020 The Quassel Project
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.malheur.collectors
import android.app.Application
import android.os.Debug
import android.os.Environment
import de.kuschku.malheur.CrashContext
import de.kuschku.malheur.config.EnvConfig
import de.kuschku.malheur.data.EnvInfo
import de.kuschku.malheur.data.MemoryInfo
import de.kuschku.malheur.util.reflectionCollectGetters
import java.io.File
class EnvCollector(application: Application) : Collector<EnvInfo, EnvConfig> {
private val configurationCollector = ConfigurationCollector(application)
override fun collect(context: CrashContext, config: EnvConfig) = EnvInfo(
paths = collectIf(config.paths) {
reflectionCollectGetters(
Environment::class.java
)?.map { (key, value) ->
key to if (value is File) {
value.canonicalPath
} else {
value
}
}?.toMap()
},
memory = collectIf(config.memory) {
val memoryInfo = Debug.MemoryInfo()
Debug.getMemoryInfo(memoryInfo)
MemoryInfo(memoryInfo)
},
configuration = configurationCollector.collectIf(context, config.configuration),
startTime = collectIf(config.startTime) {
context.startTime.time
},
crashTime = collectIf(config.crashTime) {
context.crashTime.time
}
)
}
/*
* Quasseldroid - Quassel client for Android
*
* Copyright (c) 2020 Janne Mareike Koschinski
* Copyright (c) 2020 The Quassel Project
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.malheur.collectors
import de.kuschku.malheur.CrashContext
import de.kuschku.malheur.config.LogConfig
import java.text.SimpleDateFormat
import java.util.*
class LogCollector : Collector<Map<String, List<String>>, LogConfig> {
private val logcatTimeFormatter = SimpleDateFormat("MM-dd HH:mm:ss.SSS", Locale.ROOT)
override fun collect(context: CrashContext, config: LogConfig): Map<String, List<String>> {
val since = logcatTimeFormatter.format(context.startTime)
return config.buffers.map { buffer ->
buffer to readLogCat(since, buffer)
}.toMap()
}
private fun readLogCat(since: String, buffer: String) = ProcessBuilder()
.command("logcat", "-t", since, "-b", buffer)
.redirectErrorStream(true)
.start()
.inputStream
.bufferedReader(Charsets.UTF_8)
.readLines()
}
......@@ -27,17 +27,12 @@ import de.kuschku.malheur.data.Report
class ReportCollector(application: Application) : Collector<Report, ReportConfig> {
private val crashCollector = CrashCollector()
private val threadCollector = ThreadCollector()
private val logcatCollector = LogCollector()
private val applicationCollector = AppCollector(application)
private val deviceCollector = DeviceCollector(application)
private val environmentCollector = EnvCollector(application)
override fun collect(context: CrashContext, config: ReportConfig) = Report(
timestamp = System.currentTimeMillis(),
crash = crashCollector.collectIf(context, config.crash),
threads = threadCollector.collectIf(context, config.threads),
/*logcat = logcatCollector.collectIf(context, config.logcat),*/
application = applicationCollector.collectIf(context, config.application),
device = deviceCollector.collectIf(context, config.device),
environment = environmentCollector.collectIf(context, config.environment)
)
}
......@@ -19,9 +19,11 @@
package de.kuschku.malheur.data
import kotlinx.serialization.Serializable
@Serializable
data class AppInfo(
val versionName: String?,
val versionCode: Long?,
val buildConfig: Map<String, Any?>?,
val installationSource: String?
)
......@@ -19,6 +19,9 @@
package de.kuschku.malheur.data
import kotlinx.serialization.Serializable
@Serializable
data class CrashInfo(
val cause: ExceptionInfo?,
val exception: String?
......
/*
* Quasseldroid - Quassel client for Android
*
* Copyright (c) 2020 Janne Mareike Koschinski
* Copyright (c) 2020 The Quassel Project
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.malheur.data
data class DeviceInfo(
val build: Map<String, Any?>?,
val version: Map<String, Any?>?,
val processor: String?,
val display: DisplayInfo?
)
......@@ -19,11 +19,11 @@
package de.kuschku.malheur.data
import kotlinx.serialization.Serializable
@Serializable
data class DisplayInfo(
val width: Int,
val height: Int,
val refreshRate: Float,
val hdr: List<String>?,
val isWideGamut: Boolean?,
val metrics: MetricsInfo
)
/*
* Quasseldroid - Quassel client for Android
*
* Copyright (c) 2020 Janne Mareike Koschinski
* Copyright (c) 2020 The Quassel Project
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.malheur.data
data class EnvInfo(
val paths: Map<String, Any?>?,
val memory: MemoryInfo?,
val configuration: Map<String, Any?>?,
val startTime: Long?,
val crashTime: Long?
)
......@@ -19,6 +19,9 @@
package de.kuschku.malheur.data
import kotlinx.serialization.Serializable
@Serializable
data class ExceptionInfo(
val type: String?,
val message: String?,
......
/*
* Quasseldroid - Quassel client for Android
*
* Copyright (c) 2020 Janne Mareike Koschinski
* Copyright (c) 2020 The Quassel Project
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.malheur.data
import android.os.Debug
data class MemoryInfo(
var dalvikPss: Int?,
var dalvikPrivateDirty: Int?,
var dalvikSharedDirty: Int?,
var nativePss: Int?,
var nativePrivateDirty: Int?,
var nativeSharedDirty: Int?,
var otherPss: Int?,
var otherPrivateDirty: Int?,
var otherSharedDirty: Int?
) {
constructor(memoryInfo: Debug.MemoryInfo?) : this(
dalvikPss = memoryInfo?.dalvikPss,
dalvikPrivateDirty = memoryInfo?.dalvikPrivateDirty,
dalvikSharedDirty = memoryInfo?.dalvikSharedDirty,
nativePss = memoryInfo?.nativePss,
nativePrivateDirty = memoryInfo?.nativePrivateDirty,
nativeSharedDirty = memoryInfo?.nativeSharedDirty,
otherPss = memoryInfo?.otherPss,
otherPrivateDirty = memoryInfo?.otherPrivateDirty,
otherSharedDirty = memoryInfo?.otherSharedDirty
)
}
......@@ -20,7 +20,9 @@
package de.kuschku.malheur.data
import android.util.DisplayMetrics
import kotlinx.serialization.Serializable
@Serializable
data class MetricsInfo(
val density: Float,
val scaledDensity: Float,
......
......@@ -19,11 +19,12 @@
package de.kuschku.malheur.data
import kotlinx.serialization.Serializable
@Serializable
data class Report(
val timestamp: Long? = null,
val crash: CrashInfo? = null,
val threads: ThreadsInfo? = null,
val logcat: Map<String, List<String>?>? = null,
val application: AppInfo? = null,
val device: DeviceInfo? = null,
val environment: EnvInfo? = null
)
......@@ -19,6 +19,9 @@
package de.kuschku.malheur.data
import kotlinx.serialization.Serializable
@Serializable
data class ThreadInfo(
val id: Long?,
val name: String?,
......