Skip to content

Texts and the phone's notifications on the computer: what Android allows, and how far Sioul could go with SMS

The question: the owner asked, on 8 October 2026, for "a way to display phone notifications, especially SMS on desktop, going through the vault", and, "in an ideal world", to send texts from the computer, "which involves being able to import conversations first", without ruling out "handling SMS entirely in Sioul", once it is known "how much is available as Rust crates to handle that, because it's a large undertaking to build our own SMS app". So: what can Sioul's notification listener carry to the computers through the sharing, and what must stay on the phone? What may an Android app do with texts while another app is the phone's SMS app: read the history, hear new texts, send? What does it take to be the SMS app, and what breaks when it is done badly? Which Rust crates exist? And how can a text written on a computer reach the phone and leave it once, never twice?

Researched on 8 October 2026, without a phone: nothing here was run on a device, and no message was read. Sources, primary first: Android's source at its release branches on android.googlesource.com (android15-release, android16-release, android16-qpr2-release, android17-release; the main branch there stopped in March 2025), read in frameworks/base, frameworks/opt/telephony, packages/providers/TelephonyProvider, packages/services/Mms and packages/modules/Permission; developer.android.com; crates.io's API; the projects' own repositories (KDE Connect, GSConnect, Fossify Messages, /e/OS's Message, QKSMS, QUIK, Signal, microG); the vendors' help pages. This note builds on android-chats.md, cited as "the chats note", whose section 7 says what Android's notification listener sees and may do and is not repeated here, and on call-screening.md, "the calls note" (1.6 on roles for an APK installed by hand, 1.7 on blocked numbers, 1.10 on texts). Sioul's own state: android.md ("Notifications from other apps", "In the background", "Calls"), database.md ("The calls' logs", "Sealed") and porch.md ("Calls declined").

Strength of each finding, as in the chats note: primary (documentation, source code, a licence or a vendor's own page, read at the link given), corroborated (two or more independent reports agree), report (one report or forum post), inferred (read in code or deduced, not documented). "Needs a phone" marks what only a test on a device can settle.

Answers so far

(Numbers point to the sections below.)

  1. The phone's notifications on the computer ask nothing new of Android. The listener Sioul already has reads what a text's notification says: the sender's name, usually the number, the message, the conversation, the time. It reads every SMS app alike, and RCS chats too, since a notification is all that Google Messages lets other apps see of RCS. Carrying them sealed through the sharing needs no new permission. It does reverse one of Sioul's own rules: today a notification's words never leave the phone (1.1, 1.3).
  2. Codes and approvals stay on the phone. A code on every computer and in a folder on a server weakens the second factor it is meant to be. Android itself now hides codes from apps like Sioul: in notifications from Android 15, in texts holding an app's code from Android 16's December 2025 release, and in more kinds of codes from Android 17 (1.2).
  3. Read state stays the phone's. The listener may take an SMS app's notification away, which leaves the text unread in the app; pressing the app's own "Mark as read" button would mark it, and in an RCS chat may tell the sender. Seen on a computer should take Sioul's line away on every device and touch nothing in the SMS app (1.4).
  4. What others learnt: KDE Connect and GSConnect carry notifications and texts over a direct link on the same network, at once, with per-app switches to hold back contents and pictures, and never tell the computer whether a text left; Pushbullet sealed everything with a password typed on each device in 2015, as Sioul's sharing does; Phone Link shows 30 days at most and lets nothing be deleted from the computer; Google Messages for web relays through the phone, one computer at a time (1.5).
  5. Without being the SMS app, Sioul may read, hear and send texts (READ_SMS, RECEIVE_SMS, SEND_SMS). Android files what Sioul sends in the phone's messages itself, so the SMS app shows it in its conversation. Sioul would not see drafts, failed or queued messages (other apps see the inbox and the sent box only), nor, from Android 16's December release, a text holding an app's code during its first three hours (2.2 to 2.4).
  6. Only the SMS app writes, deletes and marks messages read, receives texts first, downloads multimedia messages and writes the blocked numbers. A write by another app fails without an error (2.5).
  7. On an APK installed by hand, the SMS permissions are "hard restricted" but allowed by default at install; from Android 15 they wait behind "Allow restricted settings", the same switch as notification access, so the person passes that screen once for both (2.1).
  8. No import is needed: with READ_SMS, the phone's provider is the history. A backup file is a fallback only; reading for a backup needs READ_SMS, restoring needs the SMS role, which is why backup apps ask for it (3).
  9. Rust needs nothing for texts: Android's Java encodes, splits, sends, files and receives them. Crates exist for SMS PDUs (young ones), none for MMS's encapsulation outside a Linux modem library, and phonenumber for numbers; all have licences compatible with GPL-3.0-or-later. A full SMS app is a Java project the size of Fossify Messages, whose first duty is never to lose an incoming text: Android deletes its own copy once the SMS app has been told, whether the app saved it or not (4).
  10. Sending from the computer through the sharing works wherever there is a connection, takes from about half a minute to a few minutes, and can be made never to send twice: a sealed request with its own key, claimed in a ledger on the phone before Android is asked, an expiry, a guard against requests read again, and the outcome sealed back. KDE Connect's direct link is instant but local, and says nothing back (5).

Recommended: phase (a), the phone's notifications on the computers' Porch, texts first, now; phase (b), reading the conversations and sending from the computer without being the SMS app, next; Sioul as the SMS app, phase (c), not now. See "Options for Sioul" and "Recommendation".

1. The phone's notifications on the computer

1.1 What a text's notification gives

  • The listener's view is the chats note's (section 7): the package, the channel, the category, MessagingStyle messages with their sender, text and time, the conversation's title and whether it is a group, the people with their addresses (tel: or a contact's lookup address), the conversation's shortcut. Sioul's listener already reads all of it into appnotes::Posted and knows which app is the phone's SMS app (Telephony.Sms.getDefaultSmsPackage, AppNotes.java) (android.md, "Notifications from other apps"). Primary.
  • /e/OS's Message (foundation.e.message, "Forked from https://github.com/moezbhatti/qksms", GPL-3.0, last commit 7 September 2026, https://gitlab.e.foundation/e/os/Message): one MessagingStyle notification per conversation, category msg; each message's sender a Person named as the contact, or as the number when there is no contact, with the contact's lookup address as its URI; the number again in the notification's people, as tel:<number>; a picture as the message's data, content://mms/part/<id>; up to three buttons, chosen by the person among archive, delete, mute, mark as read, reply (a text field) and call, each with its semantic action (NotificationManagerImpl.kt, branch main). Primary. Takeaway: on a phone running /e/OS's Message, every SMS notification carries the number and the contact's name; the computer can say who wrote and offer Text back without any SMS permission.
  • Fossify Messages (GPL-3.0, https://github.com/FossifyOrg/Messages): MessagingStyle, the sender's Person keyed by the number, a reply field only when its lock-screen setting shows the message, and "Mark as read" without a semantic action (NotificationHelper.kt). Primary.
  • Google Messages (closed source): apps that show on Android Auto must post MessagingStyle notifications with a reply action marked SEMANTIC_ACTION_REPLY holding a single text field, and a mark-as-read action marked SEMANTIC_ACTION_MARK_AS_READ, neither opening a screen (https://developer.android.com/training/cars/communication/notification-messaging, updated 7 October 2026). Primary for the rule; that Google Messages follows it for SMS and RCS alike is inferred from its support of Android Auto.
  • Pictures: Android gives a listener read access to the addresses a notification carries before telling it of the notification ("Grant access before listener is notified", updateUriPermissions(r, old, info.component.getPackageName(), targetUserId), NotificationManagerService.java, android16-release). Whether /e/OS Message's content://mms/part/… then opens for Sioul depends on that provider's grants. Primary (code); needs a phone.
  • RCS: Google Messages keeps RCS chats in its own database and offers no public way in; a hidden interface served Samsung's continuity service alone (XDA Developers, 9 July 2021, report); a backup vendor reported in 2019 and 2021 that Google Messages also copies RCS chats into the phone's MMS table (SyncTech, report, unverified since). Its notifications are the one view other apps surely get. On /e/OS, microG does not carry Google's RCS: the bounty issue for it has been open since 1 August 2025, with six pull requests still open in September and October 2026 (https://github.com/microg/GmsCore/issues/2994). Primary (the issue's state) and report (why RCS fails without Google's services: Play Integrity, according to GrapheneOS users). Takeaway: through notifications, an RCS chat on a phone with Google's services reaches the computer like any text; on /e/OS today, texts are SMS and MMS only.

1.2 What must never travel

  • Codes and approvals. Sioul's listener already never holds them (appnotes::is_code: a code found as in mail, approval words, a channel named for sign-ins, a copy Android redacted). They should never travel either. A code on every computer, and sealed in a folder on a server, makes the second factor as weak as the weakest of those places. Android's own rules defend exactly this (primary):
    • from Android 15, a notification that the phone's assistant judges sensitive reaches an untrusted listener redacted (the chats note, 7);
    • from Android 16's December 2025 release (QPR2), a text holding an app's verification code (the 11-character hash of the SMS Retriever) is hidden for three hours from apps that read the SMS provider or hear new texts, unless they hold the SMS, assistant or dialer role, are system or carrier apps, have a companion-device association, or hold RECEIVE_SENSITIVE_NOTIFICATIONS (SmsProvider.java: OTP_HIDING_TIME_MS = 3 h; SmsManager.isAppTrustedForSmsOtp: "read SMS messages/receive SMS Broadcasts which contain an otp code"; android16-qpr2-release; https://developer.android.com/reference/android/provider/Telephony.Sms, updated 3 August 2026);
    • Android 17 widens it, behind two flags, to codes meant for web pages and to any code (redactWebOtpSmsApi, redactOtpAppCompatApi, android17-release).
  • A code asked for on the computer. For carrying it: the person signs in on the computer and the code comes to the phone. Against: it is the attack Android is closing, and Android will increasingly not give Sioul the code to carry. The line on the computer can say that a code came, from whom and when, and that it stays on the phone. Carrying a code would need the person's choice per sender, for minutes at a time, and it would work only on the Android versions that still show codes to Sioul. Inferred.
  • Pictures, voice notes and icons: heavy, and among the most private; the line says "a picture" instead.
  • What the person did not choose: the apps not switched on for the computer; a blocked sender's messages (as with calls: a blocked caller's calls are never shared); and, as proposed here, notifications an app marks secret (Notification.VISIBILITY_SECRET, which asks Android to keep them off the lock screen).
  • Never at all: a notification's buttons and its tap (a PendingIntent exists on the phone only), Sioul's own notifications, ongoing ones.

1.3 Sealed through the sharing

  • The calls are the model: a part of its own, a folder of lines in which each phone writes its own file, Shape::Lines, each line sealed with XChaCha20-Poly1305 under the key every device derives from the passphrase (database.md, "The calls' logs", "Sealed"). The server sees which device wrote, when and how much, never what. Primary (Sioul's design).
  • What the server still learns: a line's size follows the message's length, and its time the message's arrival. database.md already names the cure for its sealed files, sizes padded to steps (review F19, not built); for texts, padding each line to steps of, say, 256 bytes costs little. Inferred.
  • The key is on every device: a computer lost or broken into reads every text the sharing carried and still holds. That is the price of the convenience, and the reason to keep the window short.
  • How long: Phone Link shows "text messages that you've received or sent within the last 30 days" (1.5); Sioul keeps calls a month. For notifications, whose full record stays in the phone's SMS app, a week is enough: each phone would take its own lines out after 7 days, and any device another phone's lines after 10 (for calls: 31 and 45 days).
  • When a line shows: at the time its sender may reach the person, by the same matrix as on the phone (the Messages rows, attention.md), and never as a notification of its own on a computer, as for the declined calls (porch.md, "Calls declined").

1.4 Marking read

  • The listener may take a notification away when it is not ongoing (cancelNotification; the chats note, 7). Taking an SMS app's notification away does not mark the text read in that app: the app's state lives in the SMS provider, which only the SMS app writes (2.5). Primary.
  • A held notification cannot be taken away early: only a system listener may bring a snoozed notification back before its time ("Not allowed to unsnooze before deadline", unsnoozeNotificationFromSystemListener, NotificationManagerService.java, android16-release). It comes back at its time, when Sioul may take it away. Primary.
  • The app's own "Mark as read" button can be pressed by a listener (KDE Connect presses a notification's buttons by their title, NotificationsPlugin.kt); its semantic action finds it in the apps that set one (/e/OS Message, Google Messages, 1.1). It marks the text read in the app. In an RCS chat with read receipts on, marking read tells the sender, which breaks Sioul's rule that holding a message never changes what others see (android.md, "Holding is snoozing, never cancelling"). Primary (the API); inferred (the receipts).
  • Takeaway: Seen on a computer takes Sioul's line away on every device, as for calls, and touches nothing in the SMS app. A choice for later: "Seen on a computer also clears the phone's notification", which would be a cancel, never a mark-as-read, off unless the person turns it on.

1.5 How others carry notifications and texts

  • KDE Connect (Android app: GPL-2.0-only OR GPL-3.0-only OR later versions KDE accepts; https://invent.kde.org/network/kdeconnect-android, read at its GitHub mirror, last change 6 October 2026). A direct link between devices on the same network (UDP and TCP ports 1714 to 1764; https://userbase.kde.org/KDEConnect, edited 27 April 2026). Primary.
    • Notifications (NotificationsPlugin.kt): it leaves out ongoing, foreground-service, local-only and group-summary notifications, and its own; each app has a switch, and per app "block contents" and "block images"; it sends the title, the text, the conversation's messages, the app's icon and the buttons; the computer may dismiss a notification (the phone then cancels it), press a button, or answer through the app's own reply field; an option sends only while the phone's screen is off.
    • Texts (SMSPlugin.kt, SmsMmsUtils.kt): it asks for READ_SMS, SEND_SMS and READ_PHONE_STATE, and is not the SMS app. The computer asks for the conversations (the latest message of each), then for one conversation, by range; new texts are pushed by watching the provider, and only once a computer has asked. It sends what the computer asks, multimedia messages through Android's sendMultimediaMessage; twice the code says "// TODO: Notify other end": the computer is never told whether the text left.
    • Learnt: switches per app for contents and pictures; answering through the app's own reply field; nothing sent until a computer asks; no confirmation back, a gap its own code names.
  • GSConnect (GNOME Shell, GPL-2.0, KDE Connect's protocol, https://github.com/GSConnect/gnome-shell-extension-gsconnect): it keeps the conversations in plain JSON, in ~/.cache/gsconnect/<device>/sms.json, in a folder only its user can open (plugin.js, sms.js). Primary. Learnt: the computer's copy is a second store of the texts, to protect as such (inferred).
  • Pushbullet: "end-to-end encryption" for notification mirroring, copy and paste, and SMS since 11 August 2015: "All you need to do is pick a password and enter it on each device. We use this password to derive a key that's used to encrypt your data. Your password isn't stored" (https://blog.pushbullet.com/2015/08/11/end-to-end-encryption/). Otherwise, with SMS sync on, "some SMS data is uploaded and stored on Pushbullet servers", deleted with the account (its privacy policy, undated, https://help.pushbullet.com/articles/play-store-privacy-policy/). Primary. Learnt: Sioul's sharing is this design, with Argon2id to derive the key.
  • Google Messages for web: it sends "using a connection from your computer to your phone, so carrier fees will apply"; several computers may be paired but "only one computer can be active at a time"; a computer unused for a few weeks is unpaired; "Your latest conversation threads, contacts, and other settings will be encrypted and cached on your browser" (https://support.google.com/messages/answer/7611075, undated). Primary.
  • Microsoft Phone Link: "we show text messages that you've received or sent within the last 30 days"; SMS and MMS, RCS "for select Samsung devices"; "You can't manage or delete messages on your PC" (https://support.microsoft.com/en-gb/windows/apps/phonelink/send-and-receive-text-messages-from-your-pc, undated). Primary.
  • Takeaway: the large vendors keep the computer's view short and mostly for reading; the phone's app stays the record. Sioul's sharing gives what KDE Connect lacks (reach beyond the home network, an answer back, sealing at rest in the folder) and lacks what it gives (instant delivery).

2. Texts without being the SMS app

Sioul is not on the Play Store, so Google Play's rule keeping the SMS permissions for default SMS apps and a few listed exceptions (2018, https://betanews.com/2018/10/09/goolge-play-sms-call-logo-policies/) does not bind it. Android's own rules do.

2.1 The permissions on an APK installed by hand

  • "Hard restricted", and allowed by default. SEND_SMS ("costsMoney|hardRestricted"), READ_SMS, RECEIVE_SMS, RECEIVE_MMS and RECEIVE_WAP_PUSH ("hardRestricted") are runtime permissions an app may hold only when its installer allows them (core/res/AndroidManifest.xml, android15-release); but "Initially, all restricted permissions are allowlisted", and an install session allows them all unless the installer says otherwise (PackageInstaller.SessionParams, installFlags = INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS, android15-release). Primary.
  • From Android 15, behind "Allow restricted settings". Android's enhanced confirmation lists SEND_SMS, RECEIVE_SMS, READ_SMS, RECEIVE_MMS, RECEIVE_WAP_PUSH, READ_CELL_BROADCASTS and the SMS group among its protected settings, beside notification access and the SMS and dialer roles, for apps it guards (installed from a file) (EnhancedConfirmationService.java, android15-release, android16-release and main). Allowing restricted settings lifts the guard for the whole app (clearRestriction sets the app "not guarded"). Primary; the screens on /e/OS need a phone. Takeaway: the person who has given Sioul notification access has passed that screen already; the SMS permissions then come with Android's ordinary question.
  • Elsewhere, Play Protect. On phones with Google's services in some countries, Play Protect's "enhanced fraud protection" refuses to install, from a browser, a file manager or a messaging app, an app declaring RECEIVE_SMS, READ_SMS, a notification listener or an accessibility service (piloted in Singapore in February 2024, https://www.securityweek.com/google-announces-enhanced-fraud-protection-for-android/; Malaysia in April 2026, https://blog.google/intl/en-my/company-news/technology/google-launches-enhanced-protection-in-google/). Sioul declares a notification listener already. /e/OS has no Play Protect. Primary.

2.2 Reading the history (READ_SMS)

  • The providers sms, mms and mms-sms are read with READ_SMS (packages/providers/TelephonyProvider/AndroidManifest.xml, android16-release). Conversations are content://mms-sms/conversations; each message carries its address, body, date, type, read, thread_id and sub_id (which SIM); a multimedia message's participants and text are in its addr and part rows. Primary.
  • Only the inbox and the sent box. For any caller that is neither the system nor the SMS app, the provider reads from restricted views: sms_restricted, "only sent/received messages" (type inbox or sent), and pdu_restricted, inbox or sent "without wap pushes" (no multimedia message still to download); and it refuses sub-queries (ProviderUtil.isAccessRestricted, SmsProvider.query, MmsSmsDatabaseHelper.java, android16-release). Primary. Takeaway: drafts, failed, queued and outgoing texts are the SMS app's alone; a text that failed to leave never shows to Sioul. That is also why backup apps ask to become the SMS app even to back up (3).
  • Codes hidden for three hours from Android 16's December 2025 release (1.2). Primary.
  • Who wrote a sent row: rows Android writes for an app carry that app in creator (2.4). Primary.

2.3 Hearing new texts (RECEIVE_SMS)

  • The SMS app first, then everyone else. A new text goes first, as SMS_DELIVER, to the SMS app's receiver alone; once it has answered, the same message goes as SMS_RECEIVED to every app holding RECEIVE_SMS ("Now dispatch the notification only intent", InboundSmsHandler.java, android16-release). Android's documentation: other apps "may also be notified when a new SMS arrives by listening for the SMS_RECEIVED_ACTION broadcast, which is a non-abortable broadcast that may be delivered to multiple apps" (Telephony.java, class documentation). Primary.
  • It wakes Sioul. SMS_RECEIVED and WAP_PUSH_RECEIVED are among the broadcasts a receiver declared in the manifest still gets ("SMS recipient apps rely on these broadcasts", https://developer.android.com/develop/background-work/background-tasks/broadcasts/broadcast-exceptions, updated 26 February 2026), and the receivers get a short allowance to start a foreground service, in Doze too (handleSmsWhitelisting: TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED). Primary.
  • Multimedia messages: WAP_PUSH_RECEIVED only says one is waiting; the SMS app downloads and files it, and Sioul reads it from the provider afterwards. Watching the provider (a ContentObserver on content://mms-sms/, as KDE Connect does) hears both. Primary (code), inferred (the timing).

2.4 Sending (SEND_SMS)

  • Android files the sent text for an app that is not the SMS app. "Beginning with Android 4.4 (API level 19), if and only if an app is not selected as the default SMS app, the system automatically writes messages sent using this method to the SMS Provider" (SmsManager.sendTextMessage, android16-release). In the code: persistSentMessageIfRequired writes a text sent by an app that is not the SMS app into the sent box, with the SIM, address, whole body, date, seen and read, creator set to the sending app, a pending status when a delivery report was asked for, and moves it to the failed box if it fails (SMSDispatcher.java, android16-release). The sent-intent then carries that row's address (fillIn.putExtra("uri", …)). Primary. Takeaway: a text Sioul sends shows in the SMS app's conversation as if sent there; Sioul can find it again by its row.
  • Long texts: divideMessage and sendMultipartTextMessage split a text, choose GSM 7-bit or UCS-2 and join the parts with their headers; the person's phone does the counting. Primary (API).
  • Android retries for itself: up to three times, two seconds apart, each retry marked "reject duplicates" with the same message reference, so that the network drops a copy it has already received (MAX_SEND_RETRIES = 3, SEND_RETRY_DELAY = 2000, SMSDispatcher.java; TP-RD, "per TS 23.040 Section 9.2.3.6", GsmSMSDispatcher.java, android16-release). Primary. Takeaway: Sioul must never retry on top of Android.
  • What Android asks the person: a text to a premium short number waits for the person's confirmation on the phone (checkDestination), and an app sending more than 30 texts in a minute is stopped until the person agrees (SmsUsageMonitor: DEFAULT_SMS_MAX_COUNT = 30, DEFAULT_SMS_CHECK_PERIOD = 60000, android16-release). Primary.
  • Delivery reports: a second intent fires when the network reports delivery, if the carrier sends reports. Primary (API); whether French carriers send them needs a phone.
  • Two SIMs: with several SIMs and no SIM chosen for texts, Android asks the person to choose, which it can do only for an app on the screen; from the background the send fails (resolveSubscriptionForOperation, "Android does not allow background activity starts", RESULT_NO_DEFAULT_SMS_APP). SmsManager.createForSubscriptionId(subId) names the SIM and needs no more permission; listing the SIMs with their names needs READ_PHONE_STATE (SubscriptionManager.getActiveSubscriptionInfoList, android16-release). Primary. Takeaway: answer from the SIM the conversation last used (its sub_id), and name the SIM only with READ_PHONE_STATE.
  • Multimedia messages can be sent without the role: Android's MMS service asks for SEND_SMS alone (MmsServiceBroker.sendMessage) and files the sent message for an app that is not the SMS app (SendRequest.persistIfRequired, android16-release); KDE Connect sends them so. The app must build the message's binary form itself (an M-Send.req PDU), for which Android offers no public class. Primary.

2.5 What only the SMS app may do

  • Write to the provider: "Only the default SMS app … is able to write to the SMS Provider" (Telephony.java). Another app's writes are ignored, not refused: the write app-op defaults to "ignored" (OP_WRITE_SMS, MODE_IGNORED, AppOpsManager.java), and Android's MMS service answers a fake address: "Silently fail AppOps failure due to not being the default SMS app while writing the TelephonyProvider" (MmsServiceBroker.importTextMessage, android16-release). So: no deleting, no marking read, no restoring a backup, no drafts. Primary.
  • Receive first (SMS_DELIVER, WAP_PUSH_DELIVER), and download and file multimedia messages (2.3). Primary.
  • Write the blocked numbers, with the phone app (the calls note, 1.7). Primary.
  • Read codes at once (1.2). Primary.
  • Not even the SMS app receives emergency alerts: the cell-broadcast receiver needs a permission given only to the system ("signature|privileged", RECEIVE_EMERGENCY_BROADCAST); the system's own app shows them. Primary.

2.6 RCS

  • No public interface reads or sends RCS. Android 10 carried a hidden RCS message store (RcsMessageStore, marked @hide, telephony/java/android/telephony/ims/, android10-release), gone from android11-release. Google Messages holds RCS in its own database (1.1). Without Google's services, RCS does not register (the microG issue, 1.1). Primary and report. Takeaway: for Sioul, RCS is what Google Messages' notifications say, and a reply field Sioul could press (5.5); nothing more.

2.7 /e/OS

  • Its SMS app is Message, the QKSMS fork above, maintained by /e/ (1.1). Primary.
  • The rules above depend on the Android version /e/OS is built on, which its build names (-a14, -a15, -a16): the guard of 2.1 from Android 15, the hidden codes of 1.2 from Android 16's December 2025 release. Primary (AOSP); the phone's own version needs a phone.
  • microG: no RCS (1.1); texts do not depend on it.

3. Importing conversations

  • With READ_SMS, nothing is imported: the provider is the history, read in place, and Android files Sioul's sent texts there (2.2, 2.4). Primary.
  • What a backup app needs: reading for a backup needs READ_SMS; restoring writes the provider and needs the SMS role (2.5), which is why a backup app asks to take the role "temporarily". While a backup app holds the role, new texts go to it first and are filed by it; if the role is not given back, the phone's SMS app no longer receives them. Primary (rules), inferred (the risk).
  • SMS Backup & Restore's file, as a fallback for a phone Sioul cannot read: XML, <smses count backup_set backup_date>, then <sms address date type read body …> with optional date_sent, sub_id, contact_name and others, and <mms …> with <parts><part seq ct cl text data/></parts> (the data in base64) and <addrs><addr address type charset/></addrs>; dates in milliseconds since 1970; calls in a separate <calls> file; zipped, optionally encrypted with AES-256 (https://www.synctech.com.au/sms-backup-restore/fields-in-xml-backup-files/, undated). quick-xml reads it (4.2). Primary. Takeaway: Sioul does not need it; it would matter only for a person whose Sioul has no READ_SMS, or to read an old phone's history.

4. The Rust side

4.1 What Android's Java already does

Everything a text needs below the person: encoding (GSM 7-bit or UCS-2), splitting and joining long texts, the radio's retries, filing sent texts, decoding incoming ones (SmsMessage.createFromPdu), the MMS transport (sendMultimediaMessage, downloadMultimediaMessage), the SIMs. Sioul's bridge is already made for this division: Java calls Android, and Rust decides through C functions that take and return JSON (sioul_appnotes_decide, sioul_alarm_decide), with Sioul's own JNI glue in crates/sioul-app/cpp. Rust needs no SMS crate for phases (a) and (b); it needs the formats of the lines it shares, the ledger of 5.2, and number handling, which Sioul has (phones::key). Primary (Android's APIs, Sioul's code).

4.2 Crates

Read on crates.io's API on 8 October 2026. MIT, Apache-2.0, CC0-1.0 and MPL-2.0 are compatible with GPL-3.0-or-later (the Free Software Foundation's licence list).

Crate What it does Licence Last release Maintenance For Sioul
tpdu 1.0.1 3GPP TS 23.040 SMS-SUBMIT and SMS-DELIVER, RP-DATA, GSM 7-bit, UCS-2, concatenation headers; no I/O MIT 17 August 2026 new (first release 2 July 2026), 184 downloads, a telecom firm's only if Sioul ever decodes raw PDUs (phase c), Java does it
sms-pdu 1.1.0 SMS PDU encoding and decoding, cut out of huawei-modem CC0-1.0 22 September 2025 two releases as above
sms-pdu-decoder 0.1.1 GSM 03.40 decoding only MIT 28 November 2025 two releases the same day no
gsm7 0.4.1 GSM 7-bit alphabet MIT 3 July 2026 five releases since 2019, no repository listed counting a text's parts on the computer, if wanted
huawei-modem 0.2.2 AT-command modems, with PDU code CC0-1.0 23 April 2023 idle no
qmi-sim-manager 0.1.2 Linux Qualcomm modems: calls, SMS, MMS sending and downloading with its own WSP and MMS encoder MIT/Apache-2.0 26 July 2026 new, 116 downloads, Tokio and GLib a reference for MMS's encoding only
phone-backup-messages 0.5.0 claims SMS Backup XML, MMS, threading MIT 5 September 2026 one release, no repository no
rust-rcs-client 0.5.3, rust-rcs-core 0.3.1 an RCS client (SIP, MSRP) for Chinese carriers' networks Apache-2.0 9 October 2024; 14 September 2024 idle no: RCS needs the carrier's or Google's registration
phonenumber 0.3.10+9.0.33 libphonenumber's rules Apache-2.0 2 July 2026 Whisperfish's, regular, 12.7 million downloads if Sioul's own phones ever falls short
rlibphonenumber 2.2.13 another port of libphonenumber Apache-2.0 24 September 2026 frequent as above
quick-xml 0.42.0 XML MIT 22 August 2026 very active the backup file's fallback (3)
jni 0.22.4, jni-sys 0.4.1 Java's native interface MIT OR Apache-2.0 16 March 2026; 9 January 2026 (0.3.1 patched on 22 March 2026) active not needed: Sioul has its own glue
ndk 0.9.0, ndk-context 0.1.1 the NDK; the Java VM and context handles MIT OR Apache-2.0 26 April 2024; 19 April 2022 stable ndk-context is in Sioul already (android-keyring)
android-activity 0.6.1 native activities MIT OR Apache-2.0 24 March 2026 active not for Qt's activity
  • No Rust crate encodes MMS's encapsulation (WAP-230 WSP headers, M-Send.req) on its own, nor SMIL beyond general XML; the one encoder found lives inside qmi-sim-manager. Primary (search of crates.io).
  • Takeaway: Rust brings nothing a text needs on Android; for MMS, the Java libraries of 4.5 do the work.

4.3 The JNI glue

Phases (a) and (b) add Java classes (a reader of the provider, a receiver of new texts, a sender with its result receivers) and Rust functions in the existing C-and-JSON style; no new crate. Primary (Sioul's code).

4.4 What a full SMS app takes

  • The role's required parts (roles.xml, packages/modules/Permission, android16-release): a receiver for SMS_DELIVER guarded by BROADCAST_SMS; a receiver for WAP_PUSH_DELIVER with type application/vnd.wap.mms-message guarded by BROADCAST_WAP_PUSH; a service for RESPOND_VIA_MESSAGE (smsto:) guarded by SEND_RESPOND_VIA_MESSAGE (the quick replies to a call); an activity for SENDTO (smsto:; and sms:, mms:, mmsto: as preferred activities). The role grants the phone, contacts, SMS, storage, microphone, camera and notifications permissions, the write app-op, and running in the background unrestricted. It is exclusive. Primary.
  • Then everything the phone's SMS app does today: filing every incoming text and multimedia message at once; downloading multimedia messages over mobile data with the carrier's settings; sending them (the PDU, the carrier's limits); group conversations (an MMS to several people); drafts, failed texts and sending again; the person's blocked numbers; notifications with conversations, replies and shortcuts; flash texts (class 0); delivery reports; two SIMs; search; backups and moving to another app. Primary (the role) and inferred (the list, from the apps of 4.5).
  • What breaks when it is done badly: Android keeps a new text in its own table only until the SMS app has been told; after the broadcasts it deletes it "anyway", whatever the app answered ("a broadcast receiver set the result code to … deleting from raw table anyway!", InboundSmsHandler.java, android16-release). An SMS app that crashes, or files the text on a thread it never finishes, loses it, and no other app ever stored it. A role taken by another app (a backup app) moves new texts there. Writes after losing the role fail without an error (2.5). For someone waiting for a doctor's or a carer's text, a missed text is the failure that matters. Primary (code), inferred (the cases).
  • Emergency alerts are not the SMS app's (2.5).

4.5 Reference apps

App Licence Last change Size (GitHub's count of source bytes) Notes
Fossify Messages (https://github.com/FossifyOrg/Messages) GPL-3.0 8 October 2026 (release 1.9.1, 19 July 2026) Kotlin 551,768 bytes in 115 files Android 8 to 16; uses Fossify Commons (GPL-3.0) and org.fossify:mmslib 1.0.0, a fork of Klinker's android-smsmms (Apache-2.0, archived 25 June 2024); the role's four parts and 17 receivers and messaging classes
/e/OS Message (https://gitlab.e.foundation/e/os/Message) GPL-3.0 7 September 2026 (QKSMS's size) QKSMS forked in 2019, maintained by /e/
QKSMS (https://github.com/moezbhatti/qksms) GPL-3.0 2 June 2023 (unmaintained) Kotlin 1,076,204 and Java 1,037,663 bytes the base of QUIK and /e/OS Message
QUIK (https://github.com/quik-sms/quik) GPL-3.0 27 September 2026 QKSMS continued
Signal for Android (https://github.com/signalapp/Signal-Android) AGPL-3.0 7 October 2026 2.6 GB repository SMS removed: announced 12 October 2022 (https://signal.org/blog/sms-removal-android/: plaintext SMS "leak sensitive metadata", surprise bills, a confusing experience), its export library added 9 August 2022 and removed 31 January 2024; the old code lives in its history, AGPL-3.0, combinable with GPL-3.0 code (GPL-3.0 section 13) but bringing the AGPL's terms
KDE Connect for Android GPL-2.0-only OR GPL-3.0-only OR later 6 October 2026 SMSHelper.kt 46 KB, SMSPlugin.kt 24 KB, SmsMmsUtils.kt 19 KB the closest model for phase (b)

Primary (the repositories, GitHub's and GitLab's APIs).

5. Sending from the computer through the sharing

5.1 The path, and how long it takes

  • The path: the computer writes a sealed request in its own file of the sharing; the computer's sync (or Sioul itself, when it keeps the folder in step with a Nextcloud) puts it on the server; the phone gets it; the phone's background step reads it and hands the text to Android; the outcome goes back the same way (database.md, "What the sync app must do", "Kept in step by Sioul itself"). Primary (Sioul's design).
  • How long, from Sioul's own figures: the phone's background service takes a step every two minutes while another device is in use, five while the person is awake, fifteen at night, and three seconds after its sync app writes another device's file into the folder (FileObserver); with Sioul keeping the folder itself, each step looks at the server first (android.md, "In the background"). A desktop's sync app brings a change within seconds; eDrive on a phone often looks every half hour unless asked (6 October 2026: a computer's records an hour and a half late on the phone), which is why Sioul also reads the server directly (database.md, "Fetched from the server too"). Primary (Sioul's documentation; not measured for texts).
    • So: from about half a minute (Sioul keeping the folder, the phone's step soon after) to two minutes typically while the person is at the computer, more at night or with a slow sync app, then the same again for the answer.
  • Doze: the step's alarm rings through Doze (setExactAndAllowWhileIdle), and a process with a foreground service keeps the network (android.md, "Through Doze"). Primary (Android's rules as Sioul uses them). Sending the text itself needs the cellular network, not the phone's data connection (inferred).
  • KDE Connect is instant on the same network and absent elsewhere; Sioul's way works wherever both devices reach the server, slower (5.5).

5.2 Never twice

A text sent twice ("I'm on my way" twice, a cancellation sent again) is a small harm; a text sent hours late can be a large one. The doses' care applies: never say "sent" when it is not known, never send again without the person. Proposed rules, inferred from Android's behaviour (2.4) and Sioul's sharing:

  • One key per request: the computer gives each text a random key, the phone it must leave from, the address, the body, the SIM if chosen, and when it was written.
  • Claimed before Android is asked: the phone writes the key into a ledger of its own (private, never shared, written to the disk before it goes on), then calls SmsManager. A key already in the ledger is never sent again, whatever happens to the sharing. The mail notifications already work this way ("each letter is claimed before it is told: never twice", android.md, "New mail").
  • An expiry: a request older than a set time when the phone reads it (proposed: 15 minutes after it was written, on the phone's clock, with the clocks' difference Sioul already measures between devices) is not sent; the computer says so, and offers to send it again as a new request.
  • No replay: the sharing may read records again (a device's memory lost, a part switched off and on, share::rebuild). The ledger keeps the keys for longer than any request lives, and the phone ignores requests written before it started taking requests on this ledger (a mark kept beside it), so a ledger lost with the phone's data cannot make old requests new.
  • One phone: a request names its phone; another phone never sends it.
  • Android's retries are the only retries (2.4); a failed text is not sent again by Sioul; the person may press Send again, which makes a new key.
  • A crash between the claim and the result: Sioul looks in the sent and failed boxes for a row with creator = Sioul, the same address and body, dated after the claim (2.4). Found, its state is the answer; not found, the computer says "Your phone may not have sent it" and never sends it by itself.

5.3 Saying what happened

  • Outcome lines, sealed back in the phone's own file, for each key: taken (claimed), handed to Android, sent (the sent-intent's result, with the row's address), delivered (when a report comes), failed (with Android's reason: no signal, radio off, limit reached, short number refused), expired, or in doubt (5.2).
  • On the computer, in words, never red: "Waiting for your phone (it last shared at 14:02).", "Sent at 14:03.", "Delivered at 14:03.", "Not sent: your phone had no signal. It will not try again.", "Your phone may not have sent it: look in its messages."
  • On the phone, nothing to do: the text shows in the SMS app's conversation, filed by Android (2.4).

5.4 What can go wrong

What What happens What Sioul does
The phone is off or out of reach the request waits in the folder the computer says since when; past the expiry, it is not sent
The sync app is slow as above Sioul reads the server itself where it can (database.md)
No signal, airplane mode Android retries three times, then fails "Not sent", the reason, never an automatic retry
Two SIMs, none chosen for texts from the background, the send fails name the SIM: the conversation's last, or the person's choice
A short premium number Android asks the person on the phone refuse short numbers from the computer, or say to look at the phone
More than 30 texts a minute Android asks the person not a person's pace; say so
Sioul stopped between claim and send the ledger holds the key look in the provider; else "may not have sent"
The sharing reads old requests again keys and the mark refuse them nothing is sent
A request older than the expiry not sent the computer offers to send it again
Two computers send to the same person two keys, two texts as the person asked; no merging
The text holds a code from the computer it leaves as written the person's own act; nothing hides it
  • KDE Connect: a request crosses the local network at once and, when the phone sends it, nothing comes back ("// TODO: Notify other end"); there is no key, so a request sent while the link drops and comes back is the app's guess. Sioul's sharing is slower and reaches further, and can say what happened. Primary (KDE Connect's code).
  • The reply field of the app's own notification (KDE Connect's requestReplyId): the computer's text goes to the phone, where Sioul fills the SMS app's reply field (RemoteInput) and presses it; the app sends the text itself, by SMS or RCS, and files it; no SMS permission is needed, and chat apps work the same way. It works only while that conversation has a notification, it reverses Sioul's rule that it never answers in another app (android.md), and the only confirmation is the app adding the reply to its notification. Primary (API), inferred (the rest).

Options for Sioul

Option Gives Costs Risks
A The phone's notifications on the computers' Porch (phase a): the SMS app's first, other apps by the person's choice, sealed, a week, Seen on every device texts seen at the computer, by who may reach the person when; Text back through sms: links (KDE Connect on Linux) no new permission; a part of the sharing, the Porch's lines, filters the texts' words on every computer and sealed on the server; the size of each line unless padded
B A, with replies through the app's own reply field answering from the computer, by SMS or RCS, in chat apps too, with no SMS permission little beyond A only while a notification exists; Sioul answering inside other apps; a weak confirmation
C Conversations on the computer (READ_SMS, RECEIVE_SMS; phase b, reading): the last 30 days shared, older ones on request the history, sent texts included, without an import a reader, a receiver, a view on the computer more words on every computer; drafts and failed texts unseen; codes hidden for three hours on recent Android
D Sending from the computer (SEND_SMS; phase b, sending), with keys, a ledger and outcomes texts from the computer, filed by Android in the SMS app a sender, a ledger, the outcomes, the view a late text if the expiry is too long; a doubt after a crash, said
E Sioul as the SMS app (phase c) filtering texts before they ring; owning the history; MMS and groups a full SMS and MMS app in Java beside Qt, a QML messaging interface, years of upkeep a lost text when it fails; the role's restricted setting; carriers' MMS quirks
F KDE Connect beside Sioul, today texts and notifications on a Linux computer at home, now nothing to build (Sioul's sms: links already reach it) outside Sioul's matrix and sharing; same network only

Recommendation

  1. A now. It answers the first wish, texts on the computer through the vault, with what the phone already has: no permission, no new Android part, the calls' sharing as the pattern. Keep codes, approvals and pictures on the phone; keep lines a week; pad them; show them at the time their sender may reach the person; Seen stays Sioul's.
  2. C, then D, next: reading the conversations first, as the owner put it, then sending, with the never-twice rules of 5.2. Both stay outside the SMS role, so a fault of Sioul's can delay a text on the computer but never lose one on the phone: the phone's SMS app remains the record.
  3. B only as a choice for chats, if the owner accepts Sioul answering inside other apps; for texts, D is cleaner.
  4. E not now. It would add, over C and D, filtering texts before they ring (the listener already holds their notifications) and owning the history (the SMS app already keeps it), at the cost of becoming the one app whose fault loses a doctor's text. Look again only if /e/OS's Message stops being maintained, or if a need appears that C and D cannot meet.
  5. F meanwhile: for texts at home before A exists, KDE Connect works with Sioul's sms: links today.

Open questions

  1. On the phone: what a listener really receives from /e/OS's Message (the people, the tel: address, the semantic actions); whether a picture's content://mms/part/… address opens for Sioul; which Android version the phone's /e/OS is built on, and so whether the guard (2.1) and the hidden codes (1.2) apply.
  2. Restricted settings: whether the SMS permissions ask again for "Allow restricted settings" once notification access was allowed (they should not: 2.1).
  3. Delivery reports: whether the person's carrier sends them, and whether they cost anything.
  4. Latency: the request-to-sent time through eDrive, and through Sioul keeping the folder itself, measured.
  5. RCS: whether Google Messages still copies RCS chats into the MMS table (a vendor's 2021 report), for people on phones with Google's services.
  6. Two computers in use at once: whether the Porch's lines and the conversations should follow the "notices" lease (porch.md) or show on both.
  7. The computer's copy at rest: whether shared texts kept in Sioul's state on a computer should be sealed there too, unlike the calls' log.

All links were requested on 8 October 2026. Android's source was read through android.googlesource.com's ?format=TEXT at the branches named; developer.android.com pages were read through a scripted fetch; crates.io through its API (/api/v1/crates/<name>); GitHub and /e/'s GitLab through their APIs. Vendors' pages (Microsoft, Google's help, Pushbullet, SyncTech, KDE's userbase) were read through a fetch tool that summarises; the sentences quoted were checked in its answer only.

  • AOSP, android16-release unless said: frameworks/base: telephony/java/android/telephony/SmsManager.java, SubscriptionManager.java, core/java/android/provider/Telephony.java, core/java/android/app/AppOpsManager.java, services/core/java/com/android/server/MmsServiceBroker.java, services/core/java/com/android/server/notification/NotificationManagerService.java; android15-release: core/res/AndroidManifest.xml, core/java/android/content/pm/PackageInstaller.java, services/core/java/com/android/server/pm/PackageInstallerService.java, PackageInstallerSession.java, packages/PackageInstaller/…/InstallInstalling.java, InstallRepository.kt; android16-qpr2-release: SmsManager.java, Telephony.java. frameworks/opt/telephony: SMSDispatcher.java, gsm/GsmSMSDispatcher.java, SmsUsageMonitor.java, InboundSmsHandler.java (and android16-qpr2-release). packages/providers/TelephonyProvider: AndroidManifest.xml, SmsProvider.java (and android16-qpr1, android16-qpr2, android17-release, main), MmsProvider.java, MmsSmsProvider.java, MmsSmsDatabaseHelper.java, ProviderUtil.java. packages/services/Mms: SendRequest.java. packages/modules/Permission: PermissionController/res/xml/roles.xml, service/java/com/android/ecm/EnhancedConfirmationService.java (android15-release, android16-release, main). Base URL: https://android.googlesource.com/platform/.
  • developer.android.com: https://developer.android.com/reference/android/provider/Telephony.Sms; https://developer.android.com/develop/background-work/background-tasks/broadcasts/broadcast-exceptions; https://developer.android.com/training/cars/communication/notification-messaging.
  • Crates: https://crates.io/crates/tpdu, /sms-pdu, /sms-pdu-decoder, /gsm7, /huawei-modem, /qmi-sim-manager, /phone-backup-messages, /rust-rcs-client, /rust-rcs-core, /phonenumber, /rlibphonenumber, /phonelib, /quick-xml, /jni, /jni-sys, /ndk, /ndk-context, /android-activity, /ucs2.
  • Projects: https://github.com/FossifyOrg/Messages (NotificationHelper.kt, AndroidManifest.xml, gradle/libs.versions.toml), https://github.com/FossifyOrg/mmslib, https://gitlab.e.foundation/e/os/Message (NotificationManagerImpl.kt), https://github.com/moezbhatti/qksms, https://github.com/quik-sms/quik, https://github.com/signalapp/Signal-Android, https://github.com/klinker41/android-smsmms, https://github.com/jberkel/sms-backup-plus, https://github.com/KDE/kdeconnect-android (SMSPlugin.kt, SmsMmsUtils.kt, NotificationsPlugin.kt), https://github.com/GSConnect/gnome-shell-extension-gsconnect (src/service/plugin.js, src/service/plugins/sms.js), https://github.com/microg/GmsCore/issues/2994, https://github.com/Hirohumi/RustyRcs.
  • Pages: https://userbase.kde.org/KDEConnect; https://blog.pushbullet.com/2015/08/11/end-to-end-encryption/; https://help.pushbullet.com/articles/play-store-privacy-policy/; https://support.google.com/messages/answer/7611075; https://support.microsoft.com/en-gb/windows/apps/phonelink/send-and-receive-text-messages-from-your-pc; https://signal.org/blog/sms-removal-android/; https://www.synctech.com.au/sms-backup-restore/fields-in-xml-backup-files/; https://www.synctech.com.au/?p=654; https://www.xda-developers.com/google-messages-rcs-api-third-party-apps/; https://www.securityweek.com/google-announces-enhanced-fraud-protection-for-android/; https://blog.google/intl/en-my/company-news/technology/google-launches-enhanced-protection-in-google/; https://betanews.com/2018/10/09/goolge-play-sms-call-logo-policies/; https://discuss.grapheneos.org/d/1353-using-rcs-with-google-messages-on-grapheneos.