https://mobile.tmon.co.kr/deals/22915652770
#X5 #X5시즌패스 #티몬
/* //device/libs/telephony/ril_event.cpp ** ** Copyright 2008, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. */ #define LOG_TAG "RILC" #include#include #include #include #include #include #include #include #include #include static pthread_mutex_t listMutex; #define MUTEX_ACQUIRE() pthread_mutex_lock(&listMutex) #define MUTEX_RELEASE() pthread_mutex_unlock(&listMutex) #define MUTEX_INIT() pthread_mutex_init(&listMutex, NULL) #define MUTEX_DESTROY() pthread_mutex_destroy(&listMutex) #ifndef timeradd #define timeradd(tvp, uvp, vvp) \ do { \ (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \ (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \ if ((vvp)->tv_usec >= 1000000) { \ (vvp)->tv_sec++; \ (vvp)->tv_usec -= 1000000; \ } \ } while (0) #endif #ifndef timercmp #define timercmp(a, b, op) \ ((a)->tv_sec == (b)->tv_sec \ ? (a)->tv_usec op (b)->tv_usec \ : (a)->tv_sec op (b)->tv_sec) #endif #ifndef timersub #define timersub(a, b, res) \ do { \ (res)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ (res)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ if ((res)->tv_usec < 0) { \ (res)->tv_usec += 1000000; \ (res)->tv_sec -= 1; \ } \ } while(0); #endif static fd_set readFds; static int nfds = 0; static struct ril_event * watch_table[MAX_FD_EVENTS]; static struct ril_event timer_list; static struct ril_event pending_list; #define DEBUG 0 #if DEBUG #define dlog(x...) LOGD( x ) static void dump_event(struct ril_event * ev) { dlog("~~~~ Event %x ~~~~", (unsigned int)ev); dlog(" next = %x", (unsigned int)ev->next); dlog(" prev = %x", (unsigned int)ev->prev); dlog(" fd = %d", ev->fd); dlog(" pers = %d", ev->persist); dlog(" timeout = %ds + %dus", (int)ev->timeout.tv_sec, (int)ev->timeout.tv_usec); dlog(" func = %x", (unsigned int)ev->func); dlog(" param = %x", (unsigned int)ev->param); dlog("~~~~~~~~~~~~~~~~~~"); } #else #define dlog(x...) do {} while(0) #define dump_event(x) do {} while(0) #endif static void getNow(struct timeval * tv) { #ifdef HAVE_POSIX_CLOCKS struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); tv->tv_sec = ts.tv_sec; tv->tv_usec = ts.tv_nsec/1000; #else gettimeofday(tv, NULL); #endif } static void init_list(struct ril_event * list) { memset(list, 0, sizeof(struct ril_event)); list->next = list; list->prev = list; list->fd = -1; } static void addToList(struct ril_event * ev, struct ril_event * list) { ev->next = list; ev->prev = list->prev; ev->prev->next = ev; list->prev = ev; dump_event(ev); } static void removeFromList(struct ril_event * ev) { dlog("~~~~ Removing event ~~~~"); dump_event(ev); ev->next->prev = ev->prev; ev->prev->next = ev->next; ev->next = NULL; ev->prev = NULL; } static void removeWatch(struct ril_event * ev, int index) { watch_table[index] = NULL; ev->index = -1; FD_CLR(ev->fd, &readFds); if (ev->fd+1 == nfds) { int n = 0; for (int i = 0; i < MAX_FD_EVENTS; i++) { struct ril_event * rev = watch_table[i]; if ((rev != NULL) && (rev->fd > n)) { n = rev->fd; } } nfds = n + 1; dlog("~~~~ nfds = %d ~~~~", nfds); } } static void processTimeouts() { dlog("~~~~ +processTimeouts ~~~~"); MUTEX_ACQUIRE(); struct timeval now; struct ril_event * tev = timer_list.next; struct ril_event * next; getNow(&now); // walk list, see if now >= ev->timeout for any events dlog("~~~~ Looking for timers <= %ds + %dus ~~~~", (int)now.tv_sec, (int)now.tv_usec); while ((tev != &timer_list) && (timercmp(&now, &tev->timeout, >))) { // Timer expired dlog("~~~~ firing timer ~~~~"); next = tev->next; removeFromList(tev); addToList(tev, &pending_list); tev = next; } MUTEX_RELEASE(); dlog("~~~~ -processTimeouts ~~~~"); } static void processReadReadies(fd_set * rfds, int n) { dlog("~~~~ +processReadReadies (%d) ~~~~", n); MUTEX_ACQUIRE(); for (int i = 0; (i < MAX_FD_EVENTS) && (n > 0); i++) { struct ril_event * rev = watch_table[i]; if (rev != NULL && FD_ISSET(rev->fd, rfds)) { addToList(rev, &pending_list); if (rev->persist == false) { removeWatch(rev, i); } n--; } } MUTEX_RELEASE(); dlog("~~~~ -processReadReadies (%d) ~~~~", n); } static void firePending() { dlog("~~~~ +firePending ~~~~"); struct ril_event * ev = pending_list.next; while (ev != &pending_list) { struct ril_event * next = ev->next; removeFromList(ev); ev->func(ev->fd, 0, ev->param); ev = next; } dlog("~~~~ -firePending ~~~~"); } static int calcNextTimeout(struct timeval * tv) { struct ril_event * tev = timer_list.next; struct timeval now; getNow(&now); // Sorted list, so calc based on first node if (tev == &timer_list) { // no pending timers return -1; } dlog("~~~~ now = %ds + %dus ~~~~", (int)now.tv_sec, (int)now.tv_usec); dlog("~~~~ next = %ds + %dus ~~~~", (int)tev->timeout.tv_sec, (int)tev->timeout.tv_usec); if (timercmp(&tev->timeout, &now, >)) { timersub(&tev->timeout, &now, tv); } else { // timer already expired. tv->tv_sec = tv->tv_usec = 0; } return 0; } // Initialize internal data structs void ril_event_init() { MUTEX_INIT(); FD_ZERO(&readFds); init_list(&timer_list); init_list(&pending_list); memset(watch_table, 0, sizeof(watch_table)); } // Initialize an event void ril_event_set(struct ril_event * ev, int fd, bool persist, ril_event_cb func, void * param) { dlog("~~~~ ril_event_set %x ~~~~", (unsigned int)ev); memset(ev, 0, sizeof(struct ril_event)); ev->fd = fd; ev->index = -1; ev->persist = persist; ev->func = func; ev->param = param; fcntl(fd, F_SETFL, O_NONBLOCK); } // Add event to watch list void ril_event_add(struct ril_event * ev) { dlog("~~~~ +ril_event_add ~~~~"); MUTEX_ACQUIRE(); for (int i = 0; i < MAX_FD_EVENTS; i++) { if (watch_table[i] == NULL) { watch_table[i] = ev; ev->index = i; dlog("~~~~ added at %d ~~~~", i); dump_event(ev); FD_SET(ev->fd, &readFds); if (ev->fd >= nfds) nfds = ev->fd+1; dlog("~~~~ nfds = %d ~~~~", nfds); break; } } MUTEX_RELEASE(); dlog("~~~~ -ril_event_add ~~~~"); } // Add timer event void ril_timer_add(struct ril_event * ev, struct timeval * tv) { dlog("~~~~ +ril_timer_add ~~~~"); MUTEX_ACQUIRE(); struct ril_event * list; if (tv != NULL) { // add to timer list list = timer_list.next; ev->fd = -1; // make sure fd is invalid struct timeval now; getNow(&now); timeradd(&now, tv, &ev->timeout); // keep list sorted while (timercmp(&list->timeout, &ev->timeout, < ) && (list != &timer_list)) { list = list->next; } // list now points to the first event older than ev addToList(ev, list); } MUTEX_RELEASE(); dlog("~~~~ -ril_timer_add ~~~~"); } // Remove event from watch or timer list void ril_event_del(struct ril_event * ev) { dlog("~~~~ +ril_event_del ~~~~"); MUTEX_ACQUIRE(); if (ev->index < 0 || ev->index >= MAX_FD_EVENTS) { return; } removeWatch(ev, ev->index); MUTEX_RELEASE(); dlog("~~~~ -ril_event_del ~~~~"); } #if DEBUG static void printReadies(fd_set * rfds) { for (int i = 0; (i < MAX_FD_EVENTS); i++) { struct ril_event * rev = watch_table[i]; if (rev != NULL && FD_ISSET(rev->fd, rfds)) { dlog("DON: fd=%d is ready", rev->fd); } } } #else #define printReadies(rfds) do {} while(0) #endif void ril_event_loop() { int n; fd_set rfds; struct timeval tv; struct timeval * ptv; for (;;) { // make local copy of read fd_set memcpy(&rfds, &readFds, sizeof(fd_set)); if (-1 == calcNextTimeout(&tv)) { // no pending timers; block indefinitely dlog("~~~~ no timers; blocking indefinitely ~~~~"); ptv = NULL; } else { dlog("~~~~ blocking for %ds + %dus ~~~~", (int)tv.tv_sec, (int)tv.tv_usec); ptv = &tv; } printReadies(&rfds); n = select(nfds, &rfds, NULL, NULL, ptv); printReadies(&rfds); dlog("~~~~ %d events fired ~~~~", n); if (n < 0) { if (errno == EINTR) continue; LOGE("ril_event: select error (%d)", errno); // bail? return; } // Check for timeouts processTimeouts(); // Check for read-ready processReadReadies(&rfds, n); // Fire away firePending(); } } extern "C" void RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen) { RequestInfo *pRI; int ret; size_t errorOffset; pRI = (RequestInfo *)t; if (!checkAndDequeueRequestInfo(pRI)) { LOGE ("RIL_onRequestComplete: invalid RIL_Token"); return; } if (pRI->local > 0) { // Locally issued command...void only! // response does not go back up the command socket LOGD("C[locl]< %s", requestToString(pRI->pCI->requestNumber)); goto done; } appendPrintBuf("[%04d]< %s", pRI->token, requestToString(pRI->pCI->requestNumber)); if (pRI->cancelled == 0) { Parcel p; p.writeInt32 (RESPONSE_SOLICITED); p.writeInt32 (pRI->token); errorOffset = p.dataPosition(); p.writeInt32 (e); if (response != NULL) { // there is a response payload, no matter success or not. ret = pRI->pCI->responseFunction(p, response, responselen); /* if an error occurred, rewind and mark it */ if (ret != 0) { p.setDataPosition(errorOffset); p.writeInt32 (ret); } } if (e != RIL_E_SUCCESS) { appendPrintBuf("%s fails by %s", printBuf, failCauseToString(e)); } if (s_fdCommand < 0) { LOGD ("RIL onRequestComplete: Command channel closed"); } sendResponse(p); } done: extern "C" void RIL_onUnsolicitedResponse(int unsolResponse, void *data, size_t datalen) { int unsolResponseIndex; int ret; int64_t timeReceived = 0; bool shouldScheduleTimeout = false; if (s_registerCalled == 0) { // Ignore RIL_onUnsolicitedResponse before RIL_register LOGW("RIL_onUnsolicitedResponse called before RIL_register"); return; } unsolResponseIndex = unsolResponse - RIL_UNSOL_RESPONSE_BASE; if ((unsolResponseIndex < 0) || (unsolResponseIndex >= (int32_t)NUM_ELEMS(s_unsolResponses))) { LOGE("unsupported unsolicited response code %d", unsolResponse); return; } // Grab a wake lock if needed for this reponse, // as we exit we'll either release it immediately // or set a timer to release it later. switch (s_unsolResponses[unsolResponseIndex].wakeType) { case WAKE_PARTIAL: grabPartialWakeLock(); shouldScheduleTimeout = true; break; case DONT_WAKE: default: // No wake lock is grabed so don't set timeout shouldScheduleTimeout = false; break; } // Mark the time this was received, doing this // after grabing the wakelock incase getting // the elapsedRealTime might cause us to goto // sleep. if (unsolResponse == RIL_UNSOL_NITZ_TIME_RECEIVED) { timeReceived = elapsedRealtime(); } appendPrintBuf("[UNSL]< %s", requestToString(unsolResponse)); Parcel p; p.writeInt32 (RESPONSE_UNSOLICITED); p.writeInt32 (unsolResponse); ret = s_unsolResponses[unsolResponseIndex] .responseFunction(p, data, datalen); if (ret != 0) { // Problem with the response. Don't continue; goto error_exit; } // some things get more payload switch(unsolResponse) { case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED: p.writeInt32(s_callbacks.onStateRequest()); appendPrintBuf("%s {%s}", printBuf, radioStateToString(s_callbacks.onStateRequest())); break; case RIL_UNSOL_NITZ_TIME_RECEIVED: // Store the time that this was received so the // handler of this message can account for // the time it takes to arrive and process. In // particular the system has been known to sleep // before this message can be processed. p.writeInt64(timeReceived); break; } ret = sendResponse(p); if (ret != 0 && unsolResponse == RIL_UNSOL_NITZ_TIME_RECEIVED) { // Unfortunately, NITZ time is not poll/update like everything // else in the system. So, if the upstream client isn't connected, // keep a copy of the last NITZ response (with receive time noted // above) around so we can deliver it when it is connected if (s_lastNITZTimeData != NULL) { free (s_lastNITZTimeData); s_lastNITZTimeData = NULL; } s_lastNITZTimeData = malloc(p.dataSize()); s_lastNITZTimeDataSize = p.dataSize(); memcpy(s_lastNITZTimeData, p.data(), p.dataSize()); } // For now, we automatically go back to sleep after TIMEVAL_WAKE_TIMEOUT // FIXME The java code should handshake here to release wake lock if (shouldScheduleTimeout) { // Cancel the previous request if (s_last_wake_timeout_info != NULL) { s_last_wake_timeout_info->userParam = (void *)1; } s_last_wake_timeout_info = internalRequestTimedCallback(wakeTimeoutCallback, NULL, &TIMEVAL_WAKE_TIMEOUT); } // Normal exit return; error_exit: if (shouldScheduleTimeout) { releaseWakeLock(); } } free(pRI); } extern "C" void RIL_onUnsolicitedResponse(int unsolResponse, void *data, size_t datalen); extern "C" void RIL_onUnsolicitedResponse(int unsolResponse, void *data, size_t datalen) { int unsolResponseIndex; int ret; int64_t timeReceived = 0; bool shouldScheduleTimeout = false; if (s_registerCalled == 0) { // Ignore RIL_onUnsolicitedResponse before RIL_register LOGW("RIL_onUnsolicitedResponse called before RIL_register"); return; } unsolResponseIndex = unsolResponse - RIL_UNSOL_RESPONSE_BASE; if ((unsolResponseIndex < 0) || (unsolResponseIndex >= (int32_t)NUM_ELEMS(s_unsolResponses))) { LOGE("unsupported unsolicited response code %d", unsolResponse); return; } // Grab a wake lock if needed for this reponse, // as we exit we'll either release it immediately // or set a timer to release it later. switch (s_unsolResponses[unsolResponseIndex].wakeType) { case WAKE_PARTIAL: grabPartialWakeLock(); shouldScheduleTimeout = true; break; case DONT_WAKE: default: // No wake lock is grabed so don't set timeout shouldScheduleTimeout = false; break; } // Mark the time this was received, doing this // after grabing the wakelock incase getting // the elapsedRealTime might cause us to goto // sleep. if (unsolResponse == RIL_UNSOL_NITZ_TIME_RECEIVED) { timeReceived = elapsedRealtime(); } appendPrintBuf("[UNSL]< %s", requestToString(unsolResponse)); Parcel p; p.writeInt32 (RESPONSE_UNSOLICITED); p.writeInt32 (unsolResponse); ret = s_unsolResponses[unsolResponseIndex] .responseFunction(p, data, datalen); if (ret != 0) { // Problem with the response. Don't continue; goto error_exit; } // some things get more payload switch(unsolResponse) { case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED: p.writeInt32(s_callbacks.onStateRequest()); appendPrintBuf("%s {%s}", printBuf, radioStateToString(s_callbacks.onStateRequest())); break; case RIL_UNSOL_NITZ_TIME_RECEIVED: // Store the time that this was received so the // handler of this message can account for // the time it takes to arrive and process. In // particular the system has been known to sleep // before this message can be processed. p.writeInt64(timeReceived); break; } ret = sendResponse(p); if (ret != 0 && unsolResponse == RIL_UNSOL_NITZ_TIME_RECEIVED) { // Unfortunately, NITZ time is not poll/update like everything // else in the system. So, if the upstream client isn't connected, // keep a copy of the last NITZ response (with receive time noted // above) around so we can deliver it when it is connected if (s_lastNITZTimeData != NULL) { free (s_lastNITZTimeData); s_lastNITZTimeData = NULL; } s_lastNITZTimeData = malloc(p.dataSize()); s_lastNITZTimeDataSize = p.dataSize(); memcpy(s_lastNITZTimeData, p.data(), p.dataSize()); } // For now, we automatically go back to sleep after TIMEVAL_WAKE_TIMEOUT // FIXME The java code should handshake here to release wake lock if (shouldScheduleTimeout) { // Cancel the previous request if (s_last_wake_timeout_info != NULL) { s_last_wake_timeout_info->userParam = (void *)1; } s_last_wake_timeout_info = internalRequestTimedCallback(wakeTimeoutCallback, NULL, &TIMEVAL_WAKE_TIMEOUT); } // Normal exit return; error_exit: if (shouldScheduleTimeout) { releaseWakeLock(); } } extern "C" void RIL_register (const RIL_RadioFunctions *callbacks) { int ret; int flags; if (callbacks == NULL || ! (callbacks->version == RIL_VERSION || callbacks->version == 1) ) { LOGE( "RIL_register: RIL_RadioFunctions * null or invalid version" " (expected %d)", RIL_VERSION); return; } if (s_registerCalled > 0) { LOGE("RIL_register has been called more than once. " "Subsequent call ignored"); return; } memcpy(&s_callbacks, callbacks, sizeof (RIL_RadioFunctions)); s_registerCalled = 1; // Little self-check for (int i = 0; i < (int)NUM_ELEMS(s_commands); i++) { assert(i == s_commands[i].requestNumber); } for (int i = 0; i < (int)NUM_ELEMS(s_unsolResponses); i++) { assert(i + RIL_UNSOL_RESPONSE_BASE == s_unsolResponses[i].requestNumber); } // New rild impl calls RIL_startEventLoop() first // old standalone impl wants it here. if (s_started == 0) { RIL_startEventLoop(); } // start listen socket #if 0 ret = socket_local_server (SOCKET_NAME_RIL, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); if (ret < 0) { LOGE("Unable to bind socket errno:%d", errno); exit (-1); } s_fdListen = ret; #else s_fdListen = android_get_control_socket(SOCKET_NAME_RIL); if (s_fdListen < 0) { LOGE("Failed to get socket '" SOCKET_NAME_RIL "'"); exit(-1); } ret = listen(s_fdListen, 4); if (ret < 0) { LOGE("Failed to listen on control socket '%d': %s", s_fdListen, strerror(errno)); exit(-1); } #endif /* note: non-persistent so we can accept only one connection at a time */ ril_event_set (&s_listen_event, s_fdListen, false, listenCallback, NULL); rilEventAddWakeup (&s_listen_event); #if 1 // start debug interface socket s_fdDebug = android_get_control_socket(SOCKET_NAME_RIL_DEBUG); if (s_fdDebug < 0) { LOGE("Failed to get socket '" SOCKET_NAME_RIL_DEBUG "' errno:%d", errno); exit(-1); } ret = listen(s_fdDebug, 4); if (ret < 0) { LOGE("Failed to listen on ril debug socket '%d': %s", s_fdDebug, strerror(errno)); exit(-1); } ril_event_set (&s_debug_event, s_fdDebug, true, debugCallback, NULL); rilEventAddWakeup (&s_debug_event); #endif } extern "C" void RIL_requestTimedCallback (RIL_TimedCallback callback, void *param, const struct timeval *relativeTime) { internalRequestTimedCallback (callback, param, relativeTime); } // Used for testing purpose only. extern "C" void RIL_setcallbacks (const RIL_RadioFunctions *callbacks) { memcpy(&s_callbacks, callbacks, sizeof (RIL_RadioFunctions)); } extern "C" void RIL_startEventLoop(void) { int ret; pthread_attr_t attr; /* spin up eventLoop thread and wait for it to get started */ s_started = 0; pthread_mutex_lock(&s_startupMutex); pthread_attr_init (&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); ret = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL); while (s_started == 0) { pthread_cond_wait(&s_startupCond, &s_startupMutex); } pthread_mutex_unlock(&s_startupMutex); if (ret < 0) { LOGE("Failed to create dispatch thread errno:%d", errno); return; } }