您的位置:首页 > 其它

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

2017-03-09 23:06 399 查看
今天,来简单看一下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 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卡开机流程中,所作的大致用途,已经分析完成,待后续对开机流程中所遇到的具体问题,再在具体方法中进行分析
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: