Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(131)

Side by Side Diff: chrome/browser/conflicts/module_database_win.cc

Issue 2576843002: [win] Create ModuleDatabase and ModuleEventSinkImpl. (Closed)
Patch Set: Fix small bug. Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 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
5 #include "chrome/browser/conflicts/module_database_win.h"
6
7 #include <algorithm>
8 #include <tuple>
9
10 #include "base/bind.h"
11
12 namespace {
13
14 // Document the assumptions made on the ProcessType enum in order to convert
15 // them to bits.
16 static_assert(content::PROCESS_TYPE_UNKNOWN == 1,
17 "assumes unknown process type has value 1");
18 static_assert(content::PROCESS_TYPE_BROWSER == 2,
19 "assumes browser process type has value 2");
20 constexpr uint32_t kFirstValidProcessType = content::PROCESS_TYPE_BROWSER;
21
22 } // namespace
23
24 ModuleDatabase::ModuleDatabase(
25 scoped_refptr<base::SequencedTaskRunner> task_runner)
26 : task_runner_(std::move(task_runner)), weak_ptr_factory_(this) {}
27
28 ModuleDatabase::~ModuleDatabase() = default;
29
30 void ModuleDatabase::OnProcessStarted(uint32_t process_id,
31 uint64_t creation_time,
32 content::ProcessType process_type) {
33 DCHECK(task_runner_->RunsTasksOnCurrentThread());
34 CreateProcessInfo(process_id, creation_time, process_type);
35 }
36
37 void ModuleDatabase::OnModuleLoad(uint32_t process_id,
38 uint64_t creation_time,
39 const base::FilePath& module_path,
40 uint32_t module_size,
41 uint32_t module_time_date_stamp,
42 uintptr_t module_load_address) {
43 // Messages can arrive from any thread (UI thread for calls over IPC, and
44 // anywhere at all for calls from ModuleWatcher), so bounce if necessary.
45 if (!task_runner_->RunsTasksOnCurrentThread()) {
46 task_runner_->PostTask(
47 FROM_HERE, base::Bind(&ModuleDatabase::OnModuleLoad,
48 weak_ptr_factory_.GetWeakPtr(), process_id,
49 creation_time, module_path, module_size,
50 module_time_date_stamp, module_load_address));
51 return;
52 }
53
54 // In theory this should always succeed. However, it is possible for a client
55 // to misbehave and send out-of-order messages. It is easy to be tolerant of
56 // this by simply not updating the process info in this case. It's not worth
57 // crashing if this data is slightly out of sync as this is purely
58 // informational.
59 auto* process_info = GetProcessInfo(process_id, creation_time);
60 if (!process_info)
61 return;
62
63 auto* module_info =
64 FindOrCreateModuleInfo(module_path, module_size, module_time_date_stamp);
65
66 // Update the list of process types that this module has been seen in.
67 module_info->second.process_types |=
68 ProcessTypeToBit(process_info->first.process_type);
69
70 // Update the load address maps.
71 InsertLoadAddress(module_info->first.module_id, module_load_address,
72 &process_info->second.loaded_modules);
73 RemoveLoadAddressById(module_info->first.module_id,
74 &process_info->second.unloaded_modules);
75 }
76
77 void ModuleDatabase::OnModuleUnload(uint32_t process_id,
78 uint64_t creation_time,
79 uintptr_t module_load_address) {
80 // Messages can arrive from any thread (UI thread for calls over IPC, and
81 // anywhere at all for calls from ModuleWatcher), so bounce if necessary.
82 if (!task_runner_->RunsTasksOnCurrentThread()) {
83 task_runner_->PostTask(
84 FROM_HERE, base::Bind(&ModuleDatabase::OnModuleUnload,
85 weak_ptr_factory_.GetWeakPtr(), process_id,
86 creation_time, module_load_address));
87 return;
88 }
89
90 // See the long-winded comment in OnModuleLoad about reasons why this can
91 // fail (but shouldn't normally).
92 auto* process_info = GetProcessInfo(process_id, creation_time);
93 if (!process_info)
94 return;
95
96 // Find the module corresponding to this load address. This is O(1) in the
97 // common case of removing a recently removed module, but O(n) worst case.
98 // Thankfully, unload events occur far less often and n is quite small.
99 size_t i = FindLoadAddressIndexByAddress(module_load_address,
100 process_info->second.loaded_modules);
101
102 // No such module found. This shouldn't happen either, unless messages are
103 // malformed or out of order. Gracefully fail in this case.
104 if (i == kInvalidIndex)
105 return;
106
107 ModuleId module_id = process_info->second.loaded_modules[i].first;
108
109 // Remove from the loaded module list and insert into the unloaded module
110 // list.
111 RemoveLoadAddressByIndex(i, &process_info->second.loaded_modules);
112 InsertLoadAddress(module_id, module_load_address,
113 &process_info->second.unloaded_modules);
114 }
115
116 void ModuleDatabase::OnProcessEnded(uint32_t process_id,
117 uint64_t creation_time) {
118 // Messages can arrive from any thread (UI thread for calls over IPC, and
119 // anywhere at all for calls from ModuleWatcher), so bounce if necessary.
120 if (!task_runner_->RunsTasksOnCurrentThread()) {
121 task_runner_->PostTask(
122 FROM_HERE,
123 base::Bind(&ModuleDatabase::OnProcessEnded,
124 weak_ptr_factory_.GetWeakPtr(), process_id, creation_time));
125 return;
126 }
127
128 DeleteProcessInfo(process_id, creation_time);
129 }
130
131 // static
132 uint32_t ModuleDatabase::ProcessTypeToBit(content::ProcessType process_type) {
133 uint32_t bit_index =
134 static_cast<uint32_t>(process_type) - kFirstValidProcessType;
135 DCHECK_GE(31u, bit_index);
136 uint32_t bit = (1 << bit_index);
137 return bit;
138 }
139
140 // static
141 content::ProcessType ModuleDatabase::BitIndexToProcessType(uint32_t bit_index) {
142 DCHECK_GE(31u, bit_index);
143 return static_cast<content::ProcessType>(bit_index + kFirstValidProcessType);
144 }
145
146 // static
147 size_t ModuleDatabase::FindLoadAddressIndexById(
148 ModuleId module_id,
149 const ModuleLoadAddresses& load_addresses) {
150 // Process elements in reverse order so that RemoveLoadAddressById can handle
151 // the more common case of removing the maximum element in O(1).
152 for (size_t i = load_addresses.size() - 1; i < load_addresses.size(); --i) {
153 if (load_addresses[i].first == module_id)
154 return i;
155 }
156 return kInvalidIndex;
157 }
158
159 // static
160 size_t ModuleDatabase::FindLoadAddressIndexByAddress(
161 uintptr_t load_address,
162 const ModuleLoadAddresses& load_addresses) {
163 for (size_t i = 0; i < load_addresses.size(); ++i) {
164 if (load_addresses[i].second == load_address)
165 return i;
166 }
167 return kInvalidIndex;
168 }
169
170 // static
171 void ModuleDatabase::InsertLoadAddress(ModuleId module_id,
172 uintptr_t load_address,
173 ModuleLoadAddresses* load_addresses) {
174 // A very small optimization: the largest module_id is always placed at the
175 // end of the array. This is the most common case, and allows O(1)
176 // determination that a |module_id| isn't present when it's bigger than the
177 // maximum already in the array. This keeps insertions to O(1) in the usual
178 // case.
179 if (load_addresses->empty() || module_id > load_addresses->back().first) {
180 load_addresses->emplace_back(module_id, load_address);
181 return;
182 }
183
184 // If the module exists in the collection then update the load address and
185 // return. This should never really occur, unless the client is deliberately
186 // misbehaving or a race causes a reload event (at a different address) to be
187 // processed before the corresponding unload. This is very unlikely.
188 size_t i = FindLoadAddressIndexById(module_id, *load_addresses);
189 if (i != kInvalidIndex) {
190 (*load_addresses)[i].second = load_address;
191 return;
192 }
193
194 // The module does not exist, and by definition is smaller in value than
195 // the largest module ID already present. Add it, ensuring that the largest
196 // module ID stays at the end.
197 load_addresses->emplace(--load_addresses->end(), module_id, load_address);
198 }
199
200 // static
201 void ModuleDatabase::RemoveLoadAddressById(
202 ModuleId module_id,
203 ModuleLoadAddresses* load_addresses) {
204 if (load_addresses->empty())
205 return;
206
207 // This handles the special case of removing the max element in O(1), as
208 // FindLoadAddressIndexById processes the elements in reverse order.
209 size_t i = FindLoadAddressIndexById(module_id, *load_addresses);
210 RemoveLoadAddressByIndex(i, load_addresses);
211 }
212
213 // static
214 void ModuleDatabase::RemoveLoadAddressByIndex(
215 size_t index,
216 ModuleLoadAddresses* load_addresses) {
217 DCHECK_LT(index, load_addresses->size());
218
219 // Special case: removing the only remaining element.
220 if (load_addresses->size() == 1) {
221 load_addresses->clear();
222 return;
223 }
224
225 // Special case: removing the last module (with maximum id). Need to find the
226 // new maximum element and ensure it goes to the end.
227 if (load_addresses->size() > 2 && index + 1 == load_addresses->size()) {
228 // Note that |index| == load_addresses->size() - 1, and is the last
229 // indexable element in the vector.
230
231 // Find the index of the new maximum element.
232 ModuleId max_id = -1; // These start at zero.
233 size_t max_index = kInvalidIndex;
234 for (size_t i = 0; i < load_addresses->size() - 1; ++i) {
235 if ((*load_addresses)[i].first > max_id) {
236 max_id = (*load_addresses)[i].first;
237 max_index = i;
238 }
239 }
240
241 // Remove the last (max) element.
242 load_addresses->resize(index);
243
244 // If the new max element isn't in the last position, then swap it so it is.
245 size_t last_index = load_addresses->size() - 1;
246 if (max_index != last_index)
247 std::swap((*load_addresses)[max_index], (*load_addresses)[last_index]);
248
249 return;
250 }
251
252 // If the element to be removed is second last then a single copy is
253 // sufficient.
254 if (index + 2 == load_addresses->size()) {
255 (*load_addresses)[index] = (*load_addresses)[index + 1];
256 } else {
257 // In the general case two copies are necessary.
258 int max_index = load_addresses->size() - 1;
259 (*load_addresses)[index] = (*load_addresses)[max_index - 1];
260 (*load_addresses)[max_index - 1] = (*load_addresses)[max_index];
261 }
262
263 // Remove the last element, which is now duplicated.
264 load_addresses->resize(load_addresses->size() - 1);
265 }
266
267 ModuleDatabase::ModuleInfo* ModuleDatabase::FindOrCreateModuleInfo(
268 const base::FilePath& module_path,
269 uint32_t module_size,
270 uint32_t module_time_date_stamp) {
271 auto result = modules_.emplace(
272 std::piecewise_construct,
273 std::forward_as_tuple(ModuleInfoKey(
274 module_path, module_size, module_time_date_stamp, modules_.size())),
275 std::forward_as_tuple(ModuleInfoData()));
276 return &(*result.first);
277 }
278
279 ModuleDatabase::ProcessInfo* ModuleDatabase::GetProcessInfo(
280 uint32_t process_id,
281 uint64_t creation_time) {
282 ProcessInfoKey key(process_id, creation_time, content::PROCESS_TYPE_UNKNOWN);
283 auto it = processes_.find(key);
284 if (it == processes_.end())
285 return nullptr;
286 return &(*it);
287 }
288
289 void ModuleDatabase::CreateProcessInfo(uint32_t process_id,
290 uint64_t creation_time,
291 content::ProcessType process_type) {
292 processes_.emplace(std::piecewise_construct,
293 std::forward_as_tuple(ProcessInfoKey(
294 process_id, creation_time, process_type)),
295 std::forward_as_tuple(ProcessInfoData()));
296 }
297
298 void ModuleDatabase::DeleteProcessInfo(uint32_t process_id,
299 uint64_t creation_time) {
300 ProcessInfoKey key(process_id, creation_time, content::PROCESS_TYPE_UNKNOWN);
301 processes_.erase(key);
302 }
303
304 // ModuleDatabase::ModuleInfoKey -----------------------------------------------
305
306 ModuleDatabase::ModuleInfoKey::ModuleInfoKey(const base::FilePath& module_path,
307 uint32_t module_size,
308 uint32_t module_time_date_stamp,
309 uint32_t module_id)
310 : module_path(module_path),
311 module_size(module_size),
312 module_time_date_stamp(module_time_date_stamp),
313 module_id(module_id) {}
314
315 bool ModuleDatabase::ModuleInfoKey::operator<(const ModuleInfoKey& mik) const {
316 // The key consists of the triplet of
317 // (module_path, module_size, module_time_date_stamp).
318 // Use the std::tuple lexicographic comparison operator.
319 return std::make_tuple(module_path, module_size, module_time_date_stamp) <
320 std::make_tuple(mik.module_path, mik.module_size,
321 mik.module_time_date_stamp);
322 }
323
324 // ModuleDatabase::ModuleInfoData ----------------------------------------------
325
326 ModuleDatabase::ModuleInfoData::ModuleInfoData() : process_types(0) {}
327
328 // ModuleDatabase::ProcessInfoKey ----------------------------------------------
329
330 ModuleDatabase::ProcessInfoKey::ProcessInfoKey(
331 uint32_t process_id,
332 uint64_t creation_time,
333 content::ProcessType process_type)
334 : process_id(process_id),
335 creation_time(creation_time),
336 process_type(process_type) {}
337
338 ModuleDatabase::ProcessInfoKey::~ProcessInfoKey() = default;
339
340 bool ModuleDatabase::ProcessInfoKey::operator<(
341 const ProcessInfoKey& pik) const {
342 // The key consists of the pair of (process_id, creation_time).
343 // Use the std::tuple lexicographic comparison operator.
344 return std::make_tuple(process_id, creation_time) <
345 std::make_tuple(pik.process_id, pik.creation_time);
346 }
347
348 // ModuleDatabase::ProcessInfoData ---------------------------------------------
349
350 ModuleDatabase::ProcessInfoData::ProcessInfoData() = default;
351
352 ModuleDatabase::ProcessInfoData::ProcessInfoData(const ProcessInfoData& other) =
353 default;
354
355 ModuleDatabase::ProcessInfoData::~ProcessInfoData() = default;
OLDNEW
« no previous file with comments | « chrome/browser/conflicts/module_database_win.h ('k') | chrome/browser/conflicts/module_database_win_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698