Home | History | Annotate | Download | only in server
      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