1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef FRAMEWORK_NATIVE_CMD_DUMPSTATE_H_ 18 #define FRAMEWORK_NATIVE_CMD_DUMPSTATE_H_ 19 20 #include <time.h> 21 #include <unistd.h> 22 #include <stdbool.h> 23 #include <stdio.h> 24 25 #include <string> 26 #include <vector> 27 28 #include <aidl/android/hardware/dumpstate/IDumpstateDevice.h> 29 #include <android-base/macros.h> 30 #include <android-base/unique_fd.h> 31 #include <android/hardware/dumpstate/1.1/types.h> 32 #include <android/os/BnIncidentAuthListener.h> 33 #include <android/os/IDumpstate.h> 34 #include <android/os/IDumpstateListener.h> 35 #include <utils/StrongPointer.h> 36 #include <ziparchive/zip_writer.h> 37 38 #include "DumpstateUtil.h" 39 #include "DumpPool.h" 40 #include "TaskQueue.h" 41 42 // TODO: move everything under this namespace 43 // TODO: and then remove explicitly android::os::dumpstate:: prefixes 44 namespace android { 45 namespace os { 46 47 struct DumpstateOptions; 48 49 namespace dumpstate { 50 51 class DumpstateTest; 52 class ProgressTest; 53 class ZippedBugReportStreamTest; 54 55 } // namespace dumpstate 56 } // namespace os 57 } // namespace android 58 59 class ZipWriter; 60 61 // TODO: remove once moved to HAL 62 #ifdef __cplusplus 63 extern "C" { 64 #endif 65 66 /* 67 * Helper class used to report how long it takes for a section to finish. 68 * 69 * Typical usage: 70 * 71 * DurationReporter duration_reporter(title); 72 * 73 */ 74 class DurationReporter { 75 public: 76 explicit DurationReporter(const std::string& title, bool logcat_only = false, 77 bool verbose = false, int duration_fd = STDOUT_FILENO); 78 79 ~DurationReporter(); 80 81 private: 82 std::string title_; 83 bool logcat_only_; 84 bool verbose_; 85 uint64_t started_; 86 int duration_fd_; 87 88 DISALLOW_COPY_AND_ASSIGN(DurationReporter); 89 }; 90 91 /* 92 * Keeps track of current progress and estimated max, saving stats on file to tune up future runs. 93 * 94 * Each `dumpstate` section contributes to the total weight by an individual weight, so the overall 95 * progress can be calculated by dividing the estimate max progress by the current progress. 96 * 97 * The estimated max progress is initially set to a value (`kDefaultMax) defined empirically, but 98 * it's adjusted after each dumpstate run by storing the average duration in a file. 99 * 100 */ 101 class Progress { 102 friend class android::os::dumpstate::ProgressTest; 103 friend class android::os::dumpstate::DumpstateTest; 104 105 public: 106 /* 107 * Default estimation of the max duration of a bugreport generation. 108 * 109 * It does not need to match the exact sum of all sections, but ideally it should to be slight 110 * more than such sum: a value too high will cause the bugreport to finish before the user 111 * expected (for example, jumping from 70% to 100%), while a value too low will cause the 112 * progress to get stuck at an almost-finished value (like 99%) for a while. 113 * 114 * This constant is only used when the average duration from previous runs cannot be used. 115 */ 116 static const int kDefaultMax; 117 118 explicit Progress(const std::string& path = ""); 119 120 // Gets the current progress. 121 int32_t Get() const; 122 123 // Gets the current estimated max progress. 124 int32_t GetMax() const; 125 126 // Gets the initial estimated max progress. 127 int32_t GetInitialMax() const; 128 129 // Increments progress (ignored if not positive). 130 // Returns `true` if the max progress increased as well. 131 bool Inc(int32_t delta); 132 133 // Persist the stats. 134 void Save(); 135 136 void Dump(int fd, const std::string& prefix) const; 137 138 private: 139 Progress(int32_t initial_max, float growth_factor, 140 const std::string& path = ""); // Used by test cases. 141 Progress(int32_t initial_max, int32_t progress, float growth_factor); // Used by test cases. 142 void Load(); 143 int32_t initial_max_; 144 int32_t progress_; 145 int32_t max_; 146 float growth_factor_; 147 int32_t n_runs_; 148 int32_t average_max_; 149 std::string path_; 150 }; 151 152 /* 153 * List of supported zip format versions. 154 * 155 * See bugreport-format.md for more info. 156 */ 157 static std::string VERSION_CURRENT = "2.0"; 158 159 /* 160 * "Alias" for the current version. 161 */ 162 static std::string VERSION_DEFAULT = "default"; 163 164 /* 165 * Directory used by Dumpstate binary to keep its local files. 166 */ 167 static const std::string DUMPSTATE_DIRECTORY = "/bugreports"; 168 169 /* 170 * Structure that contains the information of an open dump file. 171 */ 172 struct DumpData { 173 // Path of the file. 174 std::string name; 175 176 // Open file descriptor for the file. 177 android::base::unique_fd fd; 178 179 // Modification time of the file. 180 time_t mtime; 181 }; 182 183 /* 184 * Main class driving a bugreport generation. 185 * 186 * Currently, it only contains variables that are accessed externally, but gradually the functions 187 * that are spread accross utils.cpp and dumpstate.cpp will be moved to it. 188 */ 189 class Dumpstate { 190 friend class android::os::dumpstate::DumpstateTest; 191 friend class android::os::dumpstate::ZippedBugReportStreamTest; 192 193 public: 194 enum RunStatus { OK, HELP, INVALID_INPUT, ERROR, USER_CONSENT_DENIED, USER_CONSENT_TIMED_OUT }; 195 196 // The mode under which the bugreport should be run. Each mode encapsulates a few options. 197 enum BugreportMode { 198 BUGREPORT_FULL = android::os::IDumpstate::BUGREPORT_MODE_FULL, 199 BUGREPORT_INTERACTIVE = android::os::IDumpstate::BUGREPORT_MODE_INTERACTIVE, 200 BUGREPORT_REMOTE = android::os::IDumpstate::BUGREPORT_MODE_REMOTE, 201 BUGREPORT_WEAR = android::os::IDumpstate::BUGREPORT_MODE_WEAR, 202 BUGREPORT_TELEPHONY = android::os::IDumpstate::BUGREPORT_MODE_TELEPHONY, 203 BUGREPORT_WIFI = android::os::IDumpstate::BUGREPORT_MODE_WIFI, 204 BUGREPORT_ONBOARDING = android::os::IDumpstate::BUGREPORT_MODE_ONBOARDING, 205 BUGREPORT_DEFAULT = android::os::IDumpstate::BUGREPORT_MODE_DEFAULT 206 }; 207 208 // The flags used to customize bugreport requests. 209 enum BugreportFlag { 210 BUGREPORT_USE_PREDUMPED_UI_DATA = 211 android::os::IDumpstate::BUGREPORT_FLAG_USE_PREDUMPED_UI_DATA, 212 BUGREPORT_FLAG_DEFER_CONSENT = 213 android::os::IDumpstate::BUGREPORT_FLAG_DEFER_CONSENT, 214 BUGREPORT_FLAG_KEEP_BUGREPORT_ON_RETRIEVAL = 215 android::os::IDumpstate::BUGREPORT_FLAG_KEEP_BUGREPORT_ON_RETRIEVAL 216 }; 217 218 static android::os::dumpstate::CommandOptions DEFAULT_DUMPSYS; 219 220 static Dumpstate& GetInstance(); 221 222 /* Initialize dumpstate fields before starting bugreport generation */ 223 void Initialize(); 224 225 /* 226 * Forks a command, waits for it to finish, and returns its status. 227 * 228 * |title| description of the command printed on `stdout` (or empty to skip 229 * description). 230 * |full_command| array containing the command (first entry) and its arguments. 231 * Must contain at least one element. 232 * |options| optional argument defining the command's behavior. 233 * |out_fd| A fd to support the DumpPool to output results to a temporary 234 * file. Using STDOUT_FILENO if it's not running in the parallel task. 235 */ 236 int RunCommand(const std::string& title, const std::vector<std::string>& fullCommand, 237 const android::os::dumpstate::CommandOptions& options = 238 android::os::dumpstate::CommandOptions::DEFAULT, 239 bool verbose_duration = false, int out_fd = STDOUT_FILENO); 240 241 /* 242 * Runs `dumpsys` with the given arguments, automatically setting its timeout 243 * (`-T` argument) 244 * according to the command options. 245 * 246 * |title| description of the command printed on `stdout` (or empty to skip 247 * description). 248 * |dumpsys_args| `dumpsys` arguments (except `-t`). 249 * |options| optional argument defining the command's behavior. 250 * |dumpsys_timeout| when > 0, defines the value passed to `dumpsys -T` (otherwise it uses the 251 * timeout from `options`) 252 * |out_fd| A fd to support the DumpPool to output results to a temporary 253 * file. Using STDOUT_FILENO if it's not running in the parallel task. 254 */ 255 void RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsys_args, 256 const android::os::dumpstate::CommandOptions& options = DEFAULT_DUMPSYS, 257 long dumpsys_timeout_ms = 0, int out_fd = STDOUT_FILENO); 258 259 /* 260 * Prints the contents of a file. 261 * 262 * |title| description of the command printed on `stdout` (or empty to skip 263 * description). 264 * |path| location of the file to be dumped. 265 */ 266 int DumpFile(const std::string& title, const std::string& path); 267 268 /* 269 * Adds a new entry to the existing zip file. 270 * */ 271 bool AddZipEntry(const std::string& entry_name, const std::string& entry_path); 272 273 /* 274 * Adds a new entry to the existing zip file. 275 * 276 * |entry_name| destination path of the new entry. 277 * |fd| file descriptor to read from. 278 * |timeout| timeout to terminate the read if not completed. Set 279 * value of 0s (default) to disable timeout. 280 */ 281 android::status_t AddZipEntryFromFd(const std::string& entry_name, int fd, 282 std::chrono::milliseconds timeout); 283 284 /* 285 * Adds a text entry to the existing zip file. 286 */ 287 bool AddTextZipEntry(const std::string& entry_name, const std::string& content); 288 289 /* 290 * Adds all files from a directory to the zipped bugreport file. 291 */ 292 void AddDir(const std::string& dir, bool recursive); 293 294 /* 295 * Takes a screenshot and save it to the given `path`. 296 * 297 * If `path` is empty, uses a standard path based on the bugreport name. 298 */ 299 void TakeScreenshot(const std::string& path = ""); 300 301 ///////////////////////////////////////////////////////////////////// 302 // TODO: members below should be private once refactor is finished // 303 ///////////////////////////////////////////////////////////////////// 304 305 // TODO: temporary method until Dumpstate object is properly set 306 void SetProgress(std::unique_ptr<Progress> progress); 307 308 // Dumps Dalvik and native stack traces, sets the trace file location to path 309 // if it succeeded. 310 // Note that it returns early if user consent is denied with status USER_CONSENT_DENIED. 311 // Returns OK in all other cases. 312 RunStatus DumpTraces(const char** path); 313 314 /* 315 * |out_fd| A fd to support the DumpPool to output results to a temporary file. 316 * Dumpstate can pick up later and output to the bugreport. Using STDOUT_FILENO 317 * if it's not running in the parallel task. 318 */ 319 void DumpstateBoard(int out_fd = STDOUT_FILENO); 320 321 /* 322 * Updates the overall progress of the bugreport generation by the given weight increment. 323 */ 324 void UpdateProgress(int32_t delta); 325 326 /* Prints the dumpstate header on `stdout`. */ 327 void PrintHeader() const; 328 329 /* 330 * Adds the temporary report to the existing .zip file, closes the .zip file, and removes the 331 * temporary file. 332 */ 333 bool FinishZipFile(); 334 335 /* Constructs a full path inside directory with file name formatted using the given suffix. */ 336 std::string GetPath(const std::string& directory, const std::string& suffix) const; 337 338 /* Constructs a full path inside bugreport_internal_dir_ with file name formatted using the 339 * given suffix. */ 340 std::string GetPath(const std::string& suffix) const; 341 342 /* Returns true if the current version supports priority dump feature. */ 343 bool CurrentVersionSupportsPriorityDumps() const; 344 345 struct DumpOptions; 346 347 /** 348 * Pre-dump critical UI data, e.g. data stored in short ring buffers that might get lost 349 * by the time the actual bugreport is requested. 350 */ 351 void PreDumpUiData(); 352 353 /* 354 * Main entry point for running a complete bugreport. 355 * 356 * Initialize() dumpstate before calling this method. 357 * 358 */ 359 RunStatus Run(int32_t calling_uid, const std::string& calling_package); 360 361 /* 362 * Entry point for retrieving a previous-generated bugreport. 363 * 364 * Initialize() dumpstate before calling this method. 365 */ 366 RunStatus Retrieve(int32_t calling_uid, const std::string& calling_package, 367 const bool keep_bugreport_on_retrieval, const bool skip_user_consent); 368 369 370 371 RunStatus ParseCommandlineAndRun(int argc, char* argv[]); 372 373 /* Deletes in-progress files */ 374 void Cancel(); 375 376 /* Sets runtime options. */ 377 void SetOptions(std::unique_ptr<DumpOptions> options); 378 379 /* 380 * Returns true if user consent is necessary and has been denied. 381 * Consent is only necessary if the caller has asked to copy over the bugreport to a file they 382 * provided. 383 */ 384 bool IsUserConsentDenied() const; 385 386 /* 387 * Returns true if dumpstate is called by bugreporting API 388 */ 389 bool CalledByApi() const; 390 391 /* 392 * Enqueues a task to the dumpstate's TaskQueue if the parallel run is enabled, 393 * otherwise invokes it immediately. The task adds file at path entry_path 394 * as a zip file entry with name entry_name. Unlinks entry_path when done. 395 * 396 * All enqueued tasks will be executed in the dumpstate's FinishZipFile method 397 * before the zip file is finished. Tasks will be cancelled in dumpstate's 398 * ShutdownDumpPool method if they have never been called. 399 */ 400 void EnqueueAddZipEntryAndCleanupIfNeeded(const std::string& entry_name, 401 const std::string& entry_path); 402 403 /* 404 * Structure to hold options that determine the behavior of dumpstate. 405 */ 406 struct DumpOptions { 407 bool do_vibrate = true; 408 // Writes bugreport zipped file to a socket. 409 bool stream_to_socket = false; 410 // Writes generation progress updates to a socket. 411 bool progress_updates_to_socket = false; 412 bool do_screenshot = false; 413 bool is_screenshot_copied = false; 414 bool is_consent_deferred = false; 415 bool skip_user_consent = false; 416 bool is_remote_mode = false; 417 bool show_header_only = false; 418 bool telephony_only = false; 419 bool wifi_only = false; 420 bool onboarding_only = false; 421 // Trimmed-down version of dumpstate to only include whitelisted logs. 422 bool limited_only = false; 423 // Whether progress updates should be published. 424 bool do_progress_updates = false; 425 // this is used to derive dumpstate HAL bug report mode 426 // TODO(b/148168577) get rid of the AIDL values, replace them with the HAL values instead. 427 // The HAL is actually an API surface that can be validated, while the AIDL is not (@hide). 428 BugreportMode bugreport_mode = Dumpstate::BugreportMode::BUGREPORT_DEFAULT; 429 // Will use data collected through a previous call to PreDumpUiData(). 430 bool use_predumped_ui_data; 431 // File descriptor to output zip file. Takes precedence over out_dir. 432 android::base::unique_fd bugreport_fd; 433 // File descriptor to screenshot file. 434 android::base::unique_fd screenshot_fd; 435 // Custom output directory. 436 std::string out_dir; 437 // Bugreport mode of the bugreport as a string 438 std::string bugreport_mode_string; 439 // Command-line arguments as string 440 std::string args; 441 // Notification title and description 442 std::string notification_title; 443 std::string notification_description; 444 445 /* Initializes options from commandline arguments. */ 446 RunStatus Initialize(int argc, char* argv[]); 447 448 /* Initializes options from the requested mode. */ 449 void Initialize(BugreportMode bugreport_mode, int bugreport_flags, 450 const android::base::unique_fd& bugreport_fd, 451 const android::base::unique_fd& screenshot_fd, 452 bool is_screenshot_requested, 453 bool skip_user_consent); 454 455 /* Returns true if the options set so far are consistent. */ 456 bool ValidateOptions() const; 457 458 /* Returns if options specified require writing to custom file location */ OutputToCustomFileDumpOptions459 bool OutputToCustomFile() { 460 // Custom location is only honored in limited mode. 461 return limited_only && !out_dir.empty() && bugreport_fd.get() == -1; 462 } 463 }; 464 465 // TODO: initialize fields on constructor 466 // dumpstate id - unique after each device reboot. 467 uint32_t id_; 468 469 // dumpstate pid 470 pid_t pid_; 471 472 // Runtime options. 473 std::unique_ptr<DumpOptions> options_; 474 475 // Last progress that was sent to the listener [0-100]. 476 int last_reported_percent_progress_ = 0; 477 478 // Whether it should take an screenshot earlier in the process. 479 bool do_early_screenshot_ = false; 480 481 std::unique_ptr<Progress> progress_; 482 483 // When set, defines a socket file-descriptor use to report progress to bugreportz 484 // or to stream the zipped file to. 485 int control_socket_fd_ = -1; 486 487 // Bugreport format version; 488 std::string version_ = VERSION_CURRENT; 489 490 time_t now_; 491 492 // Base name (without suffix or extensions) of the bugreport files, typically 493 // `bugreport-BUILD_ID`. 494 std::string base_name_; 495 496 // Name is the suffix part of the bugreport files - it's typically the date, 497 // but it could be changed by the user.. 498 std::string name_; 499 500 std::string bugreport_internal_dir_ = DUMPSTATE_DIRECTORY; 501 502 // Full path of the temporary file containing the bugreport, inside bugreport_internal_dir_. 503 // At the very end this file is pulled into the zip file. 504 std::string tmp_path_; 505 506 // Full path of the file containing the dumpstate logs, inside bugreport_internal_dir_. 507 // This is useful for debugging. 508 std::string log_path_; 509 510 // Full path of the bugreport zip file inside bugreport_internal_dir_. 511 std::string path_; 512 513 // Full path of the file containing the screenshot (when requested). 514 std::string screenshot_path_; 515 516 // Pointer to the zipped file. 517 std::unique_ptr<FILE, int (*)(FILE*)> zip_file{nullptr, fclose}; 518 519 // Pointer to the zip structure. 520 std::unique_ptr<ZipWriter> zip_writer_; 521 522 // Binder object listening to progress. 523 android::sp<android::os::IDumpstateListener> listener_; 524 525 // List of open tombstone dump files. 526 std::vector<DumpData> tombstone_data_; 527 528 // List of open ANR dump files. 529 std::vector<DumpData> anr_data_; 530 531 // List of open Java traces files in the anr directory. 532 std::vector<DumpData> anr_trace_data_; 533 534 // List of open shutdown checkpoint files. 535 std::vector<DumpData> shutdown_checkpoints_; 536 537 // A thread pool to execute dump tasks simultaneously if the parallel run is enabled. 538 std::unique_ptr<android::os::dumpstate::DumpPool> dump_pool_; 539 540 // A task queue to collect adding zip entry tasks inside dump tasks if the 541 // parallel run is enabled. 542 std::unique_ptr<android::os::dumpstate::TaskQueue> zip_entry_tasks_; 543 544 // A callback to IncidentCompanion service, which checks user consent for sharing the 545 // bugreport with the calling app. If the user has not responded yet to the dialog it will 546 // be neither confirmed nor denied. 547 class ConsentCallback : public android::os::BnIncidentAuthListener { 548 public: 549 ConsentCallback(); 550 android::binder::Status onReportApproved() override; 551 android::binder::Status onReportDenied() override; 552 553 enum ConsentResult { APPROVED, DENIED, UNAVAILABLE }; 554 555 ConsentResult getResult(); 556 557 // Returns the time since creating this listener 558 uint64_t getElapsedTimeMs() const; 559 560 private: 561 ConsentResult result_; 562 uint64_t start_time_; 563 std::mutex lock_; 564 }; 565 566 private: 567 RunStatus RunInternal(int32_t calling_uid, const std::string& calling_package); 568 RunStatus RetrieveInternal(int32_t calling_uid, const std::string& calling_package, 569 const bool keep_bugreport_on_retrieval, 570 const bool skip_user_consent); 571 572 RunStatus DumpstateDefaultAfterCritical(); 573 RunStatus dumpstate(); 574 575 void MaybeTakeEarlyScreenshot(); 576 std::future<std::string> MaybeSnapshotSystemTraceAsync(); 577 void MaybeWaitForSnapshotSystemTrace(std::future<std::string> task); 578 void MaybeSnapshotUiTraces(); 579 void MaybeAddUiTracesToZip(); 580 581 void onUiIntensiveBugreportDumpsFinished(int32_t calling_uid); 582 583 void MaybeCheckUserConsent(int32_t calling_uid, const std::string& calling_package); 584 585 // Removes the in progress files output files (tmp file, zip/txt file, screenshot), 586 // but leaves the log file alone. 587 void CleanupTmpFiles(); 588 589 // Create the thread pool to enable the parallel run function. 590 void EnableParallelRunIfNeeded(); 591 void ShutdownDumpPool(); 592 593 RunStatus HandleUserConsentDenied(); 594 595 void HandleRunStatus(RunStatus status); 596 597 // Copies bugreport artifacts over to the caller's directories provided there is user consent or 598 // called by Shell. 599 RunStatus CopyBugreportIfUserConsented(int32_t calling_uid); 600 601 std::function<int(const char *)> open_socket_fn_; 602 603 // Used by GetInstance() only. 604 explicit Dumpstate(const std::string& version = VERSION_CURRENT); 605 606 android::sp<ConsentCallback> consent_callback_; 607 608 std::recursive_mutex mutex_; 609 610 DISALLOW_COPY_AND_ASSIGN(Dumpstate); 611 }; 612 613 // for_each_pid_func = void (*)(int, const char*); 614 // for_each_tid_func = void (*)(int, int, const char*); 615 616 typedef void(for_each_pid_func)(int, const char*); 617 typedef void(for_each_tid_func)(int, int, const char*); 618 619 /* saves the the contents of a file as a long */ 620 int read_file_as_long(const char *path, long int *output); 621 622 /* prints the contents of the fd 623 * fd must have been opened with the flag O_NONBLOCK. 624 */ 625 int dump_file_from_fd(const char *title, const char *path, int fd); 626 627 /* calls skip to gate calling dump_from_fd recursively 628 * in the specified directory. dump_from_fd defaults to 629 * dump_file_from_fd above when set to NULL. skip defaults 630 * to false when set to NULL. dump_from_fd will always be 631 * called with title NULL. 632 */ 633 int dump_files(const std::string& title, const char* dir, bool (*skip)(const char* path), 634 int (*dump_from_fd)(const char* title, const char* path, int fd)); 635 636 /* 637 * Redirects 'redirect' to a file indicated by 'path', truncating it. 638 * 639 * Returns true if redirect succeeds. 640 */ 641 bool redirect_to_file(FILE* redirect, char* path); 642 643 /* 644 * Redirects 'redirect' to an existing file indicated by 'path', appending it. 645 * 646 * Returns true if redirect succeeds. 647 */ 648 bool redirect_to_existing_file(FILE* redirect, char* path); 649 650 /* create leading directories, if necessary */ 651 void create_parent_dirs(const char *path); 652 653 /* for each process in the system, run the specified function */ 654 void for_each_pid(for_each_pid_func func, const char *header); 655 656 /* for each thread in the system, run the specified function */ 657 void for_each_tid(for_each_tid_func func, const char *header); 658 659 /* Displays a blocked processes in-kernel wait channel */ 660 void show_wchan(int pid, int tid, const char *name); 661 662 /* Displays a processes times */ 663 void show_showtime(int pid, const char *name); 664 665 /* Gets the dmesg output for the kernel */ 666 void do_dmesg(); 667 668 /* Prints the contents of all the routing tables, both IPv4 and IPv6. */ 669 void dump_route_tables(); 670 671 /* Dump subdirectories of cgroupfs if the corresponding process is frozen */ 672 void dump_frozen_cgroupfs(); 673 674 /* Play a sound via Stagefright */ 675 void play_sound(const char *path); 676 677 /* Checks if a given path is a directory. */ 678 bool is_dir(const char* pathname); 679 680 /** Gets the last modification time of a file, or default time if file is not found. */ 681 time_t get_mtime(int fd, time_t default_mtime); 682 683 /** Gets command-line arguments. */ 684 void format_args(int argc, const char *argv[], std::string *args); 685 686 /** Main entry point for dumpstate. */ 687 int run_main(int argc, char* argv[]); 688 689 #ifdef __cplusplus 690 } 691 #endif 692 693 #endif /* FRAMEWORK_NATIVE_CMD_DUMPSTATE_H_ */ 694