Skip to content

android: An okhttp-based Unix Domain Socket server - #13177

Open
jdcormie wants to merge 5 commits into
grpc:masterfrom
jdcormie:uds-server-builder
Open

jdcormie wants to merge 5 commits into
grpc:masterfrom
jdcormie:uds-server-builder

Conversation

@jdcormie

@jdcormie jdcormie commented Nov 7, 2026 •

Copy link
Copy Markdown
Member

Our team uses the okhttp server in our Android apps so our debug/test APIs can be called from an adb-connected host. But TCP/IP has an access-control problem: Android's app sandbox does not generally restrict traffic to localhost, so any installed app holding the normal INTERNET permission can connect and call sensitive APIs whenever the server app is listening.

Unix domain sockets in Linux' abstract namespace avoid this while remaining reachable via adb forward tcp:PORT localabstract:NAME even on unrooted user builds. On Android 9+ (when the hosting app targets API 28+), SELinux's per-app categories block other apps from connecting to the abstract socket, limiting reachability to the app itself, an adb-authorized host (adbd), and privileged system processes. Listening in the file system restricts access to same-uid even on older Android versions, and prevents access via adbd on unrooted devices.

This PR adds only one new public API: UdsServerBuilder, counterpart to the existing UdsChannelBuilder stopgap.

Suggested review order:

  1. Entry point & address: UdsServerBuilder, UdsSocketAddress
  2. Server & Listening Socket Adapters: UdsServerSocketFactory, UdsServerSocket, UdsListeningSocket, UdsAbstractListeningSocket, UdsFilesystemListeningSocket
  3. Connected Socket Adapter & Channelz fix: UdsSocket, UdsSocketFactory

grpc-okhttp's channelz support (Utils.getSocketOptions, reached from the
client and server transports' getStats()) calls getKeepAlive(),
getOOBInline(), getReuseAddress() and getTrafficClass(), and only
catches SocketException (logging Level.SEVERE on catch). Returning false
/ 0 instead of throwing UnsupportedOperationException lets channelz
socket queries succeed cleanly on UDS transports.
@jdcormie
jdcormie force-pushed the uds-server-builder branch 6 times, most recently from c24b4e3 to d139f41 Compare November 10, 2026 19:34
Add the server-side counterpart to UdsChannelBuilder, delegating
reflectively to OkHttpServerBuilder with a package-private
SocketAddress and ServerSocketFactory backed by LocalServerSocket. No
changes to grpc-okhttp or grpc-core are needed. Like UdsChannelBuilder,
only UdsServerBuilder.forPath(String, Namespace) is public and
`@ExperimentalApi` pending a proper unix: address family.

This commit only supports Namespace.ABSTRACT (all LocalServerSocket
itself supports); filesystem sockets and peer-UID authorization may
follow in separate commits. The SELinux reachability tiers documented in
UdsServerBuilder's Javadoc come from AOSP system/sepolicy/private/
{domain.te,app.te,mls} and were verified with SELinux enforcing across
a server/client targetSdk 27 vs. 33 matrix at API 33, adbd (uid 2000),
and cross-app at API 24.

Tested on-device via :grpc-android:connectedDebugAndroidTest against
AOSP emulators at API 24 (minSdk), 26, and 33.
Accept Namespace.FILESYSTEM in UdsServerBuilder.forPath(), binding a
0600 socket file via LocalSocket + LocalServerSocket(FileDescriptor) so
a server under an app-private directory gets kernel-enforced same-UID
access control across all Android versions.

Verified via :grpc-android:connectedDebugAndroidTest against AOSP
emulators at API 24 (minSdk), 26, and 33 (confirming 0700 data-dir and
0771 getFilesDir() modes, stale-socket replacement without clobbering
non-sockets, and adbd uid 2000 refusal when unrooted).
UdsChannelInteropTest and TesterActivity previously proxied a raw
LocalServerSocket through UdsTcpEndpointConnector to a TCP server
because grpc-android had no UDS server. Running both directly against an
in-process UdsServerBuilder removes UdsTcpEndpointConnector and gives
UdsServerBuilder coverage across the 19-case interop matrix on Firebase
Test Lab
:grpc-android now has instrumentation tests under src/androidTest that
require a real Android kernel and were only compiled in presubmit.
Run grpc-android's debug androidTest APK on Firebase Test Lab across
API 24-30 alongside grpc-binder.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant