(M)SIM卡开机流程分析之RIL类分析
来源:互联网 发布:ai软件工具介绍 编辑:程序博客网 时间:2024/05/19 15:19
今天,来简单看一下SIM卡开机流程中的另一个重要的类,RIL.java
首先,进入RIL.java文件中
/** * RIL implementation of the CommandsInterface. * * {@hide} */// Leo,需要注意这个地方,继承自BaseCommands,实现了CommandsInterface的接口public final class RIL extends BaseCommands implements CommandsInterface { ......}注意,这个类是继承自BaseCommands,并实现了CommandsInterface接口
再来看看,PhoneFactory.java文件中的makeDefaultPhone方法中对于RIL类的创建
for (int i = 0; i < numPhones; i++) { // reads the system properties and makes commandsinterface // Get preferred network type. networkModes[i] = RILConstants.PREFERRED_NETWORK_MODE; Rlog.i(LOG_TAG, "Network Mode set to " + Integer.toString(networkModes[i])); // Leo,为每一个卡槽新建一个RIL对象 // RIL是实现了CommandsInterface的接口,因此这个地方的名称为sCommandsInterfaces sCommandsInterfaces[i] = new RIL(context, networkModes[i], cdmaSubscription, i);}
// Leo,获取Settings.Global.CDMA_SUBSCRIPTION_MODE的值int cdmaSubscription = CdmaSubscriptionSourceManager.getDefault(context);
CdmaSubscriptionSourceManager.java/** * Gets the default CDMA subscription source * * @return Default CDMA subscription source from Settings DB if present. */ public static int getDefault(Context context) { // Get the default value from the Settings int subscriptionSource = Settings.Global.getInt(context.getContentResolver(), Settings.Global.CDMA_SUBSCRIPTION_MODE, PREFERRED_CDMA_SUBSCRIPTION); Rlog.d(LOG_TAG, "subscriptionSource from settings: " + subscriptionSource); return subscriptionSource; }networkModes[i]参数,从上面可以看到,是直接赋值的,cdmaSubscription参数,从上文中看值为指定的值,暂不追究,i参数是之的第几张卡槽,接下来,看看RIL的构造函数
// Leo, RIL的构造方法// 第四个参数是第instanceId个卡槽// 第二个参数是第instanceId个卡槽的PreferredNetworkMode值// 第三个参数cdmaSubscription,是Settings.Global.CDMA_SUBSCRIPTION_MODE的值public RIL(Context context, int preferredNetworkType, int cdmaSubscription, Integer instanceId) { super(context); ...... mContext = context; mCdmaSubscription = cdmaSubscription; mPreferredNetworkType = preferredNetworkType; mPhoneType = RILConstants.NO_PHONE; mInstanceId = instanceId; PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); // Leo, 这个WakeLock是干嘛用的? mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, RILJ_LOG_TAG); mWakeLock.setReferenceCounted(false); mWakeLockTimeout = SystemProperties.getInt(TelephonyProperties.PROPERTY_WAKE_LOCK_TIMEOUT, DEFAULT_WAKE_LOCK_TIMEOUT); mWakeLockCount = 0; // Leo HandlerThread mSenderThread = new HandlerThread("RILSender" + mInstanceId); mSenderThread.start(); Looper looper = mSenderThread.getLooper(); // Leo, 这个RILSender继承Handler,并实现Runnable接口 mSender = new RILSender(looper); ConnectivityManager cm = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); if (cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) { riljLog("Not starting RILReceiver: wifi-only"); } else { riljLog("Starting RILReceiver" + mInstanceId); // Leo,实现Socket通信,Runnable对象 mReceiver = new RILReceiver(); mReceiverThread = new Thread(mReceiver, "RILReceiver" + mInstanceId); mReceiverThread.start(); DisplayManager dm = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE); mDefaultDisplay = dm.getDisplay(Display.DEFAULT_DISPLAY); dm.registerDisplayListener(mDisplayListener, null); mDefaultDisplayState = mDefaultDisplay.getState(); // Leo,监控电量变化,为啥? IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); Intent batteryStatus = context.registerReceiver(mBatteryStateListener, filter); if (batteryStatus != null) { // 0 means it's on battery mIsDevicePlugged = batteryStatus.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0; } } // Leo,刚刚在PhoneFactory调用了一次TelephonyDevController的create方法 // 此处调用getInstance方法,可以得到其对象 TelephonyDevController tdc = TelephonyDevController.getInstance(); tdc.registerRIL(this);}从代码中可以看到,RIL的构造函数中,主要是做了
1)赋值操作
2)新建一些WakeLock,这个目前我还不知道其作用,待以后分析吧
3)启动了一个HandlerThread,然后新建一个RILSender对象,这个对象继承了Handler,并且实现了Runnable接口,但是其run方法中并未做任何操作
4)在判断手机支持移动数据流量的基础上,新建一个RILReceiver对象并直接启动,这个对象实现了Runnable的接口,在其run方法中,建立通信连接,实现RIL消息的传输和RIL消息的处理,这个一会儿再看
5)监听显示设置和电量变化
6)新建了TelephonyDevController对象,并注册RIL
接下来,我们就重点看看第4)条,进入RILReceiver类
class RILReceiver implements Runnable { byte[] buffer; RILReceiver() {buffer = new byte[RIL_MAX_COMMAND_BYTES]; } @Override public void run() {int retryCount = 0;String rilSocket = "rild";// Leo,Socket通信try {for (;;) {LocalSocket s = null;LocalSocketAddress l;if (mInstanceId == null || mInstanceId == 0) {rilSocket = SOCKET_NAME_RIL[0];} else {rilSocket = SOCKET_NAME_RIL[mInstanceId];}try {s = new LocalSocket();l = new LocalSocketAddress(rilSocket, LocalSocketAddress.Namespace.RESERVED);s.connect(l);} catch (IOException ex) {try {if (s != null) {s.close();}} catch (IOException ex2) {// ignore failure to close after failure to connect}// don't print an error message after the the first time// or after the 8th timeif (retryCount == 8) {Rlog.e(RILJ_LOG_TAG, "Couldn't find '" + rilSocket+ "' socket after " + retryCount+ " times, continuing to retry silently");} else if (retryCount >= 0 && retryCount < 8) {Rlog.i(RILJ_LOG_TAG, "Couldn't find '" + rilSocket+ "' socket; retrying after timeout");}try {Thread.sleep(SOCKET_OPEN_RETRY_MILLIS);} catch (InterruptedException er) {}retryCount++;continue;}retryCount = 0; mSocket = s;......int length = 0;try { InputStream is = mSocket.getInputStream();for (;;) { Parcel p;length = readRilMessage(is, buffer);if (length < 0) {// End-of-stream reachedbreak;}p = Parcel.obtain();p.unmarshall(buffer, 0, length);p.setDataPosition(0);// Rlog.v(RILJ_LOG_TAG, "Read packet: " + length +// " bytes");processResponse(p);p.recycle();}} catch (java.io.IOException ex) {Rlog.i(RILJ_LOG_TAG, "'" + rilSocket+ "' socket closed", ex);} catch (Throwable tr) {Rlog.e(RILJ_LOG_TAG, "Uncaught exception read length="+ length + "Exception:" + tr.toString());}Rlog.i(RILJ_LOG_TAG, "(" + mInstanceId+ ") Disconnected from '" + rilSocket + "' socket");setRadioState(RadioState.RADIO_UNAVAILABLE);try {mSocket.close();} catch (IOException ex) {}mSocket = null;RILRequest.resetSerial();// Clear request list on closeclearRequestList(RADIO_NOT_AVAILABLE, false);}} catch (Throwable tr) {Rlog.e(RILJ_LOG_TAG, "Uncaught exception", tr);}/* We're disconnected so we don't know the ril version */notifyRegistrantsRilConnectionChanged(-1);}}RILReceiver类是实现了Runnable的接口,其run方法主要是新建一个死循环
1)在死循环中新建LocalSocket和LocalSocketAddress对象,并建立链接,之后将LocalSocket对象赋值给全局对象mSocket
2)再新建一个死循环,这个死循环不间断地读取底层RIL传递上来的消息,然后调用processResponse方法处理这个RIL消息,直到完全结束后,释放Socket,并通知RILCONNECTION状态变化
那么,在RIL中是如何处理底层ril传递上来的ril消息呢?
private void processResponse (Parcel p) { int type; type = p.readInt(); if (type == RESPONSE_UNSOLICITED) { processUnsolicited (p); } else if (type == RESPONSE_SOLICITED) { RILRequest rr = processSolicited (p); if (rr != null) { rr.release(); decrementWakeLock(); } }}若回复请求,则调用processSolicited方法,反之,则调用processUnsoliciterd方法
private void processUnsolicited (Parcel p) { ......}
private RILRequest processSolicited (Parcel p) { ......}针对不同的请求,处理
在看到这个RIL.java文件的时候,我们发现在其文件中有一个RILRequest类,这个类是有什么作用呢?先看看这个类中的方法
/** * Retrieves a new RILRequest instance from the pool. * * @param request RIL_REQUEST_* * @param result sent when operation completes * @return a RILRequest instance from the pool. */static RILRequest obtain(int request, Message result) { RILRequest rr = null; synchronized(sPoolSync) { 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.mParcel = Parcel.obtain(); if (result != null && result.getTarget() == null) { throw new NullPointerException("Message target must not be null"); } // first elements in any RIL Parcel rr.mParcel.writeInt(request); rr.mParcel.writeInt(rr.mSerial); return rr;}这个方法,从代码中看,首先是先创建了一个RILRequest对象,这个对象保存了传入的request对象和result对象,然后将request和自身的mSerial写入mParcel对象中
对于release方法等,在此不做其他分析,可以自己看
我们在其他地方,经常会看到,需要调用RIL对象的大量获取数据的方法,那么,我们就仅下述方法来确认,究竟是什么样的流程,如下:
@Overridepublic void getVoiceRadioTechnology(Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_VOICE_RADIO_TECH, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr);}我们看到,这个地方调用了RILRequest的obtain方法,创建一个RILRequest对象,从上述分析我们知道,这会将该对象的mRequest参数置为RIL_REQUEST_VOICE_RADIO_TECH,而mResult对象置为result消息对象没然后新建一个mParcel对象
接下来进入RIL类的send方法
private void send(RILRequest rr) { Message msg; if (mSocket == null) { rr.onError(RADIO_NOT_AVAILABLE, null); rr.release(); return; } msg = mSender.obtainMessage(EVENT_SEND, rr); acquireWakeLock(); msg.sendToTarget();}mSender从前文中,我们知道这个是RILSender对象,这个对象继承了Handler,并实现了Runnable,因此其本质为Handler,那么调用msg的sendToTarget方法,即调用了mSender对象的handleMessage方法,而且msg的what为EVENT_SEND,obj参数为刚刚新建的RILRequest对象
RILSender的handleMessage方法对于EVENT_SEND的处理为
@Override public void handleMessage(Message msg) { RILRequest rr = (RILRequest)(msg.obj); RILRequest req = null; switch (msg.what) { case EVENT_SEND: try { LocalSocket s; s = mSocket; ...... synchronized (mRequestList) { // Leo,写入 mRequestList.append(rr.mSerial, rr); } byte[] data; data = rr.mParcel.marshall(); rr.mParcel.recycle(); rr.mParcel = null; ...... // parcel length in big endian dataLength[0] = dataLength[1] = 0; dataLength[2] = (byte)((data.length >> 8) & 0xff); dataLength[3] = (byte)((data.length) & 0xff); ...... s.getOutputStream().write(dataLength); s.getOutputStream().write(data); } catch (IOException ex) { ...... } catch (RuntimeException exc) { ...... } break; ...... }}新建LocalSocket对象,并且指向mSocket,mSocket我们在前面分析过,在RILRequest内部类中进行绑定了并发送,那么谁接收呢?自然是在RILReceiver的run方法中了,还记得它是有一个死循环,不断都去RIL命令么?其调用了processResponse方法,最终调用的是processSolicited方法
private RILRequest processSolicited(Parcel p) {int serial, error;boolean found = false;serial = p.readInt();error = p.readInt();RILRequest rr;rr = findAndRemoveRequestFromList(serial);if (rr == null) {......return null;}Object ret = null;if (error == 0 || p.dataAvail() > 0) {// either command succeeds or command fails but with data payloadtry {switch (rr.mRequest) {......case RIL_REQUEST_VOICE_RADIO_TECH:ret = responseInts(p);break;......} catch (Throwable tr) {......}}......return rr;}findAndRemoveRequestFromList方法从mRequestList取出rr.mSerial对应的RILRequest,是在RILSender对象的EVENT_SEND消息处添加的
然后获取其mRequest对象,我们知道为RIL_REQUEST_VOICE_RADIO_TECH,因此调用responseInts进行处理
private Object responseInts(Parcel p) { int numInts; int response[]; numInts = p.readInt(); response = new int[numInts]; for (int i = 0 ; i < numInts ; i++) { response[i] = p.readInt(); } return response;}至此,RIL类在SIM卡开机流程中,所作的大致用途,已经分析完成,待后续对开机流程中所遇到的具体问题,再在具体方法中进行分析
- (M)SIM卡开机流程分析之RIL类分析
- (M)SIM卡开机流程分析之主线分析
- (M)SIM卡开机流程分析之SPN加载
- (M)SIM卡开机流程分析之TelephonyDevController类分析
- (M)SIM卡开机流程分析之TelephonyManager类分析
- (M)SIM卡开机流程分析之UiccController类分析
- (M)SIM卡开机流程分析之DefaultPhoneNotifier类分析
- (M)SIM卡开机流程分析之SubscriptionController类分析
- (M)SIM卡开机流程分析之默认APN设置
- (M)SIM卡开机流程分析之显示名称加载
- 开机导入Sim卡联系人流程分析
- Android-RIL流程分析
- Android-RIL流程(呼叫等待)分析
- android之Sim Tool Kit流程分析
- Android4.4 Telephony流程分析——SIM卡开机时的初始化
- Android4.4 Telephony流程分析——SIM卡开机时的数据加载
- Android 4.4Telephony流程分析SIM卡开机时的数据加载
- Android 4.4Telephony流程分析SIM卡开机时的初始化
- gulp预编译less和自动刷新网页
- Maven构建部署项目遇到的各种问题以及解决办法
- LeetCode 第六题 ZigZag(求讨论)
- 队列和循环队列
- SQL Server时间算法总结
- (M)SIM卡开机流程分析之RIL类分析
- 今天的小bug , 表单按钮自动提交问题
- printf格式问题
- 鸟哥的linux私房菜学习笔记《二十三》通配符、重定向、管道等bash用法
- 基于 SpringBoot 和 webSocket 的匿名聊天室
- Java Collection框架
- CNN卷积神经网络应用于人脸识别(详细流程+代码实现)和相应的超参数解释
- Tomcat第一课--构建简单静态资源访问
- 卡尔曼滤波器(KF)和粒子滤波器(PF)简述