• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
Die(const char * msg)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 
StartDebugServer(const unsigned short port,const bool forceUseFile,const unsigned int maxFileSize,const char * const filePath)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 
StopDebugServer()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 
Receive(glesv2debugger::Message & cmd)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 
TryReceive(glesv2debugger::Message & cmd)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 
Send(const glesv2debugger::Message & msg,glesv2debugger::Message & cmd)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 
SetProp(DbgContext * const dbg,const glesv2debugger::Message & cmd)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 
MessageLoop(FunctionCall & functionCall,glesv2debugger::Message & msg,const glesv2debugger::Message_Function function)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