Merge "Revert "Add Sms/Mms sent failure reasons parsing in sl4a.""
diff --git a/Utils/src/com/googlecode/android_scripting/SimpleServer.java b/Utils/src/com/googlecode/android_scripting/SimpleServer.java
index a995ed7..de15b4e 100644
--- a/Utils/src/com/googlecode/android_scripting/SimpleServer.java
+++ b/Utils/src/com/googlecode/android_scripting/SimpleServer.java
@@ -38,330 +38,371 @@
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
-//import com.googlecode.android_scripting.jsonrpc.RpcReceiverManager;
/**
* A simple server.
*/
public abstract class SimpleServer {
- private static int threadIndex = 0;
- private final ConcurrentHashMap<Integer, ConnectionThread> mConnectionThreads =
- new ConcurrentHashMap<Integer, ConnectionThread>();
- private final List<SimpleServerObserver> mObservers = Lists.newArrayList();
- private volatile boolean mStopServer = false;
- private ServerSocket mServer;
- private Thread mServerThread;
+ private static int threadIndex = 0;
+ private final ConcurrentHashMap<Integer, ConnectionThread> mConnectionThreads =
+ new ConcurrentHashMap<>();
+ private final List<SimpleServerObserver> mObservers = Lists.newArrayList();
+ private volatile boolean mStopServer = false;
+ private ServerSocket mServer;
+ private Thread mServerThread;
- public interface SimpleServerObserver {
- public void onConnect();
- public void onDisconnect();
- }
-
- protected abstract void handleConnection(Socket socket) throws Exception;
- protected abstract void handleRPCConnection(Socket socket,
- Integer UID,
- BufferedReader reader,
- PrintWriter writer) throws Exception;
-
- /** Adds an observer. */
- public void addObserver(SimpleServerObserver observer) {
- mObservers.add(observer);
- }
-
- /** Removes an observer. */
- public void removeObserver(SimpleServerObserver observer) {
- mObservers.remove(observer);
- }
-
- private void notifyOnConnect() {
- for (SimpleServerObserver observer : mObservers) {
- observer.onConnect();
- }
- }
-
- private void notifyOnDisconnect() {
- for (SimpleServerObserver observer : mObservers) {
- observer.onDisconnect();
- }
- }
-
- private final class ConnectionThread extends Thread {
- private final Socket mmSocket;
- private final BufferedReader reader;
- private final PrintWriter writer;
- private final Integer UID;
- private final boolean isRpc;
-
- private ConnectionThread(Socket socket, boolean rpc, Integer uid, BufferedReader reader, PrintWriter writer) {
- setName("SimpleServer ConnectionThread " + getId());
- mmSocket = socket;
- this.UID = uid;
- this.reader = reader;
- this.writer = writer;
- this.isRpc = rpc;
+ /**
+ * An interface for accessing SimpleServer events.
+ */
+ public interface SimpleServerObserver {
+ /** The function to be called when a ConnectionThread is established.*/
+ void onConnect();
+ /** The function to be called when a ConnectionThread disconnects.*/
+ void onDisconnect();
}
- @Override
- public void run() {
- Log.v("Server thread " + getId() + " started.");
- try {
- if(isRpc) {
- Log.d("Handling RPC connection in "+getId());
- handleRPCConnection(mmSocket, UID, reader, writer);
- }else{
- Log.d("Handling Non-RPC connection in "+getId());
- handleConnection(mmSocket);
+ /** An abstract method for handling non-RPC connections. */
+ protected abstract void handleConnection(Socket socket) throws Exception;
+
+ /** An abstract method for handling RPC connections. */
+ protected abstract void handleRPCConnection(Socket socket,
+ Integer UID,
+ BufferedReader reader,
+ PrintWriter writer) throws Exception;
+
+ /**
+ * Adds an observer.
+ */
+ public void addObserver(SimpleServerObserver observer) {
+ mObservers.add(observer);
+ }
+
+ /**
+ * Removes an observer.
+ */
+ public void removeObserver(SimpleServerObserver observer) {
+ mObservers.remove(observer);
+ }
+
+ /** Notifies all subscribers when a new ConnectionThread has been created.
+ *
+ * This applies to both newly instantiated sessions and continued sessions.
+ */
+ private void notifyOnConnect() {
+ for (SimpleServerObserver observer : mObservers) {
+ observer.onConnect();
}
- } catch (Exception e) {
- if (!mStopServer) {
- Log.e("Server error.", e);
- }
- } finally {
- close();
- mConnectionThreads.remove(this.UID);
- notifyOnDisconnect();
- Log.v("Server thread " + getId() + " stopped.");
- }
}
- private void close() {
- if (mmSocket != null) {
+ /** Notifies all subscribers when a ConnectionThread has been terminated. */
+ private void notifyOnDisconnect() {
+ for (SimpleServerObserver observer : mObservers) {
+ observer.onDisconnect();
+ }
+ }
+
+ /** An implementation of a thread that holds data about its server connection status. */
+ private final class ConnectionThread extends Thread {
+ /** The socket used for communication. */
+ private final Socket mmSocket;
+ /** The BufferedReader providing input to the socket. */
+ private final BufferedReader reader;
+ /** The PrintWriter bound to the socket's output. */
+ private final PrintWriter writer;
+ /** The SessionID associated with this connection. */
+ private final Integer UID;
+ private final boolean isRpc;
+
+ private ConnectionThread(Socket socket, boolean rpc, Integer uid, BufferedReader reader,
+ PrintWriter writer) {
+ setName("SimpleServer ConnectionThread " + getId());
+ mmSocket = socket;
+ this.UID = uid;
+ this.reader = reader;
+ this.writer = writer;
+ this.isRpc = rpc;
+ }
+
+ @Override
+ public void run() {
+ Log.v("Server thread " + getId() + " started.");
+ try {
+ if (isRpc) {
+ Log.d("Handling RPC connection in " + getId());
+ handleRPCConnection(mmSocket, UID, reader, writer);
+ } else {
+ Log.d("Handling Non-RPC connection in " + getId());
+ handleConnection(mmSocket);
+ }
+ } catch (Exception e) {
+ if (!mStopServer) {
+ Log.e("Server error.", e);
+ }
+ } finally {
+ close();
+ mConnectionThreads.remove(this.UID);
+ notifyOnDisconnect();
+ Log.v("Server thread " + getId() + " stopped.");
+ }
+ }
+
+ private void close() {
+ if (mmSocket != null) {
+ try {
+ mmSocket.close();
+ } catch (IOException e) {
+ Log.e(e.getMessage(), e);
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns the number of active connections to this server.
+ */
+ public int getNumberOfConnections() {
+ return mConnectionThreads.size();
+ }
+
+ /**
+ * Returns the private InetAddress
+ * @return the private InetAddress
+ * @throws UnknownHostException If unable to resolve localhost during fallback.
+ * @throws SocketException if an IOError occurs while querying the network interfaces.
+ */
+ public static InetAddress getPrivateInetAddress() throws UnknownHostException, SocketException {
+ InetAddress candidate = null;
+ Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces();
+ for (NetworkInterface netint : Collections.list(nets)) {
+ if (!netint.isLoopback() || !netint.isUp()) { // Ignore if localhost or not active
+ continue;
+ }
+ Enumeration<InetAddress> addresses = netint.getInetAddresses();
+ for (InetAddress address : Collections.list(addresses)) {
+ if (address instanceof Inet4Address) {
+ Log.d("local address " + address);
+ return address; // Prefer ipv4
+ }
+ candidate = address; // Probably an ipv6
+ }
+ }
+ if (candidate != null) {
+ return candidate; // return ipv6 address if no suitable ipv6
+ }
+ return InetAddress.getLocalHost(); // No damn matches. Give up, return local host.
+ }
+
+ /**
+ * Returns the public InetAddress
+ * @return the private InetAddress
+ * @throws UnknownHostException If unable to resolve localhost during fallback.
+ * @throws SocketException if an IOError occurs while querying the network interfaces.
+ */
+ public static InetAddress getPublicInetAddress() throws UnknownHostException, SocketException {
+ InetAddress candidate = null;
+ Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces();
+ for (NetworkInterface netint : Collections.list(nets)) {
+ // TODO(markdr): The only diff between this and above fn is the ! on the line below.
+ // Merge these two functions.
+ if (netint.isLoopback() || !netint.isUp()) { // Ignore if localhost or not active
+ continue;
+ }
+ Enumeration<InetAddress> addresses = netint.getInetAddresses();
+ for (InetAddress address : Collections.list(addresses)) {
+ if (address instanceof Inet4Address) {
+ return address; // Prefer ipv4
+ }
+ candidate = address; // Probably an ipv6
+ }
+ }
+ if (candidate != null) {
+ return candidate; // return ipv6 address if no suitable ipv6
+ }
+ return InetAddress.getLocalHost(); // No damn matches. Give up, return local host.
+ }
+
+ /**
+ * Starts the RPC server bound to the localhost address.
+ *
+ * @param port the port to bind to or 0 to pick any unused port
+ * @return the port that the server is bound to
+ * @throws IOException
+ */
+ public InetSocketAddress startLocal(int port) {
+ InetAddress address;
try {
- mmSocket.close();
- } catch (IOException e) {
- Log.e(e.getMessage(), e);
+ // address = InetAddress.getLocalHost();
+ address = getPrivateInetAddress();
+ mServer = new ServerSocket(port, 5, address);
+ } catch (BindException e) {
+ Log.e("Port " + port + " already in use.");
+ try {
+ address = getPrivateInetAddress();
+ mServer = new ServerSocket(0, 5, address);
+ } catch (IOException e1) {
+ e1.printStackTrace();
+ return null;
+ }
+ } catch (Exception e) {
+ Log.e("Failed to start server.", e);
+ return null;
}
- }
+ int boundPort = start();
+ return InetSocketAddress.createUnresolved(mServer.getInetAddress().getHostAddress(),
+ boundPort);
}
- }
- /** Returns the number of active connections to this server. */
- public int getNumberOfConnections() {
- return mConnectionThreads.size();
- }
-
- public static InetAddress getPrivateInetAddress() throws UnknownHostException, SocketException {
-
- InetAddress candidate = null;
- Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces();
- for (NetworkInterface netint : Collections.list(nets)) {
- if (!netint.isLoopback() || !netint.isUp()) { // Ignore if localhost or not active
- continue;
- }
- Enumeration<InetAddress> addresses = netint.getInetAddresses();
- for (InetAddress address : Collections.list(addresses)) {
- if (address instanceof Inet4Address) {
- Log.d("local address " + address);
- return address; // Prefer ipv4
+ /**
+ * Starts the RPC server bound to the public facing address.
+ *
+ * @param port the port to bind to or 0 to pick any unused port
+ * @return the port that the server is bound to
+ */
+ public InetSocketAddress startPublic(int port) {
+ InetAddress address;
+ try {
+ // address = getPublicInetAddress();
+ address = null;
+ mServer = new ServerSocket(port, 5 /* backlog */, address);
+ } catch (Exception e) {
+ Log.e("Failed to start server.", e);
+ return null;
}
- candidate = address; // Probably an ipv6
- }
+ int boundPort = start();
+ return InetSocketAddress.createUnresolved(mServer.getInetAddress().getHostAddress(),
+ boundPort);
}
- if (candidate != null) {
- return candidate; // return ipv6 address if no suitable ipv6
- }
- return InetAddress.getLocalHost(); // No damn matches. Give up, return local host.
- }
- public static InetAddress getPublicInetAddress() throws UnknownHostException, SocketException {
-
- InetAddress candidate = null;
- Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces();
- for (NetworkInterface netint : Collections.list(nets)) {
- if (netint.isLoopback() || !netint.isUp()) { // Ignore if localhost or not active
- continue;
- }
- Enumeration<InetAddress> addresses = netint.getInetAddresses();
- for (InetAddress address : Collections.list(addresses)) {
- if (address instanceof Inet4Address) {
- return address; // Prefer ipv4
+ /**
+ * Starts the RPC server bound to all interfaces.
+ *
+ * @param port the port to bind to or 0 to pick any unused port
+ * @return the port that the server is bound to
+ */
+ public InetSocketAddress startAllInterfaces(int port) {
+ try {
+ mServer = new ServerSocket(port, 5 /* backlog */);
+ } catch (Exception e) {
+ Log.e("Failed to start server.", e);
+ return null;
}
- candidate = address; // Probably an ipv6
- }
+ int boundPort = start();
+ return InetSocketAddress.createUnresolved(mServer.getInetAddress().getHostAddress(),
+ boundPort);
}
- if (candidate != null) {
- return candidate; // return ipv6 address if no suitable ipv6
- }
- return InetAddress.getLocalHost(); // No damn matches. Give up, return local host.
- }
- /**
- * Starts the RPC server bound to the localhost address.
- *
- * @param port
- * the port to bind to or 0 to pick any unused port
- *
- * @return the port that the server is bound to
- * @throws IOException
- */
- public InetSocketAddress startLocal(int port) {
- InetAddress address;
- try {
- // address = InetAddress.getLocalHost();
- address = getPrivateInetAddress();
- mServer = new ServerSocket(port, 5, address);
- } catch (BindException e) {
- Log.e("Port " + port + " already in use.");
- try {
- address = getPrivateInetAddress();
- mServer = new ServerSocket(0, 5, address);
- } catch (IOException e1) {
- e1.printStackTrace();
- return null;
- }
- } catch (Exception e) {
- Log.e("Failed to start server.", e);
- return null;
+ private int start() {
+ mServerThread = new Thread(() -> {
+ while (!mStopServer) {
+ try {
+ Socket sock = mServer.accept();
+ if (!mStopServer) {
+ startConnectionThread(sock);
+ } else {
+ sock.close();
+ }
+ } catch (IOException e) {
+ if (!mStopServer) {
+ Log.e("Failed to accept connection.", e);
+ }
+ } catch (JSONException e) {
+ if (!mStopServer) {
+ Log.e("Failed to parse request.", e);
+ }
+ }
+ }
+ });
+ mServerThread.start();
+ Log.v("Bound to " + mServer.getInetAddress());
+ return mServer.getLocalPort();
}
- int boundPort = start();
- return InetSocketAddress.createUnresolved(mServer.getInetAddress().getHostAddress(), boundPort);
- }
- /**
- * data Starts the RPC server bound to the public facing address.
- *
- * @param port
- * the port to bind to or 0 to pick any unused port
- *
- * @return the port that the server is bound to
- */
- public InetSocketAddress startPublic(int port) {
- InetAddress address;
- try {
- // address = getPublicInetAddress();
- address = null;
- mServer = new ServerSocket(port, 5 /* backlog */, address);
- } catch (Exception e) {
- Log.e("Failed to start server.", e);
- return null;
- }
- int boundPort = start();
- return InetSocketAddress.createUnresolved(mServer.getInetAddress().getHostAddress(), boundPort);
- }
-
- /**
- * data Starts the RPC server bound to all interfaces
- *
- * @param port
- * the port to bind to or 0 to pick any unused port
- *
- * @return the port that the server is bound to
- */
- public InetSocketAddress startAllInterfaces(int port) {
- try {
- mServer = new ServerSocket(port, 5 /* backlog */);
- } catch (Exception e) {
- Log.e("Failed to start server.", e);
- return null;
- }
- int boundPort = start();
- return InetSocketAddress.createUnresolved(mServer.getInetAddress().getHostAddress(), boundPort);
- }
-
- private int start() {
- mServerThread = new Thread() {
- @Override
- public void run() {
- while (!mStopServer) {
- try {
- Socket sock = mServer.accept();
- if (!mStopServer) {
- startConnectionThread(sock);
+ /**
+ * Starts a ConnectionThread for a given socket.
+ *
+ * @param sock the Socket to start a ConnectionThread over
+ * @throws IOException when I/O Errors appear during read/writes.
+ * @throws JSONException when the received data from the socket is not in the expected format
+ */
+ private void startConnectionThread(final Socket sock) throws IOException, JSONException {
+ BufferedReader reader =
+ new BufferedReader(new InputStreamReader(sock.getInputStream()), 8192);
+ PrintWriter writer = new PrintWriter(sock.getOutputStream(), true);
+ String data;
+ if ((data = reader.readLine()) != null) {
+ Log.v("Received: " + data);
+ JSONObject request = new JSONObject(data);
+ if (request.has("cmd") && request.has("uid")) {
+ String cmd = request.getString("cmd");
+ int uid = request.getInt("uid");
+ JSONObject result = new JSONObject();
+ if (cmd.equals("initiate")) {
+ Log.d("Initiate a new session");
+ threadIndex += 1;
+ int mUID = threadIndex;
+ ConnectionThread networkThread = new ConnectionThread(sock, true, mUID,
+ reader, writer);
+ mConnectionThreads.put(mUID, networkThread);
+ networkThread.start();
+ notifyOnConnect();
+ result.put("uid", mUID);
+ result.put("status", true);
+ result.put("error", null);
+ } else if (cmd.equals("continue")) {
+ Log.d("Continue an existing session");
+ Log.d("keys: " + mConnectionThreads.keySet().toString());
+ if (!mConnectionThreads.containsKey(uid)) {
+ result.put("uid", uid);
+ result.put("status", false);
+ result.put("error", "Session does not exist.");
+ } else {
+ ConnectionThread networkThread = new ConnectionThread(sock, true, uid,
+ reader, writer);
+ mConnectionThreads.put(uid, networkThread);
+ networkThread.start();
+ notifyOnConnect();
+ result.put("uid", uid);
+ result.put("status", true);
+ result.put("error", null);
+ }
+ } else {
+ result.put("uid", uid);
+ result.put("status", false);
+ result.put("error", "Unrecognized command.");
+ }
+ writer.write(result + "\n");
+ writer.flush();
+ Log.v("Sent: " + result);
} else {
- sock.close();
+ ConnectionThread networkThread = new ConnectionThread(sock, false, 0, reader,
+ writer);
+ mConnectionThreads.put(0, networkThread);
+ networkThread.start();
+ notifyOnConnect();
}
- } catch (IOException e) {
- if (!mStopServer) {
- Log.e("Failed to accept connection.", e);
- }
- } catch (JSONException e) {
- if (!mStopServer) {
- Log.e("Failed to parse request.", e);
- }
- }
}
- }
- };
- mServerThread.start();
- Log.v("Bound to " + mServer.getInetAddress());
- return mServer.getLocalPort();
- }
+ }
- private void startConnectionThread(final Socket sock) throws IOException, JSONException {
- BufferedReader reader =
- new BufferedReader(new InputStreamReader(sock.getInputStream()), 8192);
- PrintWriter writer = new PrintWriter(sock.getOutputStream(), true);
- String data;
- if((data = reader.readLine()) != null) {
- Log.v("Received: " + data);
- JSONObject request = new JSONObject(data);
- if(request.has("cmd") && request.has("uid")) {
- String cmd = request.getString("cmd");
- int uid = request.getInt("uid");
- JSONObject result = new JSONObject();
- if(cmd.equals("initiate")) {
- Log.d("Initiate a new session");
- threadIndex += 1;
- int mUID = threadIndex;
- ConnectionThread networkThread = new ConnectionThread(sock,true,mUID,reader,writer);
- mConnectionThreads.put(mUID, networkThread);
- networkThread.start();
- notifyOnConnect();
- result.put("uid", mUID);
- result.put("status",true);
- result.put("error", null);
- }else if(cmd.equals("continue")) {
- Log.d("Continue an existing session");
- Log.d("keys: "+mConnectionThreads.keySet().toString());
- if(!mConnectionThreads.containsKey(uid)) {
- result.put("uid", uid);
- result.put("status",false);
- result.put("error", "Session does not exist.");
- }else{
- ConnectionThread networkThread = new ConnectionThread(sock,true,uid,reader,writer);
- mConnectionThreads.put(uid, networkThread);
- networkThread.start();
- notifyOnConnect();
- result.put("uid", uid);
- result.put("status",true);
- result.put("error", null);
- }
- }else {
- result.put("uid", uid);
- result.put("status",false);
- result.put("error", "Unrecognized command.");
+ /** Closes the server, preventing new connections from being added. */
+ public void shutdown() {
+ // Stop listening on the server socket to ensure that
+ // beyond this point there are no incoming requests.
+ mStopServer = true;
+ try {
+ mServer.close();
+ } catch (IOException e) {
+ Log.e("Failed to close server socket.", e);
}
- writer.write(result + "\n");
- writer.flush();
- Log.v("Sent: " + result);
- }else{
- ConnectionThread networkThread = new ConnectionThread(sock,false,0,reader,writer);
- mConnectionThreads.put(0, networkThread);
- networkThread.start();
- notifyOnConnect();
- }
+ // Since the server is not running, the mNetworkThreads set can only
+ // shrink from this point onward. We can just stop all of the running helper
+ // threads. In the worst case, one of the running threads will already have
+ // shut down. Since this is a CopyOnWriteList, we don't have to worry about
+ // concurrency issues while iterating over the set of threads.
+ for (ConnectionThread connectionThread : mConnectionThreads.values()) {
+ connectionThread.close();
+ }
+ for (SimpleServerObserver observer : mObservers) {
+ removeObserver(observer);
+ }
}
- }
-
- public void shutdown() {
- // Stop listening on the server socket to ensure that
- // beyond this point there are no incoming requests.
- mStopServer = true;
- try {
- mServer.close();
- } catch (IOException e) {
- Log.e("Failed to close server socket.", e);
- }
- // Since the server is not running, the mNetworkThreads set can only
- // shrink from this point onward. We can just stop all of the running helper
- // threads. In the worst case, one of the running threads will already have
- // shut down. Since this is a CopyOnWriteList, we don't have to worry about
- // concurrency issues while iterating over the set of threads.
- for (ConnectionThread connectionThread : mConnectionThreads.values()) {
- connectionThread.close();
- }
- for (SimpleServerObserver observer : mObservers) {
- removeObserver(observer);
- }
- }
}