1*cf78ab8cSAndroid Build Coastguard Worker // Copyright 2022 The Android Open Source Project
2*cf78ab8cSAndroid Build Coastguard Worker //
3*cf78ab8cSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*cf78ab8cSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*cf78ab8cSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*cf78ab8cSAndroid Build Coastguard Worker //
7*cf78ab8cSAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0
8*cf78ab8cSAndroid Build Coastguard Worker //
9*cf78ab8cSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*cf78ab8cSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*cf78ab8cSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*cf78ab8cSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*cf78ab8cSAndroid Build Coastguard Worker // limitations under the License.
14*cf78ab8cSAndroid Build Coastguard Worker
15*cf78ab8cSAndroid Build Coastguard Worker #include "backend/packet_streamer_client.h"
16*cf78ab8cSAndroid Build Coastguard Worker
17*cf78ab8cSAndroid Build Coastguard Worker #include <chrono>
18*cf78ab8cSAndroid Build Coastguard Worker #include <mutex>
19*cf78ab8cSAndroid Build Coastguard Worker #include <optional>
20*cf78ab8cSAndroid Build Coastguard Worker #include <thread>
21*cf78ab8cSAndroid Build Coastguard Worker #ifdef _WIN32
22*cf78ab8cSAndroid Build Coastguard Worker #include <Windows.h>
23*cf78ab8cSAndroid Build Coastguard Worker #else
24*cf78ab8cSAndroid Build Coastguard Worker #include <unistd.h>
25*cf78ab8cSAndroid Build Coastguard Worker #endif
26*cf78ab8cSAndroid Build Coastguard Worker
27*cf78ab8cSAndroid Build Coastguard Worker #include "aemu/base/process/Command.h"
28*cf78ab8cSAndroid Build Coastguard Worker #include "android/base/system/System.h"
29*cf78ab8cSAndroid Build Coastguard Worker #include "android/emulation/control/interceptor/MetricsInterceptor.h"
30*cf78ab8cSAndroid Build Coastguard Worker #include "grpcpp/channel.h"
31*cf78ab8cSAndroid Build Coastguard Worker #include "grpcpp/create_channel.h"
32*cf78ab8cSAndroid Build Coastguard Worker #include "grpcpp/security/credentials.h"
33*cf78ab8cSAndroid Build Coastguard Worker #include "util/log.h"
34*cf78ab8cSAndroid Build Coastguard Worker #include "util/os_utils.h"
35*cf78ab8cSAndroid Build Coastguard Worker #include "util/string_utils.h"
36*cf78ab8cSAndroid Build Coastguard Worker
37*cf78ab8cSAndroid Build Coastguard Worker using android::control::interceptor::MetricsInterceptorFactory;
38*cf78ab8cSAndroid Build Coastguard Worker
39*cf78ab8cSAndroid Build Coastguard Worker namespace netsim::packet {
40*cf78ab8cSAndroid Build Coastguard Worker namespace {
41*cf78ab8cSAndroid Build Coastguard Worker
42*cf78ab8cSAndroid Build Coastguard Worker const std::chrono::duration kConnectionDeadline = std::chrono::seconds(1);
43*cf78ab8cSAndroid Build Coastguard Worker std::string custom_packet_stream_endpoint = "";
44*cf78ab8cSAndroid Build Coastguard Worker std::shared_ptr<grpc::Channel> packet_stream_channel;
45*cf78ab8cSAndroid Build Coastguard Worker std::mutex channel_mutex;
46*cf78ab8cSAndroid Build Coastguard Worker
CreateGrpcChannel()47*cf78ab8cSAndroid Build Coastguard Worker std::shared_ptr<grpc::Channel> CreateGrpcChannel() {
48*cf78ab8cSAndroid Build Coastguard Worker auto endpoint = custom_packet_stream_endpoint;
49*cf78ab8cSAndroid Build Coastguard Worker if (endpoint.empty()) {
50*cf78ab8cSAndroid Build Coastguard Worker auto port = netsim::osutils::GetServerAddress();
51*cf78ab8cSAndroid Build Coastguard Worker if (!port.has_value()) return nullptr;
52*cf78ab8cSAndroid Build Coastguard Worker endpoint = "localhost:" + port.value();
53*cf78ab8cSAndroid Build Coastguard Worker }
54*cf78ab8cSAndroid Build Coastguard Worker
55*cf78ab8cSAndroid Build Coastguard Worker if (endpoint.empty()) return nullptr;
56*cf78ab8cSAndroid Build Coastguard Worker BtsLogInfo("Creating a Grpc channel to %s", endpoint.c_str());
57*cf78ab8cSAndroid Build Coastguard Worker
58*cf78ab8cSAndroid Build Coastguard Worker std::vector<
59*cf78ab8cSAndroid Build Coastguard Worker std::unique_ptr<grpc::experimental::ClientInterceptorFactoryInterface>>
60*cf78ab8cSAndroid Build Coastguard Worker interceptors;
61*cf78ab8cSAndroid Build Coastguard Worker interceptors.emplace_back(std::make_unique<MetricsInterceptorFactory>());
62*cf78ab8cSAndroid Build Coastguard Worker grpc::ChannelArguments args;
63*cf78ab8cSAndroid Build Coastguard Worker return grpc::experimental::CreateCustomChannelWithInterceptors(
64*cf78ab8cSAndroid Build Coastguard Worker endpoint, grpc::InsecureChannelCredentials(), args,
65*cf78ab8cSAndroid Build Coastguard Worker std::move(interceptors));
66*cf78ab8cSAndroid Build Coastguard Worker }
67*cf78ab8cSAndroid Build Coastguard Worker
GrpcChannelReady(const std::shared_ptr<grpc::Channel> & channel)68*cf78ab8cSAndroid Build Coastguard Worker bool GrpcChannelReady(const std::shared_ptr<grpc::Channel> &channel) {
69*cf78ab8cSAndroid Build Coastguard Worker if (channel) {
70*cf78ab8cSAndroid Build Coastguard Worker auto deadline = std::chrono::system_clock::now() + kConnectionDeadline;
71*cf78ab8cSAndroid Build Coastguard Worker return channel->WaitForConnected(deadline);
72*cf78ab8cSAndroid Build Coastguard Worker }
73*cf78ab8cSAndroid Build Coastguard Worker return false;
74*cf78ab8cSAndroid Build Coastguard Worker }
75*cf78ab8cSAndroid Build Coastguard Worker
RunNetsimd(NetsimdOptions options)76*cf78ab8cSAndroid Build Coastguard Worker std::unique_ptr<android::base::ObservableProcess> RunNetsimd(
77*cf78ab8cSAndroid Build Coastguard Worker NetsimdOptions options) {
78*cf78ab8cSAndroid Build Coastguard Worker auto exe = android::base::System::get()->findBundledExecutable("netsimd");
79*cf78ab8cSAndroid Build Coastguard Worker std::vector<std::string> program_with_args{exe};
80*cf78ab8cSAndroid Build Coastguard Worker if (options.no_cli_ui) program_with_args.push_back("--no-cli-ui");
81*cf78ab8cSAndroid Build Coastguard Worker if (options.no_web_ui) program_with_args.push_back("--no-web-ui");
82*cf78ab8cSAndroid Build Coastguard Worker if (!options.host_dns.empty()) {
83*cf78ab8cSAndroid Build Coastguard Worker program_with_args.push_back("--host-dns=" + options.host_dns);
84*cf78ab8cSAndroid Build Coastguard Worker }
85*cf78ab8cSAndroid Build Coastguard Worker if (!options.http_proxy.empty()) {
86*cf78ab8cSAndroid Build Coastguard Worker program_with_args.push_back("--http-proxy=" + options.http_proxy);
87*cf78ab8cSAndroid Build Coastguard Worker }
88*cf78ab8cSAndroid Build Coastguard Worker for (auto flag : stringutils::Split(options.netsim_args, " "))
89*cf78ab8cSAndroid Build Coastguard Worker program_with_args.push_back(std::string(flag));
90*cf78ab8cSAndroid Build Coastguard Worker
91*cf78ab8cSAndroid Build Coastguard Worker BtsLogInfo("Netsimd launch command:");
92*cf78ab8cSAndroid Build Coastguard Worker for (auto arg : program_with_args) BtsLogInfo("%s", arg.c_str());
93*cf78ab8cSAndroid Build Coastguard Worker auto cmd = android::base::Command::create(program_with_args);
94*cf78ab8cSAndroid Build Coastguard Worker
95*cf78ab8cSAndroid Build Coastguard Worker auto netsimd = cmd.asDeamon().execute();
96*cf78ab8cSAndroid Build Coastguard Worker if (netsimd) {
97*cf78ab8cSAndroid Build Coastguard Worker BtsLogInfo("Running netsimd as pid: %d.", netsimd->pid());
98*cf78ab8cSAndroid Build Coastguard Worker }
99*cf78ab8cSAndroid Build Coastguard Worker
100*cf78ab8cSAndroid Build Coastguard Worker return netsimd;
101*cf78ab8cSAndroid Build Coastguard Worker }
102*cf78ab8cSAndroid Build Coastguard Worker
103*cf78ab8cSAndroid Build Coastguard Worker } // namespace
104*cf78ab8cSAndroid Build Coastguard Worker
SetPacketStreamEndpoint(const std::string & endpoint)105*cf78ab8cSAndroid Build Coastguard Worker void SetPacketStreamEndpoint(const std::string &endpoint) {
106*cf78ab8cSAndroid Build Coastguard Worker if (endpoint != "default") custom_packet_stream_endpoint = endpoint;
107*cf78ab8cSAndroid Build Coastguard Worker }
108*cf78ab8cSAndroid Build Coastguard Worker
GetChannel(NetsimdOptions options)109*cf78ab8cSAndroid Build Coastguard Worker std::shared_ptr<grpc::Channel> GetChannel(NetsimdOptions options) {
110*cf78ab8cSAndroid Build Coastguard Worker std::lock_guard<std::mutex> lock(channel_mutex);
111*cf78ab8cSAndroid Build Coastguard Worker
112*cf78ab8cSAndroid Build Coastguard Worker // bool is_netsimd_started = false;
113*cf78ab8cSAndroid Build Coastguard Worker std::unique_ptr<android::base::ObservableProcess> netsimProc;
114*cf78ab8cSAndroid Build Coastguard Worker for (int second : {1, 2, 4, 8}) {
115*cf78ab8cSAndroid Build Coastguard Worker if (!packet_stream_channel) packet_stream_channel = CreateGrpcChannel();
116*cf78ab8cSAndroid Build Coastguard Worker if (GrpcChannelReady(packet_stream_channel)) return packet_stream_channel;
117*cf78ab8cSAndroid Build Coastguard Worker
118*cf78ab8cSAndroid Build Coastguard Worker packet_stream_channel.reset();
119*cf78ab8cSAndroid Build Coastguard Worker
120*cf78ab8cSAndroid Build Coastguard Worker if ((!netsimProc || !netsimProc->isAlive()) &&
121*cf78ab8cSAndroid Build Coastguard Worker custom_packet_stream_endpoint.empty()) {
122*cf78ab8cSAndroid Build Coastguard Worker BtsLogInfo("Starting netsim since %s",
123*cf78ab8cSAndroid Build Coastguard Worker netsimProc ? "the process died" : "it is not yet launched");
124*cf78ab8cSAndroid Build Coastguard Worker netsimProc = RunNetsimd(options);
125*cf78ab8cSAndroid Build Coastguard Worker }
126*cf78ab8cSAndroid Build Coastguard Worker BtsLogInfo("Retry connecting to netsim in %d second.", second);
127*cf78ab8cSAndroid Build Coastguard Worker std::this_thread::sleep_for(std::chrono::seconds(second));
128*cf78ab8cSAndroid Build Coastguard Worker }
129*cf78ab8cSAndroid Build Coastguard Worker
130*cf78ab8cSAndroid Build Coastguard Worker BtsLogError("Unable to get a packet stream channel.");
131*cf78ab8cSAndroid Build Coastguard Worker return nullptr;
132*cf78ab8cSAndroid Build Coastguard Worker }
133*cf78ab8cSAndroid Build Coastguard Worker
CreateChannel(NetsimdOptions options)134*cf78ab8cSAndroid Build Coastguard Worker std::shared_ptr<grpc::Channel> CreateChannel(NetsimdOptions options) {
135*cf78ab8cSAndroid Build Coastguard Worker return GetChannel(options);
136*cf78ab8cSAndroid Build Coastguard Worker }
137*cf78ab8cSAndroid Build Coastguard Worker
CreateChannel(std::string _rootcanal_controller_properties_file)138*cf78ab8cSAndroid Build Coastguard Worker std::shared_ptr<grpc::Channel> CreateChannel(
139*cf78ab8cSAndroid Build Coastguard Worker std::string _rootcanal_controller_properties_file) {
140*cf78ab8cSAndroid Build Coastguard Worker return GetChannel({});
141*cf78ab8cSAndroid Build Coastguard Worker }
142*cf78ab8cSAndroid Build Coastguard Worker
143*cf78ab8cSAndroid Build Coastguard Worker } // namespace netsim::packet
144