summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/com/android/internal/util/AsyncChannel.java72
-rw-r--r--core/java/com/android/internal/util/HierarchicalStateMachine.java276
2 files changed, 172 insertions, 176 deletions
diff --git a/core/java/com/android/internal/util/AsyncChannel.java b/core/java/com/android/internal/util/AsyncChannel.java
index b0778dd18224..0891acc20af8 100644
--- a/core/java/com/android/internal/util/AsyncChannel.java
+++ b/core/java/com/android/internal/util/AsyncChannel.java
@@ -32,51 +32,51 @@ import android.util.Slog;
import java.util.Stack;
/**
- * An asynchronous channel between two handlers.
+ * <p>An asynchronous channel between two handlers.</p>
*
- * The handlers maybe in the same process or in another process. There
+ * <p>The handlers maybe in the same process or in another process. There
* are two protocol styles that can be used with an AysncChannel. The
* first is a simple request/reply protocol where the server does
- * not need to know which client is issuing the request.
+ * not need to know which client is issuing the request.</p>
*
- * In a simple request/reply protocol the client/source sends requests to the
+ * <p>In a simple request/reply protocol the client/source sends requests to the
* server/destination. And the server uses the replyToMessage methods.
* In this usage model there is no need for the destination to
- * use the connect methods. The typical sequence of operations is:
- *
- * 1) Client calls AsyncChannel#connect
- * 2) Client receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel
-
- * 3) Client calls AsyncChannel#sendMessage(msgX)
- * 4) Server receives and processes msgX
- * 5) Server optionally calls AsyncChannel#replyToMessage(msgY)
- * and if sent Client receives and processes msgY
- * 6) Loop to step 3 until done
- *
- * 7) When done Client calls {@link AsyncChannel#disconnect(int)}
- * 8) Client receives CMD_CHANNEL_DISCONNECTED from AsyncChannel
- *
- * A second usage model is where the server/destination needs to know
+ * use the connect methods. The typical sequence of operations is:</p>
+ *<ol>
+ * <li>Client calls AsyncChannel#connect</li>
+ * <li>Client receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel</li>
+ * <li><code>comm-loop:</code></li>
+ * <li>Client calls AsyncChannel#sendMessage(msgX)</li>
+ * <li>Server receives and processes msgX</li>
+ * <li>Server optionally calls AsyncChannel#replyToMessage(msgY)
+ * and if sent Client receives and processes msgY</li>
+ * <li>Loop to <code>comm-loop</code> until done</li>
+ * <li>When done Client calls {@link AsyncChannel#disconnect(int)}</li>
+ * <li>Client receives CMD_CHANNEL_DISCONNECTED from AsyncChannel</li>
+ *</ol>
+ *<br/>
+ * <p>A second usage model is where the server/destination needs to know
* which client it's connected too. For example the server needs to
* send unsolicited messages back to the client. Or the server keeps
* different state for each client. In this model the server will also
- * use the connect methods. The typical sequence of operation is:
- *
- * 1) Client calls AsyncChannel#connect
- * 2) Client receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel
- * 3) Client calls AsyncChannel#sendMessage(CMD_CHANNEL_FULL_CONNECTION)
- * 4) Server receives CMD_CHANNEL_FULL_CONNECTION
- * 5) Server calls AsyncChannel#connect
- * 6) Server receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel
- * 7) Server sends AsyncChannel#sendMessage(CMD_CHANNEL_FULLY_CONNECTED)
- * 8) Client receives CMD_CHANNEL_FULLY_CONNECTED
- *
- * 9) Client/Server uses AsyncChannel#sendMessage/replyToMessage
- * to communicate and perform work
- * 10) Loop to step 9 until done
- *
- * 11) When done Client/Server calls {@link AsyncChannel#disconnect(int)}
- * 12) Client/Server receives CMD_CHANNEL_DISCONNECTED from AsyncChannel
+ * use the connect methods. The typical sequence of operation is:</p>
+ *<ol>
+ * <li>Client calls AsyncChannel#connect</li>
+ * <li>Client receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel</li>
+ * <li>Client calls AsyncChannel#sendMessage(CMD_CHANNEL_FULL_CONNECTION)</li>
+ * <li>Server receives CMD_CHANNEL_FULL_CONNECTION</li>
+ * <li>Server calls AsyncChannel#connect</li>
+ * <li>Server receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel</li>
+ * <li>Server sends AsyncChannel#sendMessage(CMD_CHANNEL_FULLY_CONNECTED)</li>
+ * <li>Client receives CMD_CHANNEL_FULLY_CONNECTED</li>
+ * <li><code>comm-loop:</code></li>
+ * <li>Client/Server uses AsyncChannel#sendMessage/replyToMessage
+ * to communicate and perform work</li>
+ * <li>Loop to <code>comm-loop</code> until done</li>
+ * <li>When done Client/Server calls {@link AsyncChannel#disconnect(int)}</li>
+ * <li>Client/Server receives CMD_CHANNEL_DISCONNECTED from AsyncChannel</li>
+ *</ol>
*/
public class AsyncChannel {
/** Log tag */
diff --git a/core/java/com/android/internal/util/HierarchicalStateMachine.java b/core/java/com/android/internal/util/HierarchicalStateMachine.java
index 7920b72dbb95..f43f459fe04f 100644
--- a/core/java/com/android/internal/util/HierarchicalStateMachine.java
+++ b/core/java/com/android/internal/util/HierarchicalStateMachine.java
@@ -28,64 +28,66 @@ import java.util.HashMap;
/**
* {@hide}
*
- * A hierarchical state machine is a state machine which processes messages
- * and can have states arranged hierarchically. A state is a <code>HierarchicalState</code>
- * object and must implement <code>processMessage</code> and optionally <code>enter/exit/getName</code>.
+ * <p>A hierarchical state machine is a state machine which processes messages
+ * and can have states arranged hierarchically.</p>
+ *
+ * <p>A state is a <code>HierarchicalState</code> object and must implement
+ * <code>processMessage</code> and optionally <code>enter/exit/getName</code>.
* The enter/exit methods are equivalent to the construction and destruction
* in Object Oriented programming and are used to perform initialization and
* cleanup of the state respectively. The <code>getName</code> method returns the
* name of the state the default implementation returns the class name it may be
* desirable to have this return the name of the state instance name instead.
- * In particular if a particular state class has multiple instances.
+ * In particular if a particular state class has multiple instances.</p>
*
- * When a state machine is created <code>addState</code> is used to build the
+ * <p>When a state machine is created <code>addState</code> is used to build the
* hierarchy and <code>setInitialState</code> is used to identify which of these
* is the initial state. After construction the programmer calls <code>start</code>
* which initializes the state machine and calls <code>enter</code> for all of the initial
* state's hierarchy, starting at its eldest parent. For example given the simple
* state machine below after start is called mP1.enter will have been called and
- * then mS1.enter.
+ * then mS1.enter.</p>
<code>
mP1
/ \
mS2 mS1 ----> initial state
</code>
- * After the state machine is created and started, messages are sent to a state
+ * <p>After the state machine is created and started, messages are sent to a state
* machine using <code>sendMessage</code> and the messages are created using
* <code>obtainMessage</code>. When the state machine receives a message the
* current state's <code>processMessage</code> is invoked. In the above example
* mS1.processMessage will be invoked first. The state may use <code>transitionTo</code>
- * to change the current state to a new state
+ * to change the current state to a new state</p>
*
- * Each state in the state machine may have a zero or one parent states and if
+ * <p>Each state in the state machine may have a zero or one parent states and if
* a child state is unable to handle a message it may have the message processed
* by its parent by returning false or NOT_HANDLED. If a message is never processed
* <code>unhandledMessage</code> will be invoked to give one last chance for the state machine
- * to process the message.
+ * to process the message.</p>
*
- * When all processing is completed a state machine may choose to call
+ * <p>When all processing is completed a state machine may choose to call
* <code>transitionToHaltingState</code>. When the current <code>processingMessage</code>
* returns the state machine will transfer to an internal <code>HaltingState</code>
* and invoke <code>halting</code>. Any message subsequently received by the state
- * machine will cause <code>haltedProcessMessage</code> to be invoked.
+ * machine will cause <code>haltedProcessMessage</code> to be invoked.</p>
*
- * If it is desirable to completely stop the state machine call <code>quit</code>. This
+ * <p>If it is desirable to completely stop the state machine call <code>quit</code>. This
* will exit the current state and its parent and then exit from the controlling thread
- * and no further messages will be processed.
+ * and no further messages will be processed.</p>
*
- * In addition to <code>processMessage</code> each <code>HierarchicalState</code> has
- * an <code>enter</code> method and <code>exit</exit> method which may be overridden.
+ * <p>In addition to <code>processMessage</code> each <code>HierarchicalState</code> has
+ * an <code>enter</code> method and <code>exit</exit> method which may be overridden.</p>
*
- * Since the states are arranged in a hierarchy transitioning to a new state
+ * <p>Since the states are arranged in a hierarchy transitioning to a new state
* causes current states to be exited and new states to be entered. To determine
* the list of states to be entered/exited the common parent closest to
* the current state is found. We then exit from the current state and its
* parent's up to but not including the common parent state and then enter all
* of the new states below the common parent down to the destination state.
* If there is no common parent all states are exited and then the new states
- * are entered.
+ * are entered.</p>
*
- * Two other methods that states can use are <code>deferMessage</code> and
+ * <p>Two other methods that states can use are <code>deferMessage</code> and
* <code>sendMessageAtFrontOfQueue</code>. The <code>sendMessageAtFrontOfQueue</code> sends
* a message but places it on the front of the queue rather than the back. The
* <code>deferMessage</code> causes the message to be saved on a list until a
@@ -93,10 +95,10 @@ import java.util.HashMap;
* will be put on the front of the state machine queue with the oldest message
* at the front. These will then be processed by the new current state before
* any other messages that are on the queue or might be added later. Both of
- * these are protected and may only be invoked from within a state machine.
+ * these are protected and may only be invoked from within a state machine.</p>
*
- * To illustrate some of these properties we'll use state machine with an 8
- * state hierarchy:
+ * <p>To illustrate some of these properties we'll use state machine with an 8
+ * state hierarchy:</p>
<code>
mP0
/ \
@@ -106,22 +108,21 @@ import java.util.HashMap;
/ \ \
mS3 mS4 mS5 ---> initial state
</code>
- *
- * After starting mS5 the list of active states is mP0, mP1, mS1 and mS5.
+ * <p>After starting mS5 the list of active states is mP0, mP1, mS1 and mS5.
* So the order of calling processMessage when a message is received is mS5,
* mS1, mP1, mP0 assuming each processMessage indicates it can't handle this
- * message by returning false or NOT_HANDLED.
+ * message by returning false or NOT_HANDLED.</p>
*
- * Now assume mS5.processMessage receives a message it can handle, and during
+ * <p>Now assume mS5.processMessage receives a message it can handle, and during
* the handling determines the machine should change states. It could call
* transitionTo(mS4) and return true or HANDLED. Immediately after returning from
* processMessage the state machine runtime will find the common parent,
* which is mP1. It will then call mS5.exit, mS1.exit, mS2.enter and then
* mS4.enter. The new list of active states is mP0, mP1, mS2 and mS4. So
- * when the next message is received mS4.processMessage will be invoked.
+ * when the next message is received mS4.processMessage will be invoked.</p>
*
- * Now for some concrete examples, here is the canonical HelloWorld as an HSM.
- * It responds with "Hello World" being printed to the log for every message.
+ * <p>Now for some concrete examples, here is the canonical HelloWorld as an HSM.
+ * It responds with "Hello World" being printed to the log for every message.</p>
<code>
class HelloWorld extends HierarchicalStateMachine {
Hsm1(String name) {
@@ -150,79 +151,76 @@ void testHelloWorld() {
hw.sendMessage(hw.obtainMessage());
}
</code>
- *
- * A more interesting state machine is one with four states
- * with two independent parent states.
+ * <p>A more interesting state machine is one with four states
+ * with two independent parent states.</p>
<code>
mP1 mP2
/ \
mS2 mS1
</code>
- *
- * Here is a description of this state machine using pseudo code.
- *
- *
- * state mP1 {
- * enter { log("mP1.enter"); }
- * exit { log("mP1.exit"); }
- * on msg {
- * CMD_2 {
- * send(CMD_3);
- * defer(msg);
- * transitonTo(mS2);
- * return HANDLED;
- * }
- * return NOT_HANDLED;
- * }
- * }
- *
- * INITIAL
- * state mS1 parent mP1 {
- * enter { log("mS1.enter"); }
- * exit { log("mS1.exit"); }
- * on msg {
- * CMD_1 {
- * transitionTo(mS1);
- * return HANDLED;
- * }
- * return NOT_HANDLED;
- * }
- * }
- *
- * state mS2 parent mP1 {
- * enter { log("mS2.enter"); }
- * exit { log("mS2.exit"); }
- * on msg {
- * CMD_2 {
- * send(CMD_4);
- * return HANDLED;
- * }
- * CMD_3 {
- * defer(msg);
- * transitionTo(mP2);
- * return HANDLED;
- * }
- * return NOT_HANDLED;
- * }
- * }
- *
- * state mP2 {
- * enter {
- * log("mP2.enter");
- * send(CMD_5);
- * }
- * exit { log("mP2.exit"); }
- * on msg {
- * CMD_3, CMD_4 { return HANDLED; }
- * CMD_5 {
- * transitionTo(HaltingState);
- * return HANDLED;
- * }
- * return NOT_HANDLED;
- * }
- * }
- *
- * The implementation is below and also in HierarchicalStateMachineTest:
+ * <p>Here is a description of this state machine using pseudo code.</p>
+ <code>
+state mP1 {
+ enter { log("mP1.enter"); }
+ exit { log("mP1.exit"); }
+ on msg {
+ CMD_2 {
+ send(CMD_3);
+ defer(msg);
+ transitonTo(mS2);
+ return HANDLED;
+ }
+ return NOT_HANDLED;
+ }
+}
+
+INITIAL
+state mS1 parent mP1 {
+ enter { log("mS1.enter"); }
+ exit { log("mS1.exit"); }
+ on msg {
+ CMD_1 {
+ transitionTo(mS1);
+ return HANDLED;
+ }
+ return NOT_HANDLED;
+ }
+}
+
+state mS2 parent mP1 {
+ enter { log("mS2.enter"); }
+ exit { log("mS2.exit"); }
+ on msg {
+ CMD_2 {
+ send(CMD_4);
+ return HANDLED;
+ }
+ CMD_3 {
+ defer(msg);
+ transitionTo(mP2);
+ return HANDLED;
+ }
+ return NOT_HANDLED;
+ }
+}
+
+state mP2 {
+ enter {
+ log("mP2.enter");
+ send(CMD_5);
+ }
+ exit { log("mP2.exit"); }
+ on msg {
+ CMD_3, CMD_4 { return HANDLED; }
+ CMD_5 {
+ transitionTo(HaltingState);
+ return HANDLED;
+ }
+ return NOT_HANDLED;
+ }
+}
+</code>
+ * <p>The implementation is below and also in HierarchicalStateMachineTest:</p>
<code>
class Hsm1 extends HierarchicalStateMachine {
private static final String TAG = "hsm1";
@@ -368,49 +366,47 @@ class Hsm1 extends HierarchicalStateMachine {
P2 mP2 = new P2();
}
</code>
- *
- * If this is executed by sending two messages CMD_1 and CMD_2
- * (Note the synchronize is only needed because we use hsm.wait())
- *
- * Hsm1 hsm = makeHsm1();
- * synchronize(hsm) {
- * hsm.sendMessage(obtainMessage(hsm.CMD_1));
- * hsm.sendMessage(obtainMessage(hsm.CMD_2));
- * try {
- * // wait for the messages to be handled
- * hsm.wait();
- * } catch (InterruptedException e) {
- * Log.e(TAG, "exception while waiting " + e.getMessage());
- * }
- * }
- *
- *
- * The output is:
- *
- * D/hsm1 ( 1999): makeHsm1 E
- * D/hsm1 ( 1999): ctor E
- * D/hsm1 ( 1999): ctor X
- * D/hsm1 ( 1999): mP1.enter
- * D/hsm1 ( 1999): mS1.enter
- * D/hsm1 ( 1999): makeHsm1 X
- * D/hsm1 ( 1999): mS1.processMessage what=1
- * D/hsm1 ( 1999): mS1.exit
- * D/hsm1 ( 1999): mS1.enter
- * D/hsm1 ( 1999): mS1.processMessage what=2
- * D/hsm1 ( 1999): mP1.processMessage what=2
- * D/hsm1 ( 1999): mS1.exit
- * D/hsm1 ( 1999): mS2.enter
- * D/hsm1 ( 1999): mS2.processMessage what=2
- * D/hsm1 ( 1999): mS2.processMessage what=3
- * D/hsm1 ( 1999): mS2.exit
- * D/hsm1 ( 1999): mP1.exit
- * D/hsm1 ( 1999): mP2.enter
- * D/hsm1 ( 1999): mP2.processMessage what=3
- * D/hsm1 ( 1999): mP2.processMessage what=4
- * D/hsm1 ( 1999): mP2.processMessage what=5
- * D/hsm1 ( 1999): mP2.exit
- * D/hsm1 ( 1999): halting
- *
+ * <p>If this is executed by sending two messages CMD_1 and CMD_2
+ * (Note the synchronize is only needed because we use hsm.wait())</p>
+<code>
+Hsm1 hsm = makeHsm1();
+synchronize(hsm) {
+ hsm.sendMessage(obtainMessage(hsm.CMD_1));
+ hsm.sendMessage(obtainMessage(hsm.CMD_2));
+ try {
+ // wait for the messages to be handled
+ hsm.wait();
+ } catch (InterruptedException e) {
+ Log.e(TAG, "exception while waiting " + e.getMessage());
+ }
+}
+</code>
+ * <p>The output is:</p>
+<code>
+D/hsm1 ( 1999): makeHsm1 E
+D/hsm1 ( 1999): ctor E
+D/hsm1 ( 1999): ctor X
+D/hsm1 ( 1999): mP1.enter
+D/hsm1 ( 1999): mS1.enter
+D/hsm1 ( 1999): makeHsm1 X
+D/hsm1 ( 1999): mS1.processMessage what=1
+D/hsm1 ( 1999): mS1.exit
+D/hsm1 ( 1999): mS1.enter
+D/hsm1 ( 1999): mS1.processMessage what=2
+D/hsm1 ( 1999): mP1.processMessage what=2
+D/hsm1 ( 1999): mS1.exit
+D/hsm1 ( 1999): mS2.enter
+D/hsm1 ( 1999): mS2.processMessage what=2
+D/hsm1 ( 1999): mS2.processMessage what=3
+D/hsm1 ( 1999): mS2.exit
+D/hsm1 ( 1999): mP1.exit
+D/hsm1 ( 1999): mP2.enter
+D/hsm1 ( 1999): mP2.processMessage what=3
+D/hsm1 ( 1999): mP2.processMessage what=4
+D/hsm1 ( 1999): mP2.processMessage what=5
+D/hsm1 ( 1999): mP2.exit
+D/hsm1 ( 1999): halting
+</code>
*/
public class HierarchicalStateMachine {