123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320 |
- // Copyright 2017 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "tools/android/forwarder2/host_controllers_manager.h"
- #include <memory>
- #include "base/bind.h"
- #include "base/logging.h"
- #include "base/process/launch.h"
- #include "base/strings/string_split.h"
- #include "base/strings/string_util.h"
- #include "base/strings/stringprintf.h"
- #include "tools/android/forwarder2/util.h"
- namespace forwarder2 {
- HostControllersManager::HostControllersManager(
- base::RepeatingCallback<int()> exit_notifier_fd_callback)
- : controllers_(new HostControllerMap()),
- exit_notifier_fd_callback_(exit_notifier_fd_callback),
- has_failed_(false),
- weak_ptr_factory_(this) {}
- HostControllersManager::~HostControllersManager() {
- if (!thread_.get())
- return;
- // Delete the controllers on the thread they were created on.
- thread_->task_runner()->DeleteSoon(FROM_HERE, controllers_.release());
- }
- void HostControllersManager::HandleRequest(
- const std::string& adb_path,
- const std::string& device_serial,
- int command,
- int device_port,
- int host_port,
- std::unique_ptr<Socket> client_socket) {
- // Lazy initialize so that the CLI process doesn't get this thread created.
- InitOnce();
- thread_->task_runner()->PostTask(
- FROM_HERE,
- base::BindOnce(&HostControllersManager::HandleRequestOnInternalThread,
- base::Unretained(this), adb_path, device_serial, command,
- device_port, host_port, std::move(client_socket)));
- }
- // static
- std::string HostControllersManager::MakeHostControllerMapKey(int adb_port,
- int device_port) {
- return base::StringPrintf("%d:%d", adb_port, device_port);
- }
- void HostControllersManager::InitOnce() {
- if (thread_.get())
- return;
- at_exit_manager_ = std::make_unique<base::AtExitManager>();
- thread_ = std::make_unique<base::Thread>("HostControllersManagerThread");
- thread_->Start();
- }
- // static
- void HostControllersManager::DeleteHostController(
- const base::WeakPtr<HostControllersManager>& manager_ptr,
- std::unique_ptr<HostController> host_controller) {
- HostController* const controller = host_controller.release();
- HostControllersManager* const manager = manager_ptr.get();
- if (!manager) {
- // Note that |controller| is not leaked in this case since the host
- // controllers manager owns the controllers. If the manager was deleted
- // then all the controllers (including |controller|) were also deleted.
- return;
- }
- DCHECK(manager->thread_->task_runner()->RunsTasksInCurrentSequence());
- // Note that this will delete |controller| which is owned by the map.
- DeleteRefCountedValueInMap(
- MakeHostControllerMapKey(controller->adb_port(),
- controller->device_port()),
- manager->controllers_.get());
- }
- void HostControllersManager::Map(const std::string& adb_path,
- const std::string& device_serial,
- int adb_port,
- int device_port,
- int host_port,
- Socket* client_socket) {
- if (host_port < 0) {
- SendMessage("ERROR: missing host port\n", client_socket);
- return;
- }
- const bool use_dynamic_port_allocation = device_port == 0;
- if (!use_dynamic_port_allocation) {
- const std::string controller_key =
- MakeHostControllerMapKey(adb_port, device_port);
- if (controllers_->find(controller_key) != controllers_->end()) {
- LOG(INFO) << "Already forwarding device port " << device_port
- << " to host port " << host_port;
- SendMessage(base::StringPrintf("%d:%d", device_port, host_port),
- client_socket);
- return;
- }
- }
- // Create a new host controller.
- std::unique_ptr<HostController> host_controller(HostController::Create(
- device_serial, device_port, host_port, adb_port,
- exit_notifier_fd_callback_.Run(),
- base::BindOnce(&HostControllersManager::DeleteHostController,
- weak_ptr_factory_.GetWeakPtr())));
- if (!host_controller.get()) {
- has_failed_ = true;
- SendMessage("ERROR: Connection to device failed.\n", client_socket);
- LogExistingControllers(client_socket);
- return;
- }
- // Get the current allocated port.
- device_port = host_controller->device_port();
- LOG(INFO) << "Forwarding device port " << device_port << " to host port "
- << host_port;
- const std::string msg = base::StringPrintf("%d:%d", device_port, host_port);
- if (!SendMessage(msg, client_socket))
- return;
- host_controller->Start();
- controllers_->emplace(MakeHostControllerMapKey(adb_port, device_port),
- std::move(host_controller));
- }
- void HostControllersManager::Unmap(const std::string& adb_path,
- const std::string& device_serial,
- int adb_port,
- int device_port,
- Socket* client_socket) {
- // Remove the previously created host controller.
- const std::string controller_key =
- MakeHostControllerMapKey(adb_port, device_port);
- const bool controller_did_exist =
- DeleteRefCountedValueInMap(controller_key, controllers_.get());
- if (!controller_did_exist) {
- SendMessage("ERROR: could not unmap port.\n", client_socket);
- LogExistingControllers(client_socket);
- } else {
- SendMessage("OK", client_socket);
- }
- RemoveAdbPortForDeviceIfNeeded(adb_path, device_serial);
- }
- void HostControllersManager::UnmapAll(const std::string& adb_path,
- const std::string& device_serial,
- int adb_port,
- Socket* client_socket) {
- const std::string adb_port_str = base::StringPrintf("%d", adb_port);
- for (auto controller_key = controllers_->begin();
- controller_key != controllers_->end(); ++controller_key) {
- std::vector<std::string> pieces =
- base::SplitString(controller_key->first, ":", base::KEEP_WHITESPACE,
- base::SPLIT_WANT_ALL);
- if (pieces.size() == 2) {
- if (pieces[0] == adb_port_str) {
- DeleteRefCountedValueInMapFromIterator(controller_key,
- controllers_.get());
- }
- } else {
- LOG(ERROR) << "Unexpected controller key: " << controller_key->first;
- }
- }
- RemoveAdbPortForDeviceIfNeeded(adb_path, device_serial);
- SendMessage("OK", client_socket);
- }
- void HostControllersManager::HandleRequestOnInternalThread(
- const std::string& adb_path,
- const std::string& device_serial,
- int command,
- int device_port,
- int host_port,
- std::unique_ptr<Socket> client_socket) {
- const int adb_port = GetAdbPortForDevice(adb_path, device_serial);
- if (adb_port < 0) {
- SendMessage(
- "ERROR: could not get adb port for device. You might need to add "
- "'adb' to your PATH or provide the device serial id.\n",
- client_socket.get());
- return;
- }
- switch (command) {
- case MAP:
- Map(adb_path, device_serial, adb_port, device_port, host_port,
- client_socket.get());
- break;
- case UNMAP:
- Unmap(adb_path, device_serial, adb_port, device_port,
- client_socket.get());
- break;
- case UNMAP_ALL:
- UnmapAll(adb_path, device_serial, adb_port, client_socket.get());
- break;
- default:
- SendMessage(
- base::StringPrintf("ERROR: unrecognized command %d\n", command),
- client_socket.get());
- break;
- }
- }
- void HostControllersManager::LogExistingControllers(Socket* client_socket) {
- SendMessage("ERROR: Existing controllers:\n", client_socket);
- for (const auto& controller : *controllers_) {
- SendMessage(base::StringPrintf("ERROR: %s\n", controller.first.c_str()),
- client_socket);
- }
- }
- bool HostControllersManager::Adb(const std::string& adb_path,
- const std::string& device_serial,
- const std::string& command,
- std::string* output_and_error) {
- // We use the vector version of GetAppOutputAndError rather than the
- // more standard base::CommandLine version because base::CommandLine
- // reorders the command s.t. switches precede arguments and doing so
- // here creates an invalid adb command.
- std::vector<std::string> adb_command{adb_path};
- if (!device_serial.empty()) {
- adb_command.push_back("-s");
- adb_command.push_back(device_serial);
- }
- const std::vector<std::string> split_command = base::SplitString(
- command, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
- adb_command.insert(adb_command.end(), split_command.begin(),
- split_command.end());
- return GetAppOutputAndError(adb_command, output_and_error);
- }
- void HostControllersManager::RemoveAdbPortForDeviceIfNeeded(
- const std::string& adb_path,
- const std::string& device_serial) {
- std::unordered_map<std::string, int>::const_iterator it =
- device_serial_to_adb_port_map_.find(device_serial);
- if (it == device_serial_to_adb_port_map_.end())
- return;
- int port = it->second;
- const std::string prefix = base::StringPrintf("%d:", port);
- for (auto others = controllers_->begin(); others != controllers_->end();
- ++others) {
- if (base::StartsWith(others->first, prefix, base::CompareCase::SENSITIVE))
- return;
- }
- // No other port is being forwarded to this device:
- // - Remove it from our internal serial -> adb port map.
- // - Remove from "adb forward" command.
- LOG(INFO) << "Device " << device_serial << " has no more ports.";
- device_serial_to_adb_port_map_.erase(device_serial);
- const std::string command =
- base::StringPrintf("forward --remove tcp:%d", port);
- std::string output;
- if (!Adb(adb_path, device_serial, command, &output)) {
- LOG(ERROR) << command << " failed. output: \"" << output << "\"";
- } else {
- LOG(INFO) << command << " (output: \"" << output << "\")";
- }
- // Wait for the socket to be fully unmapped.
- const std::string port_mapped_cmd = base::StringPrintf("lsof -nPi:%d", port);
- const std::vector<std::string> port_mapped_split_cmd = base::SplitString(
- port_mapped_cmd, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
- const int poll_interval_us = 500 * 1000;
- int retries = 3;
- while (retries) {
- // lsof failure means the port was successfully unmapped.
- bool port_unmapped = !GetAppOutputAndError(port_mapped_split_cmd, &output);
- LOG(INFO) << "Device " << device_serial << " port " << port
- << (port_unmapped ? "" : " not") << " unmapped";
- if (port_unmapped)
- break;
- --retries;
- usleep(poll_interval_us);
- }
- }
- int HostControllersManager::GetAdbPortForDevice(
- const std::string adb_path,
- const std::string& device_serial) {
- std::unordered_map<std::string, int>::const_iterator it =
- device_serial_to_adb_port_map_.find(device_serial);
- if (it != device_serial_to_adb_port_map_.end())
- return it->second;
- Socket bind_socket;
- CHECK(bind_socket.BindTcp("127.0.0.1", 0));
- const int port = bind_socket.GetPort();
- bind_socket.Close();
- const std::string command = base::StringPrintf(
- "forward tcp:%d localabstract:chrome_device_forwarder", port);
- std::string output;
- if (!Adb(adb_path, device_serial, command, &output)) {
- LOG(ERROR) << command << " failed. output: " << output;
- return -1;
- }
- LOG(INFO) << command;
- device_serial_to_adb_port_map_[device_serial] = port;
- return port;
- }
- bool HostControllersManager::SendMessage(const std::string& msg,
- Socket* client_socket) {
- bool result = client_socket->WriteString(msg);
- DCHECK(result);
- if (!result)
- has_failed_ = true;
- return result;
- }
- bool HostControllersManager::GetAppOutputAndError(
- const std::vector<std::string>& argv,
- std::string* output) {
- return base::GetAppOutputAndError(argv, output);
- }
- } // namespace forwarder2
|