scoped_critical_action.mm 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "base/ios/scoped_critical_action.h"
  5. #import <UIKit/UIKit.h>
  6. #include <float.h>
  7. #include "base/ios/ios_util.h"
  8. #include "base/logging.h"
  9. #include "base/memory/ref_counted.h"
  10. #include "base/metrics/histogram_macros.h"
  11. #include "base/metrics/user_metrics.h"
  12. #include "base/strings/string_piece.h"
  13. #include "base/strings/sys_string_conversions.h"
  14. #include "base/synchronization/lock.h"
  15. namespace base {
  16. namespace ios {
  17. ScopedCriticalAction::ScopedCriticalAction(StringPiece task_name)
  18. : core_(MakeRefCounted<ScopedCriticalAction::Core>()) {
  19. ScopedCriticalAction::Core::StartBackgroundTask(core_, task_name);
  20. }
  21. ScopedCriticalAction::~ScopedCriticalAction() {
  22. ScopedCriticalAction::Core::EndBackgroundTask(core_);
  23. }
  24. ScopedCriticalAction::Core::Core()
  25. : background_task_id_(UIBackgroundTaskInvalid) {}
  26. ScopedCriticalAction::Core::~Core() {
  27. DCHECK_EQ(background_task_id_, UIBackgroundTaskInvalid);
  28. }
  29. // This implementation calls |beginBackgroundTaskWithName:expirationHandler:|
  30. // when instantiated and |endBackgroundTask:| when destroyed, creating a scope
  31. // whose execution will continue (temporarily) even after the app is
  32. // backgrounded.
  33. // static
  34. void ScopedCriticalAction::Core::StartBackgroundTask(scoped_refptr<Core> core,
  35. StringPiece task_name) {
  36. UIApplication* application = [UIApplication sharedApplication];
  37. if (!application) {
  38. return;
  39. }
  40. AutoLock lock_scope(core->background_task_id_lock_);
  41. NSString* task_string =
  42. !task_name.empty() ? base::SysUTF8ToNSString(task_name) : nil;
  43. core->background_task_id_ = [application
  44. beginBackgroundTaskWithName:task_string
  45. expirationHandler:^{
  46. DLOG(WARNING)
  47. << "Background task with name <"
  48. << base::SysNSStringToUTF8(task_string) << "> and with "
  49. << "id " << core->background_task_id_ << " expired.";
  50. // Note if |endBackgroundTask:| is not called for each task
  51. // before time expires, the system kills the application.
  52. EndBackgroundTask(core);
  53. }];
  54. if (core->background_task_id_ == UIBackgroundTaskInvalid) {
  55. DLOG(WARNING) << "beginBackgroundTaskWithName:<" << task_name << "> "
  56. << "expirationHandler: returned an invalid ID";
  57. } else {
  58. VLOG(3) << "Beginning background task <" << task_name << "> with id "
  59. << core->background_task_id_;
  60. }
  61. }
  62. // static
  63. void ScopedCriticalAction::Core::EndBackgroundTask(scoped_refptr<Core> core) {
  64. UIBackgroundTaskIdentifier task_id;
  65. {
  66. AutoLock lock_scope(core->background_task_id_lock_);
  67. if (core->background_task_id_ == UIBackgroundTaskInvalid) {
  68. return;
  69. }
  70. task_id =
  71. static_cast<UIBackgroundTaskIdentifier>(core->background_task_id_);
  72. core->background_task_id_ = UIBackgroundTaskInvalid;
  73. }
  74. VLOG(3) << "Ending background task with id " << task_id;
  75. [[UIApplication sharedApplication] endBackgroundTask:task_id];
  76. }
  77. } // namespace ios
  78. } // namespace base