/* * Copyright 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "VtsProfilingInterface.h" #include #include #include #include #include #include #include #include #include "VtsProfilingUtil.h" #include "test/vts/proto/VtsDriverControlMessage.pb.h" #include "test/vts/proto/VtsProfilingMessage.pb.h" using namespace std; namespace android { namespace vts { VtsProfilingInterface::VtsProfilingInterface( const string& trace_file_path_prefix) : trace_file_path_prefix_(trace_file_path_prefix) {} VtsProfilingInterface::~VtsProfilingInterface() { mutex_.lock(); for (auto it = trace_map_.begin(); it != trace_map_.end(); ++it) { close(it->second); } mutex_.unlock(); } int64_t VtsProfilingInterface::NanoTime() { std::chrono::nanoseconds duration( std::chrono::steady_clock::now().time_since_epoch()); return static_cast(duration.count()); } VtsProfilingInterface& VtsProfilingInterface::getInstance( const string& trace_file_path_prefix) { static VtsProfilingInterface instance(trace_file_path_prefix); return instance; } int VtsProfilingInterface::GetTraceFile(const string& package, const string& version) { string fullname = package + "@" + version; int fd = -1; if (trace_map_.find(fullname) != trace_map_.end()) { fd = trace_map_[fullname]; struct stat statbuf; fstat(fd, &statbuf); // If file no longer exists or the file descriptor is no longer valid, // create a new trace file. if (statbuf.st_nlink <= 0 || fcntl(fd, F_GETFD) == -1) { fd = CreateTraceFile(package, version); trace_map_[fullname] = fd; } } else { // Create trace file for a new HAL. fd = CreateTraceFile(package, version); trace_map_[fullname] = fd; } return fd; } int VtsProfilingInterface::CreateTraceFile(const string& package, const string& version) { // Attach device info and timestamp for the trace file. char build_number[PROPERTY_VALUE_MAX]; char device_id[PROPERTY_VALUE_MAX]; char product_name[PROPERTY_VALUE_MAX]; property_get("ro.build.version.incremental", build_number, "unknown_build"); property_get("ro.serialno", device_id, "unknown_device"); property_get("ro.build.product", product_name, "unknown_product"); string file_path = trace_file_path_prefix_ + package + "_" + version + "_" + string(product_name) + "_" + string(device_id) + "_" + string(build_number) + "_" + to_string(NanoTime()) + ".vts.trace"; LOG(INFO) << "Creating new trace file: " << file_path; int fd = open(file_path.c_str(), O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (fd < 0) { PLOG(ERROR) << "Can not open trace file: " << file_path; return -1; } return fd; } void VtsProfilingInterface::AddTraceEvent( android::hardware::details::HidlInstrumentor::InstrumentationEvent event, const char* package, const char* version, const char* interface, const FunctionSpecificationMessage& message) { std::string version_str = std::string(version); int version_major = stoi(version_str.substr(0, version_str.find('.'))); int version_minor = stoi(version_str.substr(version_str.find('.') + 1)); // Build the VTSProfilingRecord and print it to string. VtsProfilingRecord record; record.set_timestamp(NanoTime()); record.set_event((InstrumentationEventType) static_cast(event)); record.set_package(package); record.set_version_major(version_major); record.set_version_minor(version_minor); record.set_interface(interface); *record.mutable_func_msg() = message; // Write the record string to trace file. mutex_.lock(); int fd = GetTraceFile(package, version); if (fd == -1) { LOG(ERROR) << "Failed to get trace file."; } else { google::protobuf::io::FileOutputStream trace_output(fd); if (!writeOneDelimited(record, &trace_output)) { LOG(ERROR) << "Failed to write record."; } if (!trace_output.Flush()) { PLOG(ERROR) << "Failed to flush"; } } mutex_.unlock(); } } // namespace vts } // namespace android