1 /* 2 * Copyright (C) 2007 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 17 package com.android.server; 18 19 import android.util.Slog; 20 21 import java.net.ServerSocket; 22 import java.net.Socket; 23 import java.net.InetAddress; 24 import java.io.IOException; 25 import java.io.BufferedReader; 26 import java.io.InputStreamReader; 27 import java.io.OutputStream; 28 import java.io.BufferedWriter; 29 import java.io.OutputStreamWriter; 30 31 /** 32 * The ViewServer is local socket server that can be used to communicate with the 33 * views of the opened windows. Communication with the views is ensured by the 34 * {@link com.android.server.WindowManagerService} and is a cross-process operation. 35 * 36 * {@hide} 37 */ 38 class ViewServer implements Runnable { 39 /** 40 * The default port used to start view servers. 41 */ 42 public static final int VIEW_SERVER_DEFAULT_PORT = 4939; 43 44 // Debug facility 45 private static final String LOG_TAG = "ViewServer"; 46 47 private static final String VALUE_PROTOCOL_VERSION = "2"; 48 private static final String VALUE_SERVER_VERSION = "3"; 49 50 // Protocol commands 51 // Returns the protocol version 52 private static final String COMMAND_PROTOCOL_VERSION = "PROTOCOL"; 53 // Returns the server version 54 private static final String COMMAND_SERVER_VERSION = "SERVER"; 55 // Lists all of the available windows in the system 56 private static final String COMMAND_WINDOW_MANAGER_LIST = "LIST"; 57 58 private ServerSocket mServer; 59 private Thread mThread; 60 61 private final WindowManagerService mWindowManager; 62 private final int mPort; 63 64 /** 65 * Creates a new ViewServer associated with the specified window manager. 66 * The server uses the default port {@link #VIEW_SERVER_DEFAULT_PORT}. The server 67 * is not started by default. 68 * 69 * @param windowManager The window manager used to communicate with the views. 70 * 71 * @see #start() 72 */ 73 ViewServer(WindowManagerService windowManager) { 74 this(windowManager, VIEW_SERVER_DEFAULT_PORT); 75 } 76 77 /** 78 * Creates a new ViewServer associated with the specified window manager on the 79 * specified local port. The server is not started by default. 80 * 81 * @param windowManager The window manager used to communicate with the views. 82 * @param port The port for the server to listen to. 83 * 84 * @see #start() 85 */ 86 ViewServer(WindowManagerService windowManager, int port) { 87 mWindowManager = windowManager; 88 mPort = port; 89 } 90 91 /** 92 * Starts the server. 93 * 94 * @return True if the server was successfully created, or false if it already exists. 95 * @throws IOException If the server cannot be created. 96 * 97 * @see #stop() 98 * @see #isRunning() 99 * @see WindowManagerService#startViewServer(int) 100 */ 101 boolean start() throws IOException { 102 if (mThread != null) { 103 return false; 104 } 105 106 mServer = new ServerSocket(mPort, 1, InetAddress.getLocalHost()); 107 mThread = new Thread(this, "Remote View Server [port=" + mPort + "]"); 108 mThread.start(); 109 110 return true; 111 } 112 113 /** 114 * Stops the server. 115 * 116 * @return True if the server was stopped, false if an error occured or if the 117 * server wasn't started. 118 * 119 * @see #start() 120 * @see #isRunning() 121 * @see WindowManagerService#stopViewServer() 122 */ 123 boolean stop() { 124 if (mThread != null) { 125 mThread.interrupt(); 126 mThread = null; 127 try { 128 mServer.close(); 129 mServer = null; 130 return true; 131 } catch (IOException e) { 132 Slog.w(LOG_TAG, "Could not close the view server"); 133 } 134 } 135 return false; 136 } 137 138 /** 139 * Indicates whether the server is currently running. 140 * 141 * @return True if the server is running, false otherwise. 142 * 143 * @see #start() 144 * @see #stop() 145 * @see WindowManagerService#isViewServerRunning() 146 */ 147 boolean isRunning() { 148 return mThread != null && mThread.isAlive(); 149 } 150 151 /** 152 * Main server loop. 153 */ 154 public void run() { 155 final ServerSocket server = mServer; 156 157 while (Thread.currentThread() == mThread) { 158 Socket client = null; 159 // Any uncaught exception will crash the system process 160 try { 161 client = server.accept(); 162 163 BufferedReader in = null; 164 try { 165 in = new BufferedReader(new InputStreamReader(client.getInputStream()), 1024); 166 167 final String request = in.readLine(); 168 169 String command; 170 String parameters; 171 172 int index = request.indexOf(' '); 173 if (index == -1) { 174 command = request; 175 parameters = ""; 176 } else { 177 command = request.substring(0, index); 178 parameters = request.substring(index + 1); 179 } 180 181 boolean result; 182 if (COMMAND_PROTOCOL_VERSION.equalsIgnoreCase(command)) { 183 result = writeValue(client, VALUE_PROTOCOL_VERSION); 184 } else if (COMMAND_SERVER_VERSION.equalsIgnoreCase(command)) { 185 result = writeValue(client, VALUE_SERVER_VERSION); 186 } else if (COMMAND_WINDOW_MANAGER_LIST.equalsIgnoreCase(command)) { 187 result = mWindowManager.viewServerListWindows(client); 188 } else { 189 result = mWindowManager.viewServerWindowCommand(client, 190 command, parameters); 191 } 192 193 if (!result) { 194 Slog.w(LOG_TAG, "An error occured with the command: " + command); 195 } 196 } finally { 197 if (in != null) { 198 in.close(); 199 } 200 } 201 } catch (Exception e) { 202 Slog.w(LOG_TAG, "Connection error: ", e); 203 } finally { 204 if (client != null) { 205 try { 206 client.close(); 207 } catch (IOException e) { 208 e.printStackTrace(); 209 } 210 } 211 } 212 } 213 } 214 215 private static boolean writeValue(Socket client, String value) { 216 boolean result; 217 BufferedWriter out = null; 218 try { 219 OutputStream clientStream = client.getOutputStream(); 220 out = new BufferedWriter(new OutputStreamWriter(clientStream), 8 * 1024); 221 out.write(value); 222 out.write("\n"); 223 out.flush(); 224 result = true; 225 } catch (Exception e) { 226 result = false; 227 } finally { 228 if (out != null) { 229 try { 230 out.close(); 231 } catch (IOException e) { 232 result = false; 233 } 234 } 235 } 236 return result; 237 } 238 } 239