Home | History | Annotate | Download | only in src
      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