diff options
-rw-r--r-- | base/base.gypi | 4 | ||||
-rw-r--r-- | base/critical_closure.h | 37 | ||||
-rw-r--r-- | base/critical_closure_ios.mm | 52 | ||||
-rw-r--r-- | base/ios/scoped_critical_action.h | 48 | ||||
-rw-r--r-- | base/ios/scoped_critical_action.mm | 54 |
5 files changed, 195 insertions, 0 deletions
diff --git a/base/base.gypi b/base/base.gypi index 63362f1..4610794 100644 --- a/base/base.gypi +++ b/base/base.gypi @@ -86,6 +86,8 @@ 'compiler_specific.h', 'cpu.cc', 'cpu.h', + 'critical_closure.h', + 'critical_closure_ios.mm', 'debug/alias.cc', 'debug/alias.h', 'debug/debug_on_start_win.cc', @@ -151,6 +153,8 @@ 'hi_res_timer_manager_win.cc', 'hi_res_timer_manager.h', 'id_map.h', + 'ios/scoped_critical_action.h', + 'ios/scoped_critical_action.mm', 'json/json_file_value_serializer.cc', 'json/json_file_value_serializer.h', 'json/json_parser.cc', diff --git a/base/critical_closure.h b/base/critical_closure.h new file mode 100644 index 0000000..bb038dd --- /dev/null +++ b/base/critical_closure.h @@ -0,0 +1,37 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_CRITICAL_CLOSURE_H_ +#define BASE_CRITICAL_CLOSURE_H_ + +#include "base/callback.h" + +namespace base { + +// Returns a closure that will continue to run for a period of time when the +// application goes to the background if possible on platforms where +// applications don't execute while backgrounded, otherwise the original task is +// returned. +// +// Example: +// file_message_loop_proxy_->PostTask( +// FROM_HERE, +// MakeCriticalClosure(base::Bind(&WriteToDiskTask, path_, data))); +// +// Note new closures might be posted in this closure. If the new closures need +// background running time, |MakeCriticalClosure| should be applied on them +// before posting. +#if defined(OS_IOS) +base::Closure MakeCriticalClosure(const base::Closure& closure); +#else +base::Closure MakeCriticalClosure(const base::Closure& closure) { + // No-op for platforms where the application does not need to acquire + // background time for closures to finish when it goes into the background. + return closure; +} +#endif // !defined(OS_IOS) + +} // namespace base + +#endif // BASE_CRITICAL_CLOSURE_H_ diff --git a/base/critical_closure_ios.mm b/base/critical_closure_ios.mm new file mode 100644 index 0000000..156612b --- /dev/null +++ b/base/critical_closure_ios.mm @@ -0,0 +1,52 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/critical_closure.h" + +#import <UIKit/UIKit.h> + +#include "base/bind.h" +#include "base/ios/scoped_critical_action.h" +#include "base/memory/ref_counted.h" + +namespace { + +// This class wraps a closure so it can continue to run for a period of time +// when the application goes to the background by using +// |base::ios::ScopedCriticalAction|. +class CriticalClosure : public base::RefCountedThreadSafe<CriticalClosure> { + public: + explicit CriticalClosure(base::Closure* closure) : closure_(closure) { + background_scope_.reset(new base::ios::ScopedCriticalAction()); + } + + void Run() { + closure_->Run(); + + background_scope_.reset(); + } + + private: + friend class base::RefCountedThreadSafe<CriticalClosure>; + + virtual ~CriticalClosure() {} + + scoped_ptr<base::Closure> closure_; + scoped_ptr<base::ios::ScopedCriticalAction> background_scope_; + + DISALLOW_COPY_AND_ASSIGN(CriticalClosure); +}; + +} // namespace + +namespace base { + +base::Closure MakeCriticalClosure(const base::Closure& closure) { + DCHECK([[UIDevice currentDevice] isMultitaskingSupported]); + scoped_refptr<CriticalClosure> critical_closure( + new CriticalClosure(new base::Closure(closure))); + return base::Bind(&CriticalClosure::Run, critical_closure.get()); +} + +} // namespace base diff --git a/base/ios/scoped_critical_action.h b/base/ios/scoped_critical_action.h new file mode 100644 index 0000000..660a83a --- /dev/null +++ b/base/ios/scoped_critical_action.h @@ -0,0 +1,48 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_IOS_SCOPED_CRITICAL_ACTION_H_ +#define BASE_IOS_SCOPED_CRITICAL_ACTION_H_ + +#include "base/synchronization/lock.h" + +namespace base { +namespace ios { + +// This class attempts to allow the application to continue to run for a period +// of time after it transitions to the background. The construction of an +// instance of this class marks the beginning of a task that needs background +// running time when the application is moved to the background and the +// destruction marks the end of such a task. +// +// Note there is no guarantee that the task will continue to finish when the +// application is moved to the background. +// +// This class should be used at times where leaving a task unfinished might be +// detrimental to user experience. For example, it should be used to ensure that +// the application has enough time to save important data or at least attempt to +// save such data. +class ScopedCriticalAction { + public: + ScopedCriticalAction(); + ~ScopedCriticalAction(); + + private: + // Informs the OS that the background task has completed. + void EndBackgroundTask(); + + // |UIBackgroundTaskIdentifier| returned by + // |beginBackgroundTaskWithExpirationHandler:| when marking the beginning of + // a long-running background task. It is defined as an |unsigned int| instead + // of a |UIBackgroundTaskIdentifier| so this class can be used in .cc files. + unsigned int background_task_id_; + Lock background_task_id_lock_; + + DISALLOW_COPY_AND_ASSIGN(ScopedCriticalAction); +}; + +} // namespace ios +} // namespace base + +#endif // BASE_IOS_SCOPED_CRITICAL_ACTION_H_ diff --git a/base/ios/scoped_critical_action.mm b/base/ios/scoped_critical_action.mm new file mode 100644 index 0000000..734c0a2 --- /dev/null +++ b/base/ios/scoped_critical_action.mm @@ -0,0 +1,54 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/ios/scoped_critical_action.h" + +#import <UIKit/UIKit.h> + +#include "base/logging.h" +#include "base/synchronization/lock.h" + +namespace base { +namespace ios { + +// This implementation calls |beginBackgroundTaskWithExpirationHandler:| when +// instantiated and |endBackgroundTask:| when destroyed, creating a scope whose +// execution will continue (temporarily) even after the app is backgrounded. +ScopedCriticalAction::ScopedCriticalAction() { + background_task_id_ = [[UIApplication sharedApplication] + beginBackgroundTaskWithExpirationHandler:^{ + DLOG(WARNING) << "Background task with id " << background_task_id_ + << " expired."; + // Note if |endBackgroundTask:| is not called for each task before time + // expires, the system kills the application. + EndBackgroundTask(); + }]; + if (background_task_id_ == UIBackgroundTaskInvalid) { + DLOG(WARNING) << + "beginBackgroundTaskWithExpirationHandler: returned an invalid ID"; + } else { + VLOG(3) << "Beginning background task with id " << background_task_id_; + } +} + +ScopedCriticalAction::~ScopedCriticalAction() { + EndBackgroundTask(); +} + +void ScopedCriticalAction::EndBackgroundTask() { + UIBackgroundTaskIdentifier task_id; + { + AutoLock lock_scope(background_task_id_lock_); + if (background_task_id_ == UIBackgroundTaskInvalid) + return; + task_id = background_task_id_; + background_task_id_ = UIBackgroundTaskInvalid; + } + + VLOG(3) << "Ending background task with id " << task_id; + [[UIApplication sharedApplication] endBackgroundTask:task_id]; +} + +} // namespace ios +} // namespace base |