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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
// 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 CHROME_BROWSER_EXTENSIONS_SYSTEM_INFO_PROVIDER_H_
#define CHROME_BROWSER_EXTENSIONS_SYSTEM_INFO_PROVIDER_H_
#include <queue>
#include "base/bind.h"
#include "base/callback.h"
#include "base/lazy_instance.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/sequenced_worker_pool.h"
#include "content/public/browser/browser_thread.h"
namespace extensions {
// A generic template for all kinds of system information providers. Each kind
// of SystemInfoProvider is a single shared instance. It is created if needed,
// and destroyed at exit time. This is done via LazyInstance and scoped_ptr.
//
// The SystemInfoProvider is designed to query system information on the worker
// pool. It also maintains a queue of callbacks on the UI thread which are
// waiting for the completion of querying operation. Once the query operation
// is completed, all pending callbacks in the queue get called on the UI
// thread. In this way, it avoids frequent querying operation in case of lots
// of query requests, e.g. calling systemInfo.cpu.get repeatedly in an
// extension process.
//
// Template parameter T is the system information type. It could be the
// structure type generated by IDL parser.
template<class T>
class SystemInfoProvider {
public:
// Callback type for completing to get information. The callback accepts
// two arguments. The first one is the information got already, the second
// one indicates whether its contents are valid, for example, no error
// occurs in querying the information.
typedef base::Callback<void(const T&, bool)> QueryInfoCompletionCallback;
typedef std::queue<QueryInfoCompletionCallback> CallbackQueue;
SystemInfoProvider()
: is_waiting_for_completion_(false) {
worker_pool_token_ =
content::BrowserThread::GetBlockingPool()->GetSequenceToken();
}
virtual ~SystemInfoProvider() {}
// For testing
static void InitializeForTesting(SystemInfoProvider<T>* provider) {
DCHECK(provider != NULL);
single_shared_provider_.Get().reset(provider);
}
// Start to query the system information. Should be called on UI thread.
// The |callback| will get called once the query is completed.
void StartQueryInfo(const QueryInfoCompletionCallback& callback) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
DCHECK(!callback.is_null());
callbacks_.push(callback);
if (is_waiting_for_completion_)
return;
is_waiting_for_completion_ = true;
base::SequencedWorkerPool* worker_pool =
content::BrowserThread::GetBlockingPool();
// The query task posted to the worker pool won't block shutdown, and any
// running query task at shutdown time will be ignored.
worker_pool->PostSequencedWorkerTaskWithShutdownBehavior(
worker_pool_token_,
FROM_HERE,
base::Bind(&SystemInfoProvider<T>::QueryOnWorkerPool,
base::Unretained(this)),
base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
}
// Query the system information synchronously and output the result to the
// |info| parameter. The |info| contents MUST be reset firstly in its
// platform specific implementation. Return true if it succeeds, otherwise
// false is returned.
virtual bool QueryInfo(T* info) = 0;
protected:
virtual void QueryOnWorkerPool() {
bool success = QueryInfo(&info_);
content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
base::Bind(&SystemInfoProvider<T>::OnQueryCompleted,
base::Unretained(this), success));
}
// Called on UI thread. The |success| parameter means whether it succeeds
// to get the information.
virtual void OnQueryCompleted(bool success) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
while (!callbacks_.empty()) {
QueryInfoCompletionCallback callback = callbacks_.front();
callback.Run(info_, success);
callbacks_.pop();
}
is_waiting_for_completion_ = false;
}
// Template function for creating the single shared provider instance.
// Template paramter I is the type of SystemInfoProvider implementation.
template<class I>
static I* GetInstance() {
if (!single_shared_provider_.Get().get()) {
I* impl = new I();
single_shared_provider_.Get().reset(impl);
}
return static_cast<I*>(single_shared_provider_.Get().get());
}
// The latest information filled up by QueryInfo implementation. Here we
// assume the T is disallowed to copy constructor, aligns with the structure
// type generated by IDL parser.
T info_;
private:
// The single shared provider instance. We create it only when needed.
static typename base::LazyInstance<
scoped_ptr<SystemInfoProvider<T> > > single_shared_provider_;
// The queue of callbacks waiting for the info querying completion. It is
// maintained on the UI thread.
CallbackQueue callbacks_;
// Indicates if it is waiting for the querying completion.
bool is_waiting_for_completion_;
// Unqiue sequence token so that the operation of querying inforation can
// be executed in order.
base::SequencedWorkerPool::SequenceToken worker_pool_token_;
DISALLOW_COPY_AND_ASSIGN(SystemInfoProvider<T>);
};
// Static member intialization.
template<class T>
typename base::LazyInstance<scoped_ptr<SystemInfoProvider<T> > >
SystemInfoProvider<T>::single_shared_provider_ = LAZY_INSTANCE_INITIALIZER;
} // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_SYSTEM_INFO_PROVIDER_H_
|