With the P-CSCF coming from the PDN's PCO, the configuration file has no required line left, so the apk's ConditionPathExists=/etc/imsd.env drop-in goes: the unit starts on every phone with the package, and VoLTE is on by default. Installing the package and inserting a SIM is the opt-in; the file holds overrides only, and its existence changes nothing. By the versioning rule (AGENTS §11, the first commit of this series) that is what moves the major number: the release is 1.0.0, and §11 now records it. What used to be the file's job — keeping a phone nobody configured out of a failing unit — is now a rule on facts, the same for every phone: a modem in the failed state with a SIM reason makes the script write IMSD_IDLE=no-sim to /run/imsd.env and exit 0; a profile-indexed connect series the network refuses ten times in a row — each a persistent 3GPP cause in ModemManager's typed error (not subscribed, unknown APN, barred, not authorised in the PLMN, authentication failed, the service option not supported, the wrong PDN type) with packet service at the time; counted only while the modem reads registered, connecting or connected with packet service not detached — stricter than the daemon's PacketServiceUp; any other read, a timeout or a transient cause starts the count again — writes IMSD_IDLE=no-ims-pdn; and a bring-up that ends with no P-CSCF — none configured, none discovered: no IPv6 P-CSCF read from the PCO (PCSCF_DISCOVERY=none in the hand-off, the reader's exit 2: the list absent, empty, unreadable or IPv4/FQDN only), discovery skipped (no rmnet mux id) or no hand-off at all (a manual run) — and no registration of imsd's own to resume is the daemon's own idle, decided before it takes the bus name (SaPeer and the holds' old_gone say what can be resumed; a pair the holds wrote off is taken out of the kernel there) and at the no-target bring-up, where a pair nothing can resume is written off and taken out of the kernel first. imsd reads the key, logs idle: … and exits 0, which Restart=on-failure leaves alone, so the unit stays inactive until the next boot, a systemctl start or a start of imsd-ofonod where that runs (its Wants starts an idle imsd again). What is not a fact keeps the retry: no coverage, a SIM still waiting for its PIN, a modem without an ims profile (the APN-string connect is tried), an APN-string series (the modem's own wall), a resumable pair whose attempt failed (the fatal), and a P-CSCF reader that did not answer (PCSCF_DISCOVERY=failed: the daemon exits 1 and the restart runs discovery again). A phone that never had the file keeps its stopped unit through the upgrade and starts at its next boot, registering where the rule above lets it — at the upgrade itself where imsd-ofonod runs, whose restart pulls imsd in through its Wants (systemd queues the marked unit's try-restart, collapses it to a restart and starts what the unit Wants in the same transaction: job_type_collapse, transaction_add_job_and_dependencies, 262~rc3); the opt-out is systemctl mask --now imsd, since a plain disable is undone by that Wants. imsd-ofonod.service loses its After=imsd.service: with imsd starting on every phone, GNOME Calls' backend would otherwise wait behind the ims PDN bring-up at every boot and at its marked restart at an upgrade, for the whole bring-up (up to its TimeoutStartSec=900); it starts at once and republishes when imsd's name appears (OnImsdAppeared). The configuration file's path is the IMSD_ENV seam the mock bench uses. AGENTS §6's lint figures are this tree's (109 findings in 16 of 20 files, 2026-10-13; the 72 of 2026-10-06 predate the Qmi files). Tested: crafter-build test, 8 passed; on the host build the daemon's idle exit for the script's keys and, with no pair, for every discovery verdict but failed (none, skipped, no hand-off) — exit 0 — and the exit 1 for failed; the script's arms on the mock bench; on the dev phone (KPN), in builds of this series: the daemon's idle at the no-target bring-up with the dead pair removed and before the bus name for a pair the holds had written off, the discovery-failed exit 1 and its restart, the start without the file, the pull-in by an imsd-ofonod restart and the mask holding against it and a reboot, and imsd-ofonod starting at once with imsd stopped and republishing when imsd's name appeared.
106 lines
5.5 KiB
Text
106 lines
5.5 KiB
Text
# SPDX-License-Identifier: GPL-3.0-only
|
|
# SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts®
|
|
# Maintainer: Jorijn van der Graaf <jorijnvdgraaf@catcrafts.net>
|
|
# Binary packaging: wraps a crafter-build binary cross-compiled per the
|
|
# cross-compiling flow of AGENTS.md §4.3 into a proper apk — used by this repo's
|
|
# package CI (packaging/build-package.sh, which also seds pkgver from
|
|
# implementations/main.cpp) and runnable by hand. The source tarball is
|
|
# produced by packaging/make-bin-tarball.sh; the desktop/preset files and
|
|
# the install scripts (*.post-upgrade, *.post-install) live next to it in
|
|
# packaging/ (copy them beside this file). Since 2026-09-02
|
|
# this is the only imsd packaging: fp6-img images install the apk this
|
|
# builds from the registry rather than building their own.
|
|
pkgname=imsd
|
|
pkgver=0.3.1
|
|
pkgrel=0
|
|
pkgdesc="Userspace IMS/VoLTE daemon for mainline Linux phones"
|
|
url="https://forgejo.catcrafts.net/Catcrafts/imsd"
|
|
arch="aarch64"
|
|
license="GPL-3.0-only"
|
|
# the media leg dlopen's the AMR-WB codecs; pw-record/pw-play drive PipeWire;
|
|
# polkit answers the daemons' call-control check (ImsdBus)
|
|
depends="modemmanager libc++ opencore-amr vo-amrwbenc pipewire-tools polkit"
|
|
# versioned provides = imsd satisfies soc-qcom-modem's 81voltd dependency AND
|
|
# excludes the real package: 81voltd serves the modem's own ims-PDN requests,
|
|
# which races imsd for the PDN and flaps it with a new prefix every ~2.5 min
|
|
# (fp6 journal/ims.md s57) — the two IMS stacks cannot share one PDN
|
|
provides="81voltd=$pkgver-r$pkgrel"
|
|
# no OpenRC service yet: the unit's PDN-bring-up/env-file sequencing is only
|
|
# tested under systemd; an initd is welcome once someone can verify one.
|
|
# see packaging/APKBUILD: the org.ofono shim for GNOME Calls is opt-in
|
|
# (ofono before systemd: systemd() amoves all of usr/lib/systemd/system,
|
|
# so ofono() must take imsd-ofonod.service first)
|
|
subpackages="$pkgname-ofono:ofono $pkgname-systemd"
|
|
# restart the running daemons onto an upgrade (systemd's enqueue-marked); the
|
|
# systemd subpackage marks imsd.service too, since it brings the unit file
|
|
install="$pkgname.post-upgrade $pkgname.post-install $pkgname-ofono.post-upgrade $pkgname-ofono.post-install $pkgname-systemd.post-upgrade $pkgname-systemd.post-install"
|
|
options="!check !tracedeps"
|
|
source="
|
|
imsd-$pkgver.tar.gz
|
|
org.kde.modem.daemon.desktop
|
|
80-imsd.preset
|
|
"
|
|
|
|
package() {
|
|
cd "$srcdir/imsd-$pkgver"
|
|
install -Dm755 imsd "$pkgdir"/usr/bin/imsd
|
|
install -Dm755 imsd-media "$pkgdir"/usr/libexec/imsd-media
|
|
install -Dm755 imsd-pcscf "$pkgdir"/usr/libexec/imsd-pcscf
|
|
install -Dm755 imsd-dialerd "$pkgdir"/usr/bin/imsd-dialerd
|
|
install -Dm755 ims-pdn-up.sh "$pkgdir"/usr/libexec/ims-pdn-up.sh
|
|
install -Dm755 imsd-handover.sh "$pkgdir"/usr/libexec/imsd-handover.sh
|
|
install -Dm644 imsd.service "$pkgdir"/usr/lib/systemd/system/imsd.service
|
|
install -Dm644 imsd-dialerd.desktop \
|
|
"$pkgdir"/etc/xdg/autostart/imsd-dialerd.desktop
|
|
install -Dm644 net.catcrafts.IMS1.conf \
|
|
"$pkgdir"/usr/share/dbus-1/system.d/net.catcrafts.IMS1.conf
|
|
install -Dm644 net.catcrafts.IMS1.policy \
|
|
"$pkgdir"/usr/share/polkit-1/actions/net.catcrafts.IMS1.policy
|
|
# the skel override hides kde-telephony's modem daemon autostart for the
|
|
# account created at install — imsd-dialerd owns those session bus names
|
|
install -Dm644 "$srcdir"/org.kde.modem.daemon.desktop \
|
|
"$pkgdir"/etc/skel/.config/autostart/org.kde.modem.daemon.desktop
|
|
# enabled by preset: VoLTE surviving reboots must not depend on a manual
|
|
# systemctl enable. Since 1.0.0 the unit needs no configuration file (the
|
|
# P-CSCF comes from the PDN's PCO) and starts on every phone with the
|
|
# package; without a SIM it exits cleanly and stays inactive (IMSD_IDLE),
|
|
# and `systemctl mask --now imsd` opts out (a disable is undone by
|
|
# imsd-ofonod's Wants=imsd.service)
|
|
install -Dm644 "$srcdir"/80-imsd.preset \
|
|
"$pkgdir"/usr/lib/systemd/system-preset/80-imsd.preset
|
|
mkdir -p "$pkgdir"/etc/systemd/system/multi-user.target.wants
|
|
ln -s /usr/lib/systemd/system/imsd.service \
|
|
"$pkgdir"/etc/systemd/system/multi-user.target.wants/imsd.service
|
|
install -Dm755 imsd-ofonod "$pkgdir"/usr/bin/imsd-ofonod
|
|
install -Dm755 imsd-ofono-restart-calls.sh \
|
|
"$pkgdir"/usr/libexec/imsd-ofono-restart-calls.sh
|
|
install -Dm644 imsd-ofonod.service \
|
|
"$pkgdir"/usr/lib/systemd/system/imsd-ofonod.service
|
|
install -Dm644 org.ofono.conf \
|
|
"$pkgdir"/usr/share/dbus-1/system.d/imsd-ofono.conf
|
|
install -Dm644 90_imsd-ofono.gschema.override \
|
|
"$pkgdir"/usr/share/glib-2.0/schemas/90_imsd-ofono.gschema.override
|
|
install -Dm644 80-imsd-ofono.preset \
|
|
"$pkgdir"/usr/lib/systemd/system-preset/80-imsd-ofono.preset
|
|
}
|
|
|
|
ofono() {
|
|
pkgdesc="GNOME Calls (Phosh, GNOME Mobile) backend for imsd"
|
|
depends="$pkgname=$pkgver-r$pkgrel calls"
|
|
amove usr/bin/imsd-ofonod
|
|
amove usr/libexec/imsd-ofono-restart-calls.sh
|
|
amove usr/lib/systemd/system/imsd-ofonod.service
|
|
amove usr/share/dbus-1/system.d/imsd-ofono.conf
|
|
amove usr/share/glib-2.0/schemas/90_imsd-ofono.gschema.override
|
|
amove usr/lib/systemd/system-preset/80-imsd-ofono.preset
|
|
# enabled on install, like imsd.service in the main package
|
|
mkdir -p "$subpkgdir"/etc/systemd/system/multi-user.target.wants
|
|
ln -s /usr/lib/systemd/system/imsd-ofonod.service \
|
|
"$subpkgdir"/etc/systemd/system/multi-user.target.wants/imsd-ofonod.service
|
|
}
|
|
|
|
systemd() {
|
|
install_if="$pkgname=$pkgver-r$pkgrel systemd"
|
|
|
|
amove usr/lib/systemd/system
|
|
}
|