Open source · Apache 2.0

AirDrop and Quick Share, with no Google.

Tarish is file sharing for de‑Googled Android that works with AirDrop and Quick Share. Your phone talks straight to Macs, iPhones, Windows PCs and other Android phones — with no Play Services, sandboxed or otherwise, and no account.

Works with

  • MacAirDrop
  • iPhoneAirDrop
  • Windows 11Quick Share
  • AndroidQuick Share

Send and receive, on the same Wi‑Fi or with no network at all. Tested against the real thing on each, not only against ourselves.

22 MB/s
Quick Share over shared Wi‑Fi
10.5 MB/s
Quick Share over Wi‑Fi Direct, no network
7.7–9.1 MB/s
AirDrop between two Android devices
2.6–4.7 MB/s
AirDrop to an iPhone — it keeps a sparse presence
3.4 MB/s
AirDrop between two devices running our own AWDL stack
210
protocol tests that run without a phone

All measured on hardware, with SELinux enforcing and zero Google apps installed.

On the device

What it actually looks like

Screenshots from a Pixel 10 Pro running a developer build with no Google applications installed. Peer names are the devices’ own — nothing is mocked up.

Quick Share · four ways to move a file

A medium per transfer, upgraded mid‑transfer

Quick Share does not pick one medium and hope. It discovers with no network, starts on a link that always works, and upgrades mid‑transfer to a fast one. Tarish implements the whole ladder, in both directions. Each speed below is to a stock peer, not to ourselves.

Wi‑Fi LAN

same network

A peer publishes its address over mDNS and is reached by connecting to it — TCP, no negotiation. The fast path when both devices are on one Wi‑Fi.

22 MB/s send·21.6 MB in 0.46 s receive

Wi‑Fi Direct

no network

The advertiser hosts a group, the discoverer joins, and the socket is handed across mid‑transfer. The fast path with no shared network at all.

10.5 MB/s·group up in 3.4 s on 5 GHz

Bluetooth

no network · the bootstrap

RFCOMM. Slow but universal — every off‑network transfer starts here and the bandwidth‑upgrade ladder climbs off it to Wi‑Fi Direct.

~150 KB/s send·~115 KB/s receive

Bluetooth LE

discovery

Advertise and scan, both ways. How two phones see each other with no network — framework BLE the app reaches, since a native daemon cannot.

the handshake before any of the above

The upgrade is for peers with no shared network; on one subnet Wi‑Fi LAN needs no negotiation and is already the fast path. AirDrop to Apple devices takes a different road entirely — AWDL, below.

How it works

An app, a daemon, and the other device

The app

Java · privileged system app

  • share sheet and prompts
  • Bluetooth LE
  • Wi‑Fi Direct groups
  • hands the daemon a socket

The daemon

Rust · its own SELinux domain

  • the AWDL link
  • mDNS and TLS
  • AirDrop over HTTP
  • UKEY2 and Quick Share

The other device

unmodified

  • Mac
  • iPhone
  • Windows PC
  • Android phone

Every layer is open source except the radio. AWDL — the layer Google ships as the closed libmosey — has an open implementation here, tarish-link: it brings the Pixel’s radio up, runs the master election and time sync with Apple devices, and carries IP. The one layer that stays a vendor’s is the Wi‑Fi driver and its firmware — the way a network card’s does.

The stack

Every layer but one is open source

AirDrop and Quick Share are each a tower of protocols, not a single feature. Tarish implements the tower — top to bottom — and stops only at the radio the vendor ships. Here is the whole thing, and who wrote each layer.

  1. Share sheet & prompts the app — Java, privileged system component; Wi‑Fi Direct groups and BLE open source
  2. AirDrop mDNS, TLS, the HTTP Discover / Ask / Upload exchange, Apple record formats open source
  3. Quick Share UKEY2 handshake, D2D keys, offline frames, the bandwidth‑upgrade ladder open source
  4. Secure channel HKDF, SecureMessage, sequence numbers, replay refusal — 210 tests open source
  5. AWDL new master election, time sync, channel sequence — tarish-link, replacing libmosey open source
  6. 802.11 bring‑up & injection netlink vendor commands, monitor‑mode transmit and capture — tlink-hal open source
  7. Radio driver & firmware wonder.ko + the Broadcom firmware — the one closed layer, and the vendor’s to ship vendor

The AWDL layer has an open implementation, tarish-link — see the lab.

Just landed

A note from an iPhone, actually readable

Share a note from an iPhone and it arrives as a .notesairdropdocument — an Apple Notes protobuf that nothing on Android can open. So you receive your own note, sealed.

Tarish unpacks it: the text as a .txt, each voice recording as a playable .m4a, byte‑identical to what was inside. The original stays, because it is the only thing that goes back to an Apple device intact.

one audio note in

  • .notesairdropdocumentthe original, kept
  • .txtthe note’s text
  • .m4arecording one
  • .m4arecording two

four files out

The lab

tarish-link: an open AWDL implementation

AirDrop moves its bytes over AWDL, Apple’s peer‑to‑peer Wi‑Fi. tarish-link is an independent reimplementation of it — built from over‑the‑air captures, published research and the Wireshark dissector, not from anyone’s source. In Tarish’s builds it runs in place of libmosey for the core AirDrop path — on a Pixel it brings the radio up, wins Apple’s election against real iPhones, and synchronises to an Apple device’s schedule. Sending works too — a 20 MB file to an iPhone with no libmosey in the path, in 5.5 seconds. One iPhone used to take 61 seconds for the same file; that turned out to be our own send path transmitting bulk frames three times over, not the peer, and it now takes 3–7 seconds. What that took:

no libmosey

Our own netlink code drives Google’s radio shim — the vendor commands, the monitor, the transmit path — and airs AWDL frames. The binary links no Google library at all.

Apple elects us

Advertise a winning metric and real iPhones adopt us as their master. It tracks the number we send: 530 loses to a stronger peer, 600 wins. Their own election logic, acting on our frames.

we sync to Apple

Declining the election, we track a real Apple master’s availability windows to about 10 ms inside a 65 ms slot — in software, the way libmosey does it.

slot 8 → ch 6

Every device keeps slot 8 of its 16‑slot schedule on channel 6, in all 556 sequences observed — a fixed cross‑band meeting point, and one of many findings from the captures.

Twelve of AWDL’s tags decoded — election, sync and channel sequence at 100%, with the 6 GHz tags (32, 33) the main gap. Built from captures, the 2018 AWDL paper by Stute et al., and Wireshark’s dissector read as a specification.

Devices

It comes down to the Wi‑Fi chip

AirDrop needs Google’s wonder radio shim bound to the Wi‑Fi driver, and that depends on the silicon, not the model name.

While AirDrop is running, the phone is off Wi‑Fi. Raising the AirDrop link drops the Wi‑Fi association and it does not hold — on every device below, ours and stock alike. That is the radio rather than this implementation, so it is a property to plan around and not a bug waiting on a fix. Quick Share over a shared network is unaffected, because it needs no AirDrop link at all.

And set the Apple device to “Everyone”. In “Contacts Only” an iPhone or Mac withholds its name and refuses transfers unless the sender proves it is in their contacts with an Apple‑signed record. That needs an Apple ID — the one thing this project is built not to have — so a contacts‑only device shows up unnamed and accepts nothing. Apple’s design, and not something an account‑free implementation can work around.

adb shell ls /sys/class/ieee80211/  # wonder = yes
  • Pixel 10 Pro, 10 Pro XLBCM4390 — both protocols, but AirDrop takes the Wi‑Fi radio while it runs
  • Pixel 10BCM4383 — AirDrop works, and takes the Wi‑Fi radio while it runs
  • Pixel 10ano wonder — Quick Share only

For system integrators

Built to be adopted into an OS image

Tarish ships inside the system image, not from an app store: two native daemons, a privileged app, and a SELinux policy an administrator can pin. Nothing is OS‑specific by design — the daemon asks the platform for an AWDL library and a kernel module and does not care where they came from. It runs on a custom Android image today. LineageOS is coming soon — that work is under way and is not ready.

What you add

  • tarishd — holds the AWDL link. CAP_NET_ADMIN, uid system.
  • tarishsharingd — parses what strangers send. No capabilities, its own uid.
  • TarishApp — share sheet, consent, the framework radio work. Privileged.
  • SELinux policy — two domains, plus file, service and property contexts.
  • one framework patch — a single local‑network grant in packages/modules/Connectivity.

The split is the security design: the process holding CAP_NET_ADMIN never parses remote input, and the process parsing remote input holds nothing.

What the platform provides

  • For AirDrop — Google’s wonder.ko, the silicon‑tied kernel module, already in the Pixel vendor image; Tarish drives it. The AWDL userspace is tarish-link (tlink), Tarish’s own, which every build ships — not Google’s libmosey.
  • For Quick Share — nothing beyond Wi‑Fi. It is plain Wi‑Fi and runs on any device.

The vendor pin lives with the integrator, not in either repository — which is what keeps the daemon portable to LineageOS or plain AOSP without carrying one integrator’s vendor decisions.

Three traps that look like success

file_contexts

Install the .te without it and the build succeeds, the domain exists, and nothing ever runs in it — init cannot transition without the label.

the empty table

A new interface gets its own routing table, and it starts empty. connect() returns ENETUNREACH on a healthy link until fe80::/64 is added to that table.

country 00

The world regulatory domain forbids channel 149. The vendor library accepts it, logs a healthy bring‑up, then returns NULL. tarishd refuses to start without a real country.

For developers

Every part of a transfer, without touching a screen

tarishctl drives the daemon from a shell over the same binder interface the app uses — there is no private back channel, because a debug tool that reaches past the real interface tests something nobody ships. Two phones, a script, no taps: that is how most of the interoperability work here was actually done.

# B advertises and accepts without prompting; A finds it and sends
adb -s $B shell tarishctl policy confirm off
adb -s $B shell tarishctl discoverable on 120

adb -s $A shell tarishctl refresh
PEER=$(adb -s $A shell tarishctl peers | awk '$2==1 {print $1; exit}')
adb -s $A shell tarishctl send "$PEER" /sdcard/Download/test.bin

adb -s $B shell tarishctl received

Numbers, not labels

peers prints the protocol and state as the integers the interface uses, so a test matches on 1 rather than on whatever English word was on screen that week. The name comes last, because it can contain spaces.

The transports the daemon cannot reach

Bluetooth and Wi‑Fi Direct need framework API a native daemon has no access to, so both were skipped in every end‑to‑end run until this existed. app send drives the Bluetooth bootstrap and the Wi‑Fi Direct upgrade after it, in one command.

Only where it belongs

It can start a transfer and accept an incoming one, so it is restricted twice over — in the makefile and again in SELinux policy. It is not part of a shipped image.

Full command reference: TARISHCTL.md.

For managed deployments

It behaves under a VPN kill‑switch, rather than around it

A device with an always‑on VPN in lockdown mode blocks outbound traffic that is not in the tunnel. Tarish treats that as a hard requirement: it never asks for the kill‑switch to be turned off, and ships nothing that would let it be. Where sharing cannot work inside it, sharing loses.

What an administrator controls

  • Managed configuration — four typed keys through the platform mechanism, not a vendor one. Each protocol, each direction.
  • A managed value pins the setting — the user cannot override it, and the interface names the source rather than silently disabling a control.
  • Absent means unmanaged — a key that is not set leaves the user’s own choice alone. Presence is tested, not a default value.
  • An unrecognised value reads as off — a restriction that cannot be honoured is honoured restrictively.
  • Enforcement is in the daemon, not the interface, so it holds whatever the app does.

What happens under lockdown

  • Receiving is never affected. Both blocking rules match locally generated traffic only, so inbound is never touched.
  • AirDrop is unaffected in both directions, because its routing rule is bound to one interface and the daemon binds its socket there.
  • Quick Share off‑network still sends, over Bluetooth rather than Wi‑Fi Direct. Slower, not broken.
  • Quick Share over the local network is blocked while the kill‑switch is on and no VPN is connected — deliberately. That is routed traffic on a managed network, which is what a kill‑switch exists to stop.

Discovery is multicast receive and is never blocked, so peers still appear in the list and only the connection fails. Worth knowing before it puzzles someone.

The exemption is bound to a person, not to a setting

Sharing on a link‑local interface needs one routing rule to sit above the kill‑switch. A permanent exemption would answer the wrong question. An administrator is not asking how much it can reach — they are asking who decided, and whether they were there. A phone in a drawer with an always‑on hole fails that test however small the hole is.

one priority

Authentication moves the rule above the block and nothing else. With no kill‑switch present, authenticating changes nothing observable — there was nothing to exempt.

silence closes it

The daemon asks the app every few seconds whether the window should stay open. No valid answer and the exemption is withdrawn. Nothing has to be delivered by a dying process, so there is no teardown path to get wrong.

fail‑closed

A missing, stale or unreadable state means not exempt. The failure mode is losing the exemption, never keeping it.

Status: managed configuration is built and in use. The authenticated window is built and largely verified on hardware, but is not yet wired into the normal share flow — today the exemption exists while AirDrop is on. The public document carries the measurements, the threat model with its five scopings, and the residual risk stated plainly.

Maintain a distribution and want Tarish in the image? Open an issue.

Get involved

Built into the system image

Tarish ships inside the system image: a daemon with its own SELinux domain and a privileged app. It runs on a custom Android image today; LineageOS is coming soon.

Maintain an AOSP distribution and want this in your image? Open an issue.

$ tarishctl peers
# 0 = AirDrop · 1 = Quick Share
7c1e04a9b2f3  0  MacBook Pro
f02d9e6a1c8b  0  iPhone
Q7XA          1  Pixel 9
R2MC          1  ThinkPad
$ tarishctl send 7c1e04a9b2f3 /sdcard/talk.mov
12
$ tarishctl accept 13
# the Mac asked; we said yes
How Tarish gets built and tested: two phones, a script, no screen taps. tarishctl is a debug tool for userdebug and eng builds — it is not part of a release image.