Skip to content

Instantly share code, notes, and snippets.

@kibotu
Last active March 11, 2025 12:34
Show Gist options
  • Save kibotu/dbc2b6321816652169cc21786b4c2397 to your computer and use it in GitHub Desktop.
Save kibotu/dbc2b6321816652169cc21786b4c2397 to your computer and use it in GitHub Desktop.
CoreStrictService
class App : Application() {
var strictMode: CoreStrictMode? = null
val applicationScope: CoroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
}
class StrictModeInitializer : Initializer<Unit> {
private val corePreferences: CoreSharedPreferencesRepository
get() = CoreServices.services.sharedPreferencesRepository
override fun create(context: Context) {
if (!R.bool.core_enable_development_mode.resBoolean) return
var strictMode = c24CoreApplication?.strictMode
if (strictMode == null) {
strictMode = CoreStrictMode()
c24CoreApplication?.strictMode = strictMode
}
strictMode.start()
// Start listening to violations immediately
c24CoreApplication?.applicationScope?.launch(Dispatchers.IO) {
strictMode
.strictModeViolations
.filter { it.stackTrace.contains("my.bundle.identifier", ignoreCase = true) }
.collect { violation ->
corePreferences.addLatestStrictModeViolation(violation)
if (violation.stackTrace !in CoreStrictMode.sentryBlackList) {
val throwable = violation.stackTrace.parseStackTrace { message, stacktrace ->
StrictModeViolation(message.ifEmpty { violation.description }, stacktrace)
}
if (throwable != null) {
Logger.w("StrictMode", throwable = throwable)
} else {
Logger.w(message = violation.stackTrace)
}
}
}
}
}
override fun dependencies(): List<Class<out Initializer<*>>> = emptyList()
}
class CoreStrictService {
@Suppress("KotlinConstantConditions")
var enableStrictMode: Boolean
get() = application
?.getSharedPreferences("strict-mode", MODE_PRIVATE)
?.getBoolean("enable-strict-mode", R.bool.core_enable_development_mode.resBoolean) == true
set(value) {
application
?.getSharedPreferences("strict-mode", MODE_PRIVATE)
?.edit {
putBoolean("enable-strict-mode", value)
}
toggleStrictMode(value)
}
val strictModeViolations: SharedFlow<StrictModeViolation>
field = MutableSharedFlow<StrictModeViolation>(replay = 100)
private val isDevelopment by lazy { R.bool.core_enable_development_mode.resBoolean }
fun start() {
toggleStrictMode(enableStrictMode)
}
private fun toggleStrictMode(enable: Boolean) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) return
if (!isDevelopment) return
if (enable) {
enableStrictMode()
} else {
disableStrictMode()
}
}
@RequiresApi(Build.VERSION_CODES.P)
private fun enableStrictMode() {
configureStrictModeThreadPolicy()
CoreLogger.d(TAG, "StrictMode enabled")
configureStrictModeVmPolicy()
}
private fun disableStrictMode() {
// Ensure policy is cleared on the main thread
Handler(Looper.getMainLooper()).post {
StrictMode.setThreadPolicy(
StrictMode.ThreadPolicy.Builder()
.permitAll() // Allow all operations
.build()
)
CoreLogger.d(TAG, "StrictMode disabled")
}
StrictMode.setVmPolicy(
StrictMode.VmPolicy.Builder()
.build() // No VM checks
)
}
@RequiresApi(Build.VERSION_CODES.P)
private fun configureStrictModeThreadPolicy() {
val context = c24CoreApplication?.applicationContext ?: return
// Configure thread policy for the main thread only
Handler(Looper.getMainLooper()).post {
StrictMode.setThreadPolicy(
StrictMode.ThreadPolicy.Builder().apply {
// ANR potential
detectCustomSlowCalls()
// io
detectNetwork()
detectDiskReads()
detectDiskWrites()
detectUnbufferedIo()
detectResourceMismatches()
// visual feedback during violation
penaltyFlashScreen()
penaltyListener(context.mainExecutor) { violation ->
c24CoreApplication?.applicationScope?.launch {
strictModeViolations.emit(
StrictModeViolation(
type = "Thread Policy Violation",
timestamp = now,
stackTrace = violation.stackTraceToString()
)
)
}
}
}.build()
)
}
}
@RequiresApi(Build.VERSION_CODES.P)
private fun configureStrictModeVmPolicy() {
StrictMode.setVmPolicy(
StrictMode.VmPolicy.Builder().apply {
// leaks
detectLeakedClosableObjects()
detectLeakedRegistrationObjects()
detectActivityLeaks()
detectLeakedSqlLiteObjects()
// permissions
detectContentUriWithoutPermission()
// context
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
detectIncorrectContextUse()
detectUnsafeIntentLaunch()
}
val context = c24CoreApplication ?: return
penaltyListener(context.mainExecutor) { violation ->
context.applicationScope.launch {
strictModeViolations.emit(
StrictModeViolation(
type = "VM Policy Violation",
timestamp = now,
stackTrace = violation.stackTraceToString()
)
)
}
}
}.build()
)
}
companion object {
val sentryBlackList by lazy {
listOf(
"DiskReadViolation"
)
}
val knownViolations by lazy {
listOf(
"DiskReadViolation",
"LeakedClosableViolation"
)
}
}
}
@Serializable
data class StrictModeViolation(
/**
* "Thread Policy Violation", "VM Policy Violation", "ANR Detected"
*/
val type: String,
@Contextual val timestamp: Instant,
val stackTrace: String
)
val StrictModeViolation.title: String
get() {
val firstLine = stackTrace.lineSequence().firstOrNull()?.trim() ?: return ""
val colonIndex = firstLine.indexOf(":")
return if (colonIndex != -1) {
firstLine.substring(0, colonIndex).substringAfterLast(".")
} else {
"^.*\\.(\\w+)$".toRegex().find(firstLine)?.groupValues?.get(1) ?: ""
}
}
val StrictModeViolation.description: String
get() {
val firstLine = stackTrace.lineSequence().firstOrNull()?.trim() ?: return ""
val colonIndex = firstLine.indexOf(":")
var description = if (colonIndex != -1) {
firstLine.substring(colonIndex + 1).trim()
} else {
""
}
if (description.isEmpty()) {
description = stackTrace
.lineSequence()
.filter { it.contains("de.check24.profis.partner.") }
.map {
it.trim()
.replace("at ", "")
.replace("de.check24.profis.partner.", "")
}
.firstOrNull()
.orEmpty()
}
return description
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment