Anbox 运行时主要由两个分开的实例构成,即容器管理器 ContainerManager 和会话管理器 SessionManager,但无论是 ContainerManager 还是 SessionManager,所做的最重要的事情就是处理网络 I/O 事件了。I/O 模型指一个应用处理 I/O 事件的整体框架设计,对于 Anbox 而言主要是处理各种网络 I/O 事务的整体框架设计。ContainerManager 和 SessionManager 基于一个相同的 I/O 模型运行,为了获得对 Anbox 整体行为设计的理解,有必要对其 I/O 模型有个整体的认识。
I/O 模型
Anbox 的 I/O 模型基于 boost.asio 构建。Anbox 中所有的 I/O 事件,在一个线程池中,通过一个 boost::asio::io_service 对象来派发并处理。Anbox 用 anbox::Runtime 类封装一个 boost::asio::io_service 对象,并管理执行任务的线程池。
anbox::Runtime 类的定义(位于 anbox/src/anbox/runtime.h)如下:namespace anbox {// We bundle our "global" runtime dependencies here, specifically// a dispatcher to decouple multiple in-process providers from one// another , forcing execution to a well known set of threads.class Runtime : public DoNotCopyOrMove, public std::enable_shared_from_this { public: // Our default concurrency setup.
static constexpr const std::uint32_t worker_threads = 8; // create returns a Runtime instance with pool_size worker threads
// executing the underlying service.
static std::shared_ptr create( std::uint32_t pool_size = worker_threads); // Tears down the runtime, stopping all worker threads.
~Runtime() noexcept(true); // start executes the underlying io_service on a thread pool with
// the size configured at creation time.
void start(); // stop cleanly shuts down a Runtime instance.
void stop(); // to_dispatcher_functional returns a function for integration
// with components that expect a dispatcher for operation.
std::function)> to_dispatcher_functional(); // service returns the underlying boost::asio::io_service that is executed
// by the Runtime.
boost::asio::io_service& service(); private: // Runtime constructs a new instance, firing up pool_size
// worker threads.
Runtime(std::uint32_t pool_size); std::uint32_t pool_size_;
boost::asio::io_service service_;
boost::asio::io_service::strand strand_;
boost::asio::io_service::work keep_alive_; std::vector<:thread> workers_;
};
} // namespace anbox
anbox::Runtime 类封装了一个 boost::asio::io_service 对象及多个工作线程 std::thread,它还继承 std::enable_shared_from_this 以获得从 this 指针创建智能指针 std::shared_ptr 的能力,同时继承了 DoNotCopyOrMove,以禁掉类的拷贝和移动操作。
anbox::Runtime 类的实现(位于 anbox/src/anbox/runtime.cpp)如下:namespace {void exception_safe_run(boost::asio::io_service& service) { while (true) { try {
service.run(); // a clean return from run only happens in case of
// stop() being called (we are keeping the service alive with
// a service::work instance).
break;
} catch (const std::exception& e) {
ERROR("%s", e.what());
} catch (...) {
ERROR("Unknown exception caught while executing boost::asio::io_service");
}
}
}
}namespace anbox {std::shared_ptr Runtime::create(std::uint32_t pool_size) { return std::shared_ptr(new Runtime(pool_size));
}
Runtime::Runtime(std::uint32_t pool_size)
: pool_size_{pool_size},
service_{pool_size_},
strand_{service_},
keep_alive_{service_} {}
Runtime::~Runtime() noexcept(true) { try {
stop();
} catch (...) { // Dropping all exceptions to satisfy the nothrow guarantee.
}
}void Runtime::start() { for (unsigned int i = 0; i
workers_.push_back(std::thread{exception_safe_run, std::ref(service_)});
}void Runtime::stop() {
service_.stop(); for (auto& worker : workers_) if (worker.joinable())
worker.join();
workers_.clear();
}std::function)> Runtime::to_dispatcher_functional() { // We have to make sure that we stay alive for as long as
// calling code requires the dispatcher to work.
auto sp = shared_from_this(); return [sp](std::function task) { sp->strand_.post(task); };
}
boost::asio::io_service& Runtime::service() { return service_; }
} // namespace anbox
anbox::Runtime 类有两大职责,一是 boost::asio::io_service 对象的生命周期管理;二是向 boost::asio::io_service 中提交任务。
在 anbox::Runtime::start() 函数中创建并启动多个线程,执行一个执行 boost::asio::io_service::run() 函数的函数 exception_safe_run()。在 anbox::Runtime::stop() 函数中停掉 boost::asio::io_service 的执行。anbox::Runtime 的析够函数中,还会调用 stop() 函数停掉 boost::asio::io_service 的执行。anbox::Runtime 的类型为 boost::asio::io_service::work 的成员变量 keep_alive_ 也是用于管理 boost::asio::io_service 对象的生命周期的,该对象在析够时也会停掉 boost::asio::io_service 的执行。
对于不熟悉 boost 库的朋友来说,boost::asio::io_service 可以理解为一个 I/O 多路复用器,就像许多网络库通过 select/poll/epoll/kqueue 实现的那样,或者可以理解为以 Reactor 模式实现的网络库中的一个事件循环,可以向其中提交 I/O 任务、定时器及其它任务等。boost::asio::io_service::strand 可以理解为 boost::asio::io_service 中的一个特殊的子任务队列,该类保证向其提交的所有任务都不会并发执行,以此消除这些任务之间的同步问题。
anbox::Runtime::to_dispatcher_functional() 函数返回一个接收一个函数为参数的函数,返回的这个函数可以将它接收的函数作为一个 task,通过 boost::asio::io_service::strand 提交给 boost::asio::io_service 执行。anbox::Runtime::service() 返回 boost::asio::io_service 用于方便一些 boost I/O 组件,直接向该 io_service 中提交任务。
继承自 std::enable_shared_from_this 的 shared_from_this() 可以从 this 指针创建一个指向当前对象的 std::shared_ptr 智能指针。通过对标准库源码的分析,可以知道 std::enable_shared_from_this 的实现原理大体如下:std::enable_shared_from_this 有一个类型为 std::weak_ptr 的成员,该成员在首次创建指向对象的 std::shared_ptr 智能指针的时候会被初始化。shared_from_this() 函数被调用时,会从类型为 std::weak_ptr 的成员变量创建指向当前对象的 std::shared_ptr 智能指针。
Anbox 的 I/O 模型可以理解为,底层有 一个 多路复用器或事件循环 boost::asio::io_service,有一个包含了 8 个线程的线程池基于此 boost::asio::io_service 运行,处理 I/O 事件及其它各种类型的任务。
有了用于执行 I/O 事件处理程序的 boost::asio::io_service,接下来来看一下,Anbox 都会向其中提交哪些任务。
Anbox 需要处理如下这样一些网络 I/O 过程:监听 Unix 域 Socket 接受连接。Anbox 的 SessionManager 通过 Unix 域 Socket 与 ContainerManager 进行通信,同时也通过 Unix 域 Socket 与 ContainerManager 启动的 Android 容器内的应用程序通信。首先 ContainerManager 监听在特定位置的 Unix 域 Socket 上。随后 SessionManager 监听几个位置上的 Unix 域 Socket,然后请求 ContainerManager 启动 Android 容器,并将这几个 Unix 域 Socket 映射到容器内的 /dev/ 目录下。Android 容器启动后,一些进程,如 surfaceflinger、cameraservice 等连接这些 Unix 域 Socket,并通过这些 Unix 域 Socket 与 SessionManager 通信,进而操作宿主机的硬件设备。
监听 TCP Socket 接受连接。Anbox 的 SessionManager 作为容器中运行的 Android 与 ADB 进行通信的桥梁,它在与容器中运行的 Android 通过 Unix 域 Socket 通信的同时,也需要与宿主机上的 ADB 通信。SessionManager 通过 TCP 与宿主机上的 ADB 守护进程通信。如同模拟器等 Android 设备一样,SessionManager 遵从 ADB 的通信协议,在发起与 ADB 之间的 TCP 连接的同时,也需要监听一个 TCP 端口,等待 ADB 守护进程发起的连接,以完成整个 ADB 协议。
处理从监听的 Unix 域 Socket 接受的 Unix 域 Socket。监听的 Unix 域 Socket 接受新连接之后,需要将新创建的 Unix 域 Socket 提交给底层的 I/O 多路复用器,并为该 Socket 提供读写等 I/O 事件处理处理回调,以完成 Anbox 的应用逻辑。
处理从监听的 TCP Scoket 接受的 TCP Socket。监听的 TCP Socket 接受新连接之后,需要将新创建的 TCP Socket 提交给底层的 I/O 多路复用器,并为该 Socket 提供读写等 I/O 事件处理处理回调,以完成 Anbox 的应用逻辑。
发起一个到 TCP 服务器的连接。如前面提到的,Anbox 的 SessionManager 通过 TCP 连接与 ADB 守护进程通信,它会先发起一个到 ADB 守护进程的 TCP 连接。
发起一个到 Unix 域 Socket 服务的连接。Anbox 的 SessionManager 与 ContainerManager 之间通过 Unix 域 Socket 通信,SessionManager 会发起到 ContainerManager 监听的 Unix 域 Socket 服务的连接。
监听 Unix 域 Socket 接受连接
在 boost.asio 中,监听 Socket 并接受新连接,通过 acceptor 完成,对于具体的 Unix 域 Socket 而言,是通过 boost::asio::local::stream_protocol::acceptor。boost::asio::local::stream_protocol::acceptor 类对象在