Home | History | Annotate | Download | only in remote
      1 /*
      2  * Copyright (C) 2011 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 package com.android.tradefed.command.remote;
     17 
     18 import com.android.ddmlib.Log;
     19 
     20 import org.json.JSONException;
     21 
     22 import java.io.BufferedReader;
     23 import java.io.IOException;
     24 import java.io.InputStreamReader;
     25 import java.io.PrintWriter;
     26 import java.net.InetAddress;
     27 import java.net.Socket;
     28 import java.net.UnknownHostException;
     29 import java.util.List;
     30 
     31 /**
     32  * Class for sending remote commands to another TF process.
     33  * <p/>
     34  * Currently uses JSON-encoded data sent via sockets.
     35  */
     36 public class RemoteClient implements IRemoteClient {
     37 
     38     // choose an arbitrary default port that according to the interweb is not used by another
     39     // popular program
     40     public static final int DEFAULT_PORT = 30103;
     41 
     42     private static final String TAG = RemoteClient.class.getSimpleName();
     43     private final Socket mSocket;
     44     private final PrintWriter mWriter;
     45     private final BufferedReader mReader;
     46 
     47     /**
     48      * Initialize the {@RemoteClient}, and instruct it to connect to the given port
     49      * on localhost.
     50      *
     51      * @param port the tcp/ip port number
     52      * @throws IOException
     53      * @throws UnknownHostException
     54      */
     55     private RemoteClient(int port) throws UnknownHostException, IOException {
     56         this(InetAddress.getLocalHost().getHostName(), port);
     57     }
     58 
     59     /**
     60      * Initialize the {@RemoteClient}, and instruct it to connect to the given hostname and port.
     61      *
     62      * @param hostName to connect to
     63      * @param port the tcp/ip port number
     64      * @throws IOException
     65      * @throws UnknownHostException
     66      */
     67     private RemoteClient(String hostName, int port) throws UnknownHostException, IOException {
     68         mSocket = new Socket(hostName, port);
     69         mWriter = new PrintWriter(mSocket.getOutputStream(), true);
     70         mReader = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));
     71     }
     72 
     73     /**
     74      * Send the given operation to the remote TF.
     75      *
     76      * @param op the {@link RemoteOperation} to send
     77      * @throws RemoteException if failed to perform operation
     78      */
     79     private synchronized <T> T sendOperation(RemoteOperation<T> op) throws RemoteException {
     80        try {
     81            Log.d(TAG, String.format("Sending remote op %s", op.getType()));
     82            mWriter.println(op.pack());
     83            String response = mReader.readLine();
     84            if (response == null) {
     85                throw new RemoteException("no response from remote manager");
     86            }
     87            return op.unpackResponseFromString(response);
     88        } catch (IOException e) {
     89            throw new RemoteException(e.getMessage(), e);
     90        } catch (JSONException e) {
     91            throw new RemoteException(e.getMessage(), e);
     92        }
     93     }
     94 
     95     /**
     96      * Helper method to create a {@link RemoteClient} connected to given port
     97      *
     98      * @param port the tcp/ip port
     99      * @return the {@link RemoteClient}
    100      * @throws RemoteException if failed to connect
    101      */
    102     public static IRemoteClient connect(int port) throws RemoteException {
    103         try {
    104             return new RemoteClient(port);
    105         } catch (IOException e) {
    106             throw new RemoteException(e);
    107         }
    108     }
    109 
    110     /**
    111      * Helper method to create a {@link RemoteClient} connected to given host and port
    112      *
    113      * @param hostname the host name
    114      * @param port the tcp/ip port
    115      * @return the {@link RemoteClient}
    116      * @throws RemoteException if failed to connect
    117      */
    118     public static IRemoteClient connect(String hostname, int port) throws RemoteException {
    119         try {
    120             return new RemoteClient(hostname, port);
    121         } catch (IOException e) {
    122             throw new RemoteException(e);
    123         }
    124     }
    125 
    126     /**
    127      * Helper method to create a {@link RemoteClient} connected to default port
    128      *
    129      * @return the {@link RemoteClient}
    130      * @throws RemoteException if failed to connect
    131      */
    132     public static IRemoteClient connect() throws RemoteException {
    133         return connect(DEFAULT_PORT);
    134     }
    135 
    136     /**
    137      * {@inheritDoc}
    138      */
    139     @Override
    140     public void sendAllocateDevice(String serial) throws RemoteException {
    141         sendOperation(new AllocateDeviceOp(serial));
    142     }
    143 
    144     /**
    145      * {@inheritDoc}
    146      */
    147     @Override
    148     public void sendFreeDevice(String serial) throws RemoteException {
    149         sendOperation(new FreeDeviceOp(serial));
    150     }
    151 
    152     /**
    153      * {@inheritDoc}
    154      */
    155     @Override
    156     public void sendAddCommand(long totalTime, String... commandArgs) throws RemoteException {
    157         sendOperation(new AddCommandOp(totalTime, commandArgs));
    158     }
    159 
    160     /**
    161      * {@inheritDoc}
    162      */
    163     @Override
    164     public void sendAddCommandFile(String commandFile, List<String> extraArgs)
    165             throws RemoteException {
    166         sendOperation(new AddCommandFileOp(commandFile, extraArgs));
    167     }
    168 
    169     /**
    170      * {@inheritDoc}
    171      */
    172     @Deprecated
    173     @Override
    174     public void sendClose() throws RemoteException {
    175         sendOperation(new CloseOp());
    176     }
    177 
    178     /**
    179      * {@inheritDoc}
    180      */
    181     @Override
    182     public void sendStartHandover(int port) throws RemoteException {
    183         sendOperation(new StartHandoverOp(port));
    184     }
    185 
    186     /**
    187      * {@inheritDoc}
    188      */
    189     @Override
    190     public void sendHandoverInitComplete() throws RemoteException {
    191         sendOperation(new HandoverInitCompleteOp());
    192     }
    193 
    194     /**
    195      * {@inheritDoc}
    196      */
    197     @Override
    198     public void sendHandoverComplete() throws RemoteException {
    199         sendOperation(new HandoverCompleteOp());
    200     }
    201 
    202     /**
    203      * {@inheritDoc}
    204      */
    205     @Override
    206     public List<DeviceDescriptor> sendListDevices() throws RemoteException {
    207         return sendOperation(new ListDevicesOp());
    208     }
    209 
    210     /**
    211      * {@inheritDoc}
    212      */
    213     @Override
    214     public void sendExecCommand(String serial, String[] commandArgs) throws RemoteException {
    215         sendOperation(new ExecCommandOp(serial, commandArgs));
    216     }
    217 
    218     /**
    219      * {@inheritDoc}
    220      */
    221     @Override
    222     public void sendGetLastCommandResult(String serial, ICommandResultHandler handler)
    223             throws RemoteException {
    224         CommandResult r = sendOperation(new GetLastCommandResultOp(serial));
    225         switch (r.getStatus()) {
    226             case EXECUTING:
    227                 handler.stillRunning();
    228                 break;
    229             case INVOCATION_ERROR:
    230                 handler.failure(r.getInvocationErrorDetails(), r.getFreeDeviceState(),
    231                         r.getRunMetrics());
    232                 break;
    233             case INVOCATION_SUCCESS:
    234                 handler.success(r.getRunMetrics());
    235                 break;
    236             case NO_ACTIVE_COMMAND:
    237                 handler.noActiveCommand();
    238                 break;
    239             case NOT_ALLOCATED:
    240                 handler.notAllocated();
    241                 break;
    242             default:
    243                 throw new RemoteException("unrecognized status " + r.getStatus().name());
    244         }
    245     }
    246 
    247     /**
    248      * {@inheritDoc}
    249      */
    250     @Override
    251     public synchronized void close() {
    252         if (mSocket != null) {
    253             try {
    254                 mSocket.close();
    255             } catch (IOException e) {
    256                 Log.w(TAG, String.format("exception closing socket: %s", e.toString()));
    257             }
    258         }
    259         if (mWriter != null) {
    260             mWriter.close();
    261         }
    262     }
    263 }
    264