1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
// Copyright 2015 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 "chrome/browser/data_usage/tab_id_provider.h"
#include <vector>
#include "base/bind.h"
#include "base/callback.h"
#include "base/location.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/single_thread_task_runner.h"
#include "base/task_runner.h"
#include "base/task_runner_util.h"
namespace chrome_browser_data_usage {
namespace {
// Convenience typedefs for clarity.
typedef base::Callback<int32_t(void)> TabIdGetter;
typedef base::Callback<void(int32_t)> TabIdCallback;
} // namespace
// Object that can run a list of callbacks that take tab IDs. New callbacks
// can only be added before it starts running the callbacks. Callbacks added
// will each be run exactly once.
class TabIdProvider::CallbackRunner {
public:
CallbackRunner() : is_done_(false), weak_ptr_factory_(this) {}
~CallbackRunner() {
// Ensure that no callbacks are abandoned without being run.
if (!is_done_)
RunAll(-1);
}
// Adds a new callback to be run later. New callbacks must not be added after
// RunAll has been called.
void AddCallback(const TabIdCallback& callback) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(!is_done_);
callbacks_.push_back(callback);
}
// Runs all the callbacks in the order that they were added. This method must
// not be called more than once.
void RunAll(int32_t tab_id) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(!is_done_);
is_done_ = true;
// It's safe to run the |callbacks_| while iterating through them because
// |callbacks_| can no longer be modified at this point, so it's impossible
// for one of the |callbacks_| to add more callbacks to this CallbackRunner.
for (const auto& callback : callbacks_)
callback.Run(tab_id);
callbacks_.clear();
}
base::WeakPtr<CallbackRunner> GetWeakPtr() {
DCHECK(thread_checker_.CalledOnValidThread());
return weak_ptr_factory_.GetWeakPtr();
}
private:
base::ThreadChecker thread_checker_;
bool is_done_;
std::vector<TabIdCallback> callbacks_;
base::WeakPtrFactory<CallbackRunner> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(CallbackRunner);
};
TabIdProvider::TabIdProvider(base::TaskRunner* task_runner,
const tracked_objects::Location& from_here,
const TabIdGetter& tab_id_getter)
: is_tab_id_ready_(false), tab_id_(-1), weak_ptr_factory_(this) {
scoped_ptr<CallbackRunner> callback_runner(new CallbackRunner());
weak_callback_runner_ = callback_runner->GetWeakPtr();
callback_runner->AddCallback(
base::Bind(&TabIdProvider::OnTabIdReady, GetWeakPtr()));
// The posted task takes ownership of |callback_runner|. If the task fails to
// be posted, then the destructor of |callback_runner| will pass a tab ID of
// -1 to OnTabIdReady, so that case doesn't need to be explicitly handled
// here.
base::PostTaskAndReplyWithResult(
task_runner, from_here, tab_id_getter,
base::Bind(&CallbackRunner::RunAll,
base::Owned(callback_runner.release())));
}
TabIdProvider::~TabIdProvider() {}
void TabIdProvider::ProvideTabId(const TabIdCallback& callback) {
DCHECK(thread_checker_.CalledOnValidThread());
if (is_tab_id_ready_) {
callback.Run(tab_id_);
return;
}
if (weak_callback_runner_) {
weak_callback_runner_->AddCallback(callback);
return;
}
// If no cached tab ID is available and |weak_callback_runner_| has been
// destroyed, pass a tab ID of -1 to the callback indicating that no tab was
// found.
callback.Run(-1);
}
base::WeakPtr<TabIdProvider> TabIdProvider::GetWeakPtr() {
DCHECK(thread_checker_.CalledOnValidThread());
return weak_ptr_factory_.GetWeakPtr();
}
// static
const void* TabIdProvider::kUserDataKey =
static_cast<void*>(&TabIdProvider::kUserDataKey);
void TabIdProvider::OnTabIdReady(int32_t tab_id) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(!is_tab_id_ready_);
tab_id_ = tab_id;
is_tab_id_ready_ = true;
}
} // namespace chrome_browser_data_usage
|