• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #pragma once
17 
18 #include <android-base/unique_fd.h>
19 #include <binder/IBinder.h>
20 #include <binder/RpcAddress.h>
21 #include <utils/Errors.h>
22 #include <utils/RefBase.h>
23 
24 #include <map>
25 #include <optional>
26 #include <thread>
27 #include <vector>
28 
29 // WARNING: This is a feature which is still in development, and it is subject
30 // to radical change. Any production use of this may subject your code to any
31 // number of problems.
32 
33 namespace android {
34 
35 class Parcel;
36 class RpcServer;
37 class RpcSocketAddress;
38 class RpcState;
39 
40 /**
41  * This represents a session (group of connections) between a client
42  * and a server. Multiple connections are needed for multiple parallel "binder"
43  * calls which may also have nested calls.
44  */
45 class RpcSession final : public virtual RefBase {
46 public:
47     static sp<RpcSession> make();
48 
49     /**
50      * This should be called once per thread, matching 'join' in the remote
51      * process.
52      */
53     [[nodiscard]] bool setupUnixDomainClient(const char* path);
54 
55     /**
56      * Connects to an RPC server at the CVD & port.
57      */
58     [[nodiscard]] bool setupVsockClient(unsigned int cvd, unsigned int port);
59 
60     /**
61      * Connects to an RPC server at the given address and port.
62      */
63     [[nodiscard]] bool setupInetClient(const char* addr, unsigned int port);
64 
65     /**
66      * For debugging!
67      *
68      * Sets up an empty connection. All queries to this connection which require a
69      * response will never be satisfied. All data sent here will be
70      * unceremoniously cast down the bottomless pit, /dev/null.
71      */
72     [[nodiscard]] bool addNullDebuggingClient();
73 
74     /**
75      * Query the other side of the session for the root object hosted by that
76      * process's RpcServer (if one exists)
77      */
78     sp<IBinder> getRootObject();
79 
80     /**
81      * Query the other side of the session for the maximum number of threads
82      * it supports (maximum number of concurrent non-nested synchronous transactions)
83      */
84     status_t getRemoteMaxThreads(size_t* maxThreads);
85 
86     [[nodiscard]] status_t transact(const RpcAddress& address, uint32_t code, const Parcel& data,
87                                     Parcel* reply, uint32_t flags);
88     [[nodiscard]] status_t sendDecStrong(const RpcAddress& address);
89 
90     ~RpcSession();
91 
92     wp<RpcServer> server();
93 
94     // internal only
state()95     const std::unique_ptr<RpcState>& state() { return mState; }
96 
97     class PrivateAccessorForId {
98     private:
99         friend class RpcSession;
100         friend class RpcState;
PrivateAccessorForId(const RpcSession * session)101         explicit PrivateAccessorForId(const RpcSession* session) : mSession(session) {}
102 
get()103         const std::optional<int32_t> get() { return mSession->mId; }
104 
105         const RpcSession* mSession;
106     };
getPrivateAccessorForId()107     PrivateAccessorForId getPrivateAccessorForId() const { return PrivateAccessorForId(this); }
108 
109 private:
110     friend PrivateAccessorForId;
111     friend sp<RpcSession>;
112     friend RpcServer;
113     RpcSession();
114 
115     status_t readId();
116 
117     // transfer ownership of thread
118     void preJoin(std::thread thread);
119     // join on thread passed to preJoin
120     void join(base::unique_fd client);
121     void terminateLocked();
122 
123     struct RpcConnection : public RefBase {
124         base::unique_fd fd;
125 
126         // whether this or another thread is currently using this fd to make
127         // or receive transactions.
128         std::optional<pid_t> exclusiveTid;
129     };
130 
131     bool setupSocketClient(const RpcSocketAddress& address);
132     bool setupOneSocketClient(const RpcSocketAddress& address, int32_t sessionId);
133     void addClientConnection(base::unique_fd fd);
134     void setForServer(const wp<RpcServer>& server, int32_t sessionId);
135     sp<RpcConnection> assignServerToThisThread(base::unique_fd fd);
136     bool removeServerConnection(const sp<RpcConnection>& connection);
137 
138     enum class ConnectionUse {
139         CLIENT,
140         CLIENT_ASYNC,
141         CLIENT_REFCOUNT,
142     };
143 
144     // RAII object for session connection
145     class ExclusiveConnection {
146     public:
147         explicit ExclusiveConnection(const sp<RpcSession>& session, ConnectionUse use);
148         ~ExclusiveConnection();
fd()149         const base::unique_fd& fd() { return mConnection->fd; }
150 
151     private:
152         static void findConnection(pid_t tid, sp<RpcConnection>* exclusive,
153                                    sp<RpcConnection>* available,
154                                    std::vector<sp<RpcConnection>>& sockets,
155                                    size_t socketsIndexHint);
156 
157         sp<RpcSession> mSession; // avoid deallocation
158         sp<RpcConnection> mConnection;
159 
160         // whether this is being used for a nested transaction (being on the same
161         // thread guarantees we won't write in the middle of a message, the way
162         // the wire protocol is constructed guarantees this is safe).
163         bool mReentrant = false;
164     };
165 
166     // On the other side of a session, for each of mClientConnections here, there should
167     // be one of mServerConnections on the other side (and vice versa).
168     //
169     // For the simplest session, a single server with one client, you would
170     // have:
171     //  - the server has a single 'mServerConnections' and a thread listening on this
172     //  - the client has a single 'mClientConnections' and makes calls to this
173     //  - here, when the client makes a call, the server can call back into it
174     //    (nested calls), but outside of this, the client will only ever read
175     //    calls from the server when it makes a call itself.
176     //
177     // For a more complicated case, the client might itself open up a thread to
178     // serve calls to the server at all times (e.g. if it hosts a callback)
179 
180     wp<RpcServer> mForServer; // maybe null, for client sessions
181 
182     // TODO(b/183988761): this shouldn't be guessable
183     std::optional<int32_t> mId;
184 
185     std::unique_ptr<RpcState> mState;
186 
187     std::mutex mMutex; // for all below
188 
189     std::condition_variable mAvailableConnectionCv; // for mWaitingThreads
190     size_t mWaitingThreads = 0;
191     // hint index into clients, ++ when sending an async transaction
192     size_t mClientConnectionsOffset = 0;
193     std::vector<sp<RpcConnection>> mClientConnections;
194     std::vector<sp<RpcConnection>> mServerConnections;
195 
196     // TODO(b/185167543): use for reverse sessions (allow client to also
197     // serve calls on a session).
198     // TODO(b/185167543): allow sharing between different sessions in a
199     // process? (or combine with mServerConnections)
200     std::map<std::thread::id, std::thread> mThreads;
201     bool mTerminated = false;
202 };
203 
204 } // namespace android
205