1 /*
2  * Copyright 2016 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 #include "VtsProfilingInterface.h"
17 
18 #include <cutils/properties.h>
19 #include <fcntl.h>
20 #include <fstream>
21 #include <string>
22 
23 #include <android-base/logging.h>
24 #include <google/protobuf/text_format.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 
28 #include "VtsProfilingUtil.h"
29 #include "test/vts/proto/VtsDriverControlMessage.pb.h"
30 #include "test/vts/proto/VtsProfilingMessage.pb.h"
31 
32 using namespace std;
33 
34 namespace android {
35 namespace vts {
36 
VtsProfilingInterface(const string & trace_file_path_prefix)37 VtsProfilingInterface::VtsProfilingInterface(
38     const string& trace_file_path_prefix)
39     : trace_file_path_prefix_(trace_file_path_prefix) {}
40 
~VtsProfilingInterface()41 VtsProfilingInterface::~VtsProfilingInterface() {
42   mutex_.lock();
43   for (auto it = trace_map_.begin(); it != trace_map_.end(); ++it) {
44     close(it->second);
45   }
46   mutex_.unlock();
47 }
48 
NanoTime()49 int64_t VtsProfilingInterface::NanoTime() {
50   std::chrono::nanoseconds duration(
51       std::chrono::steady_clock::now().time_since_epoch());
52   return static_cast<int64_t>(duration.count());
53 }
54 
getInstance(const string & trace_file_path_prefix)55 VtsProfilingInterface& VtsProfilingInterface::getInstance(
56     const string& trace_file_path_prefix) {
57   static VtsProfilingInterface instance(trace_file_path_prefix);
58   return instance;
59 }
60 
GetTraceFile(const string & package,const string & version)61 int VtsProfilingInterface::GetTraceFile(const string& package,
62                                         const string& version) {
63   string fullname = package + "@" + version;
64   int fd = -1;
65   if (trace_map_.find(fullname) != trace_map_.end()) {
66     fd = trace_map_[fullname];
67     struct stat statbuf;
68     fstat(fd, &statbuf);
69     // If file no longer exists or the file descriptor is no longer valid,
70     // create a new trace file.
71     if (statbuf.st_nlink <= 0 || fcntl(fd, F_GETFD) == -1) {
72       fd = CreateTraceFile(package, version);
73       trace_map_[fullname] = fd;
74     }
75   } else {
76     // Create trace file for a new HAL.
77     fd = CreateTraceFile(package, version);
78     trace_map_[fullname] = fd;
79   }
80   return fd;
81 }
82 
CreateTraceFile(const string & package,const string & version)83 int VtsProfilingInterface::CreateTraceFile(const string& package,
84                                            const string& version) {
85   // Attach device info and timestamp for the trace file.
86   char build_number[PROPERTY_VALUE_MAX];
87   char device_id[PROPERTY_VALUE_MAX];
88   char product_name[PROPERTY_VALUE_MAX];
89   property_get("ro.build.version.incremental", build_number, "unknown_build");
90   property_get("ro.serialno", device_id, "unknown_device");
91   property_get("ro.build.product", product_name, "unknown_product");
92 
93   string file_path = trace_file_path_prefix_ + package + "_" + version + "_" +
94                      string(product_name) + "_" + string(device_id) + "_" +
95                      string(build_number) + "_" + to_string(NanoTime()) +
96                      ".vts.trace";
97 
98   LOG(INFO) << "Creating new trace file: " << file_path;
99   int fd = open(file_path.c_str(), O_RDWR | O_CREAT | O_EXCL,
100                 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
101   if (fd < 0) {
102     PLOG(ERROR) << "Can not open trace file: " << file_path;
103     return -1;
104   }
105   return fd;
106 }
107 
AddTraceEvent(android::hardware::details::HidlInstrumentor::InstrumentationEvent event,const char * package,const char * version,const char * interface,const FunctionSpecificationMessage & message)108 void VtsProfilingInterface::AddTraceEvent(
109     android::hardware::details::HidlInstrumentor::InstrumentationEvent event,
110     const char* package, const char* version, const char* interface,
111     const FunctionSpecificationMessage& message) {
112   std::string version_str = std::string(version);
113   int version_major = stoi(version_str.substr(0, version_str.find('.')));
114   int version_minor = stoi(version_str.substr(version_str.find('.') + 1));
115   // Build the VTSProfilingRecord and print it to string.
116   VtsProfilingRecord record;
117   record.set_timestamp(NanoTime());
118   record.set_event((InstrumentationEventType) static_cast<int>(event));
119   record.set_package(package);
120   record.set_version_major(version_major);
121   record.set_version_minor(version_minor);
122   record.set_interface(interface);
123   *record.mutable_func_msg() = message;
124 
125   // Write the record string to trace file.
126   mutex_.lock();
127   int fd = GetTraceFile(package, version);
128   if (fd == -1) {
129     LOG(ERROR) << "Failed to get trace file.";
130   } else {
131     google::protobuf::io::FileOutputStream trace_output(fd);
132     if (!writeOneDelimited(record, &trace_output)) {
133       LOG(ERROR) << "Failed to write record.";
134     }
135     if (!trace_output.Flush()) {
136       PLOG(ERROR) << "Failed to flush";
137     }
138   }
139   mutex_.unlock();
140 }
141 
142 }  // namespace vts
143 }  // namespace android
144