| /* |
| * Copyright (C) 2018 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. |
| */ |
| |
| #ifndef SRC_PERFETTO_CMD_PERFETTO_CMD_H_ |
| #define SRC_PERFETTO_CMD_PERFETTO_CMD_H_ |
| |
| #include <cstdint> |
| #include <functional> |
| #include <list> |
| #include <memory> |
| #include <optional> |
| #include <string> |
| #include <vector> |
| |
| #include "perfetto/base/build_config.h" |
| #include "perfetto/ext/base/event_fd.h" |
| #include "perfetto/ext/base/pipe.h" |
| #include "perfetto/ext/base/scoped_file.h" |
| #include "perfetto/ext/base/thread_task_runner.h" |
| #include "perfetto/ext/base/unix_task_runner.h" |
| #include "perfetto/ext/base/uuid.h" |
| #include "perfetto/ext/base/weak_ptr.h" |
| #include "perfetto/ext/tracing/core/basic_types.h" |
| #include "perfetto/ext/tracing/core/consumer.h" |
| #include "perfetto/ext/tracing/ipc/consumer_ipc_client.h" |
| #include "perfetto/tracing/core/forward_decls.h" |
| #include "src/android_stats/perfetto_atoms.h" |
| #include "src/perfetto_cmd/packet_writer.h" |
| |
| namespace perfetto { |
| |
| // Directory for local state and temporary files. This is automatically |
| // created by the system by setting setprop persist.traced.enable=1. |
| extern const char* kStateDir; |
| |
| class PerfettoCmd : public Consumer { |
| public: |
| PerfettoCmd(); |
| ~PerfettoCmd() override; |
| |
| // The main() is split in two stages: cmdline parsing and actual interaction |
| // with traced. This is to allow tools like tracebox to avoid spawning the |
| // service for no reason if the cmdline parsing fails. |
| // Return value: |
| // std::nullopt: no error, the caller should call |
| // ConnectToServiceRunAndMaybeNotify. |
| // 0-N: the caller should exit() with the given exit code. |
| std::optional<int> ParseCmdlineAndMaybeDaemonize(int argc, char** argv); |
| int ConnectToServiceRunAndMaybeNotify(); |
| |
| // perfetto::Consumer implementation. |
| void OnConnect() override; |
| void OnDisconnect() override; |
| void OnTracingDisabled(const std::string& error) override; |
| void OnTraceData(std::vector<TracePacket>, bool has_more) override; |
| void OnDetach(bool) override; |
| void OnAttach(bool, const TraceConfig&) override; |
| void OnTraceStats(bool, const TraceStats&) override; |
| void OnObservableEvents(const ObservableEvents&) override; |
| void OnSessionCloned(const OnSessionClonedArgs&) override; |
| |
| void SignalCtrlC() { ctrl_c_evt_.Notify(); } |
| |
| private: |
| enum CloneThreadMode { kSingleExtraThread, kNewThreadPerRequest }; |
| |
| bool OpenOutputFile(); |
| void SetupCtrlCSignalHandler(); |
| void FinalizeTraceAndExit(); |
| void PrintUsage(const char* argv0); |
| void PrintServiceState(bool success, const TracingServiceState&); |
| void CloneAllBugreportTraces(bool success, const TracingServiceState&); |
| void CloneSessionOnThread(TracingSessionID, |
| const std::string& cmdline, // \0 separated. |
| CloneThreadMode, |
| std::string clone_trigger_name, |
| std::function<void()> on_clone_callback); |
| void OnTimeout(); |
| bool is_detach() const { return !detach_key_.empty(); } |
| bool is_attach() const { return !attach_key_.empty(); } |
| bool is_clone() const { |
| return clone_tsid_.has_value() || !clone_name_.empty(); |
| } |
| |
| // Once we call ReadBuffers we expect one or more calls to OnTraceData |
| // with the last call having |has_more| set to false. However we should |
| // gracefully handle the service failing to ever call OnTraceData or |
| // setting |has_more| incorrectly. To do this we maintain a timeout |
| // which finalizes and exits the client if we don't receive OnTraceData |
| // within OnTraceDataTimeoutMs of when we expected to. |
| void CheckTraceDataTimeout(); |
| |
| int ConnectToServiceAndRun(); |
| |
| void ReadbackTraceDataAndQuit(const std::string& error); |
| |
| enum BgProcessStatus : char { |
| kBackgroundOk = 0, |
| kBackgroundOtherError = 1, |
| kBackgroundTimeout = 2, |
| }; |
| |
| // Used to implement the --background-wait flag. |
| // |
| // Waits (up to 30s) for the child process to signal (success or an error). |
| // |
| // Returns the status received from the child process or kTimeout, in case of |
| // timeout. |
| BgProcessStatus WaitOnBgProcessPipe(); |
| |
| // Used to implement the --background-wait flag. |
| // |
| // Signals the parent process (if there is one) that it can exit (successfully |
| // or with an error). |
| // |
| // Only the first time this function is called is significant. Further calls |
| // will have no effect. |
| void NotifyBgProcessPipe(BgProcessStatus status); |
| |
| void OnCloneSnapshotTriggerReceived(TracingSessionID, |
| std::string trigger_name); |
| |
| #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) |
| static base::ScopedFile CreateUnlinkedTmpFile(); |
| void SaveTraceIntoIncidentOrCrash(); |
| void SaveOutputToIncidentTraceOrCrash(); |
| void ReportTraceToAndroidFrameworkOrCrash(); |
| #endif |
| void LogUploadEvent(PerfettoStatsdAtom atom); |
| void LogUploadEvent(PerfettoStatsdAtom atom, const std::string& trigger_name); |
| void LogTriggerEvents(PerfettoTriggerAtom atom, |
| const std::vector<std::string>& trigger_names); |
| |
| base::UnixTaskRunner task_runner_; |
| |
| std::unique_ptr<perfetto::TracingService::ConsumerEndpoint> |
| consumer_endpoint_; |
| std::unique_ptr<TraceConfig> trace_config_; |
| std::optional<PacketWriter> packet_writer_; |
| base::ScopedFstream trace_out_stream_; |
| std::vector<std::string> triggers_to_activate_; |
| std::string trace_out_path_; |
| base::EventFd ctrl_c_evt_; |
| bool ctrl_c_handler_installed_ = false; |
| base::Pipe background_wait_pipe_; |
| bool save_to_incidentd_ = false; |
| bool report_to_android_framework_ = false; |
| bool statsd_logging_ = false; |
| bool tracing_succeeded_ = false; |
| uint64_t bytes_written_ = 0; |
| std::string detach_key_; |
| std::string attach_key_; |
| bool stop_trace_once_attached_ = false; |
| bool redetach_once_attached_ = false; |
| bool query_service_ = false; |
| bool query_service_output_raw_ = false; |
| bool query_service_long_ = false; |
| bool clone_all_bugreport_traces_ = false; |
| bool bugreport_ = false; |
| bool background_ = false; |
| bool background_wait_ = false; |
| bool ignore_guardrails_ = false; |
| bool upload_flag_ = false; |
| bool connected_ = false; |
| std::string uuid_; |
| std::optional<TracingSessionID> clone_tsid_{}; |
| std::string clone_name_; |
| bool clone_for_bugreport_ = false; |
| std::function<void()> on_session_cloned_; |
| |
| // How long we expect to trace for or 0 if the trace is indefinite. |
| uint32_t expected_duration_ms_ = 0; |
| bool trace_data_timeout_armed_ = false; |
| |
| // The aux threads used to invoke secondary instances of PerfettoCmd to create |
| // snapshots. This is used only when the trace config involves a |
| // CLONE_SNAPSHOT trigger or when using --save-all-for-bugreport. |
| std::list<base::ThreadTaskRunner> snapshot_threads_; |
| int snapshot_count_ = 0; |
| std::string snapshot_config_; |
| std::string snapshot_trigger_name_; |
| |
| base::WeakPtrFactory<PerfettoCmd> weak_factory_{this}; |
| }; |
| |
| } // namespace perfetto |
| |
| #endif // SRC_PERFETTO_CMD_PERFETTO_CMD_H_ |