1 /* 2 ** Copyright 2011, 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 #include <sys/ioctl.h> 18 #include <unistd.h> 19 #include <sys/socket.h> 20 #include <fcntl.h> 21 #include <netinet/in.h> 22 #include <arpa/inet.h> 23 #include <pthread.h> 24 25 #include "header.h" 26 27 namespace android 28 { 29 30 int serverSock = -1, clientSock = -1; 31 FILE * file = NULL; 32 unsigned int MAX_FILE_SIZE = 0; 33 int timeMode = SYSTEM_TIME_THREAD; 34 35 static void Die(const char * msg) 36 { 37 LOGD("\n*\n*\n* GLESv2_dbg: Die: %s \n*\n*", msg); 38 StopDebugServer(); 39 exit(1); 40 } 41 42 void StartDebugServer(const unsigned short port, const bool forceUseFile, 43 const unsigned int maxFileSize, const char * const filePath) 44 { 45 MAX_FILE_SIZE = maxFileSize; 46 47 LOGD("GLESv2_dbg: StartDebugServer"); 48 if (serverSock >= 0 || file) 49 return; 50 51 LOGD("GLESv2_dbg: StartDebugServer create socket"); 52 struct sockaddr_in server = {}, client = {}; 53 54 /* Create the TCP socket */ 55 if (forceUseFile || (serverSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { 56 file = fopen(filePath, "wb"); 57 if (!file) 58 Die("Failed to create socket and file"); 59 else 60 return; 61 } 62 /* Construct the server sockaddr_in structure */ 63 server.sin_family = AF_INET; /* Internet/IP */ 64 server.sin_addr.s_addr = htonl(INADDR_LOOPBACK); /* Incoming addr */ 65 server.sin_port = htons(port); /* server port */ 66 67 /* Bind the server socket */ 68 socklen_t sizeofSockaddr_in = sizeof(sockaddr_in); 69 if (bind(serverSock, (struct sockaddr *) &server, 70 sizeof(server)) < 0) { 71 Die("Failed to bind the server socket"); 72 } 73 /* Listen on the server socket */ 74 if (listen(serverSock, 1) < 0) { 75 Die("Failed to listen on server socket"); 76 } 77 78 LOGD("server started on %d \n", server.sin_port); 79 80 81 /* Wait for client connection */ 82 if ((clientSock = 83 accept(serverSock, (struct sockaddr *) &client, 84 &sizeofSockaddr_in)) < 0) { 85 Die("Failed to accept client connection"); 86 } 87 88 LOGD("Client connected: %s\n", inet_ntoa(client.sin_addr)); 89 // fcntl(clientSock, F_SETFL, O_NONBLOCK); 90 } 91 92 void StopDebugServer() 93 { 94 LOGD("GLESv2_dbg: StopDebugServer"); 95 if (clientSock > 0) { 96 close(clientSock); 97 clientSock = -1; 98 } 99 if (serverSock > 0) { 100 close(serverSock); 101 serverSock = -1; 102 } 103 if (file) { 104 fclose(file); 105 file = NULL; 106 } 107 } 108 109 void Receive(glesv2debugger::Message & cmd) 110 { 111 if (clientSock < 0) 112 return; 113 unsigned len = 0; 114 int received = recv(clientSock, &len, 4, MSG_WAITALL); 115 if (received < 0) 116 Die("Failed to receive response length"); 117 else if (4 != received) { 118 LOGD("received %dB: %.8X", received, len); 119 Die("Received length mismatch, expected 4"); 120 } 121 static void * buffer = NULL; 122 static unsigned bufferSize = 0; 123 if (bufferSize < len) { 124 buffer = realloc(buffer, len); 125 assert(buffer); 126 bufferSize = len; 127 } 128 received = recv(clientSock, buffer, len, MSG_WAITALL); 129 if (received < 0) 130 Die("Failed to receive response"); 131 else if (len != received) 132 Die("Received length mismatch"); 133 cmd.Clear(); 134 cmd.ParseFromArray(buffer, len); 135 } 136 137 bool TryReceive(glesv2debugger::Message & cmd) 138 { 139 if (clientSock < 0) 140 return false; 141 fd_set readSet; 142 FD_ZERO(&readSet); 143 FD_SET(clientSock, &readSet); 144 timeval timeout; 145 timeout.tv_sec = timeout.tv_usec = 0; 146 147 int rc = select(clientSock + 1, &readSet, NULL, NULL, &timeout); 148 if (rc < 0) 149 Die("failed to select clientSock"); 150 151 bool received = false; 152 if (FD_ISSET(clientSock, &readSet)) { 153 LOGD("TryReceive: avaiable for read"); 154 Receive(cmd); 155 return true; 156 } 157 return false; 158 } 159 160 float Send(const glesv2debugger::Message & msg, glesv2debugger::Message & cmd) 161 { 162 // TODO: use per DbgContext send/receive buffer and async socket 163 // instead of mutex and blocking io; watch out for large messages 164 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 165 struct Autolock { 166 Autolock() { 167 pthread_mutex_lock(&mutex); 168 } 169 ~Autolock() { 170 pthread_mutex_unlock(&mutex); 171 } 172 } autolock; 173 174 if (msg.function() != glesv2debugger::Message_Function_ACK) 175 assert(msg.has_context_id() && msg.context_id() != 0); 176 static std::string str; 177 msg.SerializeToString(&str); 178 const uint32_t len = str.length(); 179 if (clientSock < 0) { 180 if (file) { 181 fwrite(&len, sizeof(len), 1, file); 182 fwrite(str.data(), len, 1, file); 183 if (ftell(file) >= MAX_FILE_SIZE) { 184 fclose(file); 185 Die("MAX_FILE_SIZE reached"); 186 } 187 } 188 return 0; 189 } 190 int sent = -1; 191 sent = send(clientSock, &len, sizeof(len), 0); 192 if (sent != sizeof(len)) { 193 LOGD("actual sent=%d expected=%d clientSock=%d", sent, sizeof(len), clientSock); 194 Die("Failed to send message length"); 195 } 196 nsecs_t c0 = systemTime(timeMode); 197 sent = send(clientSock, str.data(), str.length(), 0); 198 float t = (float)ns2ms(systemTime(timeMode) - c0); 199 if (sent != str.length()) { 200 LOGD("actual sent=%d expected=%d clientSock=%d", sent, str.length(), clientSock); 201 Die("Failed to send message"); 202 } 203 // TODO: factor Receive & TryReceive out and into MessageLoop, or add control argument. 204 // mean while, if server is sending a SETPROP then don't try to receive, 205 // because server will not be processing received command 206 if (msg.function() == msg.SETPROP) 207 return t; 208 // try to receive commands even though not expecting response, 209 // since client can send SETPROP and other commands anytime 210 if (!msg.expect_response()) { 211 if (TryReceive(cmd)) { 212 if (glesv2debugger::Message_Function_SETPROP == cmd.function()) 213 LOGD("Send: TryReceived SETPROP"); 214 else 215 LOGD("Send: TryReceived %u", cmd.function()); 216 } 217 } else 218 Receive(cmd); 219 return t; 220 } 221 222 void SetProp(DbgContext * const dbg, const glesv2debugger::Message & cmd) 223 { 224 switch (cmd.prop()) { 225 case glesv2debugger::Message_Prop_CaptureDraw: 226 LOGD("SetProp Message_Prop_CaptureDraw %d", cmd.arg0()); 227 dbg->captureDraw = cmd.arg0(); 228 break; 229 case glesv2debugger::Message_Prop_TimeMode: 230 LOGD("SetProp Message_Prop_TimeMode %d", cmd.arg0()); 231 timeMode = cmd.arg0(); 232 break; 233 case glesv2debugger::Message_Prop_ExpectResponse: 234 LOGD("SetProp Message_Prop_ExpectResponse %d=%d", cmd.arg0(), cmd.arg1()); 235 dbg->expectResponse.Bit((glesv2debugger::Message_Function)cmd.arg0(), cmd.arg1()); 236 break; 237 case glesv2debugger::Message_Prop_CaptureSwap: 238 LOGD("SetProp CaptureSwap %d", cmd.arg0()); 239 dbg->captureSwap = cmd.arg0(); 240 break; 241 default: 242 assert(0); 243 } 244 } 245 246 int * MessageLoop(FunctionCall & functionCall, glesv2debugger::Message & msg, 247 const glesv2debugger::Message_Function function) 248 { 249 DbgContext * const dbg = getDbgContextThreadSpecific(); 250 const int * ret = 0; 251 glesv2debugger::Message cmd; 252 msg.set_context_id(reinterpret_cast<int>(dbg)); 253 msg.set_type(glesv2debugger::Message_Type_BeforeCall); 254 bool expectResponse = dbg->expectResponse.Bit(function); 255 msg.set_expect_response(expectResponse); 256 msg.set_function(function); 257 258 // when not exectResponse, set cmd to CONTINUE then SKIP 259 // cmd will be overwritten by received command 260 cmd.set_function(glesv2debugger::Message_Function_CONTINUE); 261 cmd.set_expect_response(expectResponse); 262 glesv2debugger::Message_Function oldCmd = cmd.function(); 263 Send(msg, cmd); 264 expectResponse = cmd.expect_response(); 265 while (true) { 266 msg.Clear(); 267 nsecs_t c0 = systemTime(timeMode); 268 switch (cmd.function()) { 269 case glesv2debugger::Message_Function_CONTINUE: 270 ret = functionCall(&dbg->hooks->gl, msg); 271 while (GLenum error = dbg->hooks->gl.glGetError()) 272 LOGD("Function=%u glGetError() = 0x%.4X", function, error); 273 if (!msg.has_time()) // some has output data copy, so time inside call 274 msg.set_time((systemTime(timeMode) - c0) * 1e-6f); 275 msg.set_context_id(reinterpret_cast<int>(dbg)); 276 msg.set_function(function); 277 msg.set_type(glesv2debugger::Message_Type_AfterCall); 278 msg.set_expect_response(expectResponse); 279 if (!expectResponse) { 280 cmd.set_function(glesv2debugger::Message_Function_SKIP); 281 cmd.set_expect_response(false); 282 } 283 oldCmd = cmd.function(); 284 Send(msg, cmd); 285 expectResponse = cmd.expect_response(); 286 break; 287 case glesv2debugger::Message_Function_SKIP: 288 return const_cast<int *>(ret); 289 case glesv2debugger::Message_Function_SETPROP: 290 SetProp(dbg, cmd); 291 expectResponse = cmd.expect_response(); 292 if (!expectResponse) // SETPROP is "out of band" 293 cmd.set_function(oldCmd); 294 else 295 Receive(cmd); 296 break; 297 default: 298 ret = GenerateCall(dbg, cmd, msg, ret); 299 msg.set_expect_response(expectResponse); 300 if (!expectResponse) { 301 cmd.set_function(cmd.SKIP); 302 cmd.set_expect_response(expectResponse); 303 } 304 oldCmd = cmd.function(); 305 Send(msg, cmd); 306 expectResponse = cmd.expect_response(); 307 break; 308 } 309 } 310 return 0; 311 } 312 }; // namespace android { 313