xref: /aosp_15_r20/system/chre/host/common/include/chre_host/socket_client.h (revision 84e339476a462649f82315436d70fd732297a399)
1 /*
2  * Copyright (C) 2017 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 
17 #ifndef CHRE_HOST_SOCKET_CLIENT_H_
18 #define CHRE_HOST_SOCKET_CLIENT_H_
19 
20 #include <atomic>
21 #include <condition_variable>
22 #include <mutex>
23 #include <thread>
24 #include <vector>
25 
26 #include <cutils/sockets.h>
27 #include <utils/RefBase.h>
28 #include <utils/StrongPointer.h>
29 
30 namespace android {
31 namespace chre {
32 
33 class SocketClient {
34  public:
35   SocketClient();
36   ~SocketClient();
37 
38   /**
39    * Represents the callback interface used for handling events that occur on
40    * the receive thread. Note that it is *not* safe to call connect(),
41    * connectInBackground(), or disconnect() from the context of these callbacks.
42    */
43   class ICallbacks : public VirtualLightRefBase {
44    public:
45     /**
46      * Invoked from within the context of the read thread when a message is
47      * received on the socket.
48      *
49      * @param data Buffer containing received message data
50      * @param length Size of the message in bytes
51      */
52     virtual void onMessageReceived(const void *data, size_t length) = 0;
53 
54     /**
55      * Called when the socket is successfully (re-)connected.
56      */
onConnected()57     virtual void onConnected(){};
58 
59     /**
60      * Called when we have failed to (re-)connect the socket after many attempts
61      * and are giving up.
62      */
onConnectionAborted()63     virtual void onConnectionAborted(){};
64 
65     /**
66      * Invoked when the socket is disconnected, and this connection loss was not
67      * the result of an explicit call to disconnect(), i.e. the connection was
68      * terminated on the remote end.
69      */
onDisconnected()70     virtual void onDisconnected(){};
71   };
72 
73   /**
74    * Synchronously attempts to connect to the Android reserved namespace socket
75    * with the given name. If this connection attempt is successful, starts a
76    * receive thread to handle messages received on the socket, and uses this
77    * thread to automatically reconnect if disconnected by the remote end.
78    *
79    * @param socketName Name of the Android domain socket to connect to
80    * @param callbacks
81    *
82    * @return true if the connection was successful
83    */
84   bool connect(const char *socketName,
85                const ::android::sp<ICallbacks> &callbacks);
86 
87   /**
88    * Starts up the receive thread and attempts to connect to the socket in the
89    * background. The onConnected() callback will be invoked when the socket is
90    * connected successfully, or onConnectionAborted() will be invoked if the
91    * connection could not be made after many retries and the client is giving
92    * up.
93    *
94    * @param socketName Name of the Android domain socket to connect to
95    * @param callbacks
96    *
97    * @return true if the receive thread was started and will attempt to connect
98    *         the socket asynchronously
99    */
100   bool connectInBackground(const char *socketName,
101                            const ::android::sp<ICallbacks> &callbacks);
102 
103   /**
104    * Performs graceful teardown of the socket. After this function returns, this
105    * object will no longer invoke any callbacks or hold a reference to the
106    * callbacks object provided to connect().
107    */
108   void disconnect();
109 
110   /**
111    * @return true if the socket is currently connected
112    */
113   bool isConnected() const;
114 
115   /**
116    * Send a message on the connected socket. Safe to call from any thread.
117    *
118    * @param data Buffer containing message data
119    * @param length Size of the message to send in bytes
120    *
121    * @return true if the message was successfully sent
122    */
123   bool sendMessage(const void *data, size_t length);
124 
125  private:
126   //! The maximum length of a socket name.
127   static constexpr size_t kMaxSocketNameLen = 64;
128 
129   //! Receive buffer size.
130   //! The maximum message size is 32000 bytes plus some for encoding.
131   static constexpr size_t kMaxPacketSize = 32 * 1024;
132 
133   char mSocketName[kMaxSocketNameLen];
134   sp<ICallbacks> mCallbacks;
135 
136   std::atomic<int> mSockFd;
137   std::thread mRxThread;
138 
139   //! Set to true when we initiate the graceful socket shutdown procedure, so we
140   //! know not to invoke onSocketDisconnectedByRemote()
141   std::atomic<bool> mGracefulShutdown;
142 
143   //! Condition variable used as the method to wake the RX thread when we want
144   //! to disconnect, but it's trying to reconnect automatically
145   std::condition_variable mShutdownCond;
146   std::mutex mShutdownMutex;
147 
148   // A buffer to read packets into. Allocated here to prevent a large object on
149   // the stack.
150   std::vector<uint8_t> mRecvBuffer = std::vector<uint8_t>(kMaxPacketSize);
151 
152   bool doConnect(const char *socketName,
153                  const ::android::sp<ICallbacks> &callbacks,
154                  bool connectInBackground);
155   bool inReceiveThread() const;
156   void receiveThread();
157   bool receiveThreadRunning() const;
158   bool reconnect();
159   void startReceiveThread();
160   bool tryConnect(bool suppressErrorLogs = false);
161 };
162 
163 }  // namespace chre
164 }  // namespace android
165 
166 #endif  // CHRE_HOST_SOCKET_CLIENT_H_
167