| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // This file provides a thin binary wrapper around the BattOr Agent | 5 // This file provides a thin binary wrapper around the BattOr Agent |
| 6 // library. This binary wrapper provides a means for non-C++ tracing | 6 // library. This binary wrapper provides a means for non-C++ tracing |
| 7 // controllers, such as Telemetry and Android Systrace, to issue high-level | 7 // controllers, such as Telemetry and Android Systrace, to issue high-level |
| 8 // tracing commands to the BattOr.. | 8 // tracing commands to the BattOr through an interactive shell. |
| 9 // |
| 10 // Example usage of how an external trace controller might use this binary: |
| 11 // |
| 12 // 1) Telemetry's PowerTracingAgent is told to start recording power samples |
| 13 // 2) PowerTracingAgent opens up a BattOr agent binary subprocess |
| 14 // 3) PowerTracingAgent sends the subprocess the StartTracing message via |
| 15 // STDIN |
| 16 // 4) PowerTracingAgent waits for the subprocess to write a line to STDOUT |
| 17 // ('Done.' if successful, some error message otherwise) |
| 18 // 5) If the last command was successful, PowerTracingAgent waits for the |
| 19 // duration of the trace |
| 20 // 6) When the tracing should end, PowerTracingAgent records the clock sync |
| 21 // start timestamp and sends the subprocess the RecordClockSyncMark <marker>' |
| 22 // message via STDIN. |
| 23 // 7) PowerTracingAgent waits for the subprocess to write a line to STDOUT |
| 24 // ('Done.' if successful, some error message otherwise) |
| 25 // 8) If the last command was successful, PowerTracingAgent records the clock |
| 26 // sync end timestamp and sends the subprocess the StopTracing message via |
| 27 // STDIN |
| 28 // 9) PowerTracingAgent continues to read trace output lines from STDOUT until |
| 29 // the binary exits with an exit code of 1 (indicating failure) or the |
| 30 // 'Done.' line is printed to STDOUT, signaling the last line of the trace |
| 31 // 10) PowerTracingAgent returns the battery trace to the Telemetry trace |
| 32 // controller |
| 9 | 33 |
| 10 #include <stdint.h> | 34 #include <stdint.h> |
| 11 | 35 |
| 12 #include <iostream> | 36 #include <iostream> |
| 13 | 37 |
| 14 #include "base/at_exit.h" | 38 #include "base/at_exit.h" |
| 15 #include "base/bind.h" | 39 #include "base/bind.h" |
| 16 #include "base/bind_helpers.h" | 40 #include "base/bind_helpers.h" |
| 17 #include "base/command_line.h" | 41 #include "base/command_line.h" |
| 18 #include "base/location.h" | 42 #include "base/location.h" |
| 19 #include "base/logging.h" | 43 #include "base/logging.h" |
| 20 #include "base/strings/utf_string_conversions.h" | 44 #include "base/strings/utf_string_conversions.h" |
| 21 #include "base/threading/thread.h" | 45 #include "base/threading/thread.h" |
| 22 #include "tools/battor_agent/battor_agent.h" | 46 #include "tools/battor_agent/battor_agent.h" |
| 23 #include "tools/battor_agent/battor_error.h" | 47 #include "tools/battor_agent/battor_error.h" |
| 24 #include "tools/battor_agent/battor_finder.h" | 48 #include "tools/battor_agent/battor_finder.h" |
| 25 | 49 |
| 26 using std::cout; | |
| 27 using std::endl; | 50 using std::endl; |
| 28 | 51 |
| 29 namespace { | 52 namespace { |
| 30 | 53 |
| 31 const char kIoThreadName[] = "BattOr IO Thread"; | 54 const char kIoThreadName[] = "BattOr IO Thread"; |
| 32 const char kFileThreadName[] = "BattOr File Thread"; | 55 const char kFileThreadName[] = "BattOr File Thread"; |
| 33 const char kUiThreadName[] = "BattOr UI Thread"; | 56 const char kUiThreadName[] = "BattOr UI Thread"; |
| 34 const int32_t kBattOrCommandTimeoutSeconds = 10; | 57 const int32_t kBattOrCommandTimeoutSeconds = 10; |
| 35 | 58 |
| 36 void PrintUsage() { | 59 const char kUsage[] = |
| 37 cout << "Usage: battor_agent <command> <arguments> <switches>" << endl | 60 "Start the battor_agent shell with:\n" |
| 38 << endl | 61 "\n" |
| 39 << "Commands:" << endl | 62 " battor_agent <switches>\n" |
| 40 << endl | 63 "\n" |
| 41 << " StartTracing" << endl | 64 "Switches: \n" |
| 42 << " StopTracing" << endl | 65 " --battor-path=<path> Uses the specified BattOr path.\n" |
| 43 << " SupportsExplicitClockSync" << endl | 66 "\n" |
| 44 << " RecordClockSyncMarker <marker>" << endl | 67 "Once in the shell, you can issue the following commands:\n" |
| 45 << " IssueClockSyncMarker" << endl | 68 "\n" |
| 46 << " Help" << endl | 69 " StartTracing\n" |
| 47 << endl | 70 " StopTracing\n" |
| 48 << "Switches:" << endl | 71 " SupportsExplicitClockSync\n" |
| 49 << endl | 72 " RecordClockSyncMarker <marker>\n" |
| 50 << " --battor-path=<path> Uses the specified BattOr path." << endl; | 73 " Exit\n" |
| 51 } | 74 " Help\n" |
| 75 "\n"; |
| 52 | 76 |
| 53 void PrintSupportsExplicitClockSync() { | 77 void PrintSupportsExplicitClockSync() { |
| 54 cout << battor::BattOrAgent::SupportsExplicitClockSync() << endl; | 78 std::cout << battor::BattOrAgent::SupportsExplicitClockSync() << endl; |
| 55 } | |
| 56 | |
| 57 // Retrieves argument argnum from the argument list, or an empty string if the | |
| 58 // argument doesn't exist. | |
| 59 std::string GetArg(size_t argnum, base::CommandLine::StringVector args) { | |
| 60 if (argnum >= args.size()) { | |
| 61 return std::string(); | |
| 62 } | |
| 63 | |
| 64 #if defined(OS_WIN) | |
| 65 return base::WideToUTF8(args[argnum]); | |
| 66 #else | |
| 67 return args[argnum]; | |
| 68 #endif | |
| 69 } | 79 } |
| 70 | 80 |
| 71 // Checks if an error occurred and, if it did, prints the error and exits | 81 // Checks if an error occurred and, if it did, prints the error and exits |
| 72 // with an error code. | 82 // with an error code. |
| 73 void CheckError(battor::BattOrError error) { | 83 void CheckError(battor::BattOrError error) { |
| 74 if (error != battor::BATTOR_ERROR_NONE) | 84 if (error != battor::BATTOR_ERROR_NONE) |
| 75 LOG(FATAL) << "Fatal error when communicating with the BattOr: " << error; | 85 LOG(FATAL) << "Fatal error when communicating with the BattOr: " << error; |
| 76 } | 86 } |
| 77 | 87 |
| 78 // Prints an error message and exits due to a required thread failing to start. | 88 // Prints an error message and exits due to a required thread failing to start. |
| (...skipping 10 matching lines...) Expand all Loading... |
| 89 class BattOrAgentBin : public BattOrAgent::Listener { | 99 class BattOrAgentBin : public BattOrAgent::Listener { |
| 90 public: | 100 public: |
| 91 BattOrAgentBin() | 101 BattOrAgentBin() |
| 92 : done_(false, false), | 102 : done_(false, false), |
| 93 io_thread_(kIoThreadName), | 103 io_thread_(kIoThreadName), |
| 94 file_thread_(kFileThreadName), | 104 file_thread_(kFileThreadName), |
| 95 ui_thread_(kUiThreadName) {} | 105 ui_thread_(kUiThreadName) {} |
| 96 | 106 |
| 97 ~BattOrAgentBin() { DCHECK(!agent_); } | 107 ~BattOrAgentBin() { DCHECK(!agent_); } |
| 98 | 108 |
| 99 // Runs the BattOr binary and returns the exit code. | 109 // Starts the interactive BattOr agent shell and eventually returns an exit |
| 110 // code. |
| 100 int Run(int argc, char* argv[]) { | 111 int Run(int argc, char* argv[]) { |
| 101 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); | |
| 102 std::string cmd = GetArg(0, command_line->GetArgs()); | |
| 103 if (cmd.empty()) { | |
| 104 PrintUsage(); | |
| 105 exit(1); | |
| 106 } | |
| 107 | |
| 108 // SupportsExplicitClockSync doesn't need to use the serial connection, so | |
| 109 // handle it separately. | |
| 110 if (cmd == "SupportsExplicitClockSync") { | |
| 111 PrintSupportsExplicitClockSync(); | |
| 112 return 0; | |
| 113 } | |
| 114 | |
| 115 // If we don't have any BattOr to use, exit. | 112 // If we don't have any BattOr to use, exit. |
| 116 std::string path = BattOrFinder::FindBattOr(); | 113 std::string path = BattOrFinder::FindBattOr(); |
| 117 if (path.empty()) { | 114 if (path.empty()) { |
| 118 cout << "Unable to find a BattOr." << endl; | 115 std::cout << "Unable to find a BattOr." << endl; |
| 119 exit(1); | 116 exit(1); |
| 120 } | 117 } |
| 121 | 118 |
| 122 SetUp(path); | 119 SetUp(path); |
| 123 | 120 |
| 124 if (cmd == "StartTracing") { | 121 std::string cmd; |
| 125 StartTracing(); | 122 for (;;) { |
| 126 } else if (cmd == "StopTracing") { | 123 std::getline(std::cin, cmd); |
| 127 StopTracing(); | 124 |
| 128 } else if (cmd == "RecordClockSyncMarker") { | 125 if (cmd == "StartTracing") { |
| 129 // TODO(charliea): Write RecordClockSyncMarker. | 126 StartTracing(); |
| 130 } else if (cmd == "IssueClockSyncMarker") { | 127 } else if (cmd == "StopTracing") { |
| 131 // TODO(charliea): Write IssueClockSyncMarker. | 128 StopTracing(); |
| 132 } else { | 129 break; |
| 133 TearDown(); | 130 } else if (cmd == "SupportsExplicitClockSync") { |
| 134 PrintUsage(); | 131 PrintSupportsExplicitClockSync(); |
| 135 return 1; | 132 } else if (cmd == "RecordClockSyncMarker") { |
| 133 // TODO(charliea): Write RecordClockSyncMarker. |
| 134 } else if (cmd == "Exit") { |
| 135 break; |
| 136 } else { |
| 137 std::cout << kUsage << endl; |
| 138 } |
| 136 } | 139 } |
| 137 | 140 |
| 138 TearDown(); | 141 TearDown(); |
| 139 return 0; | 142 return 0; |
| 140 } | 143 } |
| 141 | 144 |
| 142 // Performs any setup necessary for the BattOr binary to run. | 145 // Performs any setup necessary for the BattOr binary to run. |
| 143 void SetUp(const std::string& path) { | 146 void SetUp(const std::string& path) { |
| 144 // TODO(charliea): Investigate whether it's possible to replace this | 147 // TODO(charliea): Investigate whether it's possible to replace this |
| 145 // separate thread with a combination of MessageLoopForIO and RunLoop. | 148 // separate thread with a combination of MessageLoopForIO and RunLoop. |
| (...skipping 19 matching lines...) Expand all Loading... |
| 165 | 168 |
| 166 void StartTracing() { | 169 void StartTracing() { |
| 167 io_thread_.task_runner()->PostTask( | 170 io_thread_.task_runner()->PostTask( |
| 168 FROM_HERE, | 171 FROM_HERE, |
| 169 base::Bind(&BattOrAgent::StartTracing, base::Unretained(agent_.get()))); | 172 base::Bind(&BattOrAgent::StartTracing, base::Unretained(agent_.get()))); |
| 170 CheckError(AwaitResult()); | 173 CheckError(AwaitResult()); |
| 171 } | 174 } |
| 172 | 175 |
| 173 void OnStartTracingComplete(BattOrError error) override { | 176 void OnStartTracingComplete(BattOrError error) override { |
| 174 error_ = error; | 177 error_ = error; |
| 178 std::cout << "Done." << endl; |
| 175 done_.Signal(); | 179 done_.Signal(); |
| 176 } | 180 } |
| 177 | 181 |
| 178 void StopTracing() { | 182 void StopTracing() { |
| 179 io_thread_.task_runner()->PostTask( | 183 io_thread_.task_runner()->PostTask( |
| 180 FROM_HERE, | 184 FROM_HERE, |
| 181 base::Bind(&BattOrAgent::StopTracing, base::Unretained(agent_.get()))); | 185 base::Bind(&BattOrAgent::StopTracing, base::Unretained(agent_.get()))); |
| 182 CheckError(AwaitResult()); | 186 CheckError(AwaitResult()); |
| 183 } | 187 } |
| 184 | 188 |
| 185 void OnStopTracingComplete(const std::string& trace, | 189 void OnStopTracingComplete(const std::string& trace, |
| 186 BattOrError error) override { | 190 BattOrError error) override { |
| 187 error_ = error; | 191 error_ = error; |
| 188 | 192 |
| 189 if (error == BATTOR_ERROR_NONE) | 193 if (error == BATTOR_ERROR_NONE) |
| 190 cout << trace << endl; | 194 std::cout << trace; |
| 195 |
| 196 std::cout << "Done." << endl; |
| 191 | 197 |
| 192 done_.Signal(); | 198 done_.Signal(); |
| 193 } | 199 } |
| 194 | 200 |
| 195 void OnRecordClockSyncMarkerComplete(BattOrError error) override { | 201 void OnRecordClockSyncMarkerComplete(BattOrError error) override { |
| 196 // TODO(charliea): Implement RecordClockSyncMarker for this binary. This | 202 // TODO(charliea): Implement RecordClockSyncMarker for this binary. This |
| 197 // will probably involve reading an external file for the actual sample | 203 // will probably involve reading an external file for the actual sample |
| 198 // number to clock sync ID map. | 204 // number to clock sync ID map. |
| 199 NOTREACHED(); | 205 NOTREACHED(); |
| 200 } | 206 } |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 255 }; | 261 }; |
| 256 | 262 |
| 257 } // namespace battor | 263 } // namespace battor |
| 258 | 264 |
| 259 int main(int argc, char* argv[]) { | 265 int main(int argc, char* argv[]) { |
| 260 base::AtExitManager exit_manager; | 266 base::AtExitManager exit_manager; |
| 261 base::CommandLine::Init(argc, argv); | 267 base::CommandLine::Init(argc, argv); |
| 262 battor::BattOrAgentBin bin; | 268 battor::BattOrAgentBin bin; |
| 263 return bin.Run(argc, argv); | 269 return bin.Run(argc, argv); |
| 264 } | 270 } |
| OLD | NEW |