blob: 361afb4afb6df84da7ccd17ab0daef52795188d5 [file]
/*
* Copyright (C) 2026 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 "src/trace_processor/shell/convert_helpers.h"
#include <cstdint>
#include <ios>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>
#include "perfetto/base/build_config.h"
#include "perfetto/base/logging.h"
#include "perfetto/ext/base/utils.h"
#include "src/protozero/text_to_proto/text_to_proto.h"
#include "src/traceconv/android_extension.descriptor.h"
#include "src/traceconv/trace.descriptor.h"
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
#include <fcntl.h>
#include <io.h>
#endif
namespace perfetto::trace_processor::shell {
base::Status OpenConversionInput(const std::string& path,
std::ifstream* owned_file,
std::istream** out_stream) {
if (!path.empty() && path != "-") {
owned_file->open(path, std::ios_base::in | std::ios_base::binary);
if (!owned_file->is_open())
return base::ErrStatus("Could not open %s", path.c_str());
*out_stream = owned_file;
return base::OkStatus();
}
if (base::IsTty(stdin)) {
return base::ErrStatus(
"Reading from stdin but it's connected to a TTY. Either pass a file "
"path on the command line or pipe data into stdin.");
}
*out_stream = &std::cin;
return base::OkStatus();
}
base::Status OpenConversionOutput(const std::string& path,
bool binary_output,
std::ofstream* owned_file,
std::ostream** out_stream) {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
// We don't want the runtime to replace "\n" with "\r\n" on `std::cout`.
_setmode(_fileno(stdout), _O_BINARY);
#endif
if (!path.empty() && path != "-") {
owned_file->open(path, std::ios_base::out | std::ios_base::trunc |
std::ios_base::binary);
if (!owned_file->is_open())
return base::ErrStatus("Could not open %s", path.c_str());
*out_stream = owned_file;
return base::OkStatus();
}
if (binary_output && base::IsTty(stdout)) {
return base::ErrStatus(
"Refusing to write binary output to stdout as it's connected to a TTY "
"(this would corrupt your terminal). Either pass an output file path "
"on the command line or redirect stdout to a file or pipe.");
}
*out_stream = &std::cout;
return base::OkStatus();
}
int TextToTrace(std::istream* input, std::ostream* output) {
std::string trace_text(std::istreambuf_iterator<char>{*input},
std::istreambuf_iterator<char>{});
std::vector<uint8_t> descriptors;
descriptors.reserve(kTraceDescriptor.size() +
kAndroidExtensionDescriptor.size());
descriptors.insert(descriptors.end(), kTraceDescriptor.begin(),
kTraceDescriptor.end());
descriptors.insert(descriptors.end(), kAndroidExtensionDescriptor.begin(),
kAndroidExtensionDescriptor.end());
auto proto_status =
protozero::TextToProto(descriptors.data(), descriptors.size(),
".perfetto.protos.Trace", "trace", trace_text);
if (!proto_status.ok()) {
PERFETTO_ELOG("Failed to parse trace: %s",
proto_status.status().c_message());
return 1;
}
const std::vector<uint8_t>& trace_proto = proto_status.value();
output->write(reinterpret_cast<const char*>(trace_proto.data()),
static_cast<int64_t>(trace_proto.size()));
return 0;
}
} // namespace perfetto::trace_processor::shell