summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/base.gypi4
-rw-r--r--base/critical_closure.h37
-rw-r--r--base/critical_closure_ios.mm52
-rw-r--r--base/ios/scoped_critical_action.h48
-rw-r--r--base/ios/scoped_critical_action.mm54
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