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