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