1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "TracingClient.h"
18 #include "perfetto_trace.pb.h"
19 
20 #include <android-base/logging.h>
21 
22 #include <fstream>
23 #include <string>
24 
25 namespace android::tools::automotive::tracing {
26 
27 // TODO: Using a secure channel.
getChannelCredentials()28 static std::shared_ptr<::grpc::ChannelCredentials> getChannelCredentials() {
29     return ::grpc::InsecureChannelCredentials();
30 }
31 
TracingClient(const std::string & addr)32 TracingClient::TracingClient(const std::string& addr)
33     : mServiceAddr(addr),
34       mGrpcChannel(::grpc::CreateChannel(mServiceAddr, getChannelCredentials())),
35       mGrpcStub(tracing_vm_proto::TracingServer::NewStub(mGrpcChannel)) {}
36 
StartTracing(const std::string & host_config,uint64_t & session_num)37 bool TracingClient::StartTracing(const std::string& host_config, uint64_t& session_num) {
38     ::grpc::ClientContext context;
39     tracing_vm_proto::StartTracingRequest request;
40     if (host_config.empty()) {
41         std::cerr << __func__ << ": missing HostConfigFile.\n";
42         return false;
43     }
44 
45     std::ifstream config_file_stream(host_config, std::fstream::binary);
46     if (!config_file_stream) {
47         std::cerr << __func__ << ": file not found " << host_config << std::endl;
48         return false;
49     }
50 
51     perfetto::protos::TraceConfig* trace_config = request.mutable_host_config();
52     if (trace_config->ParseFromIstream(&config_file_stream)) {
53         std::cerr << __func__ << ": faled to parse the host_config file " << std::endl;
54         return false;
55     }
56 
57     tracing_vm_proto::RequestStatus request_status;
58     auto grpc_status = mGrpcStub->StartTracing(&context, request, &request_status);
59     if (!grpc_status.ok()) {
60         std::cerr << __func__ << ": failed due to grpc error: " << grpc_status.error_message()
61                   << std::endl;
62         return false;
63     }
64     if (!request_status.is_ok()) {
65         std::cerr << __func__ << ": failed with error: " << request_status.error_str() << std::endl;
66         return false;
67     }
68 
69     std::cout << __func__ << ": succeed for session_id "
70               << request_status.session_id().session_id();
71     session_num = request_status.session_id().session_id();
72     return true;
73 }
74 
StopTracing(const uint64_t session_num)75 bool TracingClient::StopTracing(const uint64_t session_num) {
76     ::grpc::ClientContext context;
77     tracing_vm_proto::TracingSessionIdentifier session_id;
78     tracing_vm_proto::RequestStatus request_status;
79     session_id.set_session_id(session_num);
80     auto grpc_status = mGrpcStub->StopTracing(&context, session_id, &request_status);
81     if (!grpc_status.ok()) {
82         std::cerr << __func__ << ": for session_id " << session_num
83                   << " failed due to grpc error: " << grpc_status.error_message() << std::endl;
84         return false;
85     }
86     if (!request_status.is_ok()) {
87         std::cerr << __func__ << ": for session_id " << session_num
88                   << " failed with error code: " << request_status.error_str();
89         return false;
90     }
91 
92     std::cout << __func__ << ": succeed for session_id " << session_num << std::endl;
93     return true;
94 }
95 
GetTracingFile(const uint64_t session_num,const std::string & file_path)96 bool TracingClient::GetTracingFile(const uint64_t session_num, const std::string& file_path) {
97     if (file_path.empty()) {
98         std::cerr << __func__ << ": missing file_path.\n";
99         return false;
100     }
101     std::ofstream file_stream(file_path, std::fstream::binary);
102 
103     if (!file_stream) {
104         std::cerr << __func__ << ": for session_id " << session_num << " failed to open file "
105                   << file_path << std::endl;
106         return false;
107     }
108 
109     ::grpc::ClientContext context;
110     tracing_vm_proto::TracingSessionIdentifier session_id;
111     session_id.set_session_id(session_num);
112     auto grpc_reader = mGrpcStub->GetTracingFile(&context, session_id);
113     tracing_vm_proto::TracingFileBuffer file_buffer;
114 
115     while (grpc_reader->Read(&file_buffer)) {
116         const auto& write_buffer = file_buffer.buffer();
117         file_stream.write(write_buffer.c_str(), write_buffer.size());
118     }
119 
120     auto grpcStatus = grpc_reader->Finish();
121     if (!grpcStatus.ok()) {
122         std::cerr << __func__ << " failed for session_id " << session_num
123                   << "due to grpc error:" << grpcStatus.error_message() << std::endl;
124         return false;
125     }
126 
127     return true;
128 }
129 
130 }  // namespace android::tools::automotive::tracing
131