我想为google贡献源码
工作过程中发现Android源码也有不健壮的时候,switchWith时候概率性会出现空指针异常。
frameworks\opt\telephony\src\java\com\android\internal\telephony\imsphone\ImsPhoneCallTracker.java
public void holdActiveCallForWaitingCall() throws CallStateException {
boolean switchingWithWaitingCall = !mBackgroundCall.getState().isAlive()
&& mRingingCall.getState() == ImsPhoneCall.State.WAITING;
if (switchingWithWaitingCall) {
ImsCall callToHold = mForegroundCall.getImsCall();
HoldSwapState oldHoldState = mHoldSwitchingState;
mHoldSwitchingState = HoldSwapState.HOLDING_TO_ANSWER_INCOMING;
//mForegroundCall是ImsPhoneCall的实例,我们可以参考下具体的实现
mForegroundCall.switchWith(mBackgroundCall);
logHoldSwapState("holdActiveCallForWaitingCall");
try {
callToHold.hold();
mMetrics.writeOnImsCommand(mPhone.getPhoneId(), callToHold.getSession(),
ImsCommand.IMS_CMD_HOLD);
} catch (ImsException e) {
mForegroundCall.switchWith(mBackgroundCall);
mHoldSwitchingState = oldHoldState;
logHoldSwapState("holdActiveCallForWaitingCall - fail");
throw new CallStateException(e.getMessage());
}
}
}
frameworks\opt\telephony\src\java\com\android\internal\telephony\imsphone\ImsPhoneCall.java
public void switchWith(ImsPhoneCall that) {
if (VDBG) {
Rlog.v(LOG_TAG, "switchWith : switchCall = " + this + " withCall = " + that);
}
synchronized (ImsPhoneCall.class) {
ImsPhoneCall tmp = new ImsPhoneCall();//这里创建了个临时对象用于交换前后台通话,我们参考下ImsPhoneCall的无参构造方法
//mForegroundCall现在复制给了tmp,将tmp中的mConnections 指向内存空间中mForegroundCall的mConnections 内存空间地址
//mState,Connection的mParent都修改了指向。这个时候问题出现了。
tmp.takeOver(this);
this.takeOver(that);//
that.takeOver(tmp);
}
mOwner.logState();
}
ImsPhoneCall() {
mCallContext = CONTEXT_UNKNOWN;
//这里并没有给mOwner进行赋值。
}
//修改指向
private void takeOver(ImsPhoneCall that) {
mConnections = that.mConnections;
mState = that.mState;
for (Connection c : mConnections) {
((ImsPhoneConnection) c).changeParent(this);
}
}
问题发生场景:
当ImsPhoneConnection的changeParent改变后,原来mForegroundCall的parent现在是指向tmp的
上层创建connection的时候获取当前connection的phone的类型
调用顺序ImsPhoneConnection.getCall().getPhone()
public ImsPhoneCall getCall() {
return mParent;
}
public Phone
getPhone() {//getPhone非同步方法,switchWith持锁,并没有影响外部的getPhone(),tmp的mOwner没有初始化,默认状态是null.这时候空指针出来了
return mOwner.getPhone();
}
解决方法:
修改switchWith中new ImsPhoneCall(),创建tmp的时候使用有参构造方法即可
public ImsPhoneCall(ImsPhoneCallTracker owner, String context) {
mOwner = owner;
mCallContext = context;
}