(M)SIM卡开机流程分析之RIL类分析
2017-03-09 23:06
399 查看
今天,来简单看一下SIM卡开机流程中的另一个重要的类,RIL.java
首先,进入RIL.java文件中
再来看看,PhoneFactory.java文件中的makeDefaultPhone方法中对于RIL类的创建
1)赋值操作
2)新建一些WakeLock,这个目前我还不知道其作用,待以后分析吧
3)启动了一个HandlerThread,然后新建一个RILSender对象,这个对象继承了Handler,并且实现了Runnable接口,但是其run方法中并未做任何操作
4)在判断手机支持移动数据流量的基础上,新建一个RILReceiver对象并直接启动,这个对象实现了Runnable的接口,在其run方法中,建立通信连接,实现RIL消息的传输和RIL消息的处理,这个一会儿再看
5)监听显示设置和电量变化
6)新建了TelephonyDevController对象,并注册RIL
接下来,我们就重点看看第4)条,进入RILReceiver类
1)在死循环中新建LocalSocket和LocalSocketAddress对象,并建立链接,之后将LocalSocket对象赋值给全局对象mSocket
2)再新建一个死循环,这个死循环不间断地读取底层RIL传递上来的消息,然后调用processResponse方法处理这个RIL消息,直到完全结束后,释放Socket,并通知RILCONNECTION状态变化
那么,在RIL中是如何处理底层ril传递上来的ril消息呢?
在看到这个RIL.java文件的时候,我们发现在其文件中有一个RILRequest类,这个类是有什么作用呢?先看看这个类中的方法
对于release方法等,在此不做其他分析,可以自己看
我们在其他地方,经常会看到,需要调用RIL对象的大量获取数据的方法,那么,我们就仅下述方法来确认,究竟是什么样的流程,如下:
接下来进入RIL类的send方法
RILSender的handleMessage方法对于EVENT_SEND的处理为
然后获取其mRequest对象,我们知道为RIL_REQUEST_VOICE_RADIO_TECH,因此调用responseInts进行处理
首先,进入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 time if (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 reached break; } 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 close clearRequestList(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对象的大量获取数据的方法,那么,我们就仅下述方法来确认,究竟是什么样的流程,如下:
@Override public 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 e afa8 ndian 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 payload try { 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卡开机流程分析之TelephonyManager类分析
- (M)SIM卡开机流程分析之显示名称加载
- Android4.4 Telephony流程分析——SIM卡开机时的数据加载
- Android 4.4Telephony流程分析SIM卡开机时的数据加载
- (M)SIM卡开机流程分析之UiccController类分析
- (M)SIM卡开机流程分析之SubscriptionController类分析
- Android4.4 Telephony流程分析——SIM卡开机时的初始化
- (M)SIM卡开机流程分析之主线分析
- (M)SIM卡开机流程分析之默认APN设置
- Android4.4 Telephony流程分析——SIM卡开机时的初始化
- (M)SIM卡开机流程分析之DefaultPhoneNotifier类分析
- (M)SIM卡开机流程分析之TelephonyDevController类分析
- Android 4.4Telephony流程分析SIM卡开机时的初始化
- Ril分析四——来自网络端事件流程
- Android开机流程分析 -- init进程之配置文件解析
- Linux之RHEL6的开机流程分析
- [Android5.1]开机动画显示工作流程分析
- Linux的开机流程与主引导分区(MBR)的简单分析
- Android源码分析---系统开机流程
- Launcher3 开机后应用数据的加载流程分析