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