blob: 2d06cf92365151708f72779a6b5772312e79a3b0 [file] [log] [blame]
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.tradefed.command.remote;
import com.android.ddmlib.Log;
import org.json.JSONException;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.List;
/**
* Class for sending remote commands to another TF process.
* <p/>
* Currently uses JSON-encoded data sent via sockets.
*/
public class RemoteClient implements IRemoteClient {
// choose an arbitrary default port that according to the interweb is not used by another
// popular program
public static final int DEFAULT_PORT = 30103;
private static final String TAG = RemoteClient.class.getSimpleName();
private final Socket mSocket;
private final PrintWriter mWriter;
private final BufferedReader mReader;
/**
* Initialize the {@RemoteClient}, and instruct it to connect to the given port
* on localhost.
*
* @param port the tcp/ip port number
* @throws IOException
* @throws UnknownHostException
*/
private RemoteClient(int port) throws UnknownHostException, IOException {
this(InetAddress.getLocalHost().getHostName(), port);
}
/**
* Initialize the {@RemoteClient}, and instruct it to connect to the given hostname and port.
*
* @param hostName to connect to
* @param port the tcp/ip port number
* @throws IOException
* @throws UnknownHostException
*/
private RemoteClient(String hostName, int port) throws UnknownHostException, IOException {
mSocket = new Socket(hostName, port);
mWriter = new PrintWriter(mSocket.getOutputStream(), true);
mReader = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));
}
/**
* Send the given operation to the remote TF.
*
* @param op the {@link RemoteOperation} to send
* @throws RemoteException if failed to perform operation
*/
private synchronized <T> T sendOperation(RemoteOperation<T> op) throws RemoteException {
try {
mWriter.println(op.pack());
String response = mReader.readLine();
if (response == null) {
throw new RemoteException("no response from remote manager");
}
return op.unpackResponseFromString(response);
} catch (IOException e) {
throw new RemoteException(e.getMessage(), e);
} catch (JSONException e) {
throw new RemoteException(e.getMessage(), e);
}
}
/**
* Helper method to create a {@link RemoteClient} connected to given port
*
* @param port the tcp/ip port
* @return the {@link RemoteClient}
* @throws RemoteException if failed to connect
*/
public static IRemoteClient connect(int port) throws RemoteException {
try {
return new RemoteClient(port);
} catch (IOException e) {
throw new RemoteException(e);
}
}
/**
* Helper method to create a {@link RemoteClient} connected to given host and port
*
* @param hostname the host name
* @param port the tcp/ip port
* @return the {@link RemoteClient}
* @throws RemoteException if failed to connect
*/
public static IRemoteClient connect(String hostname, int port) throws RemoteException {
try {
return new RemoteClient(hostname, port);
} catch (IOException e) {
throw new RemoteException(e);
}
}
/**
* Helper method to create a {@link RemoteClient} connected to default port
*
* @return the {@link RemoteClient}
* @throws RemoteException if failed to connect
*/
public static IRemoteClient connect() throws RemoteException {
return connect(DEFAULT_PORT);
}
/**
* {@inheritDoc}
*/
@Override
public void sendAllocateDevice(String serial) throws RemoteException {
sendOperation(new AllocateDeviceOp(serial));
}
/**
* {@inheritDoc}
*/
@Override
public void sendFreeDevice(String serial) throws RemoteException {
sendOperation(new FreeDeviceOp(serial));
}
/**
* {@inheritDoc}
*/
@Override
public void sendAddCommand(long totalTime, String... commandArgs) throws RemoteException {
sendOperation(new AddCommandOp(totalTime, commandArgs));
}
/**
* {@inheritDoc}
*/
@Override
public void sendClose() throws RemoteException {
sendOperation(new CloseOp());
}
/**
* {@inheritDoc}
*/
@Override
public void sendHandoverClose(int port) throws RemoteException {
sendOperation(new HandoverCloseOp(port));
}
/**
* {@inheritDoc}
*/
@Override
public List<DeviceDescriptor> sendListDevices() throws RemoteException {
return sendOperation(new ListDevicesOp());
}
/**
* {@inheritDoc}
*/
@Override
public void sendExecCommand(String serial, String[] commandArgs) throws RemoteException {
sendOperation(new ExecCommandOp(serial, commandArgs));
}
/**
* {@inheritDoc}
*/
@Override
public void sendGetLastCommandResult(String serial, ICommandResultHandler handler)
throws RemoteException {
CommandResult r = sendOperation(new GetLastCommandResultOp(serial));
switch (r.getStatus()) {
case EXECUTING:
handler.stillRunning();
break;
case INVOCATION_ERROR:
handler.failure(r.getInvocationErrorDetails(), r.getFreeDeviceState(),
r.getRunMetrics());
break;
case INVOCATION_SUCCESS:
handler.success(r.getRunMetrics());
break;
case NO_ACTIVE_COMMAND:
handler.noActiveCommand();
break;
case NOT_ALLOCATED:
handler.notAllocated();
break;
default:
throw new RemoteException("unrecognized status " + r.getStatus().name());
}
}
/**
* {@inheritDoc}
*/
@Override
public synchronized void close() {
if (mSocket != null) {
try {
mSocket.close();
} catch (IOException e) {
Log.w(TAG, String.format("exception closing socket: %s", e.toString()));
}
}
if (mWriter != null) {
mWriter.close();
}
}
}