Framework中的Ril源码分析.docx_第1页
Framework中的Ril源码分析.docx_第2页
Framework中的Ril源码分析.docx_第3页
Framework中的Ril源码分析.docx_第4页
Framework中的Ril源码分析.docx_第5页
已阅读5页,还剩13页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Framework中的Ril源码分析目录(?)- 一概述 二RILRequest 三发送子线程 如何把数据发送到mSenderThread mSenderThread子线程把请求发送给RILC 四接收子线程 接收数据的过程 数据的处理流程 URC消息处理流程 非URC消息处理流程 为了区别RIL层中的RIL.cpp,我们约定framework中的RIL.java文件描述为RILJ,而hardware中的RIL.cpp描述为RILC。一、概述 所有上层对RIL层的请求,最终都需要在RILJ中转换为RIL层可识别的命令,然后通过Socket通道传输下去;同时,RIL层数据的上报,也要通过 RILJ进行解码,还原为上层容易识别的格式。因此,RILJ是framework与RIL层交互的通道。 RILJ有两个主要特点: 1、开启了两个独立线程分别负责发送数据和接收数据 2、数据的发送和接收是异步的 第一个特点很容易理解,而对于第二个特点有衍生出来了另一个问题:既然是异步的消息机制,也就是说发送者在发送完数据后就可以返回,那么当得到回应后,就要有一种方法去找到当初的请求者,并把结果返回给他。那么这个方法是什么呢? 这个方法就是令牌系统,我们将在第二节介绍。 有了以上简要的认识,我们从RILJ的入口开始展开我们的分析,也就是RILJ的构造函数: javaview plaincopy RIL.java public RIL(Context context, int preferredNetworkType, int cdmaSubscription) super(context); /发送子线程 mSenderThread = new HandlerThread(RILSender); mSenderThread.start(); Looper looper = mSenderThread.getLooper(); /mSender是发送子线程的Handler,通过他可以发送数据 mSender = new RILSender(looper); /接收子线程 mReceiver = new RILReceiver(); mReceiverThread = new Thread(mReceiver, RILReceiver); mReceiverThread.start(); 可以看到,在构造函数中开启了两个独立的子线程:mSenderThread用于给RILC发送数据,而mReceiverThread用于接收RILC上报的数据。 下面我们分析两个子线程的处理流程。而在介绍他们之前,我们先来介绍以下在RIL层中传递的消息的格式:RILRequest。二、RILRequest 我们单独拿出一小节来介绍RILRequest对象,是因为里面包含了我们在文章开始地方介绍的“消息异步传输”的秘密。 首先来看他的属性:class RILRequest ,说明这是一个独立的类,没有继承任何的父类或接口。他也在RIL.java中,同时也是RIL.java中除了RIL外唯一的类。 我们再来看一下RILRequest的构成: javaview plaincopy class RILRequest /令牌 int mSerial; int mRequest; Message mResult; Parcel mp; RILRequest mNext; /生成一个RILRequest的消息对象 static RILRequest obtain(int request, Message result) /释放资源 void release() /构造函数,内容为空 private RILRequest() /重置令牌 static void resetSerial() sNextSerial.set(sRandom.nextInt(); /用于调试 String serialString() /异常处理 void onError(int error, Object ret) 这个类并不复杂,主要的包括一些成员变量和两个重要的成员函数:用于生成消息对象的obtain方法和用于释放对象的release方法。我们先来介绍他的成员变量: mSerial:这个变量就是一个令牌,每生成(obtain)一个新的请求,都将产生一个递增的、唯一的mSerial,当从RILC得到一个数据后, 我们将通过mSerial找到当初发送这个请求的对象。这也就是异步通信最关键的联系点。我们在RIL层谈到的令牌(token)就是这个东西。 mRequest:请求码,需要和RIL层中的ril_commands.h文件内定义的请求码一致。 mResult:生成当前请求的请求者。从RILC中得到数据后,需要把数据处理后返回给mResult指向的对象。 mp:附加数据。 mNext:链表结构,代表下一个RILRequest。 然后我们介绍RILRequest中主要的方法,先来看看obtain: javaview plaincopy static RILRequest obtain(int request, Message result) RILRequest rr = null; synchronized(sPoolSync) /释放的RILRequest可以循环利用 if (sPool != null) rr = sPool; sPool = rr.mNext; rr.mNext = null; sPoolSize-; if (rr = null) rr = new RILRequest(); rr.mSerial = sNextSerial.getAndIncrement(); rr.mRequest = request; rr.mResult = result; rr.mp = Parcel.obtain(); rr.mp.writeInt(request); rr.mp.writeInt(rr.mSerial); return rr; 在obtain过程中,涉及到了sPool的用法,这个对象代表了一个RILRequest对象的链表,作用就是对RILRequest的循环利用, 具体原理就是:当一个RILRequest被销毁(release)的时候,可以把当前的RILRequest保存在sPool中,等下次需要申请 RILRequest时就去sPool中取出用即可,而无需重复的申请(new)RILRequest。同时sPool的最大个数为 4(MAX_POOL_SIZE)。 然后在obtain中对RILRequest对象的mSerial进行初始化,前面说过,这个值是当前请求的令牌,是唯一的。他是通过 getAndIncrement的方式生成的。这里补充以下AtomicInteger的知识:AtomicInteger是一个提供原子操作的 Integer的类。在Java语言中,+i和i+操作并不是线程安全的,在使用的时候,不可避免的会用到synchronized关键字。而 AtomicInteger则通过一种线程安全的加减操作接口。可以简单的理解为,getAndIncrement的方法可以得到一个绝对递增的整数。 接下来就是mResult的初始化,他的初始化过程很简单,就是简单的赋值。 然后是mp,他的初始化过程中把上面的request和mSerial都写了进去。 这就是生成RILRequest的过程。 接下来看看release方法: javaview plaincopy void release() synchronized (sPoolSync) if (sPoolSize 8) & 0xff); dataLength3 = (byte)(data.length) & 0xff); /通过Socket通道发送数据 s.getOutputStream().write(dataLength); s.getOutputStream().write(data); catch (IOException ex) catch (RuntimeException exc) break; case EVENT_WAKE_LOCK_TIMEOUT: break; 发送的过程比较直观,就是通过Socket通道把数据长度(dataLength)和数据(data)发送出去。四、接收子线程 接收子线程要完成的就是对接收数据的处理操作。我们还分为两步去分析:1、如何接收的消息;2、消息的处理流程。4.1、接收数据的过程 我们直接来看接收子线程的run方法: javaview plaincopy public void run() for (;) /开启Socket通道 s = new LocalSocket(); l = new LocalSocketAddress(SOCKET_NAME_RIL, LocalSocketAddress.Namespace.RESERVED); s.connect(l); mSocket = s; InputStream is = mSocket.getInputStream(); /接收数据过程 for (;) Parcel p; /从通道读取数据 length = readRilMessage(is, buffer); if (length 0) break; p = Parcel.obtain(); p.unmarshall(buffer, 0, length); p.setDataPosition(0); /处理数据 processResponse(p); p.recycle(); /关闭Socket,然后重新打开 mSocket.close(); mSocket = null; /清除令牌 RILRequest.resetSerial(); /清除所有请求 clearRequestList(RADIO_NOT_AVAILABLE, false); /通知ril连接状态改变 notifyRegistrantsRilConnectionChanged(-1); 从上面的过程中我们看到,我们是在接收的子线程中打开了Socket的通道,并且在通道内通过for死循环不断检测(readRilMessage)数据,然后通过processResponse去处理。如果读取的过程出现异常,将会关闭Socket通道,并且清除令牌和请求列表,重新打开Socket。 我们现在看一下readRilMessage的过程,至于处理的流程放到下一节介绍。javaview plaincopy private static int readRilMessage(InputStream is, byte buffer) throws IOException /先读取数据的长度 do /从InputStream中读取数据 countRead = is.read(buffer, offset, remaining); if (countRead 0); /计算数据长度 messageLength = (buffer0 & 0xff) 24) | (buffer1 & 0xff) 16) | (buffer2 & 0xff) 8) | (buffer3 & 0xff); remaining = messageLength; /再读取有效数据 do countRead = is.read(buffer, offset, remaining); if (countRead 0); return messageLength; 可以看出,返回的数据分为两部分,数据长度+数据内容,我们通过对InputStream的连续读取得到了完整的数据,并把数据的长度返回出来,而数据的内容通过buffer带出来。 下面介绍数据的处理流程(processResponse)。4.2、数据的处理流程 在RIL层源码分析文档中我们介绍过,RIL层收到的消息分为两部分: 一部分是Modem主动上报的消息,比如新短信的提醒、Modem状态的改变等,这类消息称为URC消息; 另一部分是由终端发送给Modem后,Modem给出的回应,属于非URC消息; 对于URC消息来说,只需要调用相应的通知机制即可;而对于非URC消息,我们还需要把相应的数据返回给当初发送请求的单位。 既然RIL层对消息的处理方式不同,那么对应的在RILJ中也要分开处理: javaview plaincopy private void processResponse (Parcel p) int type; /得到数据的类型,是URC消息还是非URC消息 type = p.readInt(); if (type = RESPONSE_UNSOLICITED) /URC消息的处理 processUnsolicited (p); else if (type = RESPONSE_SOLICITED) /非URC消息的处理 RILRequest rr = processSolicited (p); if (rr != null) rr.release(); decrementWakeLock(); 上面看到,URC消息是通过processUnsolicited处理的,而非URC消息是由processSolicited处理的,我们分别介绍两种处理流程。4.2.1、URC消息处理流程 URC消息是由processUnsolicited处理的: javaview plaincopy private void processUnsolicited (Parcel p) int response; Object ret; /读取当前消息的消息码 response = p.readInt(); /先处理 switch(response) case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED: ret = responseVoid(p); break; case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: ret = responseVoid(p); break; case RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED: ret = responseVoid(p); break; case RIL_UNSOL_RESPONSE_NEW_SMS: ret = responseString(p); break; . /再次处理 switch(response) case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED: /Radio状态改变 switchToRadioState(newState); break; case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: /通知call状态改变 mCallStateRegistrants.notifyRegistrants(new AsyncResult(null, null, null); break; case RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED: /通知网络状态改变 mVoiceNetworkStateRegistrants.notifyRegistrants(new AsyncResult(null, null, null); break; case RIL_UNSOL_RESPONSE_NEW_SMS: /新短信 SmsMessage sms; sms = SmsMessage.newFromCMT(a); if (mGsmSmsRegistrant != null) /发送短信通知 mGsmSmsRegistrant.notifyRegistrant(new AsyncResult(null, sms, null); break; case RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT: /短信报告 mSmsStatusRegistrant.notifyRegistrant( new AsyncResult(null, ret, null); break; 上面代码只挑出部分消息的处理代码,从中可以看到,URC消息的处理要经过两个switch语句的处理: A、第一个switch: 根据不同的消息码对数据进行初步解析,得到上报的有效数据。 responseVoid:当前消息的附带数据为空。 responseString:当前消息的附带数据为String型,需要得到String。 responseInts:当前消息的附带数据为int型的数组,需要得到这个数组。 B、第二个switch 在这个switch语句中针对不同的消息码用刚刚得到的有效数据进行不同的处理,主要就是调用相应的管理者去做相应的通知。4.2.2、非URC消息处理流程 非URC消息是在processSolicited中处理的: javaview plaincopy private RILRequest processSolicited (Parcel p) RILRequest rr; /得到当前的RILRequest对象,然后从mRequestList中将其删除 rr = findAndRemoveRequestFromList(serial); /得到RIL上报的数据 switch (rr.mRequest) case RIL_REQUEST_GET_SIM_STATUS: ret = responseIccCardStatus(p); break; case RIL_REQUEST_ENTER_SIM_PIN: ret = responseInts(p); break; case RIL_REQUEST_ENTER_SIM_PUK: ret = responseInts(p); break; case RIL_REQUEST_ENTER_SIM_PIN2: ret = responseInts(p); break; case RIL_REQUEST_ENTER_SIM_PUK2: ret = responseInts(p); break; case RIL_REQUEST_CHANGE_SIM_PIN: ret = responseInts(p); break; case RIL_REQUEST_CHANGE_SIM_PIN2: ret = responseInts(p); break; case RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION: ret = responseInts(p); break; case RIL_REQUEST_G

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论