libbinder: support calls over sockets
Minimal-ish change for basic binder RPC.
This enables binder to work over sockets. The main change to core code
is in 'Parcel' and 'BpBinder'. The Parcel format is now associated with
the binder that it is either for or a reply from (we no longer have
binder 'objects' for the kernel). BpBinder is extended to support
talking over sockets (ideally, this would be a subclass, but
IBinder::localBinder/remoteBinder mean there is a lot of code which
presupposes what type of binder we have).
In addition, we have a few new objects:
- RpcServer - set this up to serve a connection
- RpcConnection - symmetrical object handling dispatch to a known
server/client
- RpcAddress - (this will definitely change) randomly generated
addresses - this might include things like host VM context, ip
address, or similar in the future. In that case, the address
generation should be cryptographically secure.
- RpcState - this keeps track of known binders, their refcounts, and
async transactions, and it understand the binder socket wire
protocol
The connection itself looks like N socket accepts to a server (the
server might have M socket accepts back to the client for symmetrical
connections, that is connections which need more than nested
transactions). The number of these socket connections controls how many
synchronous transactions can be made. Wherever possible, the behavior
here seeks to mimick the binder driver, and some differences are
documented in the code.
After this CL merges, the future work I intend on completing includes:
- support to work over vsock
- performance benchmarking
- optimization of the socket code here (may include delaying refcounts)
- support to pass 'transitive' binders (pass a binder from one service
to a different service, to let it setup a new connection). This task
may be excluded from my efforts as a security hedge if I can manage.
- fuzzer for this wire format
- support for linkToDeath
- support for transaction encryption
- support for promoting from a weak pointer
- handling SIGPIPE for dead connections
- and many more! :)
Bug: 167966510
Test: binderRpcTest
Change-Id: I276c6e312f584b57f4e7a14389ea4a1d63cfa2f4
diff --git a/libs/binder/tests/IBinderRpcTest.aidl b/libs/binder/tests/IBinderRpcTest.aidl
new file mode 100644
index 0000000..2bdb264
--- /dev/null
+++ b/libs/binder/tests/IBinderRpcTest.aidl
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+interface IBinderRpcTest {
+ oneway void sendString(@utf8InCpp String str);
+ @utf8InCpp String doubleString(@utf8InCpp String str);
+
+ // number of known RPC binders to process, RpcState::countBinders
+ int countBinders();
+
+ // Caller sends server, callee pings caller's server and returns error code.
+ int pingMe(IBinder binder);
+ @nullable IBinder repeatBinder(@nullable IBinder binder);
+
+ void holdBinder(@nullable IBinder binder);
+ @nullable IBinder getHeldBinder();
+
+ // Idea is client creates its own instance of IBinderRpcTest and calls this,
+ // and the server calls 'binder' with (calls - 1) passing itself as 'binder',
+ // going back and forth until calls = 0
+ void nestMe(IBinderRpcTest binder, int calls);
+
+ // should always return the same binder
+ IBinder alwaysGiveMeTheSameBinder();
+
+ // Idea is that the server will not hold onto the session, the remote connection
+ // object must. This is to test lifetimes of binder objects, and consequently, also
+ // identity (since by assigning sessions names, we can make sure a section always
+ // references the session it was originally opened with).
+ IBinderRpcSession openSession(@utf8InCpp String name);
+
+ // Decremented in ~IBinderRpcSession
+ int getNumOpenSessions();
+
+ // primitives to test threading behavior
+ void lock();
+ oneway void unlockInMsAsync(int ms);
+ void lockUnlock(); // locks and unlocks a mutex
+
+ // take up binder thread for some time
+ void sleepMs(int ms);
+ oneway void sleepMsAsync(int ms);
+
+ void die(boolean cleanup);
+}