• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.Log;
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 = "2";
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      */
ViewServer(WindowManagerService windowManager)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      */
ViewServer(WindowManagerService windowManager, int port)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      */
start()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      */
stop()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      */
isRunning()147     boolean isRunning() {
148         return mThread != null && mThread.isAlive();
149     }
150 
151     /**
152      * Main server loop.
153      */
run()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                         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     }
214 
writeValue(Socket client, String value)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