RilProxy
For MTK platform, there is a RilProxy layer between RILC and RILJ.
One advantage of using proxy is that in the upper layer, not only RILJ and RILC are connected through Socket, but also other places can connect with RILC to communicate with the lower level Modem, such as sending commands directly to Modem through terminal ATCI interface.
Another advantage is that the lower layer of the proxy layer is free to switch its docking RIC layer, because for different projects, the RIC layer needs to be adapted differently, such as switching from default to C2K RIL.
Of course, the role of the proxy layer is not only to connect the upper and lower intermediaries, but also to filter some messages. For example, when Radio unavailable, it can filter some request s that need Radio to work.
As for the structure of RilProxy, it is similar to RILC. It is also divided into LibRIL layer and MtkRIL layer. In the LibRIL layer, they are quite similar, except that RilProxy listens directly to the socket interface of RILJ here. So the process of RilProxy monitoring from Socket handle, establishing stream sockets and processing stream sockets is not described here. The detailed process can be referred to Chapter 2.
7.1 RilProxy Layer Processing Flow
In RILProxy, unlike RILC, the process of calling MtkRIL callback function onRequest by LibRIL is different. Therefore, we start from this place to analyze its process.
Let's start with a general flow chart:
First, we review the onRequest function of RILC. It judges by different request codes. Finally, different functions are used to preprocess requests. Finally, requests are interpreted as AT commands and sent to AT channels.
Let's look at the onRequest function at the RilProxy layer in the following code:
1. First, request is sent directly to Rfx in ril_callbacks. Rfx is a module that handles different requests and sends them to different socket s. Its code is mainly in / ril/rilproxy/mtk-rilproxy/framework/core / directory.
2. One of Rfx is dispatch queue belonging to dispatch thread. Rfx first encapsulates the request as a Message object and puts it in the dispatch queue. In the dispatch thread, a looper reads the Mesage of the dispatch queue and distributes it to the main thread for the main thread to process.
//ril_callbacks.c
static void
onRequest (int request, void *data, size_t datalen, RIL_Token t){
//Radio is not available, filter request
if (radioState == RADIO_STATE_UNAVAILABLE &&
request != RIL_REQUEST_OEM_HOOK_RAW && //This is for ATCI
...){
}
//Add to request queue
rfx_enqueue_request_message(request, data, datalen, t, socket_id);
}
//Rfx.cpp
void rfx_enqueue_request_message(int request, void *data, size_t datalen, RIL_Token t,
RIL_SOCKET_ID socket_id) {
//Add to request queue
dispatchThread->enqueueRequestMessage(request, data, datalen, t, socket_id);
}
//RfxDispatchThread.cpp
void RfxDispatchThread::enqueueRequestMessage(int request, void *data, size_t datalen,
RIL_Token t, RIL_SOCKET_ID socket_id) {
RequestInfo *requestInfo = (RequestInfo *)t;
...
//Analysis of Message Objects Using Request Data Purchase R
sp<RfxMessage> msg = RfxMessage::obtainRequest(socket_id, dest, request, requestInfo->token,
parcel, t);
//Building MessageObj
MessageObj *obj = createMessageObj(msg);
//Adding messages to dispatchRequestQueue
dispatchRequestQueue.enqueue(obj);
}
// RfxDispatchThread.cpp
extern "C"
void *rfx_process_request_messages_loop(void *arg) {
while (1) {
RfxDispatchThread *dispatchThread = (RfxDispatchThread *) arg;
dispatchThread->processRequestMessageLooper();
}
return NULL;
}
//RfxDispatchThread.cpp
void RfxDispatchThread::processRequestMessageLooper() {
//Extract a MessageObj from dispatch Request Queueh
MessageObj *obj = dispatchRequestQueue.dequeue();
RfxMainThread::waitLooper();
//Add MessageObj to the queue of MainThread
RfxMainThread::enqueueMessage(obj->msg);
//Delete from this queue
delete(obj);
}
//RfxMainThread.cpp
void RfxMainThread::enqueueMessage(const sp<RfxMessage>& message) {
...
//Using message to build RfxMessageHandler
sp<MessageHandler> handler = new RfxMessageHandler(message);
//Let Looper call handler processing
s_self->m_looper->sendMessage(handler, s_self->m_dummy_msg);
}
The final Message processing above is in RfxMainThread, as shown in the following code.
There are two main steps:
1. Use Message to create a RfxRootController to process this message
2. In RfxRootController, the Hander corresponding to the Message is obtained first. If it is obtained, the Handler is used to process the Message, otherwise the default function is called.
//RfxMainThread.cpp
virtual void onHandleMessage(const Message& message) {
//fault tolerant
...
// dispatch msg to root controller, it will
// do further dispatch
//Create a RfxRootController object
RfxRootController *root = RFX_OBJ_GET_INSTANCE(RfxRootController);
//Use RfxRootController to process messages, where m_msg is the message passed in by the parameter
root->processMessage(m_msg);
}
//RfxRootController.cpp
bool RfxRootController::processMessage(const sp<RfxMessage>& message) {
RfxController *handler = NULL;
...
//handler for Getting Different Types of Message s
if (message->getType() == REQUEST) {
handler = findMsgHandler(message->getId(), message->getSlotId(), m_request_list);
} else if (message->getType() == URC) {
handler = findMsgHandler(message->getId(), message->getSlotId(), m_urc_list);
} else if (message->getType() == RESPONSE || message->getType() == REQUEST_ACK) {
handler = findMsgHandler(message->getId(), message->getSlotId(), m_request_list);
}
bool ret = false;
//If the Handler is not obtained, different types of Message call different default function processing
if (handler == NULL) {
if (REQUEST == message->getType()) {
//Send the request to GSM RILC
requestToRild(message);
ret = true;
} else if (REQUEST_ACK == message->getType()) {
requestAckToRilj(message);
ret = true;
} else {
ret = responseToRilj(message);
}
} else {
//If you get the Handler, handle it with the Handler
ret = handler->processMessage(message);
}
if (message->getType() == RESPONSE || message->getType() == URC) {
handleSendResponseAck(message);
}
return ret;
}
The request above can be processed in a variety of ways. Here, take the request ToRild (message) as an example:
The following code first sends the size of the data to Socket, and then sends the content of the data to the past.
//RfxRilAdapter.cpp
void RfxRilAdapter::requestToRild(const sp<RfxMessage>& message) {
//fault tolerant
requestToRildX(message);
}
bool RfxRilAdapter::requestToRildX(const sp<RfxMessage>& message) {
//fault tolerant
// fd check
int slotId = message->getSlotId();
int dest = message->getDest();
int targetFd = socket_fds[slotId][dest];
Parcel *parcel = NULL;
parcel = message->getParcel();
//Get data size
int dataSize = parcel->dataSize();
//get data
const uint8_t* data = parcel->data();
// parcel length in big endian
dataLength[0] = dataLength[1] = 0;
dataLength[2] = ((dataSize >> 8) & 0xff);
dataLength[3] = ((dataSize) & 0xff);
//Send data size first
sent = send(targetFd , dataLength , 4, 0);
//Re-send data
sent += send(targetFd , data , dataSize, 0);
}
The above process just sends the data size and data to each other.
In general, the RilProxy layer uses Message and Looper mechanisms to package our requests into Messages, then create corresponding Handler objects with Messages, and finally send Handler objects to Looper for processing.
Notable is the socket_fds[slotId][dest] array, which specifies the target we are sending, so let's see what values it initializes. So you can know what targets it specifically represents.
7.2 socket_fds initialization
Start tracing from the assignment of socket_fds:
//RfxRilAdapter.cpp
bool RfxRilAdapter::setSocket(int slotId, RILD_RadioTechnology_Group group, int fd) {
...
socket_fds[slotId][group] = fd;
return true;
}
//RfxSocketStateManager.cpp
void RfxSocketStateManager::setSocketState(RILD_RadioTechnology_Group groupId,
bool isConnected, int slotId, int socFd) {
RfxRilAdapter::getInstance()->setSocket(slotId, groupId, socFd);
}
//RfxSocketStateManager.cpp
void RfxSocketStateManager::processMessage(const sp<RfxSocketStateMessage>& message) {
setSocketState(message->getGroupId(), message->getIsConnected(), message->getSlotId(),
message->getSocketFd());
}
//RfxSocketStateManager.cpp
class RfxSocketMessageHandler : public RfxMainHandler {
public:
explicit RfxSocketMessageHandler(
const sp<RfxSocketStateMessage>& msg) : m_msg(msg) {}
protected:
/**
* Handles a message.
*/
virtual void onHandleMessage(const Message& message) {
...
mgr->processMessage(m_msg);
}
}
//RfxSocketStateManager.cpp
void RfxSocketStateManager::notifySocketState(
RILD_RadioTechnology_Group group, int slotId, int fd, bool isConnected) {
RfxSocketState::SOCKET_ID socId;
Message dummyMsg;
sp<RfxSocketStateMessage> new_msg = new RfxSocketStateMessage(group, isConnected, slotId, fd);
//Create a corresponding RfxSocketMessageHandler object using Message
sp<MessageHandler> handler = new RfxSocketMessageHandler(new_msg);
//Send this Message to MainLooper for processing
RfxMainThread::waitLooper()->sendMessageAtTime(0, handler, dummyMsg);
}
//Rfx.cpp
void rfx_set_socket(RILD_RadioTechnology_Group group, int slotId, int fd) {
RfxSocketStateManager::notifySocketState(group, slotId, fd, true);
}
//socket_channel.cpp
void RilpSocket::connectSocket(void)
{
RLOGI ("connectSocket to %d %d socket_name %s\n", group, id, name);
while (1) {
//Try using Socket Name to get Socket handle
socketFd = socket_local_client(name,
ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_STREAM);
if(socketFd > 0) {
RLOGI ("connectSocket to %d\n", socketFd);
rfx_set_socket(group, id, socketFd);
return;
} else {
RLOGD ("connectSocket fail, try again %d\n", socketFd);
sleep(1);
}
}
}
//socket_channel.cpp
void RilpSocket::initSocket(const char *socketName, RIL_SOCKET_ID socketid, RILD_RadioTechnology_Group groupId) {
pthread_attr_t attr;
PthreadPtr pptr = ril_socket_reader_looper;
int result;
RilpSocket* socket = new RilpSocket(socketName, socketid, groupId);
socket->connectSocket();
...
}
//socket_channel.cpp
extern "C"
void ril_socket_init() {
int i=0;
char *socketName;
//Initialization of Socket in GSM RIL
for(i=0; i<SIM_COUNT; i++) {
socketName = RilpSocketUtil::getSocketName(RADIO_TECH_GROUP_GSM, RIL_SOCKET_ID(i));
RilpSocket::initSocket(socketName, RIL_SOCKET_ID(i), RADIO_TECH_GROUP_GSM);
}
socketName = RilpSocketUtil::getSocketName(RADIO_TECH_GROUP_C2K, RIL_SOCKET_1);
if(RpFeatureOptionUtils::isC2kSupport()) {
RilpSocket::initSocket(socketName, RIL_SOCKET_1, RADIO_TECH_GROUP_C2K);
}
for (i=0; i<SIM_COUNT; i++) {
setRadioState(RADIO_STATE_OFF, RIL_SOCKET_ID(i));
}
//Initialize the Socket of ATCI
socketName = RilpSocketUtil::getSocketName(RADIO_TECH_GROUP_ATCI, RIL_SOCKET_1);
RilpAtciSocket::initSocket(socketName);
...
}
For the above step-by-step reverse tracking, a flow chart is summarized.
Firstly, SocketName is obtained through the Socket type and ID in ril_socket_init(), and then the static function of RilpSocket is invoked to initialize the SocketName.
In the initialization process, a RilpSocket object is created using SocketName, and then the RilpSocket object is called connectSocket(). The connectSocket function creates a Message in the RfxSocketStateManager to handle the Connect operation of the Socket. Finally, the Socket handle is added to the two-dimensional array of socket_fds.
The ril_socket_init() function is called in the mainloop() function of the Mtk-RIL layer of RipProxy. So far, the Socket initialization operation has been completed. Through the following Log, we can see which Sockets have been initialized:
//Socket of SIM slot 1
09:47:54.193526 1148 1174 I : connectSocket to 0 0 socket_name mrild
09:47:54.195757 1148 1174 I : connectSocket to 24
//Socket of SIM slot 2
09:47:54.205873 1148 1174 I : connectSocket to 0 1 socket_name mrild2
09:47:54.208010 1148 1174 I : connectSocket to 29
//Socket of ATCI Port
09:47:54.209648 1148 1174 I : connectSocket to 0 socket_name rilproxy-atci
09:47:54.209725 1148 1174 I : connectSocket to 15
09:47:54.212312 1148 1174 I : connectSocket to 0 socket_name msap_uim_socket1
09:47:54.214344 1148 1174 I : connectSocket to 30
Attachment: RilProxy, RILC corresponding file LOG TAG, easy to locate code according to Log
RILC:
rild.c #define LOG_TAG "RILD"
ril.cpp #define LOG_TAG "RILC"
ril_event.c #define LOG_TAG "RILC"
ril_callbacks.c #define LOG_TAG "RIL"
atchannel.c #define LOG_TAG "AT"
RilProxy:
rild.c #define LOG_TAG "RILP"
ril.cpp #define LOG_TAG "RILC-RP"
ril_event.cpp #define LOG_TAG "RILC-RP"
ril_callbacks.c #define LOG_TAG "RIL-RP"
atchannel.c #define LOG_TAG "AT"