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

0 0