由于Android几乎所有的代码都是公开的,如果要对Framework层分析就必需先拿到Framework层的代码,我在前面已经搭建好了ubuntu14.04的环境,下载好了Android4.0的源码,其中也包括了Framework层和Package的代码,导出到宿主机Windows XP中用Source Insight 3.5工具来查看源码,Package中的代码可以导入到Eclipse下查看,我是把frameworks\base整个目录都导入到Source Insight 3.5工程中,可以选择我们需要的目录导入,如frameworks\base\media\tests\contents\media_api目录下有很多音、视频文件,可以只导入frameworks\base\core、frameworks\base\telephony、frameworks\base\services、frameworks\base\include等目录。需要代码的可以到这下载:http://pan.baidu.com/s/1i3KczeX在PhoneApp初始化时,有以下代码
@Override
public void onCreate() {
//...........
if (phone == null) {
// 初始化phone frameworks层
PhoneFactory.makeDefaultPhones(this);
// 获取默认的phone对象
phone = PhoneFactory.getDefaultPhone();
mCM = CallManager.getInstance();
mCM.registerPhone(phone);
//.............
}
//...............
}
在应用层的PhoneApp中调用PhoneFactory的静态方法makeDefaultPhones创建一个默认的Phone对象,而framework中采用的是代理模式和工厂模式实现,在makedefaultPhone中
//***** Class Methods
public static void makeDefaultPhones(Context context) {
makeDefaultPhone(context);
}
/**
* FIXME replace this with some other way of making these
* instances
*/
public static void makeDefaultPhone(Context context) {
synchronized(Phone.class) {
if (!sMadeDefaults) {
sLooper = Looper.myLooper();
sContext = context;
if (sLooper == null) {
throw new RuntimeException(
"PhoneFactory.makeDefaultPhone must be called from Looper thread");
}
int retryCount = 0;
for(;;) {
boolean hasException = false;
retryCount ++;
try {
// use UNIX domain socket to
// prevent subsequent initialization
new LocalServerSocket("com.android.internal.telephony");
} catch (java.io.IOException ex) {
hasException = true;
}
if ( !hasException ) {
break;
} else if (retryCount > SOCKET_OPEN_MAX_RETRY) {
throw new RuntimeException("PhoneFactory probably already running");
} else {
try {
Thread.sleep(SOCKET_OPEN_RETRY_MILLIS);
} catch (InterruptedException er) {
}
}
}
sPhoneNotifier = new DefaultPhoneNotifier();
// Get preferred network mode
int preferredNetworkMode = RILConstants.PREFERRED_NETWORK_MODE;
if (BaseCommands.getLteOnCdmaModeStatic() == Phone.LTE_ON_CDMA_TRUE) {
preferredNetworkMode = Phone.NT_MODE_GLOBAL;
}
int networkMode = Settings.Secure.getInt(context.getContentResolver(),
Settings.Secure.PREFERRED_NETWORK_MODE, preferredNetworkMode);
Log.i(LOG_TAG, "Network Mode set to " + Integer.toString(networkMode));
// Get cdmaSubscription
// TODO: Change when the ril will provides a way to know at runtime
// the configuration, bug 4202572. And the ril issues the
// RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED, bug 4295439.
int cdmaSubscription;
int lteOnCdma = BaseCommands.getLteOnCdmaModeStatic();
switch (lteOnCdma) {
case Phone.LTE_ON_CDMA_FALSE:
cdmaSubscription = RILConstants.SUBSCRIPTION_FROM_NV;
Log.i(LOG_TAG, "lteOnCdma is 0 use SUBSCRIPTION_FROM_NV");
break;
case Phone.LTE_ON_CDMA_TRUE:
cdmaSubscription = RILConstants.SUBSCRIPTION_FROM_RUIM;
Log.i(LOG_TAG, "lteOnCdma is 1 use SUBSCRIPTION_FROM_RUIM");
break;
case Phone.LTE_ON_CDMA_UNKNOWN:
default:
//Get cdmaSubscription mode from Settings.System
cdmaSubscription = Settings.Secure.getInt(context.getContentResolver(),
Settings.Secure.PREFERRED_CDMA_SUBSCRIPTION,
preferredCdmaSubscription);
Log.i(LOG_TAG, "lteOnCdma not set, using PREFERRED_CDMA_SUBSCRIPTION");
break;
}
Log.i(LOG_TAG, "Cdma Subscription set to " + cdmaSubscription);
//reads the system properties and makes commandsinterface
sCommandsInterface = new RIL(context, networkMode, cdmaSubscription);
int phoneType = getPhoneType(networkMode);
if (phoneType == Phone.PHONE_TYPE_GSM) {
Log.i(LOG_TAG, "Creating GSMPhone");
sProxyPhone = new PhoneProxy(new GSMPhone(context,
sCommandsInterface, sPhoneNotifier));
} else if (phoneType == Phone.PHONE_TYPE_CDMA) {
switch (BaseCommands.getLteOnCdmaModeStatic()) {
case Phone.LTE_ON_CDMA_TRUE:
Log.i(LOG_TAG, "Creating CDMALTEPhone");
sProxyPhone = new PhoneProxy(new CDMALTEPhone(context,
sCommandsInterface, sPhoneNotifier));
break;
case Phone.LTE_ON_CDMA_FALSE:
default:
Log.i(LOG_TAG, "Creating CDMAPhone");
sProxyPhone = new PhoneProxy(new CDMAPhone(context,
sCommandsInterface, sPhoneNotifier));
break;
}
}
sMadeDefaults = true;
}
}
}
在PhoneFactory.java类中定义了
static private CommandsInterface sCommandsInterface = null;
//reads the system properties and makes commandsinterface
sCommandsInterface = new RIL(context, networkMode, cdmaSubscription);
所以后面用到的CommandsInterface对象都是RIL类,由于RIL实现了CommandsInterface
在以下代码中根据不同的类型创建Phone,如GSM(2G中国移动和联通)、CDMA(中国电信)等,采用了向上转型,向上转型是安全的。
int phoneType = getPhoneType(networkMode);
if (phoneType == Phone.PHONE_TYPE_GSM) {
Log.i(LOG_TAG, "Creating GSMPhone");
sProxyPhone = new PhoneProxy(new GSMPhone(context,
sCommandsInterface, sPhoneNotifier));
} else if (phoneType == Phone.PHONE_TYPE_CDMA) {
switch (BaseCommands.getLteOnCdmaModeStatic()) {
case Phone.LTE_ON_CDMA_TRUE:
Log.i(LOG_TAG, "Creating CDMALTEPhone");
sProxyPhone = new PhoneProxy(new CDMALTEPhone(context,
sCommandsInterface, sPhoneNotifier));
break;
case Phone.LTE_ON_CDMA_FALSE:
default:
Log.i(LOG_TAG, "Creating CDMAPhone");
sProxyPhone = new PhoneProxy(new CDMAPhone(context,
sCommandsInterface, sPhoneNotifier));
break;
}
}
GSMPhone和
CDMAPhone都继承了
PhoneBase,以下分析默认创建的是GSMPhone;在
GSMPhone.java的构造函数中
// Constructors
public
GSMPhone (Context context, CommandsInterface ci, PhoneNotifier notifier) {
this(context,ci,notifier, false);
}
public
GSMPhone (Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode) {
super(notifier, context, ci, unitTestMode);
if (ci instanceof SimulatedRadioControl) {
mSimulatedRadioControl = (SimulatedRadioControl) ci;
}
mCM.setPhoneType(Phone.PHONE_TYPE_GSM);
mCT = new GsmCallTracker(this); //通话管理
mSST = new GsmServiceStateTracker (this);
mSMS = new GsmSMSDispatcher(this, mSmsStorageMonitor, mSmsUsageMonitor);
mIccFileHandler = new SIMFileHandler(this);
mIccRecords = new SIMRecords(this);
mDataConnectionTracker = new GsmDataConnectionTracker (this);
mIccCard = new SimCard(this);
if (!unitTestMode) {
mSimPhoneBookIntManager = new SimPhoneBookInterfaceManager(this);
mSimSmsIntManager = new SimSmsInterfaceManager(this, mSMS);
mSubInfo = new PhoneSubInfo(this);
}
mStkService = CatService.getInstance(mCM, mIccRecords, mContext, mIccFileHandler, mIccCard);
mCM.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
mIccRecords.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
mCM.registerForOn(this, EVENT_RADIO_ON, null);
mCM.setOnUSSD(this, EVENT_USSD, null);
mCM.setOnSuppServiceNotification(this, EVENT_SSN, null);
mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null);
if (false) {
try {
//debugSocket = new LocalServerSocket("com.android.internal.telephony.debug");
debugSocket = new ServerSocket();
debugSocket.setReuseAddress(true);
debugSocket.bind (new InetSocketAddress("127.0.0.1", 6666));
debugPortThread
= new Thread(
new Runnable() {
public void run() {
for(;;) {
try {
Socket sock;
sock = debugSocket.accept();
Log.i(LOG_TAG, "New connection; resetting radio");
mCM.resetRadio(null);
sock.close();
} catch (IOException ex) {
Log.w(LOG_TAG,
"Exception accepting socket", ex);
}
}
}
},
"GSMPhone debug");
debugPortThread.start();
} catch (IOException ex) {
Log.w(LOG_TAG, "Failure to open com.android.internal.telephony.debug socket", ex);
}
}
//Change the system property
SystemProperties.set(TelephonyProperties.CURRENT_ACTIVE_PHONE,
new Integer(Phone.PHONE_TYPE_GSM).toString());
}
在这里创建了通话管理类GsmCallTracker mCT = new GsmCallTracker(this); //通话管理
//***** Constructors
GsmCallTracker (GSMPhone phone) {
this.phone = phone;
cm = phone.mCM;
cm.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null);
cm.registerForOn(this, EVENT_RADIO_AVAILABLE, null);
cm.registerForNotAvailable(this, EVENT_RADIO_NOT_AVAILABLE, null);
}
由于GsmCallTracker的父类继承了Handler,有以下方法
//****** Overridden from Handler
public void
handleMessage (Message msg) {
AsyncResult ar;
switch (msg.what) {
case EVENT_POLL_CALLS_RESULT:
ar = (AsyncResult)msg.obj;
if (msg == lastRelevantPoll) {
if (DBG_POLL) log(
"handle EVENT_POLL_CALL_RESULT: set needsPoll=F");
needsPoll = false;
lastRelevantPoll = null;
handlePollCalls((AsyncResult)msg.obj);
}
break;
case EVENT_OPERATION_COMPLETE:
ar = (AsyncResult)msg.obj;
operationComplete();
break;
case EVENT_SWITCH_RESULT:
case EVENT_CONFERENCE_RESULT:
case EVENT_SEPARATE_RESULT:
case EVENT_ECT_RESULT:
ar = (AsyncResult)msg.obj;
if (ar.exception != null) {
phone.notifySuppServiceFailed(getFailedService(msg.what));
}
operationComplete();
break;
case EVENT_GET_LAST_CALL_FAIL_CAUSE:
int causeCode;
ar = (AsyncResult)msg.obj;
operationComplete();
if (ar.exception != null) {
// An exception occurred...just treat the disconnect
// cause as "normal"
causeCode = CallFailCause.NORMAL_CLEARING;
Log.i(LOG_TAG,
"Exception during getLastCallFailCause, assuming normal disconnect");
} else {
causeCode = ((int[])ar.result)[0];
}
// Log the causeCode if its not normal
if (causeCode == CallFailCause.NO_CIRCUIT_AVAIL ||
causeCode == CallFailCause.TEMPORARY_FAILURE ||
causeCode == CallFailCause.SWITCHING_CONGESTION ||
causeCode == CallFailCause.CHANNEL_NOT_AVAIL ||
causeCode == CallFailCause.QOS_NOT_AVAIL ||
causeCode == CallFailCause.BEARER_NOT_AVAIL ||
causeCode == CallFailCause.ERROR_UNSPECIFIED) {
GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation());
EventLog.writeEvent(EventLogTags.CALL_DROP,
causeCode, loc != null ? loc.getCid() : -1,
TelephonyManager.getDefault().getNetworkType());
}
for (int i = 0, s = droppedDuringPoll.size()
; i < s ; i++
) {
GsmConnection conn = droppedDuringPoll.get(i);
conn.onRemoteDisconnect(causeCode);
}
updatePhoneState();
phone.notifyPreciseCallStateChanged();
droppedDuringPoll.clear();
break;
case EVENT_REPOLL_AFTER_DELAY:
case EVENT_CALL_STATE_CHANGE:
pollCallsWhenSafe();
break;
case EVENT_RADIO_AVAILABLE:
handleRadioAvailable();
break;
case EVENT_RADIO_NOT_AVAILABLE:
handleRadioNotAvailable();
break;
}
}
在这个分支
case EVENT_CALL_STATE_CHANGE: 去获取当前的状态
protected void pollCallsWhenSafe() {
needsPoll = true;
if (checkNoOperationsPending()) {
lastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);
cm.getCurrentCalls(lastRelevantPoll);
}
}
在RIL.java类中的实现
public void
getCurrentCalls (Message result) {
RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_CURRENT_CALLS, result);
if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
send(rr);
}
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();
}
在这里通知应用层改变状态
事件通知流程
为了加深理解,我也自己写了一个例子,在GsmCallTracker开一个线程去随机模拟电话状态的改变,程序相当简单
程序目录结构
在PhoneApp中做一些全局的初始化工作
package com.dzt.phonemsg;
import android.app.Application;
import android.util.Log;
import com.dzt.phonemsg.framework.CallManager;
import com.dzt.phonemsg.framework.Phone;
/**
* 演示Phone程序中的事件传递,由于Phone应用程序在代码跟踪时不是很方便,
* 并且Phone的消息通讯也比较复杂,就自己把部分代码拿出来模拟Handler的消息传递,用到了觀察者模式
*
* @author Administrator
* @date 2014.08.01
*/
public class PhoneApp extends Application {
private static final String TAG = "PhoneApp_dzt";
private static final boolean mIsShowLog = true;
static PhoneApp instance = null;
Phone phone = new Phone();
CallManager mCM;
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
instance = this;
mCM = CallManager.getInstance();
mCM.registerPhone(phone);
print_i("PhoneApp", "onCreate");
}
/**
* Returns the singleton instance of the PhoneApp.
*/
static PhoneApp getInstance() {
return instance;
}
static boolean isRunning() {
if (instance != null)
return true;
return false;
}
/**
* 打印消息
*
* @param pkg
* @param msg
*/
public static void print_i(String pkg, String msg) {
if (mIsShowLog)
Log.i(TAG, "[" + pkg + "]-------------------->" + msg);
}
}
在InCallScreen类中注册需要处理的消息,并根据不同的状态使用一个TextView来更新
package com.dzt.phonemsg;
import com.dzt.phonemsg.framework.CallManager;
import com.dzt.phonemsg.framework.Phone;
import com.dzt.phonemsg.os.AsyncResult;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.TextView;
public class InCallScreen extends Activity {
private static final int PHONE_STATE_CHANGED = 101;
private static final int REQUEST_UPDATE_SCREEN = 122;
private TextView mText = null;
private Phone.State mState = Phone.State.IDLE;
private CallManager mCM;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mText = (TextView) findViewById(R.id.tv_text);
mCM = PhoneApp.getInstance().mCM;
registerForPhoneStates();
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
if (PhoneApp.isRunning()) {
PhoneApp.getInstance().phone.exitPhone();
}
super.onDestroy();
}
/**
* Something has changed in the phone's state. Update the UI.
*/
private void onPhoneStateChanged(AsyncResult r) {
mState = mCM.getState();
requestUpdateScreen();
}
/**
* 注册PHONE_STATE_CHANGED标记,跟CallManager通讯
*/
private void registerForPhoneStates() {
mCM.registerForPreciseCallStateChanged(mHandler, PHONE_STATE_CHANGED,
null);
}
/* package */void requestUpdateScreen() {
PhoneApp.print_i("MainActivity", "requestUpdateScreen()...");
mHandler.removeMessages(REQUEST_UPDATE_SCREEN);
mHandler.sendEmptyMessage(REQUEST_UPDATE_SCREEN);
}
/**
* 处理UI的操作,如更新通话状态和时间
*/
private void updateScreen() {
mText.setText(mState.toString());
}
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case PHONE_STATE_CHANGED:
onPhoneStateChanged((AsyncResult) msg.obj);
break;
case REQUEST_UPDATE_SCREEN:
updateScreen();
break;
default:
break;
}
};
};
}
GsmCallTracker这个类去改变不同的状态,用一个线程来获取随机来改变
package com.dzt.phonemsg.framework;
import java.util.Random;
/**
* 在这里随机改变状态,模拟通话管理
*
* @author Administrator
*
*/
public class GsmCallTracker {
Phone.State state = Phone.State.IDLE;
boolean mIsRunning = false;
Phone mPhone = null;
GsmCallTracker(Phone phone) {
// TODO Auto-generated constructor stub
mIsRunning = true;
mPhone = phone;
new CallTrackerThread().start();
}
public void exitGsmCallTracker() {
mIsRunning = false;
}
class CallTrackerThread extends Thread {
@Override
public void run() {
// TODO Auto-generated method stub
while (mIsRunning) {
Random random = new Random();
int data = random.nextInt(3);
switch (data) {
case 0:
state = Phone.State.IDLE;
break;
case 1:
state = Phone.State.RINGING;
break;
case 2:
state = Phone.State.OFFHOOK;
break;
default:
state = Phone.State.IDLE;
break;
}
mPhone.notifyPreciseCallStateChanged();
// PhoneApp.print_i("GsmCallTracker",
// "CallTrackerThread data = "
// + data + "----" + state.toString());
try {
sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}