电话是一种开放的通信渠道,任何人都可以随时向任何电话号码致电或者发送短信,因此 Android 用户需要能够轻松屏蔽骚扰电话和短信。在 Android N 推出之前,Android 用户只能依靠下载的应用来限制来自骚扰电话号码的来电和短信。但是,由于没有适当的 API 来屏蔽来电和短信,这些应用大部分要么达不到预期效果,要么用户体验不佳。
一些制造商可能会提供他们自己的开箱即用型屏蔽解决方案,但是如果用户更换设备,由于缺乏互用性,他们的屏蔽列表可能会完全丢失。最后,即便用户采用了提供此类功能的拨号应用和短信客户端,他们可能仍需在每个应用中执行屏蔽操作,才能有效屏蔽来电和短信。Android 7.0 版本引入了 BlockedNumberProvider 内容提供程序,该程序可以存储用户指定的无法通过电话通讯(通话、短信、彩信)与他们联系的电话号码列表。系统会参考屏蔽列表中的号码,限制来自这些号码的来电和短信。Android 7.0 不仅会显示屏蔽号码列表,还可让用户添加和删除号码。
hardware\ril\rild\rild.c
int main(int argc, char **argv) {
// vendor ril lib path either passed in as -l parameter, or read from rild.libpath property
const char *rilLibPath = NULL;
// ril arguments either passed in as -- parameter, or read from rild.libargs property
char **rilArgv;
//厂商ril库句柄
void *dlHandle;
//厂商ril库回调
const RIL_RadioFunctions *(*rilInit)(const struct RIL_Env *, int, char **);
// Pointer to sap init function in vendor ril
RIL_RadioFunctions *(*rilUimInit)(const struct RIL_Env *, int, char **);
const char *err_str = NULL;
// functions returned by ril init function in vendor ril
const RIL_RadioFunctions *funcs;
......
//打开厂商库
dlHandle = dlopen(rilLibPath, RTLD_NOW);
//启动事件循环
RIL_startEventLoop();
//调用系统库
rilInit =(const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))dlsym(dlHandle, "RIL_Init");
rilUimInit =(RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))dlsym(dlHandle, "RIL_SAP_Init");
//初始化rilInit
funcs = rilInit(&s_rilEnv, argc, rilArgv);
//注册回调函数
RIL_register(funcs);
//注册套接
if (rilUimInit) {
RIL_register_socket(rilUimInit, RIL_SAP_SOCKET, argc, rilArgv);
}
done:
.....
rilc_thread_pool();
.....
}
hardware\ril\libril\ril.cpp
extern "C" void
RIL_startEventLoop(void) {
......
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
//启动线程,运行 eventLoop
int result = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL);
while (s_started == 0) {
pthread_cond_wait(&s_startupCond, &s_startupMutex);
}
......
hardware\ril\libril\ril.cpp
static void *
eventLoop(void *param) {
int ret;
int filedes[2];
//初始化事件链表
ril_event_init();
//创建管道
ret = pipe(filedes);
//读写唤醒描述符
s_fdWakeupRead = filedes[0];
s_fdWakeupWrite = filedes[1];
//执行
fcntl(s_fdWakeupRead, F_SETFL, O_NONBLOCK);
//设置事件描述符和事件处理函数
ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true,
processWakeupCallback, NULL);
rilEventAddWakeup (&s_wakeupfd_event);
//开始ril事件循环
ril_event_loop();
......
return NULL;
}
hardware\ril\libril\ril_event.cpp
void ril_event_init()
{
MUTEX_INIT();
FD_ZERO(&readFds);
init_list(&timer_list); //初始化事件链表
init_list(&pending_list);
memset(watch_table, 0, sizeof(watch_table));
}
static void init_list(struct ril_event * list)
{
memset(list, 0, sizeof(struct ril_event));
list->next = list;
list->prev = list;
list->fd = -1; //存储文件描述符
}
hardware\ril\libril\ril_event.cpp
void ril_event_loop()
{
int n;
fd_set rfds;
struct timeval tv;
struct timeval * ptv;
for (;;) {
......
n = select(nfds, &rfds, NULL, NULL, ptv); //开始select
......
// Check for timeouts
processTimeouts();
// Check for read-ready
processReadReadies(&rfds, n);
// Fire away
firePending();
}
}
static void processReadReadies(fd_set * rfds, int n)
{
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--;
}
}
}
static void 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); //执行函数 processWakeupCallback
ev = next;
}
}
hardware\ril\libril\ril.cpp
static void processWakeupCallback(int fd, short flags, void *param) {
char buff[16];
int ret;
//循环从套接端读取
do {
ret = read(s_fdWakeupRead, &buff, sizeof(buff));
} while (ret > 0 || (ret < 0 && errno == EINTR));
}
hardware\ril\libril\ril.cpp
static void rilEventAddWakeup(struct ril_event *ev) {
ril_event_add(ev);
triggerEvLoop();
}
hardware\ril\libril\ril_event.cpp
void ril_event_add(struct ril_event * ev)
{
for (int i = 0; i < MAX_FD_EVENTS; i++) {
if (watch_table[i] == NULL) {
watch_table[i] = ev; //加入事件观察表中
ev->index = i; //加索引
FD_SET(ev->fd, &readFds);
if (ev->fd >= nfds) nfds = ev->fd+1;
break;
}
}
}
hardware\ril\libril\ril.cpp
static void triggerEvLoop() {
int ret;
if (!pthread_equal(pthread_self(), s_tid_dispatch)) {
//循环触发唤醒事件循环
do {
ret = write (s_fdWakeupWrite, " ", 1);
} while (ret < 0 && errno == EINTR);
}
}
hardware\ril\reference-ril\reference-ril.c
const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)
{
......
//启动线程,开始主循环
ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);
......
return &s_callbacks; //返回操作结构体
}
//函数回调结构表
static const RIL_RadioFunctions s_callbacks = {
RIL_VERSION,
onRequest,
currentState,
onSupports,
onCancel,
getVersion
};
hardware\ril\reference-ril\reference-ril.c
开始打开BP(基带处理器)
static void *
mainLoop(void *param __unused)
{
int fd;
int ret;
at_set_on_reader_closed(onATReaderClosed);
at_set_on_timeout(onATTimeout);
for (;;) {
fd = -1;
while (fd < 0) {
if (isInEmulator()) {
fd = qemu_pipe_open("pipe:qemud:gsm"); //模拟
} else if (s_port > 0) {
fd = socket_network_client("localhost", s_port, SOCK_STREAM); //网络
} else if (s_device_socket) { //本地
fd = socket_local_client(s_device_path,
ANDROID_SOCKET_NAMESPACE_FILESYSTEM,
SOCK_STREAM);
} else if (s_device_path != NULL) {
fd = open (s_device_path, O_RDWR); //打开基带处理器
if ( fd >= 0 && !memcmp( s_device_path, "/dev/ttyS", 9 ) ) {
/* disable echo on serial ports */
struct termios ios;
tcgetattr( fd, &ios );
ios.c_lflag = 0; /* disable ECHO, ICANON, etc... */
tcsetattr( fd, TCSANOW, &ios );
}
}
......
}
s_closed = 0;
ret = at_open(fd, onUnsolicited); // 开始基带处理通讯,出入文件描述符,回调处理函数
RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);
......
}
}
hardware\ril\reference-ril\atchannel.c
int at_open(int fd, ATUnsolHandler h)
{
int ret;
pthread_t tid;
pthread_attr_t attr;
s_fd = fd;
s_unsolHandler = h; //回调处理句柄
s_readerClosed = 0;
//开线程循环读取
ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr);
......
return 0;
}
hardware\ril\reference-ril\atchannel.c
循环读取基带处理器的AT指令
static void *readerLoop(void *arg __unused)
{
for (;;) {
const char * line;
line = readline(); //读取AT命令
if (line == NULL) {
break;
}
if(isSMSUnsolicited(line)) { //是未经请求的回复
char *line1;
const char *line2;
// The scope of string returned by 'readline()' is valid only
// till next call to 'readline()' hence making a copy of line
// before calling readline again.
line1 = strdup(line);
line2 = readline();
if (line2 == NULL) {
free(line1);
break;
}
if (s_unsolHandler != NULL) {
s_unsolHandler (line1, line2); //回调
}
free(line1);
} else {
processLine(line); //处理
}
}
onReaderClosed();
return NULL;
}
hardware\ril\reference-ril\atchannel.c
读取AT命令行
static const char *readline()
{
ssize_t count;
char *p_read = NULL;
char *p_eol = NULL;
char *ret;
/* this is a little odd. I use *s_ATBufferCur == 0 to
* mean "buffer consumed completely". If it points to a character, than
* the buffer continues until a \0
*/
if (*s_ATBufferCur == '\0') {
/* empty buffer */
s_ATBufferCur = s_ATBuffer;
*s_ATBufferCur = '\0';
p_read = s_ATBuffer;
} else { /* *s_ATBufferCur != '\0' */
/* there's data in the buffer from the last read */
// skip over leading newlines
while (*s_ATBufferCur == '\r' || *s_ATBufferCur == '\n')
s_ATBufferCur++;
p_eol = findNextEOL(s_ATBufferCur);
if (p_eol == NULL) {
/* a partial line. move it up and prepare to read more */
size_t len;
len = strlen(s_ATBufferCur);
memmove(s_ATBuffer, s_ATBufferCur, len + 1);
p_read = s_ATBuffer + len;
s_ATBufferCur = s_ATBuffer;
}
/* Otherwise, (p_eol !- NULL) there is a complete line */
/* that will be returned the while () loop below */
}
while (p_eol == NULL) {
if (0 == MAX_AT_RESPONSE - (p_read - s_ATBuffer)) {
RLOGE("ERROR: Input line exceeded buffer\n");
/* ditch buffer and start over again */
s_ATBufferCur = s_ATBuffer;
*s_ATBufferCur = '\0';
p_read = s_ATBuffer;
}
do {
//循环读取AT指令数据
count = read(s_fd, p_read,
MAX_AT_RESPONSE - (p_read - s_ATBuffer));
} while (count < 0 && errno == EINTR);
if (count > 0) {
AT_DUMP( "<< ", p_read, count );
p_read[count] = '\0';
// skip over leading newlines
while (*s_ATBufferCur == '\r' || *s_ATBufferCur == '\n')
s_ATBufferCur++;
p_eol = findNextEOL(s_ATBufferCur);
p_read += count;
} else if (count <= 0) {
/* read error encountered or EOF reached */
if(count == 0) {
RLOGD("atchannel: EOF reached");
} else {
RLOGD("atchannel: read error %s", strerror(errno));
}
return NULL;
}
}
/* a full line in the buffer. Place a \0 over the \r and return */
ret = s_ATBufferCur;
*p_eol = '\0';
s_ATBufferCur = p_eol + 1; /* this will always be <= p_read, */
/* and there will be a \0 at *p_read */
RLOGD("AT< %s\n", ret);
return ret;
}
hardware\ril\reference-ril\atchannel.c
处理命令行
static void processLine(const char *line)
{
pthread_mutex_lock(&s_commandmutex);
if (sp_response == NULL) {
/* no command pending */
handleUnsolicited(line); //处理未经请求的回复
} else if (isFinalResponseSuccess(line)) {
sp_response->success = 1;
handleFinalResponse(line);
} else if (isFinalResponseError(line)) {
sp_response->success = 0;
handleFinalResponse(line);
} else if (s_smsPDU != NULL && 0 == strcmp(line, "> ")) {
// See eg. TS 27.005 4.3
// Commands like AT+CMGS have a "> " prompt
writeCtrlZ(s_smsPDU);
s_smsPDU = NULL;
} else switch (s_type) {
case NO_RESULT:
handleUnsolicited(line);
break;
case NUMERIC:
if (sp_response->p_intermediates == NULL
&& isdigit(line[0])
) {
addIntermediate(line);
} else {
/* either we already have an intermediate response or
the line doesn't begin with a digit */
handleUnsolicited(line);
}
break;
case SINGLELINE:
if (sp_response->p_intermediates == NULL
&& strStartsWith (line, s_responsePrefix)
) {
addIntermediate(line);
} else {
/* we already have an intermediate response */
handleUnsolicited(line);
}
break;
case MULTILINE:
if (strStartsWith (line, s_responsePrefix)) {
addIntermediate(line);
} else {
handleUnsolicited(line);
}
break;
default: /* this should never be reached */
RLOGE("Unsupported AT command type %d\n", s_type);
handleUnsolicited(line);
break;
}
pthread_mutex_unlock(&s_commandmutex);
}
hardware\ril\reference-ril\atchannel.c
回调处理
static void handleUnsolicited(const char *line)
{
if (s_unsolHandler != NULL) {
s_unsolHandler(line, NULL);
}
}
hardware\ril\reference-ril\reference-ril.c
处理来自基带处理器的AT指令
static void onUnsolicited (const char *s, const char *sms_pdu)
{
char *line = NULL, *p;
int err;
/* Ignore unsolicited responses until we're initialized.
* This is OK because the RIL library will poll for initial state
*/
if (sState == RADIO_STATE_UNAVAILABLE) {
return;
}
if (strStartsWith(s, "%CTZV:")) {
/* TI specific -- NITZ time */
char *response;
line = p = strdup(s);
at_tok_start(&p);
err = at_tok_nextstr(&p, &response);
if (err != 0) {
RLOGE("invalid NITZ line %s\n", s);
} else {
RIL_onUnsolicitedResponse (
RIL_UNSOL_NITZ_TIME_RECEIVED,
response, strlen(response));
}
free(line);
} else if (strStartsWith(s,"+CRING:")
|| strStartsWith(s,"RING")
|| strStartsWith(s,"NO CARRIER")
|| strStartsWith(s,"+CCWA")
) {
RIL_onUnsolicitedResponse (
RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,
NULL, 0);
#ifdef WORKAROUND_FAKE_CGEV
RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL); //TODO use new function
#endif /* WORKAROUND_FAKE_CGEV */
} else if (strStartsWith(s,"+CREG:")
|| strStartsWith(s,"+CGREG:")
) {
RIL_onUnsolicitedResponse (
RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED,
NULL, 0);
#ifdef WORKAROUND_FAKE_CGEV
RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
#endif /* WORKAROUND_FAKE_CGEV */
} else if (strStartsWith(s, "+CMT:")) {
RIL_onUnsolicitedResponse (
RIL_UNSOL_RESPONSE_NEW_SMS,
sms_pdu, strlen(sms_pdu));
} else if (strStartsWith(s, "+CDS:")) {
RIL_onUnsolicitedResponse (
RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT,
sms_pdu, strlen(sms_pdu));
} else if (strStartsWith(s, "+CGEV:")) {
/* Really, we can ignore NW CLASS and ME CLASS events here,
* but right now we don't since extranous
* RIL_UNSOL_DATA_CALL_LIST_CHANGED calls are tolerated
*/
/* can't issue AT commands here -- call on main thread */
RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
#ifdef WORKAROUND_FAKE_CGEV
} else if (strStartsWith(s, "+CME ERROR: 150")) {
RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
#endif /* WORKAROUND_FAKE_CGEV */
} else if (strStartsWith(s, "+CTEC: ")) {
int tech, mask;
switch (parse_technology_response(s, &tech, NULL))
{
case -1: // no argument could be parsed.
RLOGE("invalid CTEC line %s\n", s);
break;
case 1: // current mode correctly parsed
case 0: // preferred mode correctly parsed
mask = 1 << tech;
if (mask != MDM_GSM && mask != MDM_CDMA &&
mask != MDM_WCDMA && mask != MDM_LTE) {
RLOGE("Unknown technology %d\n", tech);
} else {
setRadioTechnology(sMdmInfo, tech);
}
break;
}
} else if (strStartsWith(s, "+CCSS: ")) {
int source = 0;
line = p = strdup(s);
if (!line) {
RLOGE("+CCSS: Unable to allocate memory");
return;
}
if (at_tok_start(&p) < 0) {
free(line);
return;
}
if (at_tok_nextint(&p, &source) < 0) {
RLOGE("invalid +CCSS response: %s", line);
free(line);
return;
}
SSOURCE(sMdmInfo) = source;
RIL_onUnsolicitedResponse(RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED,
&source, sizeof(source));
}
......
}
hardware\ril\libril\ril.cpp
响应请求
#if defined(ANDROID_MULTI_SIM)
extern "C"
void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,
size_t datalen, RIL_SOCKET_ID socket_id)
#else
extern "C"
void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,
size_t datalen)
#endif
{
int unsolResponseIndex;
unsolResponseIndex = unsolResponse - RIL_UNSOL_RESPONSE_BASE;
// 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;
}
appendPrintBuf("[UNSL]< %s", requestToString(unsolResponse));
int responseType;
if (s_callbacks.version >= 13
&& s_unsolResponses[unsolResponseIndex].wakeType == WAKE_PARTIAL) {
responseType = RESPONSE_UNSOLICITED_ACK_EXP;
} else {
responseType = RESPONSE_UNSOLICITED;
}
pthread_rwlock_t *radioServiceRwlockPtr = radio::getRadioServiceRwlock((int) soc_id);
int rwlockRet = pthread_rwlock_rdlock(radioServiceRwlockPtr);
assert(rwlockRet == 0);
//执行响应函数
ret = s_unsolResponses[unsolResponseIndex].responseFunction(
(int) soc_id, responseType, 0, RIL_E_SUCCESS, const_cast<void*>(data),
datalen);
......
}
hardware\ril\libril\ril.cpp
static UnsolResponseInfo s_unsolResponses[] = {
#include "ril_unsol_commands.h"
};
hardware\ril\libril\ril_unsol_commands.h
函数表,由responseFunction查表调用
{RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, radio::radioStateChangedInd, WAKE_PARTIAL},
{RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, radio::callStateChangedInd, WAKE_PARTIAL},
{RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, radio::networkStateChangedInd, WAKE_PARTIAL},
{RIL_UNSOL_RESPONSE_NEW_SMS, radio::newSmsInd, WAKE_PARTIAL},
......
hardware\ril\libril\ril.cpp
注册回调函数
extern "C" void
RIL_register (const RIL_RadioFunctions *callbacks) {
int ret;
int flags;
//内存分配
memcpy(&s_callbacks, callbacks, sizeof (RIL_RadioFunctions));
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);
}
//注册
radio::registerService(&s_callbacks, s_commands);
}
hardware\ril\libril\ril_service.cpp
回调函数和函数路由表
void radio::registerService(RIL_RadioFunctions *callbacks, CommandInfo *commands) {
using namespace android::hardware;
int simCount = 1;
const char *serviceNames[] = {
android::RIL_getServiceName()
#if (SIM_COUNT >= 2)
, RIL2_SERVICE_NAME
#if (SIM_COUNT >= 3)
, RIL3_SERVICE_NAME
#if (SIM_COUNT >= 4)
, RIL4_SERVICE_NAME
#endif
#endif
#endif
};
#if (SIM_COUNT >= 2)
simCount = SIM_COUNT;
#endif
configureRpcThreadpool(1, true /* callerWillJoin */); //RPC线程池
for (int i = 0; i < simCount; i++) { //一张sim卡对应一项服务
pthread_rwlock_t *radioServiceRwlockPtr = getRadioServiceRwlock(i);
int ret = pthread_rwlock_wrlock(radioServiceRwlockPtr);
assert(ret == 0);
radioService[i] = new RadioImpl;
radioService[i]->mSlotId = i;
oemHookService[i] = new OemHookImpl;
oemHookService[i]->mSlotId = i;
RLOGD("registerService: starting IRadio %s", serviceNames[i]);
android::status_t status = radioService[i]->registerAsService(serviceNames[i]);
status = oemHookService[i]->registerAsService(serviceNames[i]);
ret = pthread_rwlock_unlock(radioServiceRwlockPtr);
assert(ret == 0);
}
s_vendorFunctions = callbacks;
s_commands = commands;
}
hardware\ril\libril\ril_service.cpp
s_vendorFunctions为上述RIL_RadioFunctions
#if defined(ANDROID_MULTI_SIM)
#define CALL_ONREQUEST(a, b, c, d, e) \
s_vendorFunctions->onRequest((a), (b), (c), (d), ((RIL_SOCKET_ID)(e)))
#define CALL_ONSTATEREQUEST(a) s_vendorFunctions->onStateRequest((RIL_SOCKET_ID)(a))
#else
#define CALL_ONREQUEST(a, b, c, d, e) s_vendorFunctions->onRequest((a), (b), (c), (d))
#define CALL_ONSTATEREQUEST(a) s_vendorFunctions->onStateRequest()
#endif
hardware\ril\libril\ril_service.cpp
bool dispatchVoid(int serial, int slotId, int request) {
RequestInfo *pRI = android::addRequestToList(serial, slotId, request);
if (pRI == NULL) {
return false;
}
CALL_ONREQUEST(request, NULL, 0, pRI, slotId);
return true;
}
hardware\ril\reference-ril\reference-ril.c
宏调用
static void
onRequest (int request, void *data, size_t datalen, RIL_Token t)
{
ATResponse *p_response;
int err;
......
switch (request) {
......
case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND:
// 3GPP 22.030 6.5.5
// "Releases all held calls or sets User Determined User Busy
// (UDUB) for a waiting call."
at_send_command("AT+CHLD=0", NULL); //发送AT指令
default:
RLOGD("Request not supported. Tech: %d",TECH(sMdmInfo));
RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0); //处理请求
break;
}
}
hardware\ril\libril\ril.cpp
同上未经请求的回复,对应一张函数表,AT命令的请求相应均由函数跳转表路由到hardware\ril\libril\ril_service.cpp 去执行
static CommandInfo s_commands[] = {
#include "ril_commands.h"
};
hardware\ril\libril\ril_service.cpp
Return<void> RadioImpl::getModemActivityInfo(int32_t serial) { //查询活跃信息
#if VDBG
RLOGD("getModemActivityInfo: serial %d", serial);
#endif
dispatchVoid(serial, mSlotId, RIL_REQUEST_GET_ACTIVITY_INFO); //上述请求派发函数
return Void();
}
hardware\ril\libril\ril_service.cpp
struct RadioImpl : public IRadio {
int32_t mSlotId;
sp<IRadioResponse> mRadioResponse;
sp<IRadioIndication> mRadioIndication;
Return<void> setResponseFunctions(
const ::android::sp<IRadioResponse>& radioResponse,
const ::android::sp<IRadioIndication>& radioIndication);
}
intermediates\hardware\interfaces\radio\1.0\[email protected]_genc++_headers\gen\android\hardware\radio\1.0\IRadio.h
一项HAL的Binder服务接口;在hardware\interfaces\radio\1.0\vts\functional提供了一些接口和测试案例
struct IRadio : public ::android::hidl::base::V1_0::IBase {
virtual bool isRemote() const override { return false; }
......
}
暂且分析到这,以后在扩展到上层系统框架。