diff options
| author | The Android Open Source Project <initial-contribution@android.com> | 2009-01-09 17:51:23 -0800 |
|---|---|---|
| committer | The Android Open Source Project <initial-contribution@android.com> | 2009-01-09 17:51:23 -0800 |
| commit | e933faefa1e899dbd5bf371f499cc682aff46c83 (patch) | |
| tree | 8fb31ff5c9a41aec9912d0253be7ef0445e2f58a /WebKit/android/wds/client | |
| parent | 1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353 (diff) | |
| download | external_webkit-e933faefa1e899dbd5bf371f499cc682aff46c83.zip external_webkit-e933faefa1e899dbd5bf371f499cc682aff46c83.tar.gz external_webkit-e933faefa1e899dbd5bf371f499cc682aff46c83.tar.bz2 | |
auto import from //branches/cupcake/...@125939
Diffstat (limited to 'WebKit/android/wds/client')
| -rw-r--r-- | WebKit/android/wds/client/AdbConnection.cpp | 228 | ||||
| -rw-r--r-- | WebKit/android/wds/client/AdbConnection.h | 38 | ||||
| -rw-r--r-- | WebKit/android/wds/client/Android.mk | 32 | ||||
| -rw-r--r-- | WebKit/android/wds/client/ClientUtils.cpp | 26 | ||||
| -rw-r--r-- | WebKit/android/wds/client/ClientUtils.h | 29 | ||||
| -rw-r--r-- | WebKit/android/wds/client/Device.cpp | 22 | ||||
| -rw-r--r-- | WebKit/android/wds/client/Device.h | 53 | ||||
| -rw-r--r-- | WebKit/android/wds/client/DeviceList.h | 26 | ||||
| -rw-r--r-- | WebKit/android/wds/client/main.cpp | 164 |
9 files changed, 618 insertions, 0 deletions
diff --git a/WebKit/android/wds/client/AdbConnection.cpp b/WebKit/android/wds/client/AdbConnection.cpp new file mode 100644 index 0000000..79b49d7 --- /dev/null +++ b/WebKit/android/wds/client/AdbConnection.cpp @@ -0,0 +1,228 @@ +/* + * Copyright 2009, 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. + */ + +#define LOG_TAG "wdsclient" + +#include "AdbConnection.h" +#include "ClientUtils.h" +#include "Device.h" +#include <arpa/inet.h> +#include <errno.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <utils/Log.h> + +void AdbConnection::close() { + if (m_fd != -1) { + shutdown(m_fd, SHUT_RDWR); + ::close(m_fd); + m_fd = -1; + } +} + +// Default adb port +#define ADB_PORT 5037 + +bool AdbConnection::connect() { + // Some commands (host:devices for example) close the connection so we call + // connect after the response. + close(); + + m_fd = socket(PF_INET, SOCK_STREAM, 0); + if (m_fd < 0) { + log_errno("Failed to create socket for connecting to adb"); + return false; + } + + // Create the socket address struct + sockaddr_in adb; + createTcpSocket(adb, ADB_PORT); + + // Connect to adb + if (::connect(m_fd, (sockaddr*) &adb, sizeof(adb)) < 0) { + log_errno("Failed to connect to adb"); + return false; + } + + // Connected + return true; +} + +// Adb protocol stuff +#define MAX_COMMAND_LENGTH 1024 +#define PAYLOAD_LENGTH 4 +#define PAYLOAD_FORMAT "%04X" + +bool AdbConnection::sendRequest(const char* fmt, ...) const { + if (m_fd == -1) { + LOGE("Connection is closed"); + return false; + } + + // Build the command (service) + char buf[MAX_COMMAND_LENGTH]; + va_list args; + va_start(args, fmt); + int res = vsnprintf(buf, MAX_COMMAND_LENGTH, fmt, args); + va_end(args); + + LOGV("Sending command: %04X%.*s", res, res, buf); + + // Construct the payload length + char payloadLen[PAYLOAD_LENGTH + 1]; + snprintf(payloadLen, sizeof(payloadLen), PAYLOAD_FORMAT, res); + + // First, send the payload length + if (send(m_fd, payloadLen, PAYLOAD_LENGTH, 0) < 0) { + log_errno("Failure when sending payload"); + return false; + } + + // Send the actual command + if (send(m_fd, buf, res, 0) < 0) { + log_errno("Failure when sending command"); + return false; + } + + // Check for the OKAY from adb + return checkOkayResponse(); +} + +static void printFailureMessage(int fd) { + // Grab the payload length + char lenStr[PAYLOAD_LENGTH + 1]; + int payloadLen = recv(fd, lenStr, sizeof(lenStr) - 1, 0); + LOG_ASSERT(payloadLen == PAYLOAD_LENGTH, "Incorrect payload size"); + lenStr[PAYLOAD_LENGTH] = 0; + + // Parse the hex payload + payloadLen = strtol(lenStr, NULL, 16); + if (payloadLen < 0) + return; + + // Grab the message + char* msg = new char[payloadLen + 1]; // include null-terminator + int res = recv(fd, msg, payloadLen, 0); + if (res < 0) { + log_errno("Failure reading failure message from adb"); + return; + } else if (res != payloadLen) { + LOGE("Incorrect payload length %d - expected %d", res, payloadLen); + return; + } + msg[res] = 0; + + // Tell somebody about it + LOGE("Received failure from adb: %s", msg); + + // Cleanup + delete[] msg; +} + +#define ADB_RESPONSE_LENGTH 4 + +bool AdbConnection::checkOkayResponse() const { + LOG_ASSERT(m_fd != -1, "Connection has been closed!"); + + char buf[ADB_RESPONSE_LENGTH]; + int res = recv(m_fd, buf, sizeof(buf), 0); + if (res < 0) { + log_errno("Failure reading response from adb"); + return false; + } + + // Check for a response other than OKAY/FAIL + if ((res == ADB_RESPONSE_LENGTH) && (strncmp(buf, "OKAY", res) == 0)) { + LOGV("Command OKAY"); + return true; + } else if (strncmp(buf, "FAIL", ADB_RESPONSE_LENGTH) == 0) { + // Something happened, print out the reason for failure + printFailureMessage(m_fd); + return false; + } + LOGE("Incorrect response from adb - '%.*s'", res, buf); + return false; +} + +void AdbConnection::clearDevices() { + for (unsigned i = 0; i < m_devices.size(); i++) + delete m_devices.editItemAt(i); + m_devices.clear(); +} + +const DeviceList& AdbConnection::getDeviceList() { + // Clear the current device list + clearDevices(); + + if (m_fd == -1) { + LOGE("Connection is closed"); + return m_devices; + } + + // Try to send the device list request + if (!sendRequest("host:devices")) { + LOGE("Failed to get device list from adb"); + return m_devices; + } + + // Get the payload length + char lenStr[PAYLOAD_LENGTH + 1]; + int res = recv(m_fd, lenStr, sizeof(lenStr) - 1, 0); + if (res < 0) { + log_errno("Failure to read payload size of device list"); + return m_devices; + } + lenStr[PAYLOAD_LENGTH] = 0; + + // Parse the hex payload + int payloadLen = strtol(lenStr, NULL, 16); + if (payloadLen < 0) + return m_devices; + + // Grab the list of devices. The format is as follows: + // <serialno><tab><state><newline> + char* msg = new char[payloadLen + 1]; + res = recv(m_fd, msg, payloadLen, 0); + if (res < 0) { + log_errno("Failure reading the device list"); + return m_devices; + } else if (res != payloadLen) { + LOGE("Incorrect payload length %d - expected %d", res, payloadLen); + return m_devices; + } + msg[res] = 0; + + char serial[32]; + char state[32]; + int numRead; + char* ptr = msg; + while (sscanf(ptr, "%31s\t%31s\n%n", serial, state, &numRead) > 1) { + Device::DeviceType t = Device::DEVICE; + static const char emulator[] = "emulator-"; + if (strncmp(serial, emulator, sizeof(emulator) - 1) == 0) + t = Device::EMULATOR; + LOGV("Adding device %s (%s)", serial, state); + m_devices.add(new Device(serial, t, this)); + + // Reset for the next line + ptr += numRead; + } + // Cleanup + delete[] msg; + + return m_devices; +} diff --git a/WebKit/android/wds/client/AdbConnection.h b/WebKit/android/wds/client/AdbConnection.h new file mode 100644 index 0000000..0b5419f --- /dev/null +++ b/WebKit/android/wds/client/AdbConnection.h @@ -0,0 +1,38 @@ +/* + * Copyright 2009, 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. + */ + +#ifndef WDS_ADB_CONNECTION_H +#define WDS_ADB_CONNECTION_H + +#include "DeviceList.h" + +class AdbConnection { +public: + AdbConnection() : m_fd(-1) {} + ~AdbConnection() { clearDevices(); } + void close(); + bool connect(); + bool sendRequest(const char* fmt, ...) const; + const DeviceList& getDeviceList(); + +private: + bool checkOkayResponse() const; + void clearDevices(); + DeviceList m_devices; + int m_fd; +}; + +#endif diff --git a/WebKit/android/wds/client/Android.mk b/WebKit/android/wds/client/Android.mk new file mode 100644 index 0000000..5d07a31 --- /dev/null +++ b/WebKit/android/wds/client/Android.mk @@ -0,0 +1,32 @@ +## +## +## Copyright 2008, 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. +## + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + AdbConnection.cpp \ + ClientUtils.cpp \ + Device.cpp \ + main.cpp + +LOCAL_STATIC_LIBRARIES := liblog libutils libcutils + +LOCAL_MODULE:= wdsclient + +include $(BUILD_HOST_EXECUTABLE) + diff --git a/WebKit/android/wds/client/ClientUtils.cpp b/WebKit/android/wds/client/ClientUtils.cpp new file mode 100644 index 0000000..067775e --- /dev/null +++ b/WebKit/android/wds/client/ClientUtils.cpp @@ -0,0 +1,26 @@ +/* + * Copyright 2009, 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. + */ + +#include "ClientUtils.h" +#include <arpa/inet.h> +#include <string.h> + +void createTcpSocket(sockaddr_in& addr, short port) { + memset(&addr, 0, sizeof(sockaddr_in)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr); +} diff --git a/WebKit/android/wds/client/ClientUtils.h b/WebKit/android/wds/client/ClientUtils.h new file mode 100644 index 0000000..dc8b23f --- /dev/null +++ b/WebKit/android/wds/client/ClientUtils.h @@ -0,0 +1,29 @@ +/* + * Copyright 2009, 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. + */ + +#ifndef WDS_CLIENT_UTILS_H +#define WDS_CLIENT_UTILS_H + +#include <arpa/inet.h> + +// Callers need to include Log.h and errno.h to use this macro +#define log_errno(str) LOGE("%s: %s", str, strerror(errno)) + +// Fill in the sockaddr_in structure for binding to the localhost on the given +// port +void createTcpSocket(sockaddr_in& addr, short port); + +#endif diff --git a/WebKit/android/wds/client/Device.cpp b/WebKit/android/wds/client/Device.cpp new file mode 100644 index 0000000..03b4507 --- /dev/null +++ b/WebKit/android/wds/client/Device.cpp @@ -0,0 +1,22 @@ +/* + * Copyright 2009, 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. + */ + +#include "AdbConnection.h" +#include "Device.h" + +bool Device::sendRequest(const char* req) const { + return m_connection->sendRequest("host-serial:%s:%s", m_name, req); +} diff --git a/WebKit/android/wds/client/Device.h b/WebKit/android/wds/client/Device.h new file mode 100644 index 0000000..c6d77f3 --- /dev/null +++ b/WebKit/android/wds/client/Device.h @@ -0,0 +1,53 @@ +/* + * Copyright 2009, 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. + */ + +#ifndef WDS_DEVICE_H +#define WDS_DEVICE_H + +#include <stdlib.h> + +class AdbConnection; + +class Device { +public: + // Type of device. + // TODO: Add simulator support + enum DeviceType { + NONE = -1, + EMULATOR, + DEVICE + }; + + // Takes ownership of name + Device(char* name, DeviceType type, const AdbConnection* conn) + : m_connection(conn) + , m_name(strdup(name)) + , m_type(type) {} + ~Device() { free(m_name); } + + const char* name() const { return m_name; } + DeviceType type() const { return m_type; } + + // Send a request to this device. + bool sendRequest(const char* req) const; + +private: + const AdbConnection* m_connection; + char* m_name; + DeviceType m_type; +}; + +#endif diff --git a/WebKit/android/wds/client/DeviceList.h b/WebKit/android/wds/client/DeviceList.h new file mode 100644 index 0000000..9139238 --- /dev/null +++ b/WebKit/android/wds/client/DeviceList.h @@ -0,0 +1,26 @@ +/* + * Copyright 2009, 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. + */ + +#ifndef WDS_DEVICE_LIST_H +#define WDS_DEVICE_LIST_H + +#include <utils/Vector.h> + +class Device; + +typedef android::Vector<Device*> DeviceList; + +#endif diff --git a/WebKit/android/wds/client/main.cpp b/WebKit/android/wds/client/main.cpp new file mode 100644 index 0000000..5899b16 --- /dev/null +++ b/WebKit/android/wds/client/main.cpp @@ -0,0 +1,164 @@ +/* + * Copyright 2008, 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. + */ + +#define LOG_TAG "wdsclient" + +#include "AdbConnection.h" +#include "ClientUtils.h" +#include "Device.h" +#include <arpa/inet.h> +#include <errno.h> +#include <getopt.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <utils/Log.h> + +#define DEFAULT_WDS_PORT 9999 +#define STR(x) #x +#define XSTR(x) STR(x) +#define PORT_STR XSTR(DEFAULT_WDS_PORT) + +int wds_open() { + // Create the structure for connecting to the forwarded 9999 port + sockaddr_in addr; + createTcpSocket(addr, DEFAULT_WDS_PORT); + + // Create our socket + int fd = socket(PF_INET, SOCK_STREAM, 0); + if (fd < 0) { + log_errno("Failed to create file descriptor"); + return -1; + } + // Connect to the remote wds server thread + if (connect(fd, (sockaddr*)&addr, sizeof(addr)) < 0) { + log_errno("Failed to connect to remote debug server"); + return -1; + } + return fd; +} + +// Clean up the file descriptor and connections +void wds_close(int fd) { + if (fd != -1) { + shutdown(fd, SHUT_RDWR); + close(fd); + } +} + +int main(int argc, char** argv) { + + Device::DeviceType type = Device::NONE; + + if (argc <= 1) { + LOGE("wdsclient takes at least 1 argument"); + return 1; + } else { + // Parse the options, look for -e or -d to choose a device. + while (true) { + int c = getopt(argc, argv, "ed"); + if (c == -1) + break; + switch (c) { + case 'e': + type = Device::EMULATOR; + break; + case 'd': + type = Device::DEVICE; + break; + default: + break; + } + } + if (optind == argc) { + LOGE("No command specified"); + return 1; + } + } + + // Do the initial connection. + AdbConnection conn; + conn.connect(); + + const DeviceList& devices = conn.getDeviceList(); + // host:devices closes the connection, reconnect + conn.connect(); + + // No device specified and more than one connected, bail + if (type == Device::NONE && devices.size() > 1) { + LOGE("More than one device/emulator, please specify with -e or -d"); + return 1; + } else if (devices.size() == 0) { + LOGE("No devices connected"); + return 1; + } + + // Find the correct device + const Device* device = NULL; + if (type == Device::NONE) + device = devices[0]; // grab the only one + else { + // Search for a matching device type + for (unsigned i = 0; i < devices.size(); i++) { + if (devices[i]->type() == type) { + device = devices[i]; + break; + } + } + } + + if (!device) { + LOGE("No device found!"); + return 1; + } + + // Forward tcp:9999 + if (!device->sendRequest("forward:tcp:" PORT_STR ";tcp:" PORT_STR)) { + LOGE("Failed to send forwarding request"); + return 1; + } + + LOGV("Connecting to localhost port " PORT_STR); + + const char* command = argv[optind]; + int commandLen = strlen(command); +#define WDS_COMMAND_LENGTH 4 + if (commandLen != WDS_COMMAND_LENGTH) { + LOGE("Commands must be 4 characters '%s'", command); + return 1; + } + + // Open the wds connection + int wdsFd = wds_open(); + if (wdsFd == -1) + return 1; + + // Send the command specified + send(wdsFd, command, WDS_COMMAND_LENGTH, 0); // commands are 4 bytes + + // Read and display the response + char response[256]; + int res = 0; + while ((res = recv(wdsFd, response, sizeof(response), 0)) > 0) + printf("%.*s", res, response); + printf("\n\n"); + + // Shutdown + wds_close(wdsFd); + + return 0; +} |
