You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
154 lines
5.0 KiB
154 lines
5.0 KiB
/* |
|
* Copyright (C) 2015 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 "sysdeps.h" |
|
|
|
#include <stdio.h> |
|
|
|
#include <android-base/file.h> |
|
#include <android-base/logging.h> |
|
#include <android-base/strings.h> |
|
#include <cutils/sockets.h> |
|
|
|
#include "adb.h" |
|
#include "adb_client.h" |
|
#include "adb_io.h" |
|
#include "adb_utils.h" |
|
|
|
// Return the console authentication command for the emulator, if needed |
|
static std::string adb_construct_auth_command() { |
|
static const char auth_token_filename[] = ".emulator_console_auth_token"; |
|
|
|
std::string auth_token_path = adb_get_homedir_path(); |
|
auth_token_path += OS_PATH_SEPARATOR; |
|
auth_token_path += auth_token_filename; |
|
|
|
// read the token |
|
std::string token; |
|
if (!android::base::ReadFileToString(auth_token_path, &token) |
|
|| token.empty()) { |
|
// we either can't read the file, or it doesn't exist, or it's empty - |
|
// either way we won't add any authentication command. |
|
return {}; |
|
} |
|
|
|
// now construct and return the actual command: "auth <token>\n" |
|
std::string command = "auth "; |
|
command += token; |
|
command += '\n'; |
|
return command; |
|
} |
|
|
|
// Return the console port of the currently connected emulator (if any) or -1 if |
|
// there is no emulator, and -2 if there is more than one. |
|
static int adb_get_emulator_console_port(const char* serial) { |
|
if (serial) { |
|
// The user specified a serial number; is it an emulator? |
|
int port; |
|
return (sscanf(serial, "emulator-%d", &port) == 1) ? port : -1; |
|
} |
|
|
|
// No specific device was given, so get the list of connected devices and |
|
// search for emulators. If there's one, we'll take it. If there are more |
|
// than one, that's an error. |
|
std::string devices; |
|
std::string error; |
|
if (!adb_query("host:devices", &devices, &error)) { |
|
fprintf(stderr, "error: no emulator connected: %s\n", error.c_str()); |
|
return -1; |
|
} |
|
|
|
int port; |
|
size_t emulator_count = 0; |
|
for (const auto& device : android::base::Split(devices, "\n")) { |
|
if (sscanf(device.c_str(), "emulator-%d", &port) == 1) { |
|
if (++emulator_count > 1) { |
|
fprintf( |
|
stderr, "error: more than one emulator detected; use -s\n"); |
|
return -1; |
|
} |
|
} |
|
} |
|
|
|
if (emulator_count == 0) { |
|
fprintf(stderr, "error: no emulator detected\n"); |
|
return -1; |
|
} |
|
|
|
return port; |
|
} |
|
|
|
static int connect_to_console(const char* serial) { |
|
int port = adb_get_emulator_console_port(serial); |
|
if (port == -1) { |
|
return -1; |
|
} |
|
|
|
std::string error; |
|
int fd = network_loopback_client(port, SOCK_STREAM, &error); |
|
if (fd == -1) { |
|
fprintf(stderr, "error: could not connect to TCP port %d: %s\n", port, |
|
error.c_str()); |
|
return -1; |
|
} |
|
return fd; |
|
} |
|
|
|
int adb_send_emulator_command(int argc, const char** argv, const char* serial) { |
|
int fd = connect_to_console(serial); |
|
if (fd == -1) { |
|
return 1; |
|
} |
|
|
|
std::string commands = adb_construct_auth_command(); |
|
|
|
for (int i = 1; i < argc; i++) { |
|
commands.append(argv[i]); |
|
commands.push_back(i == argc - 1 ? '\n' : ' '); |
|
} |
|
|
|
commands.append("quit\n"); |
|
|
|
if (!WriteFdExactly(fd, commands)) { |
|
fprintf(stderr, "error: cannot write to emulator: %s\n", |
|
strerror(errno)); |
|
adb_close(fd); |
|
return 1; |
|
} |
|
|
|
// Drain output that the emulator console has sent us to prevent a problem |
|
// on Windows where if adb closes the socket without reading all the data, |
|
// the emulator's next call to recv() will have an ECONNABORTED error, |
|
// preventing the emulator from reading the command that adb has sent. |
|
// https://code.google.com/p/android/issues/detail?id=21021 |
|
int result; |
|
do { |
|
char buf[BUFSIZ]; |
|
result = adb_read(fd, buf, sizeof(buf)); |
|
// Keep reading until zero bytes (orderly/graceful shutdown) or an |
|
// error. If 'adb emu kill' is executed, the emulator calls exit() with |
|
// the socket open (and shutdown(SD_SEND) was not called), which causes |
|
// Windows to send a TCP RST segment which causes adb to get ECONNRESET. |
|
// Any other emu command is followed by the quit command that we |
|
// appended above, and that causes the emulator to close the socket |
|
// which should cause zero bytes (orderly/graceful shutdown) to be |
|
// returned. |
|
} while (result > 0); |
|
|
|
adb_close(fd); |
|
|
|
return 0; |
|
}
|
|
|