blob: 61d5f3a89c2f7e09fe321df9b58d7a79ab7a126b [file] [log] [blame]
/*
* Copyright 2019 The Chromium OS 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 <fcntl.h>
#include <base/at_exit.h>
#include <base/logging.h>
#include <brillo/flag_helper.h>
#include <brillo/syslog_logging.h>
#include "arc/adbd/adbd.h"
namespace {
constexpr char kRuntimePath[] = "/run/arc/adbd";
} // namespace
int main(int argc, char** argv) {
DEFINE_string(serialnumber, "", "Serial number of the Android container");
base::AtExitManager at_exit;
brillo::FlagHelper::Init(argc, argv, "ADB over USB proxy.");
brillo::InitLog(brillo::kLogToSyslog | brillo::kLogToStderrIfTty);
const base::FilePath runtime_path(kRuntimePath);
adbd::AdbdConfiguration config;
if (!adbd::GetConfiguration(&config)) {
LOG(INFO) << "Unable to find the configuration for this service. "
<< "This device does not support ADB over USB.";
return 0;
}
const std::string board = adbd::GetStrippedReleaseBoard();
const base::FilePath control_pipe_path = runtime_path.Append("ep0");
if (!adbd::CreatePipe(control_pipe_path))
return 1;
char buffer[4096];
bool configured = false;
base::ScopedFD control_file;
while (true) {
LOG(INFO) << "arc-adbd ready to receive connections";
// O_RDONLY on a FIFO waits until another endpoint has opened the file with
// O_WRONLY or O_RDWR.
base::ScopedFD control_pipe(
open(control_pipe_path.value().c_str(), O_RDONLY));
if (!control_pipe.is_valid()) {
PLOG(ERROR) << "Failed to open FIFO at " << control_pipe_path.value();
return 1;
}
LOG(INFO) << "arc-adbd connected";
// Given that a FIFO can be opened by multiple processes, once a process has
// opened it, we atomically replace it with a new FIFO (by using rename(2))
// so no other process can open it. This causes that when that process
// close(2)s the FD, we will get an EOF when we attempt to read(2) from it.
// This also causes any other process that attempts to open the new FIFO to
// block until we are done processing the current one.
//
// There is a very small chance there is a race here if multiple processes
// get to open the FIFO between the point in time where this process opens
// the FIFO and CreatePipe() returns. That seems unavoidable, but should not
// present too much of a problem since exactly one process in Android has
// the correct user to open this file in the first place (adbd).
if (!adbd::CreatePipe(control_pipe_path))
return 1;
// Once adbd has opened the control pipe, we set up the adb gadget on behalf
// of that process, if we have not already.
if (!configured) {
if (!adbd::SetupKernelModules(config.kernel_modules)) {
LOG(ERROR) << "Failed to load kernel modules";
return 1;
}
const std::string udc_driver_name = adbd::GetUDCDriver();
if (udc_driver_name.empty()) {
LOG(ERROR)
<< "Unable to find any registered UDC drivers in /sys/class/udc/. "
<< "This device does not support ADB using GadgetFS.";
return 1;
}
if (!adbd::SetupConfigFS(FLAGS_serialnumber, config.usb_product_id,
board)) {
LOG(ERROR) << "Failed to configure ConfigFS";
return 1;
}
control_file = adbd::SetupFunctionFS(udc_driver_name);
if (!control_file.is_valid()) {
LOG(ERROR) << "Failed to configure FunctionFS";
return 1;
}
configured = true;
}
// Drain the FIFO and wait until the other side closes it.
// The data that is sent is kControlPayloadV2 (or kControlPayloadV1)
// followed by kControlStrings. We ignore it completely since we have
// already sent it to the underlying FunctionFS file, and also to avoid
// parsing it to decrease the attack surface area.
while (true) {
ssize_t bytes_read = read(control_pipe.get(), buffer, sizeof(buffer));
if (bytes_read < 0)
PLOG(ERROR) << "Failed to read from FIFO";
if (bytes_read <= 0)
break;
}
}
return 0;
}