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