app: an IMS network is not a blocked measurement

rmnet_data1 on the OnePlus is the carrier's IMS/VoLTE network: it carries
IMS&MMTEL but neither INTERNET nor NOT_RESTRICTED, so binding needs
CONNECTIVITY_USE_RESTRICTED_NETWORKS - signature-level, unobtainable.
EPERM there is permanent and says nothing about any network's health, but
the constraint detector counted it, so a phone with VoLTE reported
'measurement blocked' on every run and every verdict came out
INCONCLUSIVE. Capabilities now decide: networks an app may never bind are
recorded as app_usable:false in networks[] and skipped, rather than
reported as something the run failed to do.

Also retires the 'while it tears down' wording, which was a guess that
turned out to be wrong - the refusal outlasts the VPN indefinitely, so
the text now names the VPN as the usual cause without asserting a
timeline it cannot know.

App version 0.2.4.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
mrambossek
2026-08-02 14:11:08 +02:00
co-authored by Claude Opus 5
parent d420a71a01
commit ab6e278272
7 changed files with 54 additions and 9 deletions
@@ -40,6 +40,12 @@ object ConstraintDetector {
for (e in entries) {
// The tunnel itself stays bindable — it is the underlying networks the OS walls off.
if (e.model.transport == Transport.VPN) continue
// Networks an app may never bind (carrier IMS/VoLTE, MMS, XCAP — no INTERNET, no
// NOT_RESTRICTED) refuse with EPERM permanently, VPN or no VPN. Counting them as a
// constraint is what made a phone with VoLTE report "measurement blocked" forever
// and forced every run INCONCLUSIVE. They are recorded in networks[] as
// app_usable:false; they are not something a run failed to do.
if (e.model.appUsable == false) continue
val err = try {
DatagramSocket().use { s -> e.handle.bindSocket(s) }
null
@@ -65,6 +65,20 @@ object NetworkInventory {
/** @SystemApi NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY, API 28+. */
private const val NET_CAPABILITY_PARTIAL_CONNECTIVITY = 24
/**
* Can an ordinary app send on this network?
*
* The carrier's special-purpose networks (IMS/VoLTE, MMS, XCAP) sit in `allNetworks` next to
* the real ones, carrying `IMS`/`MMS` but neither `INTERNET` nor `NOT_RESTRICTED`. Binding
* to them fails with EPERM forever, because it needs `CONNECTIVITY_USE_RESTRICTED_NETWORKS`
* — signature-level, unobtainable for this app. Asking the capabilities up front is what
* separates "the OS will never let us measure this" from "something is blocking us", which
* a bind attempt alone cannot distinguish and which the constraint logic must not confuse.
*/
private fun appUsable(caps: NetworkCapabilities): Boolean =
caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) &&
caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
private fun toModel(id: String, caps: NetworkCapabilities, lp: LinkProperties): MNetwork {
val transport = when {
caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> Transport.WIFI
@@ -99,6 +113,7 @@ object NetworkInventory {
id = id, transport = transport, iface = lp.interfaceName,
link = Link(mtu = lp.mtu.takeIf { it > 0 }, addresses = addresses, routes = routes, dns = dns),
systemVerdict = systemVerdict(caps),
appUsable = appUsable(caps),
)
}
}