PageRenderTime 31ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/android/upstream/com/android/internal/util/StateMachine.java

https://bitbucket.org/festevezga/xobotos
Java | 1496 lines | 495 code | 141 blank | 860 comment | 78 complexity | d50666242a09d035d305b0321022f175 MD5 | raw file
  1. /**
  2. * Copyright (C) 2009 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package com.android.internal.util;
  17. import android.os.Handler;
  18. import android.os.HandlerThread;
  19. import android.os.Looper;
  20. import android.os.Message;
  21. import android.util.Log;
  22. import java.util.ArrayList;
  23. import java.util.HashMap;
  24. import java.util.Vector;
  25. /**
  26. * {@hide}
  27. *
  28. * <p>The state machine defined here is a hierarchical state machine which processes messages
  29. * and can have states arranged hierarchically.</p>
  30. *
  31. * <p>A state is a <code>State</code> object and must implement
  32. * <code>processMessage</code> and optionally <code>enter/exit/getName</code>.
  33. * The enter/exit methods are equivalent to the construction and destruction
  34. * in Object Oriented programming and are used to perform initialization and
  35. * cleanup of the state respectively. The <code>getName</code> method returns the
  36. * name of the state the default implementation returns the class name it may be
  37. * desirable to have this return the name of the state instance name instead.
  38. * In particular if a particular state class has multiple instances.</p>
  39. *
  40. * <p>When a state machine is created <code>addState</code> is used to build the
  41. * hierarchy and <code>setInitialState</code> is used to identify which of these
  42. * is the initial state. After construction the programmer calls <code>start</code>
  43. * which initializes the state machine and calls <code>enter</code> for all of the initial
  44. * state's hierarchy, starting at its eldest parent. For example given the simple
  45. * state machine below after start is called mP1.enter will have been called and
  46. * then mS1.enter.</p>
  47. <code>
  48. mP1
  49. / \
  50. mS2 mS1 ----> initial state
  51. </code>
  52. * <p>After the state machine is created and started, messages are sent to a state
  53. * machine using <code>sendMessage</code> and the messages are created using
  54. * <code>obtainMessage</code>. When the state machine receives a message the
  55. * current state's <code>processMessage</code> is invoked. In the above example
  56. * mS1.processMessage will be invoked first. The state may use <code>transitionTo</code>
  57. * to change the current state to a new state</p>
  58. *
  59. * <p>Each state in the state machine may have a zero or one parent states and if
  60. * a child state is unable to handle a message it may have the message processed
  61. * by its parent by returning false or NOT_HANDLED. If a message is never processed
  62. * <code>unhandledMessage</code> will be invoked to give one last chance for the state machine
  63. * to process the message.</p>
  64. *
  65. * <p>When all processing is completed a state machine may choose to call
  66. * <code>transitionToHaltingState</code>. When the current <code>processingMessage</code>
  67. * returns the state machine will transfer to an internal <code>HaltingState</code>
  68. * and invoke <code>halting</code>. Any message subsequently received by the state
  69. * machine will cause <code>haltedProcessMessage</code> to be invoked.</p>
  70. *
  71. * <p>If it is desirable to completely stop the state machine call <code>quit</code>. This
  72. * will exit the current state and its parent and then exit from the controlling thread
  73. * and no further messages will be processed.</p>
  74. *
  75. * <p>In addition to <code>processMessage</code> each <code>State</code> has
  76. * an <code>enter</code> method and <code>exit</exit> method which may be overridden.</p>
  77. *
  78. * <p>Since the states are arranged in a hierarchy transitioning to a new state
  79. * causes current states to be exited and new states to be entered. To determine
  80. * the list of states to be entered/exited the common parent closest to
  81. * the current state is found. We then exit from the current state and its
  82. * parent's up to but not including the common parent state and then enter all
  83. * of the new states below the common parent down to the destination state.
  84. * If there is no common parent all states are exited and then the new states
  85. * are entered.</p>
  86. *
  87. * <p>Two other methods that states can use are <code>deferMessage</code> and
  88. * <code>sendMessageAtFrontOfQueue</code>. The <code>sendMessageAtFrontOfQueue</code> sends
  89. * a message but places it on the front of the queue rather than the back. The
  90. * <code>deferMessage</code> causes the message to be saved on a list until a
  91. * transition is made to a new state. At which time all of the deferred messages
  92. * will be put on the front of the state machine queue with the oldest message
  93. * at the front. These will then be processed by the new current state before
  94. * any other messages that are on the queue or might be added later. Both of
  95. * these are protected and may only be invoked from within a state machine.</p>
  96. *
  97. * <p>To illustrate some of these properties we'll use state machine with an 8
  98. * state hierarchy:</p>
  99. <code>
  100. mP0
  101. / \
  102. mP1 mS0
  103. / \
  104. mS2 mS1
  105. / \ \
  106. mS3 mS4 mS5 ---> initial state
  107. </code>
  108. * <p>After starting mS5 the list of active states is mP0, mP1, mS1 and mS5.
  109. * So the order of calling processMessage when a message is received is mS5,
  110. * mS1, mP1, mP0 assuming each processMessage indicates it can't handle this
  111. * message by returning false or NOT_HANDLED.</p>
  112. *
  113. * <p>Now assume mS5.processMessage receives a message it can handle, and during
  114. * the handling determines the machine should change states. It could call
  115. * transitionTo(mS4) and return true or HANDLED. Immediately after returning from
  116. * processMessage the state machine runtime will find the common parent,
  117. * which is mP1. It will then call mS5.exit, mS1.exit, mS2.enter and then
  118. * mS4.enter. The new list of active states is mP0, mP1, mS2 and mS4. So
  119. * when the next message is received mS4.processMessage will be invoked.</p>
  120. *
  121. * <p>Now for some concrete examples, here is the canonical HelloWorld as a state machine.
  122. * It responds with "Hello World" being printed to the log for every message.</p>
  123. <code>
  124. class HelloWorld extends StateMachine {
  125. HelloWorld(String name) {
  126. super(name);
  127. addState(mState1);
  128. setInitialState(mState1);
  129. }
  130. public static HelloWorld makeHelloWorld() {
  131. HelloWorld hw = new HelloWorld("hw");
  132. hw.start();
  133. return hw;
  134. }
  135. class State1 extends State {
  136. &#64;Override public boolean processMessage(Message message) {
  137. Log.d(TAG, "Hello World");
  138. return HANDLED;
  139. }
  140. }
  141. State1 mState1 = new State1();
  142. }
  143. void testHelloWorld() {
  144. HelloWorld hw = makeHelloWorld();
  145. hw.sendMessage(hw.obtainMessage());
  146. }
  147. </code>
  148. * <p>A more interesting state machine is one with four states
  149. * with two independent parent states.</p>
  150. <code>
  151. mP1 mP2
  152. / \
  153. mS2 mS1
  154. </code>
  155. * <p>Here is a description of this state machine using pseudo code.</p>
  156. <code>
  157. state mP1 {
  158. enter { log("mP1.enter"); }
  159. exit { log("mP1.exit"); }
  160. on msg {
  161. CMD_2 {
  162. send(CMD_3);
  163. defer(msg);
  164. transitonTo(mS2);
  165. return HANDLED;
  166. }
  167. return NOT_HANDLED;
  168. }
  169. }
  170. INITIAL
  171. state mS1 parent mP1 {
  172. enter { log("mS1.enter"); }
  173. exit { log("mS1.exit"); }
  174. on msg {
  175. CMD_1 {
  176. transitionTo(mS1);
  177. return HANDLED;
  178. }
  179. return NOT_HANDLED;
  180. }
  181. }
  182. state mS2 parent mP1 {
  183. enter { log("mS2.enter"); }
  184. exit { log("mS2.exit"); }
  185. on msg {
  186. CMD_2 {
  187. send(CMD_4);
  188. return HANDLED;
  189. }
  190. CMD_3 {
  191. defer(msg);
  192. transitionTo(mP2);
  193. return HANDLED;
  194. }
  195. return NOT_HANDLED;
  196. }
  197. }
  198. state mP2 {
  199. enter {
  200. log("mP2.enter");
  201. send(CMD_5);
  202. }
  203. exit { log("mP2.exit"); }
  204. on msg {
  205. CMD_3, CMD_4 { return HANDLED; }
  206. CMD_5 {
  207. transitionTo(HaltingState);
  208. return HANDLED;
  209. }
  210. return NOT_HANDLED;
  211. }
  212. }
  213. </code>
  214. * <p>The implementation is below and also in StateMachineTest:</p>
  215. <code>
  216. class Hsm1 extends StateMachine {
  217. private static final String TAG = "hsm1";
  218. public static final int CMD_1 = 1;
  219. public static final int CMD_2 = 2;
  220. public static final int CMD_3 = 3;
  221. public static final int CMD_4 = 4;
  222. public static final int CMD_5 = 5;
  223. public static Hsm1 makeHsm1() {
  224. Log.d(TAG, "makeHsm1 E");
  225. Hsm1 sm = new Hsm1("hsm1");
  226. sm.start();
  227. Log.d(TAG, "makeHsm1 X");
  228. return sm;
  229. }
  230. Hsm1(String name) {
  231. super(name);
  232. Log.d(TAG, "ctor E");
  233. // Add states, use indentation to show hierarchy
  234. addState(mP1);
  235. addState(mS1, mP1);
  236. addState(mS2, mP1);
  237. addState(mP2);
  238. // Set the initial state
  239. setInitialState(mS1);
  240. Log.d(TAG, "ctor X");
  241. }
  242. class P1 extends State {
  243. &#64;Override public void enter() {
  244. Log.d(TAG, "mP1.enter");
  245. }
  246. &#64;Override public boolean processMessage(Message message) {
  247. boolean retVal;
  248. Log.d(TAG, "mP1.processMessage what=" + message.what);
  249. switch(message.what) {
  250. case CMD_2:
  251. // CMD_2 will arrive in mS2 before CMD_3
  252. sendMessage(obtainMessage(CMD_3));
  253. deferMessage(message);
  254. transitionTo(mS2);
  255. retVal = HANDLED;
  256. break;
  257. default:
  258. // Any message we don't understand in this state invokes unhandledMessage
  259. retVal = NOT_HANDLED;
  260. break;
  261. }
  262. return retVal;
  263. }
  264. &#64;Override public void exit() {
  265. Log.d(TAG, "mP1.exit");
  266. }
  267. }
  268. class S1 extends State {
  269. &#64;Override public void enter() {
  270. Log.d(TAG, "mS1.enter");
  271. }
  272. &#64;Override public boolean processMessage(Message message) {
  273. Log.d(TAG, "S1.processMessage what=" + message.what);
  274. if (message.what == CMD_1) {
  275. // Transition to ourself to show that enter/exit is called
  276. transitionTo(mS1);
  277. return HANDLED;
  278. } else {
  279. // Let parent process all other messages
  280. return NOT_HANDLED;
  281. }
  282. }
  283. &#64;Override public void exit() {
  284. Log.d(TAG, "mS1.exit");
  285. }
  286. }
  287. class S2 extends State {
  288. &#64;Override public void enter() {
  289. Log.d(TAG, "mS2.enter");
  290. }
  291. &#64;Override public boolean processMessage(Message message) {
  292. boolean retVal;
  293. Log.d(TAG, "mS2.processMessage what=" + message.what);
  294. switch(message.what) {
  295. case(CMD_2):
  296. sendMessage(obtainMessage(CMD_4));
  297. retVal = HANDLED;
  298. break;
  299. case(CMD_3):
  300. deferMessage(message);
  301. transitionTo(mP2);
  302. retVal = HANDLED;
  303. break;
  304. default:
  305. retVal = NOT_HANDLED;
  306. break;
  307. }
  308. return retVal;
  309. }
  310. &#64;Override public void exit() {
  311. Log.d(TAG, "mS2.exit");
  312. }
  313. }
  314. class P2 extends State {
  315. &#64;Override public void enter() {
  316. Log.d(TAG, "mP2.enter");
  317. sendMessage(obtainMessage(CMD_5));
  318. }
  319. &#64;Override public boolean processMessage(Message message) {
  320. Log.d(TAG, "P2.processMessage what=" + message.what);
  321. switch(message.what) {
  322. case(CMD_3):
  323. break;
  324. case(CMD_4):
  325. break;
  326. case(CMD_5):
  327. transitionToHaltingState();
  328. break;
  329. }
  330. return HANDLED;
  331. }
  332. &#64;Override public void exit() {
  333. Log.d(TAG, "mP2.exit");
  334. }
  335. }
  336. &#64;Override
  337. void halting() {
  338. Log.d(TAG, "halting");
  339. synchronized (this) {
  340. this.notifyAll();
  341. }
  342. }
  343. P1 mP1 = new P1();
  344. S1 mS1 = new S1();
  345. S2 mS2 = new S2();
  346. P2 mP2 = new P2();
  347. }
  348. </code>
  349. * <p>If this is executed by sending two messages CMD_1 and CMD_2
  350. * (Note the synchronize is only needed because we use hsm.wait())</p>
  351. <code>
  352. Hsm1 hsm = makeHsm1();
  353. synchronize(hsm) {
  354. hsm.sendMessage(obtainMessage(hsm.CMD_1));
  355. hsm.sendMessage(obtainMessage(hsm.CMD_2));
  356. try {
  357. // wait for the messages to be handled
  358. hsm.wait();
  359. } catch (InterruptedException e) {
  360. Log.e(TAG, "exception while waiting " + e.getMessage());
  361. }
  362. }
  363. </code>
  364. * <p>The output is:</p>
  365. <code>
  366. D/hsm1 ( 1999): makeHsm1 E
  367. D/hsm1 ( 1999): ctor E
  368. D/hsm1 ( 1999): ctor X
  369. D/hsm1 ( 1999): mP1.enter
  370. D/hsm1 ( 1999): mS1.enter
  371. D/hsm1 ( 1999): makeHsm1 X
  372. D/hsm1 ( 1999): mS1.processMessage what=1
  373. D/hsm1 ( 1999): mS1.exit
  374. D/hsm1 ( 1999): mS1.enter
  375. D/hsm1 ( 1999): mS1.processMessage what=2
  376. D/hsm1 ( 1999): mP1.processMessage what=2
  377. D/hsm1 ( 1999): mS1.exit
  378. D/hsm1 ( 1999): mS2.enter
  379. D/hsm1 ( 1999): mS2.processMessage what=2
  380. D/hsm1 ( 1999): mS2.processMessage what=3
  381. D/hsm1 ( 1999): mS2.exit
  382. D/hsm1 ( 1999): mP1.exit
  383. D/hsm1 ( 1999): mP2.enter
  384. D/hsm1 ( 1999): mP2.processMessage what=3
  385. D/hsm1 ( 1999): mP2.processMessage what=4
  386. D/hsm1 ( 1999): mP2.processMessage what=5
  387. D/hsm1 ( 1999): mP2.exit
  388. D/hsm1 ( 1999): halting
  389. </code>
  390. */
  391. public class StateMachine {
  392. private static final String TAG = "StateMachine";
  393. private String mName;
  394. /** Message.what value when quitting */
  395. public static final int SM_QUIT_CMD = -1;
  396. /** Message.what value when initializing */
  397. public static final int SM_INIT_CMD = -1;
  398. /**
  399. * Convenience constant that maybe returned by processMessage
  400. * to indicate the the message was processed and is not to be
  401. * processed by parent states
  402. */
  403. public static final boolean HANDLED = true;
  404. /**
  405. * Convenience constant that maybe returned by processMessage
  406. * to indicate the the message was NOT processed and is to be
  407. * processed by parent states
  408. */
  409. public static final boolean NOT_HANDLED = false;
  410. /**
  411. * {@hide}
  412. *
  413. * The information maintained for a processed message.
  414. */
  415. public static class ProcessedMessageInfo {
  416. private int what;
  417. private State state;
  418. private State orgState;
  419. /**
  420. * Constructor
  421. * @param message
  422. * @param state that handled the message
  423. * @param orgState is the first state the received the message but
  424. * did not processes the message.
  425. */
  426. ProcessedMessageInfo(Message message, State state, State orgState) {
  427. update(message, state, orgState);
  428. }
  429. /**
  430. * Update the information in the record.
  431. * @param state that handled the message
  432. * @param orgState is the first state the received the message but
  433. * did not processes the message.
  434. */
  435. public void update(Message message, State state, State orgState) {
  436. this.what = message.what;
  437. this.state = state;
  438. this.orgState = orgState;
  439. }
  440. /**
  441. * @return the command that was executing
  442. */
  443. public int getWhat() {
  444. return what;
  445. }
  446. /**
  447. * @return the state that handled this message
  448. */
  449. public State getState() {
  450. return state;
  451. }
  452. /**
  453. * @return the original state that received the message.
  454. */
  455. public State getOriginalState() {
  456. return orgState;
  457. }
  458. /**
  459. * @return as string
  460. */
  461. @Override
  462. public String toString() {
  463. StringBuilder sb = new StringBuilder();
  464. sb.append("what=");
  465. sb.append(what);
  466. sb.append(" state=");
  467. sb.append(cn(state));
  468. sb.append(" orgState=");
  469. sb.append(cn(orgState));
  470. return sb.toString();
  471. }
  472. /**
  473. * @return an objects class name
  474. */
  475. private String cn(Object n) {
  476. if (n == null) {
  477. return "null";
  478. } else {
  479. String name = n.getClass().getName();
  480. int lastDollar = name.lastIndexOf('$');
  481. return name.substring(lastDollar + 1);
  482. }
  483. }
  484. }
  485. /**
  486. * A list of messages recently processed by the state machine.
  487. *
  488. * The class maintains a list of messages that have been most
  489. * recently processed. The list is finite and may be set in the
  490. * constructor or by calling setSize. The public interface also
  491. * includes size which returns the number of recent messages,
  492. * count which is the number of message processed since the
  493. * the last setSize, get which returns a processed message and
  494. * add which adds a processed messaged.
  495. */
  496. private static class ProcessedMessages {
  497. private static final int DEFAULT_SIZE = 20;
  498. private Vector<ProcessedMessageInfo> mMessages = new Vector<ProcessedMessageInfo>();
  499. private int mMaxSize = DEFAULT_SIZE;
  500. private int mOldestIndex = 0;
  501. private int mCount = 0;
  502. /**
  503. * Constructor
  504. */
  505. ProcessedMessages() {
  506. }
  507. /**
  508. * Set size of messages to maintain and clears all current messages.
  509. *
  510. * @param maxSize number of messages to maintain at anyone time.
  511. */
  512. void setSize(int maxSize) {
  513. mMaxSize = maxSize;
  514. mCount = 0;
  515. mMessages.clear();
  516. }
  517. /**
  518. * @return the number of recent messages.
  519. */
  520. int size() {
  521. return mMessages.size();
  522. }
  523. /**
  524. * @return the total number of messages processed since size was set.
  525. */
  526. int count() {
  527. return mCount;
  528. }
  529. /**
  530. * @return the information on a particular record. 0 is the oldest
  531. * record and size()-1 is the newest record. If the index is to
  532. * large null is returned.
  533. */
  534. ProcessedMessageInfo get(int index) {
  535. int nextIndex = mOldestIndex + index;
  536. if (nextIndex >= mMaxSize) {
  537. nextIndex -= mMaxSize;
  538. }
  539. if (nextIndex >= size()) {
  540. return null;
  541. } else {
  542. return mMessages.get(nextIndex);
  543. }
  544. }
  545. /**
  546. * Add a processed message.
  547. *
  548. * @param message
  549. * @param state that handled the message
  550. * @param orgState is the first state the received the message but
  551. * did not processes the message.
  552. */
  553. void add(Message message, State state, State orgState) {
  554. mCount += 1;
  555. if (mMessages.size() < mMaxSize) {
  556. mMessages.add(new ProcessedMessageInfo(message, state, orgState));
  557. } else {
  558. ProcessedMessageInfo pmi = mMessages.get(mOldestIndex);
  559. mOldestIndex += 1;
  560. if (mOldestIndex >= mMaxSize) {
  561. mOldestIndex = 0;
  562. }
  563. pmi.update(message, state, orgState);
  564. }
  565. }
  566. }
  567. private static class SmHandler extends Handler {
  568. /** The debug flag */
  569. private boolean mDbg = false;
  570. /** The quit object */
  571. private static final Object mQuitObj = new Object();
  572. /** The current message */
  573. private Message mMsg;
  574. /** A list of messages that this state machine has processed */
  575. private ProcessedMessages mProcessedMessages = new ProcessedMessages();
  576. /** true if construction of the state machine has not been completed */
  577. private boolean mIsConstructionCompleted;
  578. /** Stack used to manage the current hierarchy of states */
  579. private StateInfo mStateStack[];
  580. /** Top of mStateStack */
  581. private int mStateStackTopIndex = -1;
  582. /** A temporary stack used to manage the state stack */
  583. private StateInfo mTempStateStack[];
  584. /** The top of the mTempStateStack */
  585. private int mTempStateStackCount;
  586. /** State used when state machine is halted */
  587. private HaltingState mHaltingState = new HaltingState();
  588. /** State used when state machine is quitting */
  589. private QuittingState mQuittingState = new QuittingState();
  590. /** Reference to the StateMachine */
  591. private StateMachine mSm;
  592. /**
  593. * Information about a state.
  594. * Used to maintain the hierarchy.
  595. */
  596. private class StateInfo {
  597. /** The state */
  598. State state;
  599. /** The parent of this state, null if there is no parent */
  600. StateInfo parentStateInfo;
  601. /** True when the state has been entered and on the stack */
  602. boolean active;
  603. /**
  604. * Convert StateInfo to string
  605. */
  606. @Override
  607. public String toString() {
  608. return "state=" + state.getName() + ",active=" + active
  609. + ",parent=" + ((parentStateInfo == null) ?
  610. "null" : parentStateInfo.state.getName());
  611. }
  612. }
  613. /** The map of all of the states in the state machine */
  614. private HashMap<State, StateInfo> mStateInfo =
  615. new HashMap<State, StateInfo>();
  616. /** The initial state that will process the first message */
  617. private State mInitialState;
  618. /** The destination state when transitionTo has been invoked */
  619. private State mDestState;
  620. /** The list of deferred messages */
  621. private ArrayList<Message> mDeferredMessages = new ArrayList<Message>();
  622. /**
  623. * State entered when transitionToHaltingState is called.
  624. */
  625. private class HaltingState extends State {
  626. @Override
  627. public boolean processMessage(Message msg) {
  628. mSm.haltedProcessMessage(msg);
  629. return true;
  630. }
  631. }
  632. /**
  633. * State entered when a valid quit message is handled.
  634. */
  635. private class QuittingState extends State {
  636. @Override
  637. public boolean processMessage(Message msg) {
  638. return NOT_HANDLED;
  639. }
  640. }
  641. /**
  642. * Handle messages sent to the state machine by calling
  643. * the current state's processMessage. It also handles
  644. * the enter/exit calls and placing any deferred messages
  645. * back onto the queue when transitioning to a new state.
  646. */
  647. @Override
  648. public final void handleMessage(Message msg) {
  649. if (mDbg) Log.d(TAG, "handleMessage: E msg.what=" + msg.what);
  650. /** Save the current message */
  651. mMsg = msg;
  652. /**
  653. * Check that construction was completed
  654. */
  655. if (!mIsConstructionCompleted) {
  656. Log.e(TAG, "The start method not called, ignore msg: " + msg);
  657. return;
  658. }
  659. /**
  660. * Process the message abiding by the hierarchical semantics
  661. * and perform any requested transitions.
  662. */
  663. processMsg(msg);
  664. performTransitions();
  665. if (mDbg) Log.d(TAG, "handleMessage: X");
  666. }
  667. /**
  668. * Do any transitions
  669. */
  670. private void performTransitions() {
  671. /**
  672. * If transitionTo has been called, exit and then enter
  673. * the appropriate states. We loop on this to allow
  674. * enter and exit methods to use transitionTo.
  675. */
  676. State destState = null;
  677. while (mDestState != null) {
  678. if (mDbg) Log.d(TAG, "handleMessage: new destination call exit");
  679. /**
  680. * Save mDestState locally and set to null
  681. * to know if enter/exit use transitionTo.
  682. */
  683. destState = mDestState;
  684. mDestState = null;
  685. /**
  686. * Determine the states to exit and enter and return the
  687. * common ancestor state of the enter/exit states. Then
  688. * invoke the exit methods then the enter methods.
  689. */
  690. StateInfo commonStateInfo = setupTempStateStackWithStatesToEnter(destState);
  691. invokeExitMethods(commonStateInfo);
  692. int stateStackEnteringIndex = moveTempStateStackToStateStack();
  693. invokeEnterMethods(stateStackEnteringIndex);
  694. /**
  695. * Since we have transitioned to a new state we need to have
  696. * any deferred messages moved to the front of the message queue
  697. * so they will be processed before any other messages in the
  698. * message queue.
  699. */
  700. moveDeferredMessageAtFrontOfQueue();
  701. }
  702. /**
  703. * After processing all transitions check and
  704. * see if the last transition was to quit or halt.
  705. */
  706. if (destState != null) {
  707. if (destState == mQuittingState) {
  708. /**
  709. * We are quitting so ignore all messages.
  710. */
  711. mSm.quitting();
  712. if (mSm.mSmThread != null) {
  713. // If we made the thread then quit looper which stops the thread.
  714. getLooper().quit();
  715. mSm.mSmThread = null;
  716. }
  717. } else if (destState == mHaltingState) {
  718. /**
  719. * Call halting() if we've transitioned to the halting
  720. * state. All subsequent messages will be processed in
  721. * in the halting state which invokes haltedProcessMessage(msg);
  722. */
  723. mSm.halting();
  724. }
  725. }
  726. }
  727. /**
  728. * Complete the construction of the state machine.
  729. */
  730. private final void completeConstruction() {
  731. if (mDbg) Log.d(TAG, "completeConstruction: E");
  732. /**
  733. * Determine the maximum depth of the state hierarchy
  734. * so we can allocate the state stacks.
  735. */
  736. int maxDepth = 0;
  737. for (StateInfo si : mStateInfo.values()) {
  738. int depth = 0;
  739. for (StateInfo i = si; i != null; depth++) {
  740. i = i.parentStateInfo;
  741. }
  742. if (maxDepth < depth) {
  743. maxDepth = depth;
  744. }
  745. }
  746. if (mDbg) Log.d(TAG, "completeConstruction: maxDepth=" + maxDepth);
  747. mStateStack = new StateInfo[maxDepth];
  748. mTempStateStack = new StateInfo[maxDepth];
  749. setupInitialStateStack();
  750. /**
  751. * Construction is complete call all enter methods
  752. * starting at the first entry.
  753. */
  754. mIsConstructionCompleted = true;
  755. mMsg = obtainMessage(SM_INIT_CMD);
  756. invokeEnterMethods(0);
  757. /**
  758. * Perform any transitions requested by the enter methods
  759. */
  760. performTransitions();
  761. if (mDbg) Log.d(TAG, "completeConstruction: X");
  762. }
  763. /**
  764. * Process the message. If the current state doesn't handle
  765. * it, call the states parent and so on. If it is never handled then
  766. * call the state machines unhandledMessage method.
  767. */
  768. private final void processMsg(Message msg) {
  769. StateInfo curStateInfo = mStateStack[mStateStackTopIndex];
  770. if (mDbg) {
  771. Log.d(TAG, "processMsg: " + curStateInfo.state.getName());
  772. }
  773. while (!curStateInfo.state.processMessage(msg)) {
  774. /**
  775. * Not processed
  776. */
  777. curStateInfo = curStateInfo.parentStateInfo;
  778. if (curStateInfo == null) {
  779. /**
  780. * No parents left so it's not handled
  781. */
  782. mSm.unhandledMessage(msg);
  783. if (isQuit(msg)) {
  784. transitionTo(mQuittingState);
  785. }
  786. break;
  787. }
  788. if (mDbg) {
  789. Log.d(TAG, "processMsg: " + curStateInfo.state.getName());
  790. }
  791. }
  792. /**
  793. * Record that we processed the message
  794. */
  795. if (curStateInfo != null) {
  796. State orgState = mStateStack[mStateStackTopIndex].state;
  797. mProcessedMessages.add(msg, curStateInfo.state, orgState);
  798. } else {
  799. mProcessedMessages.add(msg, null, null);
  800. }
  801. }
  802. /**
  803. * Call the exit method for each state from the top of stack
  804. * up to the common ancestor state.
  805. */
  806. private final void invokeExitMethods(StateInfo commonStateInfo) {
  807. while ((mStateStackTopIndex >= 0) &&
  808. (mStateStack[mStateStackTopIndex] != commonStateInfo)) {
  809. State curState = mStateStack[mStateStackTopIndex].state;
  810. if (mDbg) Log.d(TAG, "invokeExitMethods: " + curState.getName());
  811. curState.exit();
  812. mStateStack[mStateStackTopIndex].active = false;
  813. mStateStackTopIndex -= 1;
  814. }
  815. }
  816. /**
  817. * Invoke the enter method starting at the entering index to top of state stack
  818. */
  819. private final void invokeEnterMethods(int stateStackEnteringIndex) {
  820. for (int i = stateStackEnteringIndex; i <= mStateStackTopIndex; i++) {
  821. if (mDbg) Log.d(TAG, "invokeEnterMethods: " + mStateStack[i].state.getName());
  822. mStateStack[i].state.enter();
  823. mStateStack[i].active = true;
  824. }
  825. }
  826. /**
  827. * Move the deferred message to the front of the message queue.
  828. */
  829. private final void moveDeferredMessageAtFrontOfQueue() {
  830. /**
  831. * The oldest messages on the deferred list must be at
  832. * the front of the queue so start at the back, which
  833. * as the most resent message and end with the oldest
  834. * messages at the front of the queue.
  835. */
  836. for (int i = mDeferredMessages.size() - 1; i >= 0; i-- ) {
  837. Message curMsg = mDeferredMessages.get(i);
  838. if (mDbg) Log.d(TAG, "moveDeferredMessageAtFrontOfQueue; what=" + curMsg.what);
  839. sendMessageAtFrontOfQueue(curMsg);
  840. }
  841. mDeferredMessages.clear();
  842. }
  843. /**
  844. * Move the contents of the temporary stack to the state stack
  845. * reversing the order of the items on the temporary stack as
  846. * they are moved.
  847. *
  848. * @return index into mStateStack where entering needs to start
  849. */
  850. private final int moveTempStateStackToStateStack() {
  851. int startingIndex = mStateStackTopIndex + 1;
  852. int i = mTempStateStackCount - 1;
  853. int j = startingIndex;
  854. while (i >= 0) {
  855. if (mDbg) Log.d(TAG, "moveTempStackToStateStack: i=" + i + ",j=" + j);
  856. mStateStack[j] = mTempStateStack[i];
  857. j += 1;
  858. i -= 1;
  859. }
  860. mStateStackTopIndex = j - 1;
  861. if (mDbg) {
  862. Log.d(TAG, "moveTempStackToStateStack: X mStateStackTop="
  863. + mStateStackTopIndex + ",startingIndex=" + startingIndex
  864. + ",Top=" + mStateStack[mStateStackTopIndex].state.getName());
  865. }
  866. return startingIndex;
  867. }
  868. /**
  869. * Setup the mTempStateStack with the states we are going to enter.
  870. *
  871. * This is found by searching up the destState's ancestors for a
  872. * state that is already active i.e. StateInfo.active == true.
  873. * The destStae and all of its inactive parents will be on the
  874. * TempStateStack as the list of states to enter.
  875. *
  876. * @return StateInfo of the common ancestor for the destState and
  877. * current state or null if there is no common parent.
  878. */
  879. private final StateInfo setupTempStateStackWithStatesToEnter(State destState) {
  880. /**
  881. * Search up the parent list of the destination state for an active
  882. * state. Use a do while() loop as the destState must always be entered
  883. * even if it is active. This can happen if we are exiting/entering
  884. * the current state.
  885. */
  886. mTempStateStackCount = 0;
  887. StateInfo curStateInfo = mStateInfo.get(destState);
  888. do {
  889. mTempStateStack[mTempStateStackCount++] = curStateInfo;
  890. curStateInfo = curStateInfo.parentStateInfo;
  891. } while ((curStateInfo != null) && !curStateInfo.active);
  892. if (mDbg) {
  893. Log.d(TAG, "setupTempStateStackWithStatesToEnter: X mTempStateStackCount="
  894. + mTempStateStackCount + ",curStateInfo: " + curStateInfo);
  895. }
  896. return curStateInfo;
  897. }
  898. /**
  899. * Initialize StateStack to mInitialState.
  900. */
  901. private final void setupInitialStateStack() {
  902. if (mDbg) {
  903. Log.d(TAG, "setupInitialStateStack: E mInitialState="
  904. + mInitialState.getName());
  905. }
  906. StateInfo curStateInfo = mStateInfo.get(mInitialState);
  907. for (mTempStateStackCount = 0; curStateInfo != null; mTempStateStackCount++) {
  908. mTempStateStack[mTempStateStackCount] = curStateInfo;
  909. curStateInfo = curStateInfo.parentStateInfo;
  910. }
  911. // Empty the StateStack
  912. mStateStackTopIndex = -1;
  913. moveTempStateStackToStateStack();
  914. }
  915. /**
  916. * @return current message
  917. */
  918. private final Message getCurrentMessage() {
  919. return mMsg;
  920. }
  921. /**
  922. * @return current state
  923. */
  924. private final IState getCurrentState() {
  925. return mStateStack[mStateStackTopIndex].state;
  926. }
  927. /**
  928. * Add a new state to the state machine. Bottom up addition
  929. * of states is allowed but the same state may only exist
  930. * in one hierarchy.
  931. *
  932. * @param state the state to add
  933. * @param parent the parent of state
  934. * @return stateInfo for this state
  935. */
  936. private final StateInfo addState(State state, State parent) {
  937. if (mDbg) {
  938. Log.d(TAG, "addStateInternal: E state=" + state.getName()
  939. + ",parent=" + ((parent == null) ? "" : parent.getName()));
  940. }
  941. StateInfo parentStateInfo = null;
  942. if (parent != null) {
  943. parentStateInfo = mStateInfo.get(parent);
  944. if (parentStateInfo == null) {
  945. // Recursively add our parent as it's not been added yet.
  946. parentStateInfo = addState(parent, null);
  947. }
  948. }
  949. StateInfo stateInfo = mStateInfo.get(state);
  950. if (stateInfo == null) {
  951. stateInfo = new StateInfo();
  952. mStateInfo.put(state, stateInfo);
  953. }
  954. // Validate that we aren't adding the same state in two different hierarchies.
  955. if ((stateInfo.parentStateInfo != null) &&
  956. (stateInfo.parentStateInfo != parentStateInfo)) {
  957. throw new RuntimeException("state already added");
  958. }
  959. stateInfo.state = state;
  960. stateInfo.parentStateInfo = parentStateInfo;
  961. stateInfo.active = false;
  962. if (mDbg) Log.d(TAG, "addStateInternal: X stateInfo: " + stateInfo);
  963. return stateInfo;
  964. }
  965. /**
  966. * Constructor
  967. *
  968. * @param looper for dispatching messages
  969. * @param sm the hierarchical state machine
  970. */
  971. private SmHandler(Looper looper, StateMachine sm) {
  972. super(looper);
  973. mSm = sm;
  974. addState(mHaltingState, null);
  975. addState(mQuittingState, null);
  976. }
  977. /** @see StateMachine#setInitialState(State) */
  978. private final void setInitialState(State initialState) {
  979. if (mDbg) Log.d(TAG, "setInitialState: initialState" + initialState.getName());
  980. mInitialState = initialState;
  981. }
  982. /** @see StateMachine#transitionTo(IState) */
  983. private final void transitionTo(IState destState) {
  984. mDestState = (State) destState;
  985. if (mDbg) Log.d(TAG, "StateMachine.transitionTo EX destState" + mDestState.getName());
  986. }
  987. /** @see StateMachine#deferMessage(Message) */
  988. private final void deferMessage(Message msg) {
  989. if (mDbg) Log.d(TAG, "deferMessage: msg=" + msg.what);
  990. /* Copy the "msg" to "newMsg" as "msg" will be recycled */
  991. Message newMsg = obtainMessage();
  992. newMsg.copyFrom(msg);
  993. mDeferredMessages.add(newMsg);
  994. }
  995. /** @see StateMachine#deferMessage(Message) */
  996. private final void quit() {
  997. if (mDbg) Log.d(TAG, "quit:");
  998. sendMessage(obtainMessage(SM_QUIT_CMD, mQuitObj));
  999. }
  1000. /** @see StateMachine#isQuit(Message) */
  1001. private final boolean isQuit(Message msg) {
  1002. return (msg.what == SM_QUIT_CMD) && (msg.obj == mQuitObj);
  1003. }
  1004. /** @see StateMachine#isDbg() */
  1005. private final boolean isDbg() {
  1006. return mDbg;
  1007. }
  1008. /** @see StateMachine#setDbg(boolean) */
  1009. private final void setDbg(boolean dbg) {
  1010. mDbg = dbg;
  1011. }
  1012. /** @see StateMachine#setProcessedMessagesSize(int) */
  1013. private final void setProcessedMessagesSize(int maxSize) {
  1014. mProcessedMessages.setSize(maxSize);
  1015. }
  1016. /** @see StateMachine#getProcessedMessagesSize() */
  1017. private final int getProcessedMessagesSize() {
  1018. return mProcessedMessages.size();
  1019. }
  1020. /** @see StateMachine#getProcessedMessagesCount() */
  1021. private final int getProcessedMessagesCount() {
  1022. return mProcessedMessages.count();
  1023. }
  1024. /** @see StateMachine#getProcessedMessageInfo(int) */
  1025. private final ProcessedMessageInfo getProcessedMessageInfo(int index) {
  1026. return mProcessedMessages.get(index);
  1027. }
  1028. }
  1029. private SmHandler mSmHandler;
  1030. private HandlerThread mSmThread;
  1031. /**
  1032. * Initialize.
  1033. *
  1034. * @param looper for this state machine
  1035. * @param name of the state machine
  1036. */
  1037. private void initStateMachine(String name, Looper looper) {
  1038. mName = name;
  1039. mSmHandler = new SmHandler(looper, this);
  1040. }
  1041. /**
  1042. * Constructor creates a StateMachine with its own thread.
  1043. *
  1044. * @param name of the state machine
  1045. */
  1046. protected StateMachine(String name) {
  1047. mSmThread = new HandlerThread(name);
  1048. mSmThread.start();
  1049. Looper looper = mSmThread.getLooper();
  1050. initStateMachine(name, looper);
  1051. }
  1052. /**
  1053. * Constructor creates an StateMachine using the looper.
  1054. *
  1055. * @param name of the state machine
  1056. */
  1057. protected StateMachine(String name, Looper looper) {
  1058. initStateMachine(name, looper);
  1059. }
  1060. /**
  1061. * Add a new state to the state machine
  1062. * @param state the state to add
  1063. * @param parent the parent of state
  1064. */
  1065. protected final void addState(State state, State parent) {
  1066. mSmHandler.addState(state, parent);
  1067. }
  1068. /**
  1069. * @return current message
  1070. */
  1071. protected final Message getCurrentMessage() {
  1072. return mSmHandler.getCurrentMessage();
  1073. }
  1074. /**
  1075. * @return current state
  1076. */
  1077. protected final IState getCurrentState() {
  1078. return mSmHandler.getCurrentState();
  1079. }
  1080. /**
  1081. * Add a new state to the state machine, parent will be null
  1082. * @param state to add
  1083. */
  1084. protected final void addState(State state) {
  1085. mSmHandler.addState(state, null);
  1086. }
  1087. /**
  1088. * Set the initial state. This must be invoked before
  1089. * and messages are sent to the state machine.
  1090. *
  1091. * @param initialState is the state which will receive the first message.
  1092. */
  1093. protected final void setInitialState(State initialState) {
  1094. mSmHandler.setInitialState(initialState);
  1095. }
  1096. /**
  1097. * transition to destination state. Upon returning
  1098. * from processMessage the current state's exit will
  1099. * be executed and upon the next message arriving
  1100. * destState.enter will be invoked.
  1101. *
  1102. * this function can also be called inside the enter function of the
  1103. * previous transition target, but the behavior is undefined when it is
  1104. * called mid-way through a previous transition (for example, calling this
  1105. * in the enter() routine of a intermediate node when the current transition
  1106. * target is one of the nodes descendants).
  1107. *
  1108. * @param destState will be the state that receives the next message.
  1109. */
  1110. protected final void transitionTo(IState destState) {
  1111. mSmHandler.transitionTo(destState);
  1112. }
  1113. /**
  1114. * transition to halt state. Upon returning
  1115. * from processMessage we will exit all current
  1116. * states, execute the halting() method and then
  1117. * all subsequent messages haltedProcessMesage
  1118. * will be called.
  1119. */
  1120. protected final void transitionToHaltingState() {
  1121. mSmHandler.transitionTo(mSmHandler.mHaltingState);
  1122. }
  1123. /**
  1124. * Defer this message until next state transition.
  1125. * Upon transitioning all deferred messages will be
  1126. * placed on the queue and reprocessed in the original
  1127. * order. (i.e. The next state the oldest messages will
  1128. * be processed first)
  1129. *
  1130. * @param msg is deferred until the next transition.
  1131. */
  1132. protected final void deferMessage(Message msg) {
  1133. mSmHandler.deferMessage(msg);
  1134. }
  1135. /**
  1136. * Called when message wasn't handled
  1137. *
  1138. * @param msg that couldn't be handled.
  1139. */
  1140. protected void unhandledMessage(Message msg) {
  1141. if (mSmHandler.mDbg) Log.e(TAG, mName + " - unhandledMessage: msg.what=" + msg.what);
  1142. }
  1143. /**
  1144. * Called for any message that is received after
  1145. * transitionToHalting is called.
  1146. */
  1147. protected void haltedProcessMessage(Message msg) {
  1148. }
  1149. /**
  1150. * This will be called once after handling a message that called
  1151. * transitionToHalting. All subsequent messages will invoke
  1152. * {@link StateMachine#haltedProcessMessage(Message)}
  1153. */
  1154. protected void halting() {
  1155. }
  1156. /**
  1157. * This will be called once after a quit message that was NOT handled by
  1158. * the derived StateMachine. The StateMachine will stop and any subsequent messages will be
  1159. * ignored. In addition, if this StateMachine created the thread, the thread will
  1160. * be stopped after this method returns.
  1161. */
  1162. protected void quitting() {
  1163. }
  1164. /**
  1165. * @return the name
  1166. */
  1167. public final String getName() {
  1168. return mName;
  1169. }
  1170. /**
  1171. * Set size of messages to maintain and clears all current messages.
  1172. *
  1173. * @param maxSize number of messages to maintain at anyone time.
  1174. */
  1175. public final void setProcessedMessagesSize(int maxSize) {
  1176. mSmHandler.setProcessedMessagesSize(maxSize);
  1177. }
  1178. /**
  1179. * @return number of messages processed
  1180. */
  1181. public final int getProcessedMessagesSize() {
  1182. return mSmHandler.getProcessedMessagesSize();
  1183. }
  1184. /**
  1185. * @return the total number of messages processed
  1186. */
  1187. public final int getProcessedMessagesCount() {
  1188. return mSmHandler.getProcessedMessagesCount();
  1189. }
  1190. /**
  1191. * @return a processed message information
  1192. */
  1193. public final ProcessedMessageInfo getProcessedMessageInfo(int index) {
  1194. return mSmHandler.getProcessedMessageInfo(index);
  1195. }
  1196. /**
  1197. * @return Handler
  1198. */
  1199. public final Handler getHandler() {
  1200. return mSmHandler;
  1201. }
  1202. /**
  1203. * Get a message and set Message.target = this.
  1204. *
  1205. * @return message
  1206. */
  1207. public final Message obtainMessage()
  1208. {
  1209. return Message.obtain(mSmHandler);
  1210. }
  1211. /**
  1212. * Get a message and set Message.target = this and what
  1213. *
  1214. * @param what is the assigned to Message.what.
  1215. * @return message
  1216. */
  1217. public final Message obtainMessage(int what) {
  1218. return Message.obtain(mSmHandler, what);
  1219. }
  1220. /**
  1221. * Get a message and set Message.target = this,
  1222. * what and obj.
  1223. *
  1224. * @param what is the assigned to Message.what.
  1225. * @param obj is assigned to Message.obj.
  1226. * @return message
  1227. */
  1228. public final Message obtainMessage(int what, Object obj)
  1229. {
  1230. return Message.obtain(mSmHandler, what, obj);
  1231. }
  1232. /**
  1233. * Get a message and set Message.target = this,
  1234. * what, arg1 and arg2
  1235. *
  1236. * @param what is assigned to Message.what
  1237. * @param arg1 is assigned to Message.arg1
  1238. * @param arg2 is assigned to Message.arg2
  1239. * @return A Message object from the global pool.
  1240. */
  1241. public final Message obtainMessage(int what, int arg1, int arg2)
  1242. {
  1243. return Message.obtain(mSmHandler, what, arg1, arg2);
  1244. }
  1245. /**
  1246. * Get a message and set Message.target = this,
  1247. * what, arg1, arg2 and obj
  1248. *
  1249. * @param what is assigned to Message.what
  1250. * @param arg1 is assigned to Message.arg1
  1251. * @param arg2 is assigned to Message.arg2
  1252. * @param obj is assigned to Message.obj
  1253. * @return A Message object from the global pool.
  1254. */
  1255. public final Message obtainMessage(int what, int arg1, int arg2, Object obj)
  1256. {
  1257. return Message.obtain(mSmHandler, what, arg1, arg2, obj);
  1258. }
  1259. /**
  1260. * Enqueue a message to this state machine.
  1261. */
  1262. public final void sendMessage(int what) {
  1263. mSmHandler.sendMessage(obtainMessage(what));
  1264. }
  1265. /**
  1266. * Enqueue a message to this state machine.
  1267. */
  1268. public final void sendMessage(int what, Object obj) {
  1269. mSmHandler.sendMessage(obtainMessage(what,obj));
  1270. }
  1271. /**
  1272. * Enqueue a message to this state machine.
  1273. */
  1274. public final void sendMessage(Message msg) {
  1275. mSmHandler.sendMessage(msg);
  1276. }
  1277. /**
  1278. * Enqueue a message to this state machine after a delay.
  1279. */
  1280. public final void sendMessageDelayed(int what, long delayMillis) {
  1281. mSmHandler.sendMessageDelayed(obtainMessage(what), delayMillis);
  1282. }
  1283. /**
  1284. * Enqueue a message to this state machine after a delay.
  1285. */
  1286. public final void sendMessageDelayed(int what, Object obj, long delayMillis) {
  1287. mSmHandler.sendMessageDelayed(obtainMessage(what, obj), delayMillis);
  1288. }
  1289. /**
  1290. * Enqueue a message to this state machine after a delay.
  1291. */
  1292. public final void sendMessageDelayed(Message msg, long delayMillis) {
  1293. mSmHandler.sendMessageDelayed(msg, delayMillis);
  1294. }
  1295. /**
  1296. * Enqueue a message to the front of the queue for this state machine.
  1297. * Protected, may only be called by instances of StateMachine.
  1298. */
  1299. protected final void sendMessageAtFrontOfQueue(int what, Object obj) {
  1300. mSmHandler.sendMessageAtFrontOfQueue(obtainMessage(what, obj));
  1301. }
  1302. /**
  1303. * Enqueue a message to the front of the queue for this state machine.
  1304. * Protected, may only be called by instances of StateMachine.
  1305. */
  1306. protected final void sendMessageAtFrontOfQueue(int what) {
  1307. mSmHandler.sendMessageAtFrontOfQueue(obtainMessage(what));
  1308. }
  1309. /**
  1310. * Enqueue a message to the front of the queue for this state machine.
  1311. * Protected, may only be called by instances of StateMachine.
  1312. */
  1313. protected final void sendMessageAtFrontOfQueue(Message msg) {
  1314. mSmHandler.sendMessageAtFrontOfQueue(msg);
  1315. }
  1316. /**
  1317. * Removes a message from the message queue.
  1318. * Protected, may only be called by instances of StateMachine.
  1319. */
  1320. protected final void removeMessages(int what) {
  1321. mSmHandler.removeMessages(what);
  1322. }
  1323. /**
  1324. * Conditionally quit the looper and stop execution.
  1325. *
  1326. * This sends the SM_QUIT_MSG to the state machine and
  1327. * if not handled by any state's processMessage then the
  1328. * state machine will be stopped and no further messages
  1329. * will be processed.
  1330. */
  1331. public final void quit() {
  1332. mSmHandler.quit();
  1333. }
  1334. /**
  1335. * @return ture if msg is quit
  1336. */
  1337. protected final boolean isQuit(Message msg) {
  1338. return mSmHandler.isQuit(msg);