Delete historical data usage from store when user clears data usage.
[chromium-blink-merge.git] / rlz / win / lib / rlz_value_store_registry.cc
blob4a133ebc7d4e2e5e6285d09e75e424a82360a553
1 // Copyright (c) 2012 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.
5 #include "rlz/win/lib/rlz_value_store_registry.h"
7 #include "base/strings/stringprintf.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "base/win/registry.h"
10 #include "rlz/lib/assert.h"
11 #include "rlz/lib/lib_values.h"
12 #include "rlz/lib/rlz_lib.h"
13 #include "rlz/lib/string_utils.h"
14 #include "rlz/win/lib/registry_util.h"
16 using base::ASCIIToUTF16;
18 namespace rlz_lib {
20 namespace {
23 // Registry keys:
25 // RLZ's are stored as:
26 // <AccessPointName> = <RLZ value> @ kRootKey\kLibKeyName\kRlzsSubkeyName.
28 // Events are stored as:
29 // <AccessPointName><EventName> = 1 @
30 // HKCU\kLibKeyName\kEventsSubkeyName\GetProductName(product).
32 // The OEM Deal Confirmation Code (DCC) is stored as
33 // kDccValueName = <DCC value> @ HKLM\kLibKeyName
35 // The last ping time, per product is stored as:
36 // GetProductName(product) = <last ping time> @
37 // HKCU\kLibKeyName\kPingTimesSubkeyName.
39 // The server does not care about any of these constants.
41 const char kLibKeyName[] = "Software\\Google\\Common\\Rlz";
42 const wchar_t kGoogleKeyName[] = L"Software\\Google";
43 const wchar_t kGoogleCommonKeyName[] = L"Software\\Google\\Common";
44 const char kRlzsSubkeyName[] = "RLZs";
45 const char kEventsSubkeyName[] = "Events";
46 const char kStatefulEventsSubkeyName[] = "StatefulEvents";
47 const char kPingTimesSubkeyName[] = "PTimes";
49 std::wstring GetWideProductName(Product product) {
50 return ASCIIToUTF16(GetProductName(product));
53 void AppendBrandToString(std::string* str) {
54 std::string brand(SupplementaryBranding::GetBrand());
55 if (!brand.empty())
56 base::StringAppendF(str, "\\_%s", brand.c_str());
59 // Function to get the specific registry keys.
60 bool GetRegKey(const char* name, REGSAM access, base::win::RegKey* key) {
61 std::string key_location;
62 base::StringAppendF(&key_location, "%s\\%s", kLibKeyName, name);
63 AppendBrandToString(&key_location);
64 base::string16 key_location16 = ASCIIToUTF16(key_location);
66 LONG ret;
67 if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK))
68 ret = key->Create(HKEY_CURRENT_USER, key_location16.c_str(), access);
69 else
70 ret = key->Open(HKEY_CURRENT_USER, key_location16.c_str(), access);
71 return ret == ERROR_SUCCESS;
74 bool GetPingTimesRegKey(REGSAM access, base::win::RegKey* key) {
75 return GetRegKey(kPingTimesSubkeyName, access, key);
79 bool GetEventsRegKey(const char* event_type,
80 const rlz_lib::Product* product,
81 REGSAM access, base::win::RegKey* key) {
82 std::string key_location;
83 base::StringAppendF(&key_location, "%s\\%s", kLibKeyName,
84 event_type);
85 AppendBrandToString(&key_location);
87 if (product != NULL) {
88 std::string product_name = GetProductName(*product);
89 if (product_name.empty())
90 return false;
92 base::StringAppendF(&key_location, "\\%s", product_name.c_str());
94 base::string16 key_location16 = ASCIIToUTF16(key_location);
96 LONG ret;
97 if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK))
98 ret = key->Create(HKEY_CURRENT_USER, key_location16.c_str(), access);
99 else
100 ret = key->Open(HKEY_CURRENT_USER, key_location16.c_str(), access);
101 return ret == ERROR_SUCCESS;
104 bool GetAccessPointRlzsRegKey(REGSAM access, base::win::RegKey* key) {
105 return GetRegKey(kRlzsSubkeyName, access, key);
108 bool ClearAllProductEventValues(rlz_lib::Product product, const char* key) {
109 std::wstring product_name = GetWideProductName(product);
110 if (product_name.empty())
111 return false;
113 base::win::RegKey reg_key;
114 GetEventsRegKey(key, NULL, KEY_WRITE, &reg_key);
115 reg_key.DeleteKey(product_name.c_str());
117 // Verify that the value no longer exists.
118 base::win::RegKey product_events(
119 reg_key.Handle(), product_name.c_str(), KEY_READ);
120 if (product_events.Valid()) {
121 ASSERT_STRING("ClearAllProductEvents: Key deletion failed");
122 return false;
125 return true;
128 // Deletes a registry key if it exists and has no subkeys or values.
129 // TODO: Move this to a registry_utils file and add unittest.
130 bool DeleteKeyIfEmpty(HKEY root_key, const wchar_t* key_name) {
131 if (!key_name) {
132 ASSERT_STRING("DeleteKeyIfEmpty: key_name is NULL");
133 return false;
134 } else { // Scope needed for RegKey
135 base::win::RegKey key(root_key, key_name, KEY_READ);
136 if (!key.Valid())
137 return true; // Key does not exist - nothing to do.
139 base::win::RegistryKeyIterator key_iter(root_key, key_name);
140 if (key_iter.SubkeyCount() > 0)
141 return true; // Not empty, so nothing to do
143 base::win::RegistryValueIterator value_iter(root_key, key_name);
144 if (value_iter.ValueCount() > 0)
145 return true; // Not empty, so nothing to do
148 // The key is empty - delete it now.
149 base::win::RegKey key(root_key, L"", KEY_WRITE);
150 return key.DeleteKey(key_name) == ERROR_SUCCESS;
153 } // namespace
155 // static
156 std::wstring RlzValueStoreRegistry::GetWideLibKeyName() {
157 return ASCIIToUTF16(kLibKeyName);
160 bool RlzValueStoreRegistry::HasAccess(AccessType type) {
161 return HasUserKeyAccess(type == kWriteAccess);
164 bool RlzValueStoreRegistry::WritePingTime(Product product, int64 time) {
165 base::win::RegKey key;
166 std::wstring product_name = GetWideProductName(product);
167 return GetPingTimesRegKey(KEY_WRITE, &key) &&
168 key.WriteValue(product_name.c_str(), &time, sizeof(time),
169 REG_QWORD) == ERROR_SUCCESS;
172 bool RlzValueStoreRegistry::ReadPingTime(Product product, int64* time) {
173 base::win::RegKey key;
174 std::wstring product_name = GetWideProductName(product);
175 return GetPingTimesRegKey(KEY_READ, &key) &&
176 key.ReadInt64(product_name.c_str(), time) == ERROR_SUCCESS;
179 bool RlzValueStoreRegistry::ClearPingTime(Product product) {
180 base::win::RegKey key;
181 GetPingTimesRegKey(KEY_WRITE, &key);
183 std::wstring product_name = GetWideProductName(product);
184 key.DeleteValue(product_name.c_str());
186 // Verify deletion.
187 uint64 value;
188 DWORD size = sizeof(value);
189 if (key.ReadValue(
190 product_name.c_str(), &value, &size, NULL) == ERROR_SUCCESS) {
191 ASSERT_STRING("RlzValueStoreRegistry::ClearPingTime: Failed to delete.");
192 return false;
195 return true;
198 bool RlzValueStoreRegistry::WriteAccessPointRlz(AccessPoint access_point,
199 const char* new_rlz) {
200 const char* access_point_name = GetAccessPointName(access_point);
201 if (!access_point_name)
202 return false;
204 base::string16 access_point_name16(ASCIIToUTF16(access_point_name));
205 base::win::RegKey key;
206 GetAccessPointRlzsRegKey(KEY_WRITE, &key);
208 if (!RegKeyWriteValue(&key, access_point_name16.c_str(), new_rlz)) {
209 ASSERT_STRING("SetAccessPointRlz: Could not write the new RLZ value");
210 return false;
212 return true;
215 bool RlzValueStoreRegistry::ReadAccessPointRlz(AccessPoint access_point,
216 char* rlz,
217 size_t rlz_size) {
218 const char* access_point_name = GetAccessPointName(access_point);
219 if (!access_point_name)
220 return false;
222 size_t size = rlz_size;
223 base::win::RegKey key;
224 GetAccessPointRlzsRegKey(KEY_READ, &key);
225 base::string16 access_point_name16 = ASCIIToUTF16(access_point_name);
226 if (!RegKeyReadValue(key, access_point_name16.c_str(), rlz, &size)) {
227 rlz[0] = 0;
228 if (size > rlz_size) {
229 ASSERT_STRING("GetAccessPointRlz: Insufficient buffer size");
230 return false;
233 return true;
236 bool RlzValueStoreRegistry::ClearAccessPointRlz(AccessPoint access_point) {
237 const char* access_point_name = GetAccessPointName(access_point);
238 if (!access_point_name)
239 return false;
241 base::string16 access_point_name16(ASCIIToUTF16(access_point_name));
242 base::win::RegKey key;
243 GetAccessPointRlzsRegKey(KEY_WRITE, &key);
245 key.DeleteValue(access_point_name16.c_str());
247 // Verify deletion.
248 DWORD value;
249 if (key.ReadValueDW(access_point_name16.c_str(), &value) == ERROR_SUCCESS) {
250 ASSERT_STRING("SetAccessPointRlz: Could not clear the RLZ value.");
251 return false;
253 return true;
256 bool RlzValueStoreRegistry::AddProductEvent(Product product,
257 const char* event_rlz) {
258 base::string16 event_rlz16(ASCIIToUTF16(event_rlz));
259 base::win::RegKey reg_key;
260 GetEventsRegKey(kEventsSubkeyName, &product, KEY_WRITE, &reg_key);
261 if (reg_key.WriteValue(event_rlz16.c_str(), 1) != ERROR_SUCCESS) {
262 ASSERT_STRING("AddProductEvent: Could not write the new event value");
263 return false;
266 return true;
269 bool RlzValueStoreRegistry::ReadProductEvents(Product product,
270 std::vector<std::string>* events) {
271 // Open the events key.
272 base::win::RegKey events_key;
273 GetEventsRegKey(kEventsSubkeyName, &product, KEY_READ, &events_key);
274 if (!events_key.Valid())
275 return false;
277 // Append the events to the buffer.
278 int num_values = 0;
279 LONG result = ERROR_SUCCESS;
280 for (num_values = 0; result == ERROR_SUCCESS; ++num_values) {
281 // Max 32767 bytes according to MSDN, but we never use that much.
282 const size_t kMaxValueNameLength = 2048;
283 char buffer[kMaxValueNameLength];
284 DWORD size = arraysize(buffer);
286 result = RegEnumValueA(events_key.Handle(), num_values, buffer, &size,
287 NULL, NULL, NULL, NULL);
288 if (result == ERROR_SUCCESS)
289 events->push_back(std::string(buffer));
292 return result == ERROR_NO_MORE_ITEMS;
295 bool RlzValueStoreRegistry::ClearProductEvent(Product product,
296 const char* event_rlz) {
297 base::string16 event_rlz16(ASCIIToUTF16(event_rlz));
298 base::win::RegKey key;
299 GetEventsRegKey(kEventsSubkeyName, &product, KEY_WRITE, &key);
300 key.DeleteValue(event_rlz16.c_str());
302 // Verify deletion.
303 DWORD value;
304 if (key.ReadValueDW(event_rlz16.c_str(), &value) == ERROR_SUCCESS) {
305 ASSERT_STRING("ClearProductEvent: Could not delete the event value.");
306 return false;
309 return true;
312 bool RlzValueStoreRegistry::ClearAllProductEvents(Product product) {
313 return ClearAllProductEventValues(product, kEventsSubkeyName);
316 bool RlzValueStoreRegistry::AddStatefulEvent(Product product,
317 const char* event_rlz) {
318 base::win::RegKey key;
319 base::string16 event_rlz16(ASCIIToUTF16(event_rlz));
320 if (!GetEventsRegKey(kStatefulEventsSubkeyName, &product, KEY_WRITE, &key) ||
321 key.WriteValue(event_rlz16.c_str(), 1) != ERROR_SUCCESS) {
322 ASSERT_STRING(
323 "AddStatefulEvent: Could not write the new stateful event");
324 return false;
327 return true;
330 bool RlzValueStoreRegistry::IsStatefulEvent(Product product,
331 const char* event_rlz) {
332 DWORD value;
333 base::win::RegKey key;
334 GetEventsRegKey(kStatefulEventsSubkeyName, &product, KEY_READ, &key);
335 base::string16 event_rlz16(ASCIIToUTF16(event_rlz));
336 return key.ReadValueDW(event_rlz16.c_str(), &value) == ERROR_SUCCESS;
339 bool RlzValueStoreRegistry::ClearAllStatefulEvents(Product product) {
340 return ClearAllProductEventValues(product, kStatefulEventsSubkeyName);
343 void RlzValueStoreRegistry::CollectGarbage() {
344 // Delete each of the known subkeys if empty.
345 const char* const subkeys[] = {
346 kRlzsSubkeyName,
347 kEventsSubkeyName,
348 kStatefulEventsSubkeyName,
349 kPingTimesSubkeyName
352 for (int i = 0; i < arraysize(subkeys); i++) {
353 std::string subkey_name;
354 base::StringAppendF(&subkey_name, "%s\\%s", kLibKeyName, subkeys[i]);
355 AppendBrandToString(&subkey_name);
356 base::string16 subkey_name16 = ASCIIToUTF16(subkey_name);
358 VERIFY(DeleteKeyIfEmpty(HKEY_CURRENT_USER, subkey_name16.c_str()));
361 // Delete the library key and its parents too now if empty.
362 VERIFY(DeleteKeyIfEmpty(HKEY_CURRENT_USER, GetWideLibKeyName().c_str()));
363 VERIFY(DeleteKeyIfEmpty(HKEY_CURRENT_USER, kGoogleCommonKeyName));
364 VERIFY(DeleteKeyIfEmpty(HKEY_CURRENT_USER, kGoogleKeyName));
367 ScopedRlzValueStoreLock::ScopedRlzValueStoreLock() {
368 if (!lock_.failed())
369 store_.reset(new RlzValueStoreRegistry);
372 ScopedRlzValueStoreLock::~ScopedRlzValueStoreLock() {
375 RlzValueStore* ScopedRlzValueStoreLock::GetStore() {
376 return store_.get();
379 } // namespace rlz_lib