2222#include < functional>
2323#include < memory>
2424#include < string>
25+ #include < utility>
2526#include < vector>
2627
2728#include < fmt/core.h>
2829
30+ #include " android-base/file.h"
31+ #include " android-base/logging.h"
2932#include " cuttlefish/common/libs/utils/files.h"
3033#include " cuttlefish/common/libs/utils/flag_parser.h"
3134#include " cuttlefish/common/libs/utils/result.h"
3740#include " cuttlefish/host/commands/cvd/cli/selector/selector.h"
3841#include " cuttlefish/host/commands/cvd/cli/types.h"
3942#include " cuttlefish/host/commands/cvd/cli/utils.h"
43+ #include " cuttlefish/host/commands/cvd/instances/instance_group_record.h"
4044#include " cuttlefish/host/commands/cvd/instances/instance_manager.h"
4145#include " cuttlefish/host/commands/cvd/utils/common.h"
46+ #include " cuttlefish/host/libs/zip/zip_cc.h"
47+ #include " cuttlefish/host/libs/zip/zip_file.h"
4248
4349namespace cuttlefish {
4450namespace {
4551
4652constexpr char kSummaryHelpText [] =
4753 " Run cvd bugreport --help for command description" ;
4854
55+ // Accepts a copy of the args to not modify the original.
56+ Result<std::string> OutputFileFromArgs (cvd_common::Args args) {
57+ // This flag must match the one defined in
58+ // //cuttlefish/host/commands/host_bugreport/main.cc
59+ std::string output = " host_bugreport.zip" ;
60+ std::vector<Flag> flags = {
61+ GflagsCompatFlag (" output" , output),
62+ };
63+ CF_EXPECT (ConsumeFlags (flags, args));
64+ return output;
65+ }
66+
67+ Result<void > AddFetchLogIfPresent (const LocalInstanceGroup& instance_group,
68+ const std::string& output_file) {
69+ std::string fetch_log_path = instance_group.ProductOutPath () + " /fetch.log" ;
70+ if (!FileExists (fetch_log_path)) {
71+ // The fetch log is in the parent of the host artifacts path when cvd create
72+ // --config_file was used.
73+ fetch_log_path =
74+ android::base::Dirname (instance_group.HostArtifactsPath ()) +
75+ " /fetch.log" ;
76+ }
77+ if (!FileExists (fetch_log_path)) {
78+ // There will be no fetch log when running from local sources
79+ return {};
80+ }
81+ LOG (INFO) << " Attaching fetch.log to report" ;
82+ WritableZip archive = CF_EXPECT (ZipOpenReadWrite (output_file));
83+ CF_EXPECT (AddFileAt (archive, fetch_log_path, " fetch.log" ));
84+ CF_EXPECT (WritableZip::Finalize (std::move (archive)));
85+ return {};
86+ }
87+
4988class CvdBugreportCommandHandler : public CvdCommandHandler {
5089 public:
5190 CvdBugreportCommandHandler (InstanceManager& instance_manager);
5291
5392 Result<void > Handle (const CommandRequest& request) override ;
93+ Result<void > HandleHelp (const cvd_common::Envs& env,
94+ const cvd_common::Args& cmd_args,
95+ const CommandRequest& request);
5496 cvd_common::Args CmdList () const override ;
5597 Result<std::string> SummaryHelp () const override ;
5698 bool ShouldInterceptHelp () const override ;
@@ -77,19 +119,24 @@ Result<void> CvdBugreportCommandHandler::Handle(const CommandRequest& request) {
77119
78120 std::string android_host_out;
79121 std::string home = CF_EXPECT (SystemWideUserHome ());
80- if (!CF_EXPECT (HasHelpFlag (cmd_args))) {
81- bool has_instance_groups = CF_EXPECT (instance_manager_.HasInstanceGroups ());
82- CF_EXPECTF (!!has_instance_groups, " {}" , NoGroupMessage (request));
83-
84- auto instance_group =
85- CF_EXPECT (selector::SelectGroup (instance_manager_, request));
86- android_host_out = instance_group.HostArtifactsPath ();
87- home = instance_group.HomeDir ();
88- env[" HOME" ] = home;
89- env[kAndroidHostOut ] = android_host_out;
90- } else {
91- android_host_out = CF_EXPECT (AndroidHostPath (env));
122+
123+ if (CF_EXPECT (HasHelpFlag (cmd_args))) {
124+ CF_EXPECT (HandleHelp (env, cmd_args, request));
125+ return {};
92126 }
127+
128+ std::string output_file =
129+ CF_EXPECT (OutputFileFromArgs (cmd_args), " Failed to parse output flag" );
130+
131+ bool has_instance_groups = CF_EXPECT (instance_manager_.HasInstanceGroups ());
132+ CF_EXPECTF (!!has_instance_groups, " {}" , NoGroupMessage (request));
133+
134+ auto instance_group =
135+ CF_EXPECT (selector::SelectGroup (instance_manager_, request));
136+ android_host_out = instance_group.HostArtifactsPath ();
137+ home = instance_group.HomeDir ();
138+ env[" HOME" ] = home;
139+ env[kAndroidHostOut ] = android_host_out;
93140 auto bin_path = ConcatToString (android_host_out, " /bin/" , kHostBugreportBin );
94141
95142 ConstructCommandParam construct_cmd_param{.bin_path = bin_path,
@@ -100,11 +147,32 @@ Result<void> CvdBugreportCommandHandler::Handle(const CommandRequest& request) {
100147 .command_name = kHostBugreportBin };
101148 Command command = CF_EXPECT (ConstructCommand (construct_cmd_param));
102149
150+ // Wait for the command to finish but ignore the result. The command will fail
151+ // for reasons like the device failing to initialize the home directory or
152+ // errors during fetch, which are still debuggable states that require a
153+ // report.
154+ (void )command.Start ().Wait ();
155+
156+ auto result = AddFetchLogIfPresent (instance_group, output_file);
157+ if (!result.ok ()) {
158+ LOG (ERROR) << " Failed to add fetch log to bugreport: "
159+ << result.error ().FormatForEnv ();
160+ }
161+
162+ return {};
163+ }
164+
165+ Result<void > CvdBugreportCommandHandler::HandleHelp (
166+ const cvd_common::Envs& env, const cvd_common::Args& cmd_args,
167+ const CommandRequest& request) {
168+ std::string android_host_out = CF_EXPECT (AndroidHostPath (env));
169+ Command command = CF_EXPECT (
170+ ConstructCvdHelpCommand (kHostBugreportBin , env, cmd_args, request));
171+
103172 siginfo_t infop; // NOLINT(misc-include-cleaner)
104173 command.Start ().Wait (&infop, WEXITED);
105174
106175 CF_EXPECT (CheckProcessExitedNormally (infop));
107-
108176 return {};
109177}
110178
0 commit comments