Skip to content

Potential Main thread blocking via synchronous SQLiteDatabase#rawQuery in SavedParcelTable #22961

Description

@venkyqz

Description

Hi WordPress Android Team,

I’m a PhD student researching Android performance issues. My research group recently ran a static analysis scan for thread affinity and main thread blocking bugs, and our prototype flagged a potential issue in WordPress Android.

Checked target

  • APK-level caller: org.wordpress.android.editor.savedinstance.SavedParcelTable#getParcel
  • Detected API: android.database.sqlite.SQLiteDatabase#rawQuery
  • Observed context: main/UI thread
  • Expected context: worker/background thread

What I found

The analyzer reported that the app call:

val c = db.rawQuery("SELECT * FROM $SAVED_PARCEL_TABLE WHERE $PARCEL_ID ='$parcelId'", null)

from a main/UI-thread path.

Verified bug trace

org.wordpress.android.editor.savedinstance.SavedParcelTable#getParcel
  -> source location: libs/editor/src/main/java/org/wordpress/android/editor/savedinstance/SavedParcelTable.kt:42
  -> source call: val c = db.rawQuery("SELECT * FROM $SAVED_PARCEL_TABLE WHERE $PARCEL_ID ='$parcelId'", null)
  -> app database layer performs a synchronous SQLite/query/cursor read
  -> cursor/database processing is reached from the reported thread context
  -> analyzer/source audit observed context: main/UI thread
  -> expected context: worker/background thread
  -> possible UI freeze / delayed response / jank / ANR risk

Source context used for verification:

40:     fun <T> getParcel(readableDb: SQLiteDatabase?, parcelId: String, creator: Parcelable.Creator<T>): T? {
  41:         val db = readableDb ?: return null
> 42:         val c = db.rawQuery("SELECT * FROM $SAVED_PARCEL_TABLE WHERE $PARCEL_ID ='$parcelId'", null)
  43:         return try {
  44:             if (c.moveToFirst()) {

Why this matters

Running I/O operations synchronously on the UI thread can make WordPress Android feel frozen or delayed on slower devices, large datasets, or slow providers.

Possible fix

A possible fix is to move the blocking I/O, database, media, or system-service operation to a worker context and post only UI updates back to the main thread.

lifecycleScope.launch {
    val result = withContext(Dispatchers.IO) {
        performBlockingOperation()
    }

    renderResult(result)
}

Reference

Please confirm that you have searched existing issues in the repo.

  • Yes

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions