[Python] Run a Python web server (Quart) with Chaquopy without blocking the main android...

Discussão em 'Python' iniciado por Stack, Setembro 13, 2024.

  1. Stack

    Stack Membro Participativo

    This is not exactly a bug i assume but nothing in the rather short documentation or from online searches could help me. I am trying to build an android app that runs a Quart app in background with Chaquopy and a web view to display it full screen. The problem is i can't find a way to run Chaquopy without blocking the main thread which is kind of pointless, no matter what i try there is an error!

    Here's why i can't figure it out:

    • Running a web server in Chaquopy is a blocking long-running operation which blocks the android thread execution therefore the UI even if the UI is in a thread. So Chaquopy cannot run in the main android thread.
    • Some part of Quart (seems to be asyncio) requires it to run in the main thread of the main interpreter.

    So is it simply impossible to run a python web server and a webview in the same android app?

    Running Chaquopy in the activity like such blocks the main thread and the UI (webview) stops working:

    class MainActivity : AppCompatActivity() {

    private val tag: String = "MainActivity" // Define a tag for your logs
    private lateinit var webView: WebView

    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    Log.i(tag, "Starting server");
    if (! Python.isStarted()) {
    Python.start(AndroidPlatform(this))
    }
    // Run the Python server
    try {
    val py = Python.getInstance()
    py.getModule("app").callAttr("run")
    } catch (e: Exception) {
    Log.e(tag, "Error starting Python server: ${e.message}")
    }

    webView = findViewById(R.id.webview)
    webView.webViewClient = WebViewClient()
    webView.settings.javaScriptEnabled = true
    webView.loadUrl("http://localhost:5000")
    }

    }


    I tried running Chaquopy in an android thread as such:

    class MainActivity : AppCompatActivity() {

    private val tag: String = "MainActivity" // Define a tag for your logs
    private lateinit var webView: WebView

    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    Log.i(tag, "Starting server");
    if (! Python.isStarted()) {
    Python.start(AndroidPlatform(this))
    }
    // Run the Python server in a background thread
    Thread {
    try {
    val py = Python.getInstance()
    py.getModule("app").callAttr("run")
    } catch (e: Exception) {
    Log.e(tag, "Error starting Python server: ${e.message}")
    }
    }.start()
    webView = findViewById(R.id.webview)
    webView.webViewClient = WebViewClient()
    webView.settings.javaScriptEnabled = true
    webView.loadUrl("http://localhost:5000")
    }

    }


    Which give me this error from the activity:

    Error starting Python server: RuntimeError: set_wakeup_fd only works in main thread of the main interpreter


    I tried running the server in a Python thread like this:

    import threading
    from quart import Quart

    app = Quart(__name__)


    @app.route('/')
    async def hello():
    return 'hello'

    def run():
    # Create a new thread
    thread = threading.Thread(target=app.run, args=("1",))
    # Start the thread
    thread.start()
    # Optionally, wait for the thread to finish
    thread.join()


    Which give me this error in logcat through python.stderr:

    Exception in thread Thread-1 (run):
    Traceback (most recent call last):
    File "stdlib/asyncio/unix_events.py", line 105, in add_signal_handler
    ValueError: set_wakeup_fd only works in main thread of the main interpreter


    I tried running Chaquopy in a coroutine:

    class MainActivity : AppCompatActivity() {

    private val tag: String = "MainActivity" // Define a tag for your logs
    private lateinit var webView: WebView

    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    Log.i(tag, "Starting server");
    if (! Python.isStarted()) {
    Python.start(AndroidPlatform(this))
    }
    // Launch a coroutine to run Python code
    CoroutineScope(Dispatchers.IO).launch {
    runPythonCode()
    }
    // Run the Python server in a background thread
    Thread {

    }.start()
    webView = findViewById(R.id.webview)
    webView.webViewClient = WebViewClient()
    webView.settings.javaScriptEnabled = true
    webView.loadUrl("http://localhost:5000")
    }

    private suspend fun runPythonCode() {
    // Switch to the main thread to update UI if needed
    withContext(Dispatchers.Main) {
    try {
    val py = Python.getInstance()
    py.getModule("app").callAttr("run")
    } catch (e: Exception) {
    Log.e(tag, "Error starting Python server: ${e.message}")
    }
    }
    }

    }


    Which does start the server but still blocks the main android thread and cause this error:

    ANR in com.example.chatterbot (com.example.chatterbot/.MainActivity)
    PID: 12527
    Reason: Input dispatching timed out (7aa0a25 com.example.chatterbot/com.example.chatterbot.MainActivity (server) is not responding. Waited 10007ms for FocusEvent(hasFocus=true))
    Parent: com.example.chatterbot/.MainActivity
    ErrorId: f902fe3a-f5fa-40be-907d-fab77be9f0ca
    Frozen: s[false] g[false]
    Load: 26.58 / 26.37 / 26.93
    ------ Current CPU Core Info ------
    - offline :
    - online : 0-7
    0 1 2 3 4 5 6 7
    ------------------------------------------------------------------------------------------------------------------
    scaling_cur_freq 2301000 2301000 2301000 2301000 501000 501000 501000 501000
    scaling_governor schedutil schedutil schedutil schedutil schedutil schedutil schedutil schedutil
    scaling_max_freq 2301000 2301000 2301000 2301000 1800000 1800000 1800000 1800000 ------------------------------------------------------------------------------------------------------------------
    ----- Output from /proc/pressure/memory -----
    some avg10=1.41 avg60=1.40 avg300=1.01 total=8666562438
    full avg10=1.10 avg60=0.93 avg300=0.64 total=5116135829
    ----- End output from /proc/pressure/memory -----
    CPU usage from 0ms to 12700ms later (2024-09-13 18:29:29.762 to 2024-09-13 18:29:42.462):
    52% 3492/system_server: 33% user + 19% kernel / faults: 57585 minor 80 major
    14% 157/kswapd0: 0% user + 14% kernel
    0.2% 1040/media.swcodec: 0% user + 0.1% kernel / faults: 27482 minor 79 major
    5.9% 12527/com.example.chatterbot: 3.4% user + 2.4% kernel / faults: 26634 minor 11 major
    4.9% 307/exe_cq/0: 0% user + 4.9% kernel
    0% 995/media.extractor: 0% user + 0% kernel / faults: 6019 minor 28 major
    3% 4187/com.sec.imsservice: 1.5% user + 1.4% kernel / faults: 8117 minor 179 major
    2.9% 3843/com.android.systemui: 1.8% user + 1.1% kernel / faults: 9067 minor 33 major
    2.6% 3805/com.android.phone: 1.6% user + 1% kernel / faults: 7118 minor 41 major
    2.5% 1023/android.hardware.sensors@2.0-service-mediatek: 0.7% user + 1.8% kernel / faults: 132 minor
    2.5% 25148/adbd: 0.8% user + 1.6% kernel / faults: 152 minor
    2.3% 3253/lmkd: 0.5% user + 1.8% kernel
    2.2% 5150/com.sec.android.sdhms: 1% user + 1.1% kernel / faults: 5288 minor 71 major
    2% 1699/main_thread: 0% user + 2% kernel
    1.8% 1700/hif_thread: 0% user + 1.8% kernel
    1.7% 26185/com.menny.android.anysoftkeyboard: 1% user + 0.7% kernel / faults: 5768 minor 73 major
    0% 1022/media.codec: 0% user + 0% kernel / faults: 3617 minor 18 major
    1.5% 481/logd: 0.3% user + 1.1% kernel / faults: 90 minor
    1.4% 559/android.system.suspend@1.0-service: 0% user + 1.4% kernel / faults: 201 minor
    1.4% 3846/com.android.networkstack.process: 0.6% user + 0.8% kernel / faults: 5223 minor 27 major
    1.4% 9013/kworker/u16:2-events_unbound: 0% user + 1.4% kernel
    1.4% 7357/process-tracker: 0.1% user + 1.2% kernel / faults: 66 minor
    1.3% 21881/kworker/u16:5-pvr_misr: 0% user + 1.3% kernel
    1.2% 4170/com.sec.sve: 0.5% user + 0.7% kernel / faults: 4977 minor 44 major
    1.2% 32560/com.google.android.webview:sandboxed_process0:eek:rg.chromium.content.app.SandboxedProcessService0:0: 0.9% user + 0.3% kernel / faults: 4390 minor 4 major
    1.1% 802/surfaceflinger: 0.5% user + 0.6% kernel / faults: 1328 minor 5 major
    1% 4206/com.android.se: 0.5% user + 0.4% kernel / faults: 4264 minor 33 major
    0.9% 1701/rx_thread: 0% user + 0.9% kernel
    0.9% 11542/com.google.android.gms: 0.3% user + 0.5% kernel / faults: 2885 minor 29 major
    0.8% 7899/logcat: 0.3% user + 0.5% kernel / faults: 45 minor
    0.7% 215/chre_kthread: 0% user + 0.7% kernel
    0.7% 327/ipi_cpu_dvfs_rt: 0% user + 0.7% kernel
    0.7% 12389/com.google.android.webview:sandboxed_process0:eek:rg.chromium.content.app.SandboxedProcessService0:0: 0.6% user + 0.1% kernel / faults: 1593 minor


    I don't know what to try next and can't find much online, is running a webserver in Chaquopy whthout blocking the UI impossible?

    Continue reading...

Compartilhe esta Página