【安卓R 源码】从 Telecom CallAudioModeStateMachine详解StateMachine状态机源码
状态机是将对象的状态与行为封装在一起;可以解决庞大的分支语句带来程序阅读性差和不便于进行扩展问题,使整个结构变得更加清晰明了,降低程序管理的复杂性提高灵活度。Android系统的StateMachine机制是一个State模式的应用,StateMachine是一个分层处理消息的状态机,并且是能够有分层排列状态。以 Telecom 的CallAudioModeStateMachine 作为分析:1.
状态机是将对象的状态与行为封装在一起;可以解决庞大的分支语句带来程序阅读性差和不便于进行扩展问题,使整个结构变得更加清晰明了,降低程序管理的复杂性提高灵活度。Android系统的StateMachine机制是一个State模式的应用,StateMachine是一个分层处理消息的状态机,并且是能够有分层排列状态。
以 Telecom 的CallAudioModeStateMachine 作为分析:
1. 状态机的构造函数
- /packages/services/Telecomm/src/com/android/server/telecom/CallAudioModeStateMachine.java
public class CallAudioModeStateMachine extends StateMachine {
// 调用如下接口去初始化对象了
public static class Factory {
public CallAudioModeStateMachine create(SystemStateHelper systemStateHelper,
AudioManager am) {
return new CallAudioModeStateMachine(systemStateHelper, am);
}
}
看下构造函数
public CallAudioModeStateMachine(SystemStateHelper systemStateHelper,
AudioManager audioManager) {
// 传给父类一个参数:name
super(CallAudioModeStateMachine.class.getSimpleName());
mAudioManager = audioManager;
mSystemStateHelper = systemStateHelper;
mMostRecentMode = AudioManager.MODE_NORMAL;
// 构建 states 状态
createStates();
}
看下父类StateMachine 的构造函数
- /frameworks/base/core/java/com/android/internal/util/StateMachine.java
在
StateMachine
中,开启了一个线程HandlerThread
,其对应的Handler为SmHandler
。
@UnsupportedAppUsage
protected StateMachine(String name) {
mSmThread = new HandlerThread(name);
// 开启这个线程
mSmThread.start();
// 获取 Looper对象
Looper looper = mSmThread.getLooper();
initStateMachine(name, looper);
}
----------------
private void initStateMachine(String name, Looper looper) {
mName = name;
// 创建了 SmHandler 对象
mSmHandler = new SmHandler(looper, this);
}
SmHandler构造函数
SmHandler
构造方法中,向状态机中添加了两个状态:一个状态为状态机的暂停状态mHaltingState
、一个状态为状态机的退出状态mQuittingState
private static class SmHandler extends Handler {
// 2 个初始化的状态
private class HaltingState extends State {
@Override
public boolean processMessage(Message msg) {
mSm.haltedProcessMessage(msg);
return true;
}
}
/**
* State entered when a valid quit message is handled.
*/
private class QuittingState extends State {
@Override
public boolean processMessage(Message msg) {
return NOT_HANDLED;
}
}
private SmHandler(Looper looper, StateMachine sm) {
super(looper);
mSm = sm;
// 增加2 个状态 ,父亲state为空
addState(mHaltingState, null);
addState(mQuittingState, null);
}
- mHaltingState状态,顾名思义让状态机暂停,其对应的processMessage(Message msg)方法,返回值为true,将消息消费掉,但不处理消息。从而使状态机状态停顿到mHaltingState状态
- mQuittingState状态,若进入该状态, 状态机将退出。HandlerThread线程对应的Looper将退出,HandlerThread线程会被销毁,所有加入到状态机的状态被清空。
if (destState != null) { if (destState == mQuittingState) { /** * Call onQuitting to let subclasses cleanup. */ mSm.onQuitting(); cleanupAfterQuitting(); -------- private final void cleanupAfterQuitting() { if (mSm.mSmThread != null) { // If we made the thread then quit looper which stops the thread. getLooper().quit(); mSm.mSmThread = null; }
2. 启动状态机
继续看 构建 states 状态 createStates()
- /packages/services/Telecomm/src/com/android/server/telecom/CallAudioModeStateMachine.java
private void createStates() {
// 1. 增加如下状态
addState(mUnfocusedState);
addState(mRingingFocusState);
addState(mSimCallFocusState);
addState(mVoipCallFocusState);
addState(mAudioProcessingFocusState);
addState(mOtherFocusState);
// 2. 设置初始状态为 UnfocusedState
setInitialState(mUnfocusedState);
/// 3. 启动状态机
start();
// 4. 发送消息去初始化
sendMessage(INITIALIZE, new MessageArgs.Builder()
.setHasActiveOrDialingCalls(false)
.setHasRingingCalls(false)
.setHasHoldingCalls(false)
.setIsTonePlaying(false)
.setForegroundCallIsVoip(false)
.setSession(Log.createSubsession())
.build());
}
// 1. 增加如下状态
@UnsupportedAppUsage
public final void addState(State state) {
// 调用 SmHandler的 addState函数
// 父亲state 为null
mSmHandler.addState(state, null);
}
---------
private final StateInfo addState(State state, State parent) {
if (mDbg) {
mSm.log("addStateInternal: E state=" + state.getName() + ",parent="
+ ((parent == null) ? "" : parent.getName()));
}
StateInfo parentStateInfo = null;
// 如果parent 不为空的话,递归保存其父节点
if (parent != null) {
parentStateInfo = mStateInfo.get(parent);
if (parentStateInfo == null) {
// Recursively add our parent as it's not been added yet.
parentStateInfo = addState(parent, null);
}
}
StateInfo stateInfo = mStateInfo.get(state);
// 此时 stateInfo为空
if (stateInfo == null) {
stateInfo = new StateInfo();
//将全部6 种状态,保存到 mStateInfo散列表中
mStateInfo.put(state, stateInfo);
}
// Validate that we aren't adding the same state in two different hierarchies.
if ((stateInfo.parentStateInfo != null)
&& (stateInfo.parentStateInfo != parentStateInfo)) {
throw new RuntimeException("state already added");
}
stateInfo.state = state;
stateInfo.parentStateInfo = parentStateInfo;
stateInfo.active = false;
if (mDbg) mSm.log("addStateInternal: X stateInfo: " + stateInfo);
return stateInfo;
}
// 2. 设置初始状态为 UnfocusedState
@UnsupportedAppUsage
public final void setInitialState(State initialState) {
mSmHandler.setInitialState(initialState);
}
-------------
private final void setInitialState(State initialState) {
if (mDbg) mSm.log("setInitialState: initialState=" + initialState.getName());
// 设置初始状态 mInitialState
mInitialState = initialState;
}
// 3. 启动状态机 start()
mStateStack与mTempStateStack为两个用数组实现的堆栈。这两个堆栈的最大长度,即为maxDepth。其用来存储当前活跃状态与当前活跃状态的父状态、父父状态、...等
setupInitialStateStack();完成状态的初始化,将当前的活跃状态放入到mStateStack堆栈中。
@UnsupportedAppUsage
public void start() {
// mSmHandler can be null if the state machine has quit.
SmHandler smh = mSmHandler;
if (smh == null) return;
/** Send the complete construction message */
smh.completeConstruction();
}
---------------
* Complete the construction of the state machine.
*/
private final void completeConstruction() {
if (mDbg) mSm.log("completeConstruction: E");
/**
* Determine the maximum depth of the state hierarchy
* so we can allocate the state stacks.
*/
int maxDepth = 0;
// 由于没有父亲节点,这里 maxDepth 为 1
for (StateInfo si : mStateInfo.values()) {
int depth = 0;
for (StateInfo i = si; i != null; depth++) {
i = i.parentStateInfo;
}
if (maxDepth < depth) {
maxDepth = depth;
}
}
if (mDbg) mSm.log("completeConstruction: maxDepth=" + maxDepth);
// 状态堆栈
mStateStack = new StateInfo[maxDepth];
// 临时状态堆栈
mTempStateStack = new StateInfo[maxDepth];
// 初始化状态堆栈
setupInitialStateStack();
/** Sending SM_INIT_CMD message to invoke enter methods asynchronously */
// 发送初始化消息
sendMessageAtFrontOfQueue(obtainMessage(SM_INIT_CMD, mSmHandlerObj));
if (mDbg) mSm.log("completeConstruction: X");
}
setupInitialStateStack
private final void setupInitialStateStack() {
if (mDbg) {
mSm.log("setupInitialStateStack: E mInitialState=" + mInitialState.getName());
}
// 获取初始的状态 mUnfocusedState,将其保存在 mTempStateStack数组中
StateInfo curStateInfo = mStateInfo.get(mInitialState);
for (mTempStateStackCount = 0; curStateInfo != null; mTempStateStackCount++) {
mTempStateStack[mTempStateStackCount] = curStateInfo;
curStateInfo = curStateInfo.parentStateInfo;
}
// Empty the StateStack
mStateStackTopIndex = -1;
moveTempStateStackToStateStack();
}
------------------
// 将 临时的栈放到 mStateStack 栈中
private final int moveTempStateStackToStateStack() {
int startingIndex = mStateStackTopIndex + 1;
int i = mTempStateStackCount - 1;
int j = startingIndex;
while (i >= 0) {
if (mDbg) mSm.log("moveTempStackToStateStack: i=" + i + ",j=" + j);
mStateStack[j] = mTempStateStack[i];
j += 1;
i -= 1;
}
mStateStackTopIndex = j - 1;
if (mDbg) {
mSm.log("moveTempStackToStateStack: X mStateStackTop=" + mStateStackTopIndex
+ ",startingIndex=" + startingIndex + ",Top="
+ mStateStack[mStateStackTopIndex].state.getName());
}
return startingIndex;
}
发送初始化消息
sendMessageAtFrontOfQueue(obtainMessage(SM_INIT_CMD, mSmHandlerObj))
protected final void sendMessageAtFrontOfQueue(int what) {
// mSmHandler can be null if the state machine has quit.
SmHandler smh = mSmHandler;
if (smh == null) return;
smh.sendMessageAtFrontOfQueue(obtainMessage(what));
}
--------------
// 消息处理
@Override
public final void handleMessage(Message msg) {
if (!mHasQuit) {
if (mSm != null && msg.what != SM_INIT_CMD && msg.what != SM_QUIT_CMD) {
mSm.onPreHandleMessage(msg);
}
if (mDbg) mSm.log("handleMessage: E msg.what=" + msg.what);
/** Save the current message */
mMsg = msg;
/** State that processed the message */
State msgProcessedState = null;
if (mIsConstructionCompleted || (mMsg.what == SM_QUIT_CMD)) {
/** Normal path */
msgProcessedState = processMsg(msg);
// mIsConstructionCompleted 初始值为false
// 然后这里设置为true,就可以走到 上面的条件中去处理消息 processMsg
} else if (!mIsConstructionCompleted && (mMsg.what == SM_INIT_CMD)
&& (mMsg.obj == mSmHandlerObj)) {
/** Initial one time path. */
mIsConstructionCompleted = true;
//
invokeEnterMethods(0);
} else {
throw new RuntimeException("StateMachine.handleMessage: "
+ "The start method not called, received msg: " + msg);
}
performTransitions(msgProcessedState, msg);
// We need to check if mSm == null here as we could be quitting.
if (mDbg && mSm != null) mSm.log("handleMessage: X");
if (mSm != null && msg.what != SM_INIT_CMD && msg.what != SM_QUIT_CMD) {
mSm.onPostHandleMessage(msg);
}
}
}
------------------
private final void invokeEnterMethods(int stateStackEnteringIndex) {
for (int i = stateStackEnteringIndex; i <= mStateStackTopIndex; i++) {
if (stateStackEnteringIndex == mStateStackTopIndex) {
// Last enter state for transition
mTransitionInProgress = false;
}
if (mDbg) mSm.log("invokeEnterMethods: " + mStateStack[i].state.getName());
// 进入到 mUnfocusedState的 enter方法
mStateStack[i].state.enter();
mStateStack[i].active = true;
}
mTransitionInProgress = false; // ensure flag set to false if no methods called
}
// 4. 发送消息去初始化
sendMessage(INITIALIZE, new MessageArgs.Builder
@UnsupportedAppUsage
public void sendMessage(int what, Object obj) {
// mSmHandler can be null if the state machine has quit.
SmHandler smh = mSmHandler;
if (smh == null) return;
smh.sendMessage(obtainMessage(what, obj));
}
----------
// SmHandler 去处理消息
@Override
public final void handleMessage(Message msg) {
if (!mHasQuit) {
if (mSm != null && msg.what != SM_INIT_CMD && msg.what != SM_QUIT_CMD) {
mSm.onPreHandleMessage(msg);
}
if (mDbg) mSm.log("handleMessage: E msg.what=" + msg.what);
/** Save the current message */
mMsg = msg;
/** State that processed the message */
State msgProcessedState = null;
// 因为第一次初始化 SM_INIT_CMD 设置了 mIsConstructionCompleted为true
// 走到如下方法
if (mIsConstructionCompleted || (mMsg.what == SM_QUIT_CMD)) {
/** Normal path */
msgProcessedState = processMsg(msg);
} else if (!mIsConstructionCompleted && (mMsg.what == SM_INIT_CMD)
&& (mMsg.obj == mSmHandlerObj)) {
/** Initial one time path. */
mIsConstructionCompleted = true;
invokeEnterMethods(0);
} else {
throw new RuntimeException("StateMachine.handleMessage: "
+ "The start method not called, received msg: " + msg);
}
performTransitions(msgProcessedState, msg);
// We need to check if mSm == null here as we could be quitting.
if (mDbg && mSm != null) mSm.log("handleMessage: X");
if (mSm != null && msg.what != SM_INIT_CMD && msg.what != SM_QUIT_CMD) {
mSm.onPostHandleMessage(msg);
}
}
}
----------------
private final State processMsg(Message msg) {
// 获取初始的状态 UnfocusedState 的 StateInfo
StateInfo curStateInfo = mStateStack[mStateStackTopIndex];
if (mDbg) {
mSm.log("processMsg: " + curStateInfo.state.getName());
}
if (isQuit(msg)) {
transitionTo(mQuittingState);
} else {
// 获取 UnfocusedState然后去处理消息
// 如果processMessage返回 false,则继续找到父节点继续处理
while (!curStateInfo.state.processMessage(msg)) {
/**
* Not processed
*/
curStateInfo = curStateInfo.parentStateInfo;
if (curStateInfo == null) {
/**
* No parents left so it's not handled
*/
mSm.unhandledMessage(msg);
break;
}
if (mDbg) {
mSm.log("processMsg: " + curStateInfo.state.getName());
}
}
}
return (curStateInfo != null) ? curStateInfo.state : null;
}
UnfocusedState 处理消息 INITIALIZE,设置 mIsInitialized 为true
// 继承于 BaseState
private class UnfocusedState extends BaseState {
private class BaseState extends State {
@Override
public boolean processMessage(Message msg) {
switch (msg.what) {
case INITIALIZE:
// 这里去设置 mIsInitialized 为true
mIsInitialized = true;
// public static final boolean HANDLED = true;
// 返回时父类的 true,即在父类中不往下处理
return HANDLED;
3. 来电状态切换到 RingingFocusState 流程
如果有来电的话:
- /packages/services/Telecomm/src/com/android/server/telecom/CallAudioManager.java
消息为:NEW_RINGING_CALL
private void onCallEnteringRinging() {
if (mRingingCalls.size() == 1) {
mCallAudioModeStateMachine.sendMessageWithArgs(
CallAudioModeStateMachine.NEW_RINGING_CALL,
makeArgsForModeStateMachine());
}
}
- /packages/services/Telecomm/src/com/android/server/telecom/CallAudioModeStateMachine.java
public void sendMessageWithArgs(int messageCode, MessageArgs args) {
sendMessage(messageCode, args);
}
- /frameworks/base/core/java/com/android/internal/util/StateMachine.java
@UnsupportedAppUsage
public void sendMessage(int what, Object obj) {
// mSmHandler can be null if the state machine has quit.
SmHandler smh = mSmHandler;
if (smh == null) return;
smh.sendMessage(obtainMessage(what, obj));
}
--------
@Override
public final void handleMessage(Message msg) {
if (!mHasQuit) {
if (mSm != null && msg.what != SM_INIT_CMD && msg.what != SM_QUIT_CMD) {
mSm.onPreHandleMessage(msg);
}
if (mDbg) mSm.log("handleMessage: E msg.what=" + msg.what);
/** Save the current message */
mMsg = msg;
/** State that processed the message */
State msgProcessedState = null;
if (mIsConstructionCompleted || (mMsg.what == SM_QUIT_CMD)) {
/** Normal path */
// 1. 这里先去处理消息
msgProcessedState = processMsg(msg);
} else if (!mIsConstructionCompleted && (mMsg.what == SM_INIT_CMD)
&& (mMsg.obj == mSmHandlerObj)) {
/** Initial one time path. */
mIsConstructionCompleted = true;
invokeEnterMethods(0);
} else {
throw new RuntimeException("StateMachine.handleMessage: "
+ "The start method not called, received msg: " + msg);
}
// 2. 处理消息之后,调用状态机的 enter 方法
performTransitions(msgProcessedState, msg);
// We need to check if mSm == null here as we could be quitting.
if (mDbg && mSm != null) mSm.log("handleMessage: X");
if (mSm != null && msg.what != SM_INIT_CMD && msg.what != SM_QUIT_CMD) {
mSm.onPostHandleMessage(msg);
}
}
}
------------
private final State processMsg(Message msg) {
StateInfo curStateInfo = mStateStack[mStateStackTopIndex];
if (mDbg) {
mSm.log("processMsg: " + curStateInfo.state.getName());
}
if (isQuit(msg)) {
transitionTo(mQuittingState);
} else {
while (!curStateInfo.state.processMessage(msg)) {
- /packages/services/Telecomm/src/com/android/server/telecom/CallAudioModeStateMachine.java
private class UnfocusedState extends BaseState {
@Override
@Override
public boolean processMessage(Message msg) {
if (super.processMessage(msg) == HANDLED) {
return HANDLED;
}
MessageArgs args = (MessageArgs) msg.obj;
switch (msg.what) {
case NEW_RINGING_CALL:
// 变化状态为 RingingFocusState
transitionTo(mRingingFocusState);
return HANDLED;
transitionTo(mRingingFocusState)
@UnsupportedAppUsage
public final void transitionTo(IState destState) {
mSmHandler.transitionTo(destState);
}
----------------
private final void transitionTo(IState destState) {
if (mTransitionInProgress) {
Log.wtf(mSm.mName, "transitionTo called while transition already in progress to " +
mDestState + ", new target state=" + destState);
}
// 设置 mDestState 为 mRingingFocusState
mDestState = (State) destState;
if (mDbg) mSm.log("transitionTo: destState=" + mDestState.getName());
}
// 2. 处理消息之后,调用状态机的 enter 方法
performTransitions
private void performTransitions(State msgProcessedState, Message msg) {
/**
* If transitionTo has been called, exit and then enter
* the appropriate states. We loop on this to allow
* enter and exit methods to use transitionTo.
*/
State orgState = mStateStack[mStateStackTopIndex].state;
/**
* Record whether message needs to be logged before we transition and
* and we won't log special messages SM_INIT_CMD or SM_QUIT_CMD which
* always set msg.obj to the handler.
*/
boolean recordLogMsg = mSm.recordLogRec(mMsg) && (msg.obj != mSmHandlerObj);
if (mLogRecords.logOnlyTransitions()) {
/** Record only if there is a transition */
if (mDestState != null) {
mLogRecords.add(mSm, mMsg, mSm.getLogRecString(mMsg), msgProcessedState,
orgState, mDestState);
}
} else if (recordLogMsg) {
/** Record message */
mLogRecords.add(mSm, mMsg, mSm.getLogRecString(mMsg), msgProcessedState, orgState,
mDestState);
}
// 此时 destState 为 RingingFocusState
State destState = mDestState;
if (destState != null) {
/**
* Process the transitions including transitions in the enter/exit methods
*/
while (true) {
if (mDbg) mSm.log("handleMessage: new destination call exit/enter");
/**
* Determine the states to exit and enter and return the
* common ancestor state of the enter/exit states. Then
* invoke the exit methods then the enter methods.
*/
// 1, 将RingingFocusState 先保存到临时栈中
StateInfo commonStateInfo = setupTempStateStackWithStatesToEnter(destState);
// flag is cleared in invokeEnterMethods before entering the target state
mTransitionInProgress = true;
// 2. 触发UnFocusState 的Exit 退出方法
invokeExitMethods(commonStateInfo);
// 3. 将临时栈的数据放到 StateStack 中
int stateStackEnteringIndex = moveTempStateStackToStateStack();
4. 执行 RingingFocusState的 enter 方法,并设置标志位 active 为 true
invokeEnterMethods(stateStackEnteringIndex);
/**
* Since we have transitioned to a new state we need to have
* any deferred messages moved to the front of the message queue
* so they will be processed before any other messages in the
* message queue.
*/
moveDeferredMessageAtFrontOfQueue();
if (destState != mDestState) {
// A new mDestState so continue looping
destState = mDestState;
} else {
// No change in mDestState so we're done
break;
}
}
mDestState = null;
}
/**
* After processing all transitions check and
* see if the last transition was to quit or halt.
*/
if (destState != null) {
if (destState == mQuittingState) {
/**
* Call onQuitting to let subclasses cleanup.
*/
mSm.onQuitting();
cleanupAfterQuitting();
} else if (destState == mHaltingState) {
/**
* Call onHalting() if we've transitioned to the halting
* state. All subsequent messages will be processed in
* in the halting state which invokes haltedProcessMessage(msg);
*/
mSm.onHalting();
}
}
}
4. 执行 RingingFocusState的 enter 方法
private class RingingFocusState extends BaseState {
// Keeps track of whether we're ringing with audio focus or if we've just entered the state
// without acquiring focus because of a silent ringtone or something.
private boolean mHasFocus = false;
private void tryStartRinging() {
if (mHasFocus && mCallAudioManager.isRingtonePlaying()) {
Log.i(LOG_TAG, "RingingFocusState#tryStartRinging -- audio focus previously"
+ " acquired and ringtone already playing -- skipping.");
return;
}
if (mCallAudioManager.startRinging()) {
mAudioManager.requestAudioFocusForCall(AudioManager.STREAM_RING,
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
// Do not set MODE_RINGTONE if we were previously in the CALL_SCREENING mode -- this
// trips up the audio system.
if (mAudioManager.getMode() != AudioManager.MODE_CALL_SCREENING) {
mAudioManager.setMode(AudioManager.MODE_RINGTONE);
}
mCallAudioManager.setCallAudioRouteFocusState(
CallAudioRouteStateMachine.RINGING_FOCUS);
mHasFocus = true;
} else {
Log.i(LOG_TAG, "RINGING state, try start ringing but not acquiring audio focus");
}
}
// 进入到 enter 方法,开始响铃
@Override
public void enter() {
Log.i(LOG_TAG, "Audio focus entering RINGING state");
tryStartRinging();
mCallAudioManager.stopCallWaiting();
}
参考:
一文详解 Android状态机StateMachine 使用方式及实现原理_bjxiaxueliang的博客-CSDN博客_android statemachine 使用
更多推荐
所有评论(0)