Files
DodoSSH/src/DodoSSH.Client.Android/Properties/AndroidManifest.xml
T
jaap-jan 48ea5e22d5 Actually keep the phone's sessions alive when the app is backgrounded
The foreground service existed, and four defects in its wiring meant it
mostly did not run. A shell opening was never announced to it — only the
ending was — so the service never came up for a shell at all. An idle
connected Files session counted as nothing. Every refresh restarted the
service, which Android 12+ answers with a crash the moment the app is
backgrounded — a transfer finishing in the pocket took the remaining
connections with it. And POST_NOTIFICATIONS was declared but never
requested, so on Android 13+ the receipt was silently invisible.

Updates while backgrounded now go through the notification manager; a
foregrounded refresh still prefers a real start, so a stop still in
flight cannot leave an orphan receipt over an unprotected process.
2026-08-09 10:14:17 +02:00

73 lines
4.2 KiB
XML

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- SSH itself, the sync client, and the loopback socket the terminal renderer attaches to. -->
<uses-permission android:name="android.permission.INTERNET" />
<!--
The foreground service that keeps shells and transfers alive across backgrounding — the decision
recorded in docs/android-port.md. dataSync is the type that matches what it actually does; Android 14
(API 34) rejects a service that starts without one declared here and on the <service> element.
-->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<!--
The service's persistent notification. Requested on API 33+ from SessionForegroundService.Reconcile,
the first time in this process there is actually something to show — not at launch, where the ask
would justify nothing on screen yet. Refusal is survivable: the service still starts and still holds
the process in the foreground either way, so a "no" costs the notification and nothing else.
-->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<!-- Releases the device key. See AndroidDeviceKeyStore. -->
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<!--
◆ Hands a downloaded APK to the system installer, which is the whole of this head's updater. See
AndroidUpdateChannel and ADR 0014.
It is worth being exact about what this permission is and is not. It does not let this application
install anything: it lets it *ask*, and the platform then shows its own confirmation naming the
package and the source. On API 26 and later it is additionally gated by a per-application setting the
user has to turn on in Settings, which no permission dialogue can grant — so the first update walks
them there. Nothing is installed without two deliberate answers, neither of them to a screen this
application drew.
Declared rather than avoided by opening the release page in a browser. That would work, and it would
move the same install through Chrome's downloads and the same unknown-sources gate with one more step
and no less trust. What it would also do is give up any way of knowing a fix has been fetched, which
for an SSH client holding a team's credentials is the property ADR 0011's consequences call the
sharpest edge of shipping outside a store.
-->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<!--
allowBackup and fullBackupContent are both off deliberately, and both are vault properties rather
than defaults worth inheriting. The local cache is a SQLite file holding the ciphertext mirror, the
outbox and the offline unlock material; letting Android back it up would copy vault material into a
Google-held backup that this product's threat model says nothing about. It would also restore one
phone's outbox onto another, which is the same corruption ClientPaths already refuses by insisting on
a local, non-roaming directory.
-->
<!--
The launcher icon is the same >_ box the sign-in and locked screens draw, as a vector
adaptive icon. See Resources/mipmap-anydpi-v26/ic_launcher.xml. No android:roundIcon:
that attribute exists so a launcher wanting a circle can be handed a second bitmap, and
an adaptive icon is already masked to whatever shape the launcher asks for.
-->
<!--
@string/app_name rather than the literal that was here, because the two channels are two installable
applications and both showing "DodoSSH" under the launcher icon is a home screen nobody can read. The
release channel's copy of that string is exactly what was written here before. See
Resources/values/strings.xml, and MainActivity, which has to name the same resource.
-->
<application android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:theme="@style/DodoTheme"
android:networkSecurityConfig="@xml/network_security_config"
android:allowBackup="false"
android:fullBackupContent="false" />
</manifest>