{"id":18217262,"url":"https://github.com/manio/aa-proxy-rs","last_synced_at":"2025-04-10T11:51:43.010Z","repository":{"id":260865818,"uuid":"880802913","full_name":"manio/aa-proxy-rs","owner":"manio","description":"AndroidAuto wired/wireless proxy","archived":false,"fork":false,"pushed_at":"2025-03-31T10:10:17.000Z","size":1372,"stargazers_count":40,"open_issues_count":8,"forks_count":4,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-03-31T11:23:37.340Z","etag":null,"topics":["android-auto","io-uring","raspberry-pi","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/manio.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-10-30T11:45:07.000Z","updated_at":"2025-03-31T10:10:20.000Z","dependencies_parsed_at":null,"dependency_job_id":"6e9bbf1c-6ead-4c47-b83a-ae18cc9da1f8","html_url":"https://github.com/manio/aa-proxy-rs","commit_stats":{"total_commits":29,"total_committers":1,"mean_commits":29.0,"dds":0.0,"last_synced_commit":"718124c357a59aa602a996811536adbe75208724"},"previous_names":["manio/aa-proxy-rs"],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/manio%2Faa-proxy-rs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/manio%2Faa-proxy-rs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/manio%2Faa-proxy-rs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/manio%2Faa-proxy-rs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/manio","download_url":"https://codeload.github.com/manio/aa-proxy-rs/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248215191,"owners_count":21066621,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android-auto","io-uring","raspberry-pi","rust"],"created_at":"2024-11-03T17:04:09.259Z","updated_at":"2025-04-10T11:51:43.002Z","avatar_url":"https://github.com/manio.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🛸 aa-proxy-rs\n\n## About\nThis is a Rust-Written proxy tool to bridge between wireless Android phone and a USB-wired car head unit for using Google's Android Auto.\nCurrently it is intended to run as a more-or-less drop-in replacement of the `aawgd` from the [WirelessAndroidAutoDongle](https://github.com/nisargjhaveri/WirelessAndroidAutoDongle) project.\n\n## Features\n- written in [Rust](https://www.rust-lang.org/): reliable code and minimized all memory related issues and bugs\n- fast: main IO loop is using modern [io_uring](https://kernel.dk/io_uring.pdf) kernel API\n- reconnecting: trying to reconnect/recover AndroidAuto connection in any possible case\n- bandwidth/transfer statistics\n- stall transfer detection\n- MITM (man-in-the-middle) mode support with the following features:\n  - DPI change\n  - Disable media sink\n  - Disable TTS sink\n  - Developer mode\n\n## Current project status\nNow after a lot of stress-testing and coding I think the project has matured enough, that I can say that the main stability goal was reached.\nI am using this project almost daily in my car and trying to get rid of all issues I may encounter.\n\n## SD card images\nI am using Nisarg's RaspberryPi images from [WirelessAndroidAutoDongle](https://github.com/nisargjhaveri/WirelessAndroidAutoDongle) project and replacing `aawgd` with `aa-proxy-rs`.\u003cbr\u003e\nThose images are available on the [Release page](https://github.com/manio/aa-proxy-rs/releases).\u003cbr\u003e\nYou can also find there a pure `aa-proxy-rs` binary which you can install manually on targets with similar libc versions, or build your own (read below: [Installing into target](#installing-into-target) and [Building](#building)).\n\n## History and motivation\nThere are a lot of commercial solutions like AAWireless or Motorola MA1. I even bought a clone of those on AliExpress, but it ended up not working in my car (passed to my friend which has a compatible car for this).\n\nThen thanks to [Nicnl](https://www.reddit.com/user/Nicnl/) from reddit under my [post](https://www.reddit.com/r/RenaultZoe/comments/1c5eg2g/working_wireless_aa_for_rlink1_based_zoe/),\nI headed to a great open source solution, based on Raspberry Pi hardware:\u003cbr\u003e\n[WirelessAndroidAutoDongle](https://github.com/nisargjhaveri/WirelessAndroidAutoDongle) by [Nisarg Jhaveri](https://github.com/nisargjhaveri)\n\nThe author made a lot of great research and created a DIY working solution, and - what is most important - he shared his work to the public.\nThis is so cool and I really appreciate his work!\nBecause it's open source, I was even able to run my own additional LoRa hardware on the same Raspberry Pi for different purpose!\n\nThe original project is using `aawgd` daemon which is doing the necessary proxying of data between the phone and USB port.\n(Un)fortunately the project was not always working reliable for me (crashing, unable to reconnect, need restarting, etc.).\nFinally after making this [PR](https://github.com/nisargjhaveri/WirelessAndroidAutoDongle/pull/196), I decided that I will try to make the Rust-based alternative.\nAnd this is where this project begins and I started to reimplement the `aawgd` C++ code into rust application.\n\n## Coding\nI was trying to simplify things and original code where it was possible.\nIt was also a great opportunity and fun to learn how it was designed and how it is working, but I have to admit that I was struggling a lot with doing a final forwarding I/O:\nnormally I would just use [copy_bidirectional](https://docs.rs/tokio/latest/tokio/io/fn.copy_bidirectional.html) for this as the whole code is async and using [tokio](https://tokio.rs/), but\nthe problem with it was, that the USB socket for the \"usb-gadget\" kernel module seems to be not compatible with this approach (probably some polling/epoll problems).\nI was also trying to call read/writes in tokio tasks, but finally I decided to use different approach: using modern [io_uring](https://kernel.dk/io_uring.pdf) kernel API provided by [tokio_uring](https://github.com/tokio-rs/tokio-uring).\nAnd this finally worked perfectly fine (and also really efficient as a bonus).\n\n## Limitations\n- Currently only the default \"connection strategy\" is supported.\n- Because the project main functionality (data transfer) is dependent on kernel [io_uring](https://kernel.dk/io_uring.pdf) API, the Linux kernel has to be in version 5.10 or later.\n- My time resources are limited, so don't expect to prompt answers and ETAs on different requests. I am doing this as a hobby in my spare time.\n\n## How it works (technical)\n![Hardware overview](images/aa-proxy-rs.webp)\nThe whole connection process is not trivial and quite complex. Here I am listing the needed steps the app is doing from the start to make a connection:\n- USB: disabling all gadgets\n- USB: registering uevents (for receiving USB state changes)\n- Starting local TCP server\n- Bluetooth: powering up the bluetooth adapter and make it discoverable and pairable\n- Bluetooth: registering two profiles: one for android auto, and the other for fake headset (fooling the phone we are supported wireless AndroidAuto head unit)\n- When a phone connects to the AA profile the app is sending two frames of specific google protocol data:\n  - WifiStartRequest: with IP address and port of the destination TCP server/connection\n  - WifiInfoResponse: with Access Point information for the WiFi connection\n- after successfull response for the above, the tool is disabling bluetooth\n- the phone is connecting to car's head unit bluetooth (e.g. for phone calls)\n- in the same time the phone is connecting via WiFi to our TCP server on specified port\n- USB: switching to \"default\" followed by \"accessory\" gadgets to enable proper USB mode for data transmission to the car head unit (fooling that we are the android phone connected via USB)\n- final (and normal working stage): bidirectional forwarding the data between TCP client (phone) and USB port (car)\n\nUSB is the active part here (starting the transmission by sending 10-bytes first frame), so all of this has to be done with well timing, i.e., if we start the USB dongle connection too fast\n(when the phone is not yet connected), then it would start the transmission, and we don't have a TCP socket ready; similar in the other direction: when the phone starts too fast, and we are\nnot ready with USB connection then we can't send data to the phone and Android will close/timeout the connection.\n\n## Demo\n[![asciicast](https://asciinema.org/a/686949.svg)](https://asciinema.org/a/686949)\n\n## Building\n`rpi02w` binaries build by [WirelessAndroidAutoDongle](https://github.com/nisargjhaveri/WirelessAndroidAutoDongle) are for `arm-unknown-linux-gnueabihf` 32-bit architecture, probably\nbecause of usb-gadget module [incompatibility](https://github.com/nisargjhaveri/WirelessAndroidAutoDongle/pull/129).\nTo be able to properly crosscompile output binary I provided `.cargo/config.toml` with target set for this specific arch.\n\n### Dependencies\n1. [Installing Rust](https://www.rust-lang.org/tools/install)\n2. `gcc-arm-linux-gnueabihf` package is needed on Debian. This is distro-depended so I recommend to RTFM.\n\nTo compile you need to add proper rustup target with:\n```\nrustup target add arm-unknown-linux-gnueabihf\n```\nand make sure that it is _installed_ on target list:\n```\narm-unknown-linux-gnueabihf (installed)\n```\nand then use:\n```\ncargo build --release\n```\n\nTo compile a STATIC `aa-proxy-rs` binary (to be able to use it on target with older OSes and different libc versions), you need to compile with:\n```\nRUSTFLAGS='-C target-feature=+crt-static' cargo build --release\n```\n\n## Building using Docker\nTo build with Docker you need to have a [buildx](https://github.com/docker/buildx) and [BuildKit](https://github.com/moby/buildkit).\u003cbr\u003e\nDocker container is also preparing an SD card images based on [@nisargjhaveri](https://github.com/nisargjhaveri)'s [latests assets](https://github.com/nisargjhaveri/WirelessAndroidAutoDongle/releases).\nIt has to loop-mount that images, thus an insecure builder is [needed](https://docs.docker.com/reference/cli/docker/buildx/build/#allow).\nTo sum it up - the following commands are needed when building for the first time:\n```\nmkdir out\ndocker buildx create --use --name insecure-builder --buildkitd-flags '--allow-insecure-entitlement security.insecure'\ndocker buildx build --builder insecure-builder --allow security.insecure --output out .\n```\nAfter successful execution the resulting `aa-proxy-rs` and SD card images will be in `out` directory.\n\n## Installing into target\nIf you currently using a Raspberry Pi with working _WirelessAndroidAutoDongle_, then you can also manually install `aa-proxy-rs`:\n\nYou need to transfer the resulting output binary to the target filesystem and start it. I am using ssh/scp for this, but it should be also possible with `wget`.\nYou can also do it \"offline\" by making a changes directly on the SD card: mounting system partition and make necessary changes.\nSample [startup script](https://raw.githubusercontent.com/manio/aa-proxy-rs/refs/heads/main/contrib/S93aa-proxy-rs) is provided for convenience.\n\nExample steps:\n- put `aa-proxy-rs` into /usr/bin\n- put `S93aa-proxy-rs` into /etc/init.d\n- remove or disable /etc/init.d/S93aawgd\n\nStartup parameters (see below) are defined [here](https://github.com/manio/aa-proxy-rs/blob/main/contrib/S93aa-proxy-rs#L10).\n\n## Usage\n```\naa-proxy-rs 0.3.0\nAndroidAuto wired/wireless proxy\n\nUSAGE:\n    aa-proxy-rs [OPTIONS]\n\nOPTIONS:\n    -a, --advertise\n            BLE advertising\n\n    -b, --btalias \u003cBTALIAS\u003e\n            BLE device name\n\n    -c, --connect \u003cCONNECT\u003e\n            Auto-connect to saved phone or specified phone MAC address if provided\n\n    -d, --debug\n            Enable debug info\n\n        --developer-mode\n            MITM: Developer mode\n\n        --disable-media-sink\n            MITM: Disable media sink\n\n        --disable-tts-sink\n            MITM: Disable TTS sink\n\n        --dpi \u003cDPI\u003e\n            MITM: Force DPI (experimental)\n\n    -f, --full-frames\n            Pass only complete frames during data transfer to the headunit\n\n    -h, --help\n            Print help information\n\n        --hostapd-conf \u003cHOSTAPD_CONF\u003e\n            hostapd.conf file location [default: /etc/hostapd.conf]\n\n    -i, --iface \u003cIFACE\u003e\n            WLAN / Wi-Fi Hotspot interface [default: wlan0]\n\n    -k, --keepalive\n            Keep alive mode: BLE adapter doesn't turn off after successful connection, so that the\n            phone can remain connected (used in special configurations)\n\n    -l, --legacy\n            Enable legacy mode\n\n    -l, --logfile \u003cLOGFILE\u003e\n            Log file path [default: /var/log/aa-proxy-rs.log]\n\n    -m, --mitm\n            Enable MITM mode (experimental)\n\n    -s, --stats-interval \u003cSECONDS\u003e\n            Interval of showing data transfer statistics (0 = disabled) [default: 0]\n\n    -t, --timeout-secs \u003cSECONDS\u003e\n            Data transfer timeout [default: 10]\n\n    -u, --udc \u003cUDC\u003e\n            UDC Controller name\n\n    -V, --version\n            Print version information\n```\nMost options are self explanatory, but these needs some more attention:\u003cbr\u003e\n- `-l, --legacy`\u003cbr\u003e\nOriginal `aawgd` is using two USB gadgets: **default** and **accessory**. When connecting to car headunit, it switches first to **default** then to **accessory**.\nDuring my development I found out that my car headunit doesn't need this switching. It is working fine connecting directly to **accessory** gadget.\nMoreover with this approach it is much faster and doesn't need to wait for USB events in dedicated _UEvent_ thread. As the result I decided to leave the old (legacy)\ncode under this switch for compatibility with some headunits.\u003cbr\u003e\nIn short: if you have problems with USB connection try to enable the legacy mode.\n\n- `-c, --connect \u003cCONNECT\u003e`\u003cbr\u003e\nBy default without this switch the aa-proxy-rs is starting but it is only visible as a bluetooth dongle, to which you have to connect manually from your phone to\ninitiate AndroidAuto connection. If I am correct this was called `dongle mode` in `aawgd`.\u003cbr\u003e\nIf you provide `-c` switch without any additional address, then the daemon is trying to connect to known (paired?) bluetooth devices (phones) in a loop\n(the **bluetoothd** have a cached list of recently connected devices in /var/lib/bluetooth). This is the default mode for `aawgd` for the time I am writing this.\u003cbr\u003e\nIf you provide `-c MAC_ADDRESS` where MAC_ADDRESS is the MAC of your phone (bluetooth), then the aa-proxy-rs will try to connect only to this specified device\nin a loop (ignoring all **bluetoothd** cached devices).\n\n## MITM mode\nMan-in-the-middle mode support has been added recently. This is the mode which allows to change the data passed between the HU and the phone.\nSeparate encrypted connections are made to each device to be able to see or modify the data passed between HU and MD.\u003cbr\u003e\nThis is opening new possibilities like, e.g., forcing HU to specific DPI, adding EV capabilities to HU/cars which doesn't support this Google Maps feature.\u003cbr\u003e\nAll the above is not currently supported but should be possible and easier with this mode now implemented.\u003cbr\u003e\nTo have this mode working you need to pass `-m, --mitm` command line switch and provide certificate and private key for communication for both ends/devices.\nDefault directory where the keys are search for is: `/etc/aa-proxy-rs/`, and the following file set needs to be there:\u003cbr\u003e\n- hu_key.pem\n- hu_cert.pem\n- md_key.pem\n- md_cert.pem\n- galroot_cert.pem\n\nI will not add these files into this repository to avoid potential problems. You can find it in other places, or even other git repos, like:\u003cbr\u003e\n- https://github.com/tomasz-grobelny/AACS/tree/master/AAServer/ssl\n- https://github.com/tomasz-grobelny/AACS/tree/master/AAClient/ssl\n- https://github.com/lucalewin/vehiculum/tree/main/src/server/cert\n- https://github.com/lucalewin/vehiculum/tree/main/src/client/cert\n- https://github.com/borconi/headunit/blob/master/jni/hu_ssl.h#L29\n\nSpecial thanks to [@gamelaster](https://github.com/gamelaster/) for the help, support and his [OpenGAL Proxy](https://github.com/gamelaster/opengal_proxy) project.\n\n### DPI settings\nThanks to above MITM mode a DPI setting of the car HU can be forced/replaced. This way we can change the hardcoded value to our own. This is allowing to view more data (at cost of readability/font size).\u003cbr\u003e\nExample with Google Maps, where a `Report` button is available after changing this value:\n\n|160 DPI (default)|130 DPI|\n|---|---|\n|![](images/160dpi.png)|![](images/130dpi.png)\n\n## Troubleshooting\nSometimes deleting the system Bluetooth cache at /var/lib/bluetooth and restarting bluetoothd fixes persistent issues with device connectivity.\nConsider also using \"Forget\" of bluetooth device in the Android phone.\n\nApplication by default is logging into _/var/log/aa-proxy-rs.log_ file. This log could be helpful when trying to solve issues.\nIf you want to get logs out of device, read [here](https://github.com/nisargjhaveri/WirelessAndroidAutoDongle?tab=readme-ov-file#getting-logs) how to obtain it.\n\n## Hardening / making system read-only\nSometimes it is desirable (because of SD cards longevity) to make a whole system read-only. This would also help because we don't have any control when the car headunit is powering off the dongle (USB port).\u003cbr\u003e\nIn some corner cases the filesystem could be damaged because the system is not properly shutdown and unmounted.\n\nWhen you have the dongle set up properly and it is working as intended (you was connecting with your phone to the car, BT was paired, AA is working) you can make the following changes in the SD card:\n\n_Partition #1 (boot):_\u003cbr\u003e\nedit the `cmdline.txt` file and add `ro` at the end of the line\n\n_Partition #2 (main filesystem):_\n```diff\n--- old/etc/fstab\t2024-03-30 17:44:15.000000000 +0100\n+++ new/etc/fstab\t2024-05-03 16:33:48.083059982 +0200\n@@ -1,5 +1,5 @@\n # \u003cfile system\u003e\t\u003cmount pt\u003e\t\u003ctype\u003e\t\u003coptions\u003e\t\u003cdump\u003e\t\u003cpass\u003e\n-/dev/root\t/\t\text2\trw,noauto\t0\t1\n+/dev/root\t/\t\text2\tro,noauto\t0\t1\n proc\t\t/proc\t\tproc\tdefaults\t0\t0\n devpts\t\t/dev/pts\tdevpts\tdefaults,gid=5,mode=620,ptmxmode=0666\t0\t0\n tmpfs\t\t/dev/shm\ttmpfs\tmode=0777\t0\t0\ndiff -Nru 22/etc/inittab pizero-aa-backup/p2/etc/inittab\n--- old/etc/inittab\t2024-03-30 18:57:51.000000000 +0100\n+++ new/etc/inittab\t2024-05-03 16:45:24.184119996 +0200\n@@ -15,7 +15,7 @@\n\n # Startup the system\n ::sysinit:/bin/mount -t proc proc /proc\n-::sysinit:/bin/mount -o remount,rw /\n+#::sysinit:/bin/mount -o remount,rw /\n ::sysinit:/bin/mkdir -p /dev/pts /dev/shm\n ::sysinit:/bin/mount -a\n ::sysinit:/bin/mkdir -p /run/lock/subsys\n```\n\nAgain: before doing this, make sure that you've connect your phone at least once and all is working fine, specifically the `/var/lib/bluetooth/` directory is populated with your phone pairing information.\u003cbr\u003e\nThis way after reboot all partitions will stay in read-only mode and should work longer and without possible problems.\n\nIf you want to make some changes to the filesystem or pair new phone you should revert those changes and it will be read-write again.\u003cbr\u003e\nIt should be also possible to `ssh` and execute:\u003cbr\u003e\n`mount -o remount,rw /`\u003cbr\u003e\nto make root filesystem read-write again temporarily.\n\n## Similar/other open source AndroidAuto-related projects\n- https://github.com/nisargjhaveri/WirelessAndroidAutoDongle\n- https://github.com/nisargjhaveri/AAWirelessGateway\n- https://github.com/openDsh/openauto\n- https://github.com/qhuyduong/AAGateway\n- https://github.com/Demon000/web-auto\n- https://github.com/f1xpl/openauto\n- https://github.com/gamelaster/opengal_proxy\n- https://github.com/tomasz-grobelny/AACS\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmanio%2Faa-proxy-rs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmanio%2Faa-proxy-rs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmanio%2Faa-proxy-rs/lists"}