(M)SIM卡开机流程分析之RIL类分析

    xiaoxiao2021-03-25  100

    今天,来简单看一下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 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 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 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卡开机流程中,所作的大致用途,已经分析完成,待后续对开机流程中所遇到的具体问题,再在具体方法中进行分析

    转载请注明原文地址: https://ju.6miu.com/read-16898.html

    最新回复(0)