• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   for (auto flag : stringutils::Split(options.netsim_args, " "))
86     program_with_args.push_back(std::string(flag));
87 
88   BtsLogInfo("Netsimd launch command:");
89   for (auto arg : program_with_args) BtsLogInfo("%s", arg.c_str());
90   auto cmd = android::base::Command::create(program_with_args);
91 
92   auto netsimd = cmd.asDeamon().execute();
93   if (netsimd) {
94     BtsLogInfo("Running netsimd as pid: %d.", netsimd->pid());
95   }
96 
97   return netsimd;
98 }
99 
100 }  // namespace
101 
SetPacketStreamEndpoint(const std::string & endpoint)102 void SetPacketStreamEndpoint(const std::string &endpoint) {
103   if (endpoint != "default") custom_packet_stream_endpoint = endpoint;
104 }
105 
GetChannel(NetsimdOptions options)106 std::shared_ptr<grpc::Channel> GetChannel(NetsimdOptions options) {
107   std::lock_guard<std::mutex> lock(channel_mutex);
108 
109   // bool is_netsimd_started = false;
110   std::unique_ptr<android::base::ObservableProcess> netsimProc;
111   for (int second : {1, 2, 4, 8}) {
112     if (!packet_stream_channel) packet_stream_channel = CreateGrpcChannel();
113     if (GrpcChannelReady(packet_stream_channel)) return packet_stream_channel;
114 
115     packet_stream_channel.reset();
116 
117     if ((!netsimProc || !netsimProc->isAlive()) &&
118         custom_packet_stream_endpoint.empty()) {
119       BtsLogInfo("Starting netsim since %s",
120                  netsimProc ? "the process died" : "it is not yet launched");
121       netsimProc = RunNetsimd(options);
122     }
123     BtsLogInfo("Retry connecting to netsim in %d second.", second);
124     std::this_thread::sleep_for(std::chrono::seconds(second));
125   }
126 
127   BtsLogError("Unable to get a packet stream channel.");
128   return nullptr;
129 }
130 
CreateChannel(NetsimdOptions options)131 std::shared_ptr<grpc::Channel> CreateChannel(NetsimdOptions options) {
132   return GetChannel(options);
133 }
134 
CreateChannel(std::string _rootcanal_controller_properties_file)135 std::shared_ptr<grpc::Channel> CreateChannel(
136     std::string _rootcanal_controller_properties_file) {
137   return GetChannel({});
138 }
139 
140 }  // namespace netsim::packet
141