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