fix(aprs): the service could not start at all on Android 10 and later
The previous commit changed the manifest's foregroundServiceType to location and left
startForeground passing FOREGROUND_SERVICE_TYPE_DATA_SYNC. AOSP requires the passed
type to be a subset of the declared one - location is 0x08, dataSync is 0x01 - and
throws IllegalArgumentException otherwise, a check that has been there since API 29.
That throw landed in the surrounding catch, which calls stopSelf().
So APRS started, died, and said nothing. No notification, no beacon, no Toast, no
last-report row, and the settings switch stayed on because the config had already been
saved. This is worse than the defect the rewrite was written to fix: reporting success
for packets that never left at least sometimes worked, whereas this never ran at all,
on essentially every device in use, with no visible symptom. Two auditors found it
independently by reading the constants against AOSP's own check.
Two more findings from the same review.
Receive-only was reported as a wrong passcode. Both a deliberate -1 and a mismatched
entry log in with -1, and the server answers "unverified" to each, so the operator who
chose receive-only - the one way to test a setup without putting anything on the network
- was told to go and fix the passcode they had set on purpose. The report now carries
whether receive-only was asked for, and says so instead.
The card could show "failed - sent". The detail string was the write's own verdict, and
a write that succeeds on a refused login is exactly the case where those two disagree.
A failure now reports what actually failed.
Also: the packet is built before connecting. The reporter used to open a session and log
in only to discover it had nothing to send, which for an operator with no station
position set meant a pointless login every five minutes.
Still outstanding, and the reason this is not enough on its own: nothing tests the
service, so neither this defect nor the missing line terminator in 7ac54f0a could have
been caught by the suite. Both were found by audit. A location-typed foreground service
on API 34+ may also require a granted location permission before startForeground, which
the settings card does not request - that needs checking on hardware.
This commit is contained in:
1 parent
e0900778f0
commit
0a67f74369
7 files changed
+62
-16
No files matched your search
@@ -43,7 +43,16 @@ data class AprsReport(
|
||||
* nothing reaching the network. A login whose response we simply could not parse leaves this
|
||||
* true, since the packets may be landing and the passcode is not at fault.
|
||||
*/
|
||||
val verified: Boolean = true
|
||||
val verified: Boolean = true,
|
||||
/**
|
||||
* True when the operator asked for a receive-only connection.
|
||||
*
|
||||
* Distinguished from a refused login because both log in with -1 and the server answers
|
||||
* "unverified" to each: without this, deliberately choosing receive-only - the one way to
|
||||
* test a setup without putting anything on the network - was reported as a wrong passcode
|
||||
* and sent the operator to fix something they had set on purpose.
|
||||
*/
|
||||
val receiveOnly: Boolean = false
|
||||
)
|
||||
|
||||
/** Report scheduler (periodic + manual trigger); connection management lives in the foreground service */
|
||||
@@ -94,19 +103,9 @@ class AprsReporter(
|
||||
if (!cfg.enabled || cfg.callsign.isBlank()) return
|
||||
onState(AprsState.Connecting)
|
||||
try {
|
||||
val c = client ?: AprsIsClient(
|
||||
host = cfg.server,
|
||||
port = cfg.port,
|
||||
callsign = cfg.callsign,
|
||||
ssid = cfg.ssid,
|
||||
// Never derives one: a blank or wrong entry logs in receive-only rather than
|
||||
// transmitting under a passcode the app invented for an unchecked licence.
|
||||
passcode = AprsPasscode.loginValue(cfg.callsign, cfg.passcode),
|
||||
version = "Look4Sat 4.5.4"
|
||||
).also { client = it }
|
||||
if (!c.isConnected) c.connect()
|
||||
onState(AprsState.Connected)
|
||||
|
||||
// The packet is built BEFORE connecting: there is no reason to open a session and log
|
||||
// in only to discover there is nothing to send, which happened every five minutes for
|
||||
// an operator whose QTH was unset.
|
||||
val pos = positionProvider()
|
||||
val beacon = AprsBeacon.build(
|
||||
callsign = cfg.callsign,
|
||||
@@ -127,6 +126,23 @@ class AprsReporter(
|
||||
return
|
||||
}
|
||||
val packetLine = (beacon as AprsBeacon.Result.Line).text
|
||||
|
||||
// Receive-only is a deliberate choice, not a mistake, and has to be carried through:
|
||||
// it logs in with -1 exactly as a wrong passcode does, and the server answers
|
||||
// "unverified" to both.
|
||||
val wantsReceiveOnly = !AprsPasscode.canTransmit(cfg.callsign, cfg.passcode)
|
||||
val c = client ?: AprsIsClient(
|
||||
host = cfg.server,
|
||||
port = cfg.port,
|
||||
callsign = cfg.callsign,
|
||||
ssid = cfg.ssid,
|
||||
// Never derives one: a blank or wrong entry logs in receive-only rather than
|
||||
// transmitting under a passcode the app invented for an unchecked licence.
|
||||
passcode = AprsPasscode.loginValue(cfg.callsign, cfg.passcode),
|
||||
version = "Look4Sat 4.5.4"
|
||||
).also { client = it }
|
||||
if (!c.isConnected) c.connect()
|
||||
onState(AprsState.Connected)
|
||||
val result = c.sendPacket(packetLine)
|
||||
val sent = result?.first == true
|
||||
val detail = result?.second ?: "no connection"
|
||||
@@ -137,7 +153,21 @@ class AprsReporter(
|
||||
// the operator to fix something that is not broken.
|
||||
val refused = c.isRefusedByServer
|
||||
val ok = sent && !refused
|
||||
onReport(AprsReport(System.currentTimeMillis(), packetLine, ok, detail, !refused))
|
||||
// "sent" is the write's own verdict and reads as nonsense next to a failure - the card
|
||||
// showed "failed - sent" for a refused login. When the refusal is what failed the
|
||||
// report, say that instead.
|
||||
val reported = when {
|
||||
ok -> detail
|
||||
refused && wantsReceiveOnly -> "receive-only, not forwarded"
|
||||
refused -> "login not verified"
|
||||
else -> detail
|
||||
}
|
||||
onReport(
|
||||
AprsReport(
|
||||
System.currentTimeMillis(), packetLine, ok, reported,
|
||||
verified = !refused, receiveOnly = wantsReceiveOnly
|
||||
)
|
||||
)
|
||||
if (ok) onState(AprsState.Connected) else onState(AprsState.Error)
|
||||
} catch (e: Exception) {
|
||||
runCatching { client?.disconnect() }
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
<string name="aprs_toast_ok">APRS: laporan terkirim</string>
|
||||
<string name="aprs_toast_fail">APRS: laporan gagal - %1$s</string>
|
||||
<string name="aprs_toast_unverified">APRS-IS tidak memverifikasi passcode Anda. Laporan Anda tidak diteruskan - periksa tanda panggil dan passcode di Pengaturan.</string>
|
||||
<string name="aprs_toast_receive_only">APRS-IS menerima koneksi dalam mode terima-saja, laporan Anda tidak diteruskan. Masukkan passcode untuk mengirim.</string>
|
||||
<string name="aprs_toast_not_configured">APRS belum dikonfigurasi - isi panggilan dulu</string>
|
||||
<string name="prefs_aprs_last_report">Laporan terakhir: %1$s %2$s</string>
|
||||
<string name="prefs_aprs_last_ok">OK</string>
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
<string name="aprs_toast_ok">APRS: laporan terkirim</string>
|
||||
<string name="aprs_toast_fail">APRS: laporan gagal - %1$s</string>
|
||||
<string name="aprs_toast_unverified">APRS-IS tidak memverifikasi passcode Anda. Laporan Anda tidak diteruskan - periksa tanda panggil dan passcode di Pengaturan.</string>
|
||||
<string name="aprs_toast_receive_only">APRS-IS menerima koneksi dalam mode terima-saja, laporan Anda tidak diteruskan. Masukkan passcode untuk mengirim.</string>
|
||||
<string name="aprs_toast_not_configured">APRS belum dikonfigurasi - isi panggilan dulu</string>
|
||||
<string name="prefs_aprs_last_report">Laporan terakhir: %1$s %2$s</string>
|
||||
<string name="prefs_aprs_last_ok">OK</string>
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
<string name="aprs_toast_ok">APRS: rapor gönderildi</string>
|
||||
<string name="aprs_toast_fail">APRS: rapor başarısız - %1$s</string>
|
||||
<string name="aprs_toast_unverified">APRS-IS passcode bilginizi doğrulamadı. Raporlarınız iletilmiyor - Ayarlar bölümünde çağrı işareti ve passcode bilgisini kontrol edin.</string>
|
||||
<string name="aprs_toast_receive_only">APRS-IS baglantiyi yalnizca alma modunda kabul etti, raporlariniz iletilmiyor. Gondermek icin passcode girin.</string>
|
||||
<string name="aprs_toast_not_configured">APRS yapılandırılmadı - önce çağrı girin</string>
|
||||
<string name="prefs_aprs_last_report">Son rapor: %1$s %2$s</string>
|
||||
<string name="prefs_aprs_last_ok">OK</string>
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
<string name="aprs_toast_ok">APRS: 上报成功</string>
|
||||
<string name="aprs_toast_fail">APRS: 上报失败 - %1$s</string>
|
||||
<string name="aprs_toast_unverified">APRS-IS 未验证你的 passcode, 上报不会被转发 - 请在设置里检查呼号与 passcode。</string>
|
||||
<string name="aprs_toast_receive_only">APRS-IS 以只收模式接受了连接, 上报不会被转发。填入 passcode 才能发射。</string>
|
||||
<string name="aprs_toast_not_configured">APRS 未配置,请先填呼号</string>
|
||||
<string name="prefs_aprs_last_report">上次上报: %1$s %2$s</string>
|
||||
<string name="prefs_aprs_last_ok">成功</string>
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
<string name="aprs_toast_ok">APRS: report sent OK</string>
|
||||
<string name="aprs_toast_fail">APRS: report failed - %1$s</string>
|
||||
<string name="aprs_toast_unverified">APRS-IS did not verify your passcode. Your reports are not being passed on - check the callsign and passcode in Settings.</string>
|
||||
<string name="aprs_toast_receive_only">APRS-IS accepted the connection in receive-only mode, so your reports are not forwarded. Enter your passcode to transmit.</string>
|
||||
<string name="aprs_toast_not_configured">APRS not configured - set callsign first</string>
|
||||
<string name="prefs_aprs_last_report">Last report: %1$s %2$s</string>
|
||||
<string name="prefs_aprs_last_ok">OK</string>
|
||||
|
||||
Reference in new issue
Block a user