kivy / kivy/python-for-android

BroadcastReceiver hangs on_resume()

Open
#2,308 1 comment 0 reactions 0 assignees View on GitHub
bug
Dominant language
Python
Stars
8.9k
Forks
2k
Avg merge
12h 20m
Merged PRs (30d)
9

Description

### Checklist

- [x ] the issue is indeed a bug and not a support request
- [ x] issue doesn't already exist: https://github.com/kivy/python-for-android/issues
- [ x] I have a short, runnable example that reproduces the issue
- [ x] I reproduced the problem with the latest development version (`p4a.branch = develop`)
- [ x] I used the grave accent (aka backticks) to format code or logs when appropriated

### Versions

- Python: 3.8
- OS: Android 10
- Kivy: 1.11.1
- Cython: 29
- OpenJDK: 8

### Description
BroadcastReveiver hangs with "JVM exception occurred: Java.lang.IllegalThreadStateException" during on_resume().
This on_resume() call is the second call to BroadcastReveiver().start() after a stop() in on_pause()

I believe the issue is in pythonforandroid/recipes/android/src/android/broadcast.py
In line 49, where self.handlertheread is instantiated in \_\_init__() and it should be instantiated in start(), because it is destroyed by .quit() in stop()

To replicate, start the app, wait till the screen shows the result of at least one scan, then pause the app. Resume the app, screen should show "scanning......" but actually shows the screen at pause state - this is never updated as the app has hung.

The issue has presumably been exposed by the changes in garbage collection in Python 3.8

### test case:
```
#############################################
# WiFi Scanner
#############################################
from kivy.app import App
from kivy.uix.label import Label
from android import mActivity
from android.broadcast import BroadcastReceiver
from android.permissions import request_permissions,check_permission,Permission
from android.runnable import run_on_ui_thread
from jnius import autoclass, cast

############## References #################
# https://developer.android.com/guide/topics/connectivity/wifi-scan#java
# Android documentation error? It appears ACCESS_WIFI_STATE is also required.
#
# BUT this API is depreciated in API 28 :(
# https://developer.android.com/reference/android/net/wifi/WifiManager#startScan()
#
# Pattern for this app:
# https://python-for-android.readthedocs.io/en/stable/old_toolchain/android/#module-android.broadcast
#
# Use default buildozer.spec except:
# android.permissions = ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE, CHANGE_WIFI_STATE
#
# Tested with SDK 27, NDK 19c, Android 10
###########################################

Context = autoclass('android.content.Context')
WifiManager = autoclass('android.net.wifi.WifiManager')

class MyApp(App):

def build(self):
self.paused = False
action = WifiManager.SCAN_RESULTS_AVAILABLE_ACTION
self.wm = cast('android.net.wifi.WifiManager',
mActivity.getSystemService(Context.WIFI_SERVICE))
self.br = BroadcastReceiver(self.on_broadcast,actions=[action])
self.label = Label(text='None')
return self.label

@run_on_ui_thread
def update_label(self,text):
self.label.text = text

def on_broadcast(self, context, intent):
extras = intent.getExtras()
if extras.get(WifiManager.EXTRA_RESULTS_UPDATED):
text = 'Look what I found (Scan #'+str(self.scan)+'):\n\n'
self.scan += 1
for result in self.wm.getScanResults().toArray():
if result.SSID:
text += result.SSID + '\n'
else:
text += 'A WiFi with no SSID\n'
self.update_label(text)

def on_start(self):
request_permissions([Permission.ACCESS_FINE_LOCATION,
Permission.ACCESS_WIFI_STATE,
Permission.CHANGE_WIFI_STATE],
self.callback)

def callback(self,permissions,grants):
self.granted = all(grants)
self.start_scan()

def start_scan(self):
self.scan = 0
if self.granted:
self.br.start()
if self.wm.startScan():
self.label.text = 'Scanning.........'
else:
self.label.text = 'Start Scan Failed'
else:
self.label.text = 'Not Authorized to Scan'

def on_pause(self):
if self.granted:
# Cause of issue is "self.handlerthread.quit()" inside the next line.
self.br.stop()
# Unrelated to this issue report:
# Handle race condition with callback() on first on_pause()
self.paused = True
return True

def on_resume(self):
if self.paused:
self.granted =\
check_permission(Permission.ACCESS_FINE_LOCATION) and\
check_permission(Permission.ACCESS_WIFI_STATE) and\
check_permission(Permission.CHANGE_WIFI_STATE)
# Issue, on_resume():
# JVM exception occurred: java.lang.IllegalThreadStateException
# occurs in start_scan() then self.br.start() at self.handlerthread.start()

self.start_scan()

MyApp().run()

```

### buildozer.spec

Command:
```sh
buildozer android debug
```

Spec file:
```
Default buildozer.spec, except:
android.permissions = ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE, CHANGE_WIFI_STATE
```

### Logs

```
09-04 18:27:08.011 3778 3778 I python : Traceback (most recent call last):
09-04 18:27:08.011 3778 3778 I python : File "/home/bobf/ex/wifi/.buildozer/android/platform/build-armeabi-v7a/build/python-installs/myapp/kivy/core/window/window_sdl2.py", line 251, in _event_filter
09-04 18:27:08.011 3778 3778 I python : File "kivy/_event.pyx", line 707, in kivy._event.EventDispatcher.dispatch
09-04 18:27:08.011 3778 3778 I python : File "/home/bobf/ex/wifi/.buildozer/android/app/main.py", line 97, in on_resume
09-04 18:27:08.012 3778 3778 I python : File "/home/bobf/ex/wifi/.buildozer/android/app/main.py", line 72, in start_scan
09-04 18:27:08.012 3778 3778 I python : File "/home/bobf/ex/wifi/.buildozer/android/platform/build-armeabi-v7a/build/python-installs/myapp/android/broadcast.py", line 75, in start
09-04 18:27:08.012 3778 3778 I python : File "jnius/jnius_export_class.pxi", line 857, in jnius.jnius.JavaMethod.__call__
09-04 18:27:08.012 3778 3778 I python : File "jnius/jnius_export_class.pxi", line 954, in jnius.jnius.JavaMethod.call_method
09-04 18:27:08.012 3778 3778 I python : File "jnius/jnius_utils.pxi", line 91, in jnius.jnius.check_exception
09-04 18:27:08.012 3778 3778 I python : jnius.jnius.JavaException: JVM exception occurred: java.lang.IllegalThreadStateException
09-04 18:27:08.013 3778 3778 I python : Exception ignored in: 'kivy.core.window._window_sdl2._WindowSDL2Storage.cb_event_filter'

```

Contributor guide

Open the contributing guide

Research direction

Start with pythonforandroid/recipes/android/src/android/broadcast.py, especially BroadcastReceiver.start() and stop(), then reproduce the lifecycle in the issue's WiFi scanner example. Verify that stopping the receiver during on_pause() and starting it again during on_resume() no longer raises IllegalThreadStateException and that scanning resumes with updated results.

Written by the indexing model from the issue text.

Assessment

Tech stack
android, python
Domain
mobile-dev
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.