blob: e9a195161491f94a92599f5be641052099c28c57 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
17package com.android.server;
18
19import android.util.Log;
20
21import java.net.ServerSocket;
22import java.net.Socket;
23import java.net.InetAddress;
24import java.io.IOException;
25import java.io.BufferedReader;
26import java.io.InputStreamReader;
The Android Open Source Project10592532009-03-18 17:39:46 -070027import java.io.OutputStream;
28import java.io.BufferedWriter;
29import java.io.OutputStreamWriter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030
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 */
38class 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
The Android Open Source Project10592532009-03-18 17:39:46 -070047 private static final String VALUE_PROTOCOL_VERSION = "2";
Romain Guy089e36f2009-12-14 18:54:33 -080048 private static final String VALUE_SERVER_VERSION = "3";
The Android Open Source Project10592532009-03-18 17:39:46 -070049
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050 // Protocol commands
The Android Open Source Project10592532009-03-18 17:39:46 -070051 // 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";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055 // 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 Log.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;
The Android Open Source Project10592532009-03-18 17:39:46 -0700182 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)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800187 result = mWindowManager.viewServerListWindows(client);
188 } else {
189 result = mWindowManager.viewServerWindowCommand(client,
190 command, parameters);
191 }
192
193 if (!result) {
194 Log.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 Log.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 }
The Android Open Source Project10592532009-03-18 17:39:46 -0700214
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 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800238}