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

Side by Side Diff: goopdate/app_manager.cc

Issue 624713003: Keep only base/extractor.[cc|h]. (Closed) Base URL: https://chromium.googlesource.com/external/omaha.git@master
Patch Set: Created 6 years, 2 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
« no previous file with comments | « goopdate/app_manager.h ('k') | goopdate/app_manager_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2007-2010 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 // ========================================================================
15
16 #include "omaha/goopdate/app_manager.h"
17 #include <algorithm>
18 #include <cstdlib>
19 #include <functional>
20 #include <map>
21 #include "base/scoped_ptr.h"
22 #include "omaha/base/const_object_names.h"
23 #include "omaha/base/error.h"
24 #include "omaha/base/reg_key.h"
25 #include "omaha/base/scoped_ptr_address.h"
26 #include "omaha/base/time.h"
27 #include "omaha/base/utils.h"
28 #include "omaha/base/vistautil.h"
29 #include "omaha/common/app_registry_utils.h"
30 #include "omaha/common/config_manager.h"
31 #include "omaha/common/const_goopdate.h"
32 #include "omaha/common/oem_install_utils.h"
33 #include "omaha/goopdate/application_usage_data.h"
34 #include "omaha/goopdate/model.h"
35 #include "omaha/goopdate/server_resource.h"
36 #include "omaha/goopdate/string_formatter.h"
37
38 namespace omaha {
39
40 namespace {
41
42 const uint32 kInitialInstallTimeDiff = static_cast<uint32>(-1 * kSecondsPerDay);
43
44 // Returns the number of days haven been passed since the given time.
45 // The parameter time is in the same format as C time() returns.
46 int GetNumberOfDaysSince(int time) {
47 ASSERT1(time >= 0);
48 const int now = Time64ToInt32(GetCurrent100NSTime());
49 ASSERT1(now >= time);
50
51 if (now < time) {
52 // In case the client computer clock is adjusted in between.
53 return 0;
54 }
55 return (now - time) / kSecondsPerDay;
56 }
57
58 // Determines if an application is registered with Omaha.
59 class IsAppRegisteredFunc
60 : public std::unary_function<const CString&, HRESULT> {
61 public:
62 explicit IsAppRegisteredFunc(const CString& guid)
63 : is_registered_(false),
64 guid_(guid) {}
65
66 bool is_registered() const { return is_registered_; }
67
68 HRESULT operator() (const CString& guid) {
69 if (guid.CompareNoCase(guid_) == 0) {
70 is_registered_ = true;
71 }
72 return S_OK;
73 }
74 private:
75 CString guid_;
76 bool is_registered_;
77 };
78
79 // Enumerates all sub keys of the key and calls the functor for each of them,
80 // ignoring errors to ensure all keys are processed.
81 template <typename T>
82 HRESULT EnumerateSubKeys(const TCHAR* key_name, T* functor) {
83 RegKey client_key;
84 HRESULT hr = client_key.Open(key_name, KEY_READ);
85 if (FAILED(hr)) {
86 return hr;
87 }
88
89 int num_sub_keys = client_key.GetSubkeyCount();
90 for (int i = 0; i < num_sub_keys; ++i) {
91 CString sub_key_name;
92 hr = client_key.GetSubkeyNameAt(i, &sub_key_name);
93 if (SUCCEEDED(hr)) {
94 (*functor)(sub_key_name);
95 }
96 }
97
98 return S_OK;
99 }
100
101 } // namespace
102
103 typedef bool (*AppPredictFunc)(const AppManager& app_manager,
104 const CString& app_id);
105
106 bool IsUninstalledAppPredicate(const AppManager& app_manager,
107 const CString& app_id) {
108 return app_manager.IsAppUninstalled(app_id);
109 }
110
111 bool IsAppOemInstalledAndEulaAcceptedPredicate(const AppManager& app_manager,
112 const CString& app_id) {
113 return app_manager.IsAppOemInstalledAndEulaAccepted(app_id);
114 }
115
116 bool IsRegisteredAppPredicate(const AppManager& app_manager,
117 const CString& app_id) {
118 return app_manager.IsAppRegistered(app_id);
119 }
120
121 // Accumulates app IDs for apps that satisfies the predicate.
122 class CollectProductsFunc
123 : public std::unary_function<const CString&, HRESULT> {
124 public:
125 CollectProductsFunc(const AppPredictFunc predicate,
126 const AppManager& app_manager,
127 AppIdVector* app_ids)
128 : predicate_(predicate),
129 app_manager_(app_manager),
130 app_ids_(app_ids) {
131 ASSERT1(app_ids);
132 }
133
134 // Ignores errors and accumulates as many applications as possible.
135 HRESULT operator() (const CString& app_id) const {
136 if ((*predicate_)(app_manager_, app_id)) {
137 app_ids_->push_back(app_id);
138 }
139
140 return S_OK;
141 }
142
143 private:
144 const AppPredictFunc predicate_;
145 const AppManager& app_manager_;
146 AppIdVector* const app_ids_;
147
148 DISALLOW_IMPLICIT_CONSTRUCTORS(CollectProductsFunc);
149 };
150
151 // Runs application registration hooks registered under Omaha AppIds.
152 // Reads the Hook Clsid entry under Clients\{AppID}. CoCreates the CLSID. Calls
153 // IRegistrationUpdateHook::UpdateRegistry().
154 class RunRegistrationUpdateHooksFunc
155 : public std::unary_function<const CString&, HRESULT> {
156 public:
157 explicit RunRegistrationUpdateHooksFunc(const AppManager& app_manager)
158 : app_manager_(app_manager) {
159 }
160
161 HRESULT operator() (const CString& app_id) {
162 GUID app_guid = GUID_NULL;
163 HRESULT hr = StringToGuidSafe(app_id, &app_guid);
164 if (FAILED(hr)) {
165 return hr;
166 }
167 RegKey client_key;
168 hr = app_manager_.OpenClientKey(app_guid, &client_key);
169 if (FAILED(hr)) {
170 return hr;
171 }
172
173 CString hook_clsid_str;
174 hr = client_key.GetValue(kRegValueUpdateHookClsid, &hook_clsid_str);
175 if (FAILED(hr)) {
176 return hr;
177 }
178 GUID hook_clsid = GUID_NULL;
179 hr = StringToGuidSafe(hook_clsid_str, &hook_clsid);
180 if (FAILED(hr)) {
181 return hr;
182 }
183
184 CORE_LOG(L3, (_T("[Update Hook Clsid][%s][%s]"), app_id, hook_clsid_str));
185
186 CComPtr<IRegistrationUpdateHook> registration_hook;
187 hr = registration_hook.CoCreateInstance(hook_clsid);
188 if (FAILED(hr)) {
189 CORE_LOG(LE, (_T("[IRegistrationUpdateHook CoCreate failed][0x%x]"), hr));
190 return hr;
191 }
192
193 hr = registration_hook->UpdateRegistry(CComBSTR(app_id),
194 app_manager_.is_machine_);
195 if (FAILED(hr)) {
196 CORE_LOG(LE, (_T("[registration_hook UpdateRegistry failed][0x%x]"), hr));
197 return hr;
198 }
199
200 return S_OK;
201 }
202
203 private:
204 const AppManager& app_manager_;
205 };
206
207 AppManager* AppManager::instance_ = NULL;
208
209 // We do not worry about contention on creation because only the Worker should
210 // create AppManager during its initialization.
211 HRESULT AppManager::CreateInstance(bool is_machine) {
212 ASSERT1(!instance_);
213 if (instance_) {
214 return S_OK;
215 }
216
217 AppManager* instance(new AppManager(is_machine));
218 if (!instance->InitializeRegistryLock()) {
219 HRESULT hr(HRESULTFromLastError());
220 delete instance;
221 return hr;
222 }
223
224 instance_ = instance;
225 return S_OK;
226 }
227
228 void AppManager::DeleteInstance() {
229 delete instance_;
230 instance_ = NULL;
231 }
232
233 AppManager* AppManager::Instance() {
234 ASSERT1(instance_);
235 return instance_;
236 }
237
238 HRESULT AppManager::ReadAppVersionNoLock(bool is_machine, const GUID& app_guid,
239 CString* version) {
240 ASSERT1(version);
241 CORE_LOG(L2, (_T("[ReadAppVersionNoLock][%s]"), GuidToString(app_guid)));
242
243 AppManager app_manager(is_machine);
244 RegKey client_key;
245 HRESULT hr = app_manager.OpenClientKey(app_guid, &client_key);
246 if (FAILED(hr)) {
247 return hr;
248 }
249
250 hr = client_key.GetValue(kRegValueProductVersion, version);
251 if (FAILED(hr)) {
252 return hr;
253 }
254
255 CORE_LOG(L3, (_T("[kRegValueProductVersion][%s]"), *version));
256 return S_OK;
257 }
258
259 AppManager::AppManager(bool is_machine)
260 : is_machine_(is_machine) {
261 CORE_LOG(L3, (_T("[AppManager::AppManager][is_machine=%d]"), is_machine));
262 }
263
264 // App installers should use similar code to create a lock to acquire while
265 // modifying Omaha registry.
266 bool AppManager::InitializeRegistryLock() {
267 NamedObjectAttributes lock_attr;
268 GetNamedObjectAttributes(kRegistryAccessMutex, is_machine_, &lock_attr);
269 return registry_access_lock_.InitializeWithSecAttr(lock_attr.name,
270 &lock_attr.sa);
271 }
272
273 // Vulnerable to a race condition with installers. To prevent this, acquire
274 // GetRegistryStableStateLock().
275 bool AppManager::IsAppRegistered(const GUID& app_guid) const {
276 return IsAppRegistered(GuidToString(app_guid));
277 }
278
279 // Vulnerable to a race condition with installers. To prevent this, acquire
280 // GetRegistryStableStateLock().
281 bool AppManager::IsAppRegistered(const CString& app_id) const {
282 IsAppRegisteredFunc func(app_id);
283 HRESULT hr = EnumerateSubKeys(
284 ConfigManager::Instance()->registry_clients(is_machine_),
285 &func);
286 if (FAILED(hr)) {
287 return false;
288 }
289
290 return func.is_registered();
291 }
292
293 bool AppManager::IsAppUninstalled(const CString& app_id) const {
294 GUID app_guid = {0};
295 if (FAILED(StringToGuidSafe(app_id, &app_guid))) {
296 ASSERT1(false);
297 return false;
298 }
299 return IsAppUninstalled(app_guid);
300 }
301
302 // An app is considered uninstalled if:
303 // * The app's Clients key does not exist AND
304 // * The app's ClientState key exists and contains the pv value.
305 // We check for the pv key value in the ClientState to prevent Omaha from
306 // detecting the key created in the following scenarios as an uninstalled app.
307 // * Per-machine apps may write dr to per-user Omaha's key. Per-user Omaha
308 // must not detect this as an uninstalled app.
309 // * Omaha may create the app's ClientState key and write values from the
310 // metainstaller tag before running the installer, which creates the
311 // Clients key.
312 bool AppManager::IsAppUninstalled(const GUID& app_guid) const {
313 if (IsAppRegistered(app_guid)) {
314 return false;
315 }
316
317 return RegKey::HasValue(GetClientStateKeyName(app_guid),
318 kRegValueProductVersion);
319 }
320
321 bool AppManager::IsAppOemInstalledAndEulaAccepted(const CString& app_id) const {
322 GUID app_guid = GUID_NULL;
323 if (FAILED(StringToGuidSafe(app_id, &app_guid))) {
324 ASSERT1(false);
325 return false;
326 }
327
328 if (IsAppUninstalled(app_guid)) {
329 return false;
330 }
331
332 if (!app_registry_utils::IsAppEulaAccepted(is_machine_, app_id, false)) {
333 CORE_LOG(L3, (_T("[EULA not accepted for app %s, its OEM ping not sent.]"),
334 app_id.GetString()));
335 return false;
336 }
337
338 return RegKey::HasValue(GetClientStateKeyName(app_guid), kRegValueOemInstall);
339 }
340
341 // Vulnerable to a race condition with installers. To prevent this, hold
342 // GetRegistryStableStateLock() while calling this function and related
343 // functions, such as ReadAppPersistentData().
344 HRESULT AppManager::GetRegisteredApps(AppIdVector* app_ids) const {
345 ASSERT1(app_ids);
346
347 CollectProductsFunc func(IsRegisteredAppPredicate, *this, app_ids);
348
349 return EnumerateSubKeys(
350 ConfigManager::Instance()->registry_clients(is_machine_),
351 &func);
352 }
353
354 // Vulnerable to a race condition with installers. To prevent this, acquire
355 // GetRegistryStableStateLock().
356 HRESULT AppManager::GetUninstalledApps(AppIdVector* app_ids) const {
357 ASSERT1(app_ids);
358
359 CollectProductsFunc func(IsUninstalledAppPredicate, *this, app_ids);
360
361 return EnumerateSubKeys(
362 ConfigManager::Instance()->registry_client_state(is_machine_),
363 &func);
364 }
365
366 HRESULT AppManager::GetOemInstalledAndEulaAcceptedApps(
367 AppIdVector* app_ids) const {
368 ASSERT1(app_ids);
369
370 CollectProductsFunc func(IsAppOemInstalledAndEulaAcceptedPredicate,
371 *this,
372 app_ids);
373
374 return EnumerateSubKeys(
375 ConfigManager::Instance()->registry_client_state(is_machine_),
376 &func);
377 }
378
379 HRESULT AppManager::RunRegistrationUpdateHook(const CString& app_id) const {
380 return RunRegistrationUpdateHooksFunc(*this)(app_id);
381 }
382
383 // Vulnerable to a race condition with installers. We think this is acceptable.
384 // If there is a future requirement for greater consistency, acquire
385 // GetRegistryStableStateLock().
386 HRESULT AppManager::RunAllRegistrationUpdateHooks() const {
387 RunRegistrationUpdateHooksFunc func(*this);
388 const TCHAR* key(ConfigManager::Instance()->registry_clients(is_machine_));
389 return EnumerateSubKeys(key, &func);
390 }
391
392 CString AppManager::GetClientKeyName(const GUID& app_guid) const {
393 return app_registry_utils::GetAppClientsKey(is_machine_,
394 GuidToString(app_guid));
395 }
396
397 CString AppManager::GetClientStateKeyName(const GUID& app_guid) const {
398 return app_registry_utils::GetAppClientStateKey(is_machine_,
399 GuidToString(app_guid));
400 }
401
402 CString AppManager::GetClientStateMediumKeyName(const GUID& app_guid) const {
403 ASSERT1(is_machine_);
404 return app_registry_utils::GetAppClientStateMediumKey(is_machine_,
405 GuidToString(app_guid));
406 }
407
408 // Assumes the registry access lock is held.
409 HRESULT AppManager::OpenClientKey(const GUID& app_guid,
410 RegKey* client_key) const {
411 ASSERT1(client_key);
412 return client_key->Open(GetClientKeyName(app_guid), KEY_READ);
413 }
414
415 // Assumes the registry access lock is held.
416 HRESULT AppManager::OpenClientStateKey(const GUID& app_guid,
417 REGSAM sam_desired,
418 RegKey* client_state_key) const {
419 ASSERT1(client_state_key);
420 CString key_name = GetClientStateKeyName(app_guid);
421 return client_state_key->Open(key_name, sam_desired);
422 }
423
424 // Also creates the ClientStateMedium key for machine apps, ensuring it exists
425 // whenever ClientState exists. Does not create ClientStateMedium for Omaha.
426 // This function is called for self-updates, so it must explicitly avoid this.
427 // Assumes the registry access lock is held.
428 HRESULT AppManager::CreateClientStateKey(const GUID& app_guid,
429 RegKey* client_state_key) {
430 ASSERT1(client_state_key);
431 // TODO(omaha3): Add GetOwner() to GLock & add this to Open() functions too.
432 // ASSERT1(::GetCurrentThreadId() == registry_access_lock_.GetOwner());
433
434 const CString key_name = GetClientStateKeyName(app_guid);
435 HRESULT hr = client_state_key->Create(key_name);
436 if (FAILED(hr)) {
437 CORE_LOG(L3, (_T("[RegKey::Create failed][0x%08x]"), hr));
438 return hr;
439 }
440
441 if (!is_machine_) {
442 return S_OK;
443 }
444
445 if (::IsEqualGUID(kGoopdateGuid, app_guid)) {
446 return S_OK;
447 }
448
449 const CString medium_key_name = GetClientStateMediumKeyName(app_guid);
450 hr = RegKey::CreateKey(medium_key_name);
451 if (FAILED(hr)) {
452 CORE_LOG(L3, (_T("[RegKey::Create ClientStateMedium failed][0x%08x]"), hr));
453 return hr;
454 }
455
456 return S_OK;
457 }
458
459 // Reads the following values from the registry:
460 // Clients key
461 // pv
462 // lang
463 // name
464 // ClientState key
465 // lang (if not present in Clients)
466 // ap
467 // tttoken
468 // iid
469 // brand
470 // client
471 // experiment
472 // (referral is intentionally not read)
473 // InstallTime (converted to diff)
474 // oeminstall
475 // ClientState and ClientStateMedium key
476 // eulaaccepted
477 // ClientState key in HKCU/HKLM/Low integrity
478 // did run
479 //
480 // app_guid_ is set to the app_guid argument.
481 // Note: pv is not read from ClientState into app_data. It's
482 // presence is checked for an uninstall
483 // TODO(omaha3): We will need to get ClientState's pv when reporting uninstalls.
484 // Note: If the application is uninstalled, the Clients key may not exist.
485 HRESULT AppManager::ReadAppPersistentData(App* app) {
486 ASSERT1(app);
487
488 const GUID& app_guid = app->app_guid();
489 const CString& app_guid_string = app->app_guid_string();
490
491 CORE_LOG(L2, (_T("[AppManager::ReadAppPersistentData][%s]"),
492 app_guid_string));
493
494 ASSERT1(app->model()->IsLockedByCaller());
495
496 __mutexScope(registry_access_lock_);
497
498 const bool is_eula_accepted =
499 app_registry_utils::IsAppEulaAccepted(is_machine_,
500 app_guid_string,
501 false);
502 app->is_eula_accepted_ = is_eula_accepted ? TRISTATE_TRUE : TRISTATE_FALSE;
503
504 bool client_key_exists = false;
505 RegKey client_key;
506 HRESULT hr = OpenClientKey(app_guid, &client_key);
507 if (SUCCEEDED(hr)) {
508 client_key_exists = true;
509
510 CString version;
511 hr = client_key.GetValue(kRegValueProductVersion, &version);
512 CORE_LOG(L3, (_T("[AppManager::ReadAppPersistentData]")
513 _T("[%s][version=%s]"), app_guid_string, version));
514 if (FAILED(hr)) {
515 return hr;
516 }
517
518 app->current_version()->set_version(version);
519
520 // Language and name might not be written by installer, so ignore failures.
521 client_key.GetValue(kRegValueLanguage, &app->language_);
522 client_key.GetValue(kRegValueAppName, &app->display_name_);
523 }
524
525 // Ensure there is a valid display name.
526 if (app->display_name_.IsEmpty()) {
527 StringFormatter formatter(app->app_bundle()->display_language());
528
529 CString company_name;
530 VERIFY1(SUCCEEDED(formatter.LoadString(IDS_FRIENDLY_COMPANY_NAME,
531 &company_name)));
532
533 VERIFY1(SUCCEEDED(formatter.FormatMessage(&app->display_name_,
534 IDS_DEFAULT_APP_DISPLAY_NAME,
535 company_name)));
536 }
537
538 // If ClientState registry key doesn't exist, the function could return.
539 // Before opening the key, set days_since_last* to -1, which is the
540 // default value if reg key doesn't exist. If later we find that the values
541 // are readable, new values will overwrite current ones.
542 app->set_days_since_last_active_ping(-1);
543 app->set_days_since_last_roll_call(-1);
544
545 // The following do not rely on client_state_key, so check them before
546 // possibly returning if OpenClientStateKey fails.
547
548 // Reads the did run value.
549 ApplicationUsageData app_usage(is_machine_, vista_util::IsVistaOrLater());
550 app_usage.ReadDidRun(app_guid_string);
551
552 // Sets did_run regardless of the return value of ReadDidRun above. If read
553 // fails, active_state() should return ACTIVE_UNKNOWN which is intented.
554 app->did_run_ = app_usage.active_state();
555
556 // TODO(omaha3): Consider moving GetInstallTimeDiffSec() up here. Be careful
557 // that the results when ClientState does not exist are desirable. See the
558 // comments near that function and above set_days_since_last_active_ping call.
559
560 RegKey client_state_key;
561 hr = OpenClientStateKey(app_guid, KEY_READ, &client_state_key);
562 if (FAILED(hr)) {
563 // It is possible that the client state key has not yet been populated.
564 // In this case just return the information that we have gathered thus far.
565 // However if both keys do not exist, then we are doing something wrong.
566 CORE_LOG(LW, (_T("[AppManager::ReadAppPersistentData - No ClientState]")));
567 if (client_key_exists) {
568 return S_OK;
569 } else {
570 return hr;
571 }
572 }
573
574 // Read language from ClientState key if it was not found in the Clients key.
575 if (app->language().IsEmpty()) {
576 client_state_key.GetValue(kRegValueLanguage, &app->language_);
577 }
578
579 client_state_key.GetValue(kRegValueAdditionalParams, &app->ap_);
580 client_state_key.GetValue(kRegValueTTToken, &app->tt_token_);
581
582 CString iid;
583 client_state_key.GetValue(kRegValueInstallationId, &iid);
584 GUID iid_guid;
585 if (SUCCEEDED(StringToGuidSafe(iid, &iid_guid))) {
586 app->iid_ = iid_guid;
587 }
588
589 client_state_key.GetValue(kRegValueBrandCode, &app->brand_code_);
590 ASSERT1(app->brand_code_.GetLength() <= kBrandIdLength);
591 client_state_key.GetValue(kRegValueClientId, &app->client_id_);
592
593 // We do not need the referral_id.
594
595 DWORD last_active_ping_sec(0);
596 if (SUCCEEDED(client_state_key.GetValue(kRegValueActivePingDayStartSec,
597 &last_active_ping_sec))) {
598 int days_since_last_active_ping =
599 GetNumberOfDaysSince(static_cast<int32>(last_active_ping_sec));
600 app->set_days_since_last_active_ping(days_since_last_active_ping);
601 }
602
603 DWORD last_roll_call_sec(0);
604 if (SUCCEEDED(client_state_key.GetValue(kRegValueRollCallDayStartSec,
605 &last_roll_call_sec))) {
606 int days_since_last_roll_call =
607 GetNumberOfDaysSince(static_cast<int32>(last_roll_call_sec));
608 app->set_days_since_last_roll_call(days_since_last_roll_call);
609 }
610
611 app->install_time_diff_sec_ = GetInstallTimeDiffSec(app_guid);
612 // Generally GetInstallTimeDiffSec() shouldn't return kInitialInstallTimeDiff
613 // here. The only exception is in the unexpected case when ClientState exists
614 // without a pv.
615 ASSERT1((app->install_time_diff_sec_ != kInitialInstallTimeDiff) ||
616 !RegKey::HasValue(GetClientStateKeyName(app_guid),
617 kRegValueProductVersion));
618
619 return S_OK;
620 }
621
622 void AppManager::ReadAppInstallTimeDiff(App* app) {
623 ASSERT1(app);
624 app->install_time_diff_sec_ = GetInstallTimeDiffSec(app->app_guid());
625 }
626
627 // Calls ReadAppPersistentData() to populate app and adds the following values
628 // specific to uninstalled apps:
629 // ClientState key
630 // pv: set as current_version()->version
631 //
632 // Since this is an uninstalled app, values from the Clients key should not be
633 // populated.
634 HRESULT AppManager::ReadUninstalledAppPersistentData(App* app) {
635 ASSERT1(app);
636 ASSERT1(!IsAppRegistered(app->app_guid_string()));
637
638 HRESULT hr = ReadAppPersistentData(app);
639 if (FAILED(hr)) {
640 return hr;
641 }
642
643 ASSERT1(app->current_version()->version().IsEmpty());
644
645 RegKey client_state_key;
646 hr = OpenClientStateKey(app->app_guid(), KEY_READ, &client_state_key);
647 ASSERT(SUCCEEDED(hr), (_T("Uninstalled apps have a ClientState key.")));
648
649 CString version;
650 hr = client_state_key.GetValue(kRegValueProductVersion, &version);
651 CORE_LOG(L3, (_T("[AppManager::ReadAppPersistentData]")
652 _T("[%s][uninstalled version=%s]"),
653 app->app_guid_string(), version));
654 ASSERT(SUCCEEDED(hr), (_T("Uninstalled apps have a pv.")));
655 app->current_version()->set_version(version);
656
657 return S_OK;
658 }
659
660 // Sets the following values in the app's ClientState, to make them available to
661 // the installer:
662 // lang
663 // ap
664 // brand (in SetAppBranding)
665 // client (in SetAppBranding)
666 // experiment
667 // referral (in SetAppBranding)
668 // InstallTime (in SetAppBranding; converted from diff)
669 // oeminstall (if appropriate)
670 // eulaaccepted (set/deleted)
671 // browser
672 // usagestats
673 // Sets eulaaccepted=0 if the app is not already registered and the app's EULA
674 // has not been accepted. Deletes eulaaccepted if the EULA has been accepted.
675 // Only call for initial or over-installs. Do not call for updates to avoid
676 // mistakenly replacing data, such as the application's language, and causing
677 // unexpected changes to the app during a silent update.
678 HRESULT AppManager::WritePreInstallData(const App& app) {
679 CORE_LOG(L2, (_T("[AppManager::WritePreInstallData][%s]"),
680 app.app_guid_string()));
681
682 ASSERT1(app.app_bundle()->is_machine() == is_machine_);
683
684 ASSERT1(IsRegistryStableStateLockedByCaller());
685 __mutexScope(registry_access_lock_);
686
687 RegKey client_state_key;
688 HRESULT hr = CreateClientStateKey(app.app_guid(), &client_state_key);
689 if (FAILED(hr)) {
690 return hr;
691 }
692
693 if (app.is_eula_accepted()) {
694 hr = app_registry_utils::ClearAppEulaNotAccepted(is_machine_,
695 app.app_guid_string());
696 } else {
697 if (!IsAppRegistered(app.app_guid())) {
698 hr = app_registry_utils::SetAppEulaNotAccepted(is_machine_,
699 app.app_guid_string());
700 }
701 }
702 if (FAILED(hr)) {
703 return hr;
704 }
705
706 if (!app.language().IsEmpty()) {
707 VERIFY1(SUCCEEDED(client_state_key.SetValue(kRegValueLanguage,
708 app.language())));
709 }
710
711 if (app.ap().IsEmpty()) {
712 VERIFY1(SUCCEEDED(client_state_key.DeleteValue(kRegValueAdditionalParams)));
713 } else {
714 VERIFY1(SUCCEEDED(client_state_key.SetValue(kRegValueAdditionalParams,
715 app.ap())));
716 }
717
718 CString state_key_path = GetClientStateKeyName(app.app_guid());
719 VERIFY1(SUCCEEDED(app_registry_utils::SetAppBranding(state_key_path,
720 app.brand_code(),
721 app.client_id(),
722 app.referral_id())));
723
724 if (app.GetExperimentLabels().IsEmpty()) {
725 VERIFY1(SUCCEEDED(client_state_key.DeleteValue(kRegValueExperimentLabels)));
726 } else {
727 VERIFY1(SUCCEEDED(client_state_key.SetValue(kRegValueExperimentLabels,
728 app.GetExperimentLabels())));
729 }
730
731 if (oem_install_utils::IsOemInstalling(is_machine_)) {
732 ASSERT1(is_machine_);
733 VERIFY1(SUCCEEDED(client_state_key.SetValue(kRegValueOemInstall, _T("1"))));
734 }
735
736 if (BROWSER_UNKNOWN == app.browser_type()) {
737 VERIFY1(SUCCEEDED(client_state_key.DeleteValue(kRegValueBrowser)));
738 } else {
739 DWORD browser_type = app.browser_type();
740 VERIFY1(SUCCEEDED(client_state_key.SetValue(kRegValueBrowser,
741 browser_type)));
742 }
743
744 if (TRISTATE_NONE != app.usage_stats_enable()) {
745 VERIFY1(SUCCEEDED(app_registry_utils::SetUsageStatsEnable(
746 is_machine_,
747 app.app_guid_string(),
748 app.usage_stats_enable())));
749 }
750
751 return S_OK;
752 }
753
754 // All values are optional.
755 void AppManager::ReadInstallerResultApiValues(
756 const GUID& app_guid,
757 InstallerResult* installer_result,
758 DWORD* installer_error,
759 DWORD* installer_extra_code1,
760 CString* installer_result_uistring,
761 CString* installer_success_launch_cmd) {
762 ASSERT1(installer_result);
763 ASSERT1(installer_error);
764 ASSERT1(installer_extra_code1);
765 ASSERT1(installer_result_uistring);
766 ASSERT1(installer_success_launch_cmd);
767
768 __mutexScope(registry_access_lock_);
769
770 RegKey client_state_key;
771 HRESULT hr = OpenClientStateKey(app_guid, KEY_READ, &client_state_key);
772 if (FAILED(hr)) {
773 return;
774 }
775
776 if (SUCCEEDED(client_state_key.GetValue(
777 kRegValueInstallerResult,
778 reinterpret_cast<DWORD*>(installer_result)))) {
779 CORE_LOG(L1, (_T("[InstallerResult in registry][%u]"), *installer_result));
780 }
781 if (*installer_result >= INSTALLER_RESULT_MAX) {
782 CORE_LOG(LW, (_T("[Unsupported InstallerResult value]")));
783 *installer_result = INSTALLER_RESULT_DEFAULT;
784 }
785
786 if (SUCCEEDED(client_state_key.GetValue(kRegValueInstallerError,
787 installer_error))) {
788 CORE_LOG(L1, (_T("[InstallerError in registry][%u]"), *installer_error));
789 }
790
791 if (SUCCEEDED(client_state_key.GetValue(kRegValueInstallerExtraCode1,
792 installer_extra_code1))) {
793 CORE_LOG(L1, (_T("[InstallerExtraCode1 in registry][%u]"),
794 *installer_extra_code1));
795 }
796
797 if (SUCCEEDED(client_state_key.GetValue(kRegValueInstallerResultUIString,
798 installer_result_uistring))) {
799 CORE_LOG(L1, (_T("[InstallerResultUIString in registry][%s]"),
800 *installer_result_uistring));
801 }
802
803 if (SUCCEEDED(client_state_key.GetValue(
804 kRegValueInstallerSuccessLaunchCmdLine,
805 installer_success_launch_cmd))) {
806 CORE_LOG(L1, (_T("[InstallerSuccessLaunchCmdLine in registry][%s]"),
807 *installer_success_launch_cmd));
808 }
809
810 ClearInstallerResultApiValues(app_guid);
811 }
812
813 void AppManager::ClearInstallerResultApiValues(const GUID& app_guid) {
814 const CString client_state_key_name = GetClientStateKeyName(app_guid);
815 const CString update_key_name =
816 ConfigManager::Instance()->registry_update(is_machine_);
817
818 ASSERT1(IsRegistryStableStateLockedByCaller());
819 __mutexScope(registry_access_lock_);
820
821 // Delete the old LastXXX values. These may not exist, so don't care if they
822 // fail.
823 RegKey::DeleteValue(client_state_key_name,
824 kRegValueLastInstallerResult);
825 RegKey::DeleteValue(client_state_key_name,
826 kRegValueLastInstallerResultUIString);
827 RegKey::DeleteValue(client_state_key_name,
828 kRegValueLastInstallerError);
829 RegKey::DeleteValue(client_state_key_name,
830 kRegValueLastInstallerExtraCode1);
831 RegKey::DeleteValue(client_state_key_name,
832 kRegValueLastInstallerSuccessLaunchCmdLine);
833
834 // Also delete any values from Google\Update.
835 // TODO(Omaha): This is a temporary fix for bug 1539293. See TODO below.
836 RegKey::DeleteValue(update_key_name,
837 kRegValueLastInstallerResult);
838 RegKey::DeleteValue(update_key_name,
839 kRegValueLastInstallerResultUIString);
840 RegKey::DeleteValue(update_key_name,
841 kRegValueLastInstallerError);
842 RegKey::DeleteValue(update_key_name,
843 kRegValueLastInstallerExtraCode1);
844 RegKey::DeleteValue(update_key_name,
845 kRegValueLastInstallerSuccessLaunchCmdLine);
846
847 // Rename current InstallerResultXXX values to LastXXX.
848 RegKey::RenameValue(client_state_key_name,
849 kRegValueInstallerResult,
850 kRegValueLastInstallerResult);
851 RegKey::RenameValue(client_state_key_name,
852 kRegValueInstallerError,
853 kRegValueLastInstallerError);
854 RegKey::RenameValue(client_state_key_name,
855 kRegValueInstallerExtraCode1,
856 kRegValueLastInstallerExtraCode1);
857 RegKey::RenameValue(client_state_key_name,
858 kRegValueInstallerResultUIString,
859 kRegValueLastInstallerResultUIString);
860 RegKey::RenameValue(client_state_key_name,
861 kRegValueInstallerSuccessLaunchCmdLine,
862 kRegValueLastInstallerSuccessLaunchCmdLine);
863
864 // Copy over to the Google\Update key.
865 // TODO(Omaha3): This is a temporary fix for bug 1539293. Once Pack V2 is
866 // deprecated (Pack stops taking offline installers for new versions of
867 // Omaha apps), remove this. (It might be useful to leave the CopyValue calls
868 // in DEBUG builds only.)
869 RegKey::CopyValue(client_state_key_name,
870 update_key_name,
871 kRegValueLastInstallerResult);
872 RegKey::CopyValue(client_state_key_name,
873 update_key_name,
874 kRegValueLastInstallerError);
875 RegKey::CopyValue(client_state_key_name,
876 update_key_name,
877 kRegValueLastInstallerExtraCode1);
878 RegKey::CopyValue(client_state_key_name,
879 update_key_name,
880 kRegValueLastInstallerResultUIString);
881 RegKey::CopyValue(client_state_key_name,
882 update_key_name,
883 kRegValueLastInstallerSuccessLaunchCmdLine);
884 }
885
886 // Reads the following values from Clients:
887 // pv
888 // lang (if present)
889 // name is not read. TODO(omaha3): May change if we persist name in registry.
890 HRESULT AppManager::ReadInstallerRegistrationValues(App* app) {
891 ASSERT1(app);
892
893 const CString& app_guid_string = app->app_guid_string();
894
895 CORE_LOG(L2, (_T("[AppManager::ReadInstallerRegistrationValues][%s]"),
896 app_guid_string));
897
898 ASSERT1(app->model()->IsLockedByCaller());
899
900 __mutexScope(registry_access_lock_);
901
902 RegKey client_key;
903 if (FAILED(OpenClientKey(app->app_guid(), &client_key))) {
904 OPT_LOG(LE, (_T("[Installer did not create key][%s]"), app_guid_string));
905 return GOOPDATEINSTALL_E_INSTALLER_DID_NOT_WRITE_CLIENTS_KEY;
906 }
907
908 CString version;
909 if (FAILED(client_key.GetValue(kRegValueProductVersion, &version))) {
910 OPT_LOG(LE, (_T("[Installer did not register][%s]"), app_guid_string));
911 return GOOPDATEINSTALL_E_INSTALLER_DID_NOT_WRITE_CLIENTS_KEY;
912 }
913
914 if (version.IsEmpty()) {
915 OPT_LOG(LE, (_T("[Installer did not write version][%s]"), app_guid_string));
916 return GOOPDATEINSTALL_E_INSTALLER_DID_NOT_WRITE_CLIENTS_KEY;
917 }
918
919 app->next_version()->set_version(version);
920
921 CString language;
922 if (SUCCEEDED(client_key.GetValue(kRegValueLanguage, &language))) {
923 app->language_ = language;
924 }
925
926 return S_OK;
927 }
928
929 // Writes tttoken and updates relevant stats.
930 void AppManager::PersistSuccessfulUpdateCheckResponse(
931 const App& app,
932 bool is_update_available) {
933 CORE_LOG(L2, (_T("[AppManager::PersistSuccessfulUpdateCheckResponse]")
934 _T("[%s][%d]"), app.app_guid_string(), is_update_available));
935 __mutexScope(registry_access_lock_);
936
937 VERIFY1(SUCCEEDED(SetTTToken(app)));
938
939 const CString client_state_key = GetClientStateKeyName(app.app_guid());
940
941 if (is_update_available) {
942 if (app.error_code() == GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY) {
943 // The error indicates is_update and updates are disabled by policy.
944 ASSERT1(app.is_update());
945 app_registry_utils::ClearUpdateAvailableStats(client_state_key);
946 } else if (app.is_update()) {
947 // Only record an update available event for updates.
948 // We have other mechanisms, including IID, to track install success.
949 UpdateUpdateAvailableStats(app.app_guid());
950 }
951 } else {
952 app_registry_utils::ClearUpdateAvailableStats(client_state_key);
953 app_registry_utils::PersistSuccessfulUpdateCheck(client_state_key);
954 }
955 }
956
957 // Writes the following values to the ClientState key:
958 // pv (should be value written by installer in Clients key)
959 // lang (should be value written by installer in Clients key)
960 // iid (set/deleted)
961 //
962 // Does not write the following values because they were set by
963 // WritePreInstallData() and would not have changed during installation unless
964 // modified directly by the app installer.
965 // ap
966 // brand
967 // client
968 // experiment
969 // referral
970 // InstallTime (converted from diff)
971 // oeminstall
972 // eulaaccepted
973 // browser
974 // usagestats
975 // TODO(omaha3): Maybe we should delete referral at this point. Ask Chrome.
976 //
977 // Other values, such as tttoken were set after the update check.
978 //
979 // The caller is responsible for modifying the values in app_data as
980 // appropriate, including:
981 // * Updating values in app_data to reflect installer's values (pv and lang)
982 // * Clearing iid if appropriate.
983 // * Clearing the did run value. TODO(omaha3): Depends on TODO below.
984 void AppManager::PersistSuccessfulInstall(const App& app) {
985 CORE_LOG(L2, (_T("[AppManager::PersistSuccessfulInstall][%s]"),
986 app.app_guid_string()));
987
988 ASSERT1(IsRegistryStableStateLockedByCaller());
989 __mutexScope(registry_access_lock_);
990
991 ASSERT1(!::IsEqualGUID(kGoopdateGuid, app.app_guid()));
992
993 RegKey client_state_key;
994 VERIFY1(SUCCEEDED(CreateClientStateKey(app.app_guid(), &client_state_key)));
995
996 VERIFY1(SUCCEEDED(client_state_key.SetValue(kRegValueProductVersion,
997 app.next_version()->version())));
998
999 if (!app.language().IsEmpty()) {
1000 VERIFY1(SUCCEEDED(client_state_key.SetValue(kRegValueLanguage,
1001 app.language())));
1002 }
1003
1004 if (::IsEqualGUID(app.iid(), GUID_NULL)) {
1005 VERIFY1(SUCCEEDED(client_state_key.DeleteValue(kRegValueInstallationId)));
1006 } else {
1007 VERIFY1(SUCCEEDED(client_state_key.SetValue(
1008 kRegValueInstallationId,
1009 GuidToString(app.iid()))));
1010 }
1011
1012 const CString client_state_key_path = GetClientStateKeyName(app.app_guid());
1013 app_registry_utils::PersistSuccessfulInstall(client_state_key_path,
1014 app.is_update(),
1015 false); // TODO(omaha3): offline
1016 }
1017
1018 HRESULT AppManager::SynchronizeClientState(const GUID& app_guid) {
1019 __mutexScope(registry_access_lock_);
1020
1021 RegKey client_key;
1022 HRESULT hr = OpenClientKey(app_guid, &client_key);
1023 if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) {
1024 return S_OK;
1025 }
1026 if (FAILED(hr)) {
1027 return hr;
1028 }
1029
1030 RegKey client_state_key;
1031 hr = CreateClientStateKey(app_guid, &client_state_key);
1032 if (FAILED(hr)) {
1033 return hr;
1034 }
1035
1036 CString version;
1037 client_key.GetValue(kRegValueProductVersion, &version);
1038 if (FAILED(hr)) {
1039 return hr;
1040 }
1041 hr = client_state_key.SetValue(kRegValueProductVersion, version);
1042 if (FAILED(hr)) {
1043 return hr;
1044 }
1045
1046 CString language;
1047 client_key.GetValue(kRegValueLanguage, &language);
1048 if (!language.IsEmpty()) {
1049 return client_state_key.SetValue(kRegValueLanguage, language);
1050 }
1051
1052 return S_OK;
1053 }
1054
1055 // TODO(omaha3): tttoken is not currently read from the server response.
1056 // TODO(omaha3): When implementing offline, we must make sure that the tttoken
1057 // is not deleted by the offline response processing.
1058 // TODO(omaha3): Having the parser write the server's token to the same member
1059 // that is used for the value from the tag exposes this value to the COM setter.
1060 // It would be nice to avoid that, possibly by only allowing that setter to work
1061 // in certain states.
1062 HRESULT AppManager::SetTTToken(const App& app) {
1063 CORE_LOG(L3, (_T("[AppManager::SetTTToken][token=%s]"), app.tt_token()));
1064
1065 __mutexScope(registry_access_lock_);
1066
1067 RegKey client_state_key;
1068 HRESULT hr = CreateClientStateKey(app.app_guid(), &client_state_key);
1069 if (FAILED(hr)) {
1070 return hr;
1071 }
1072
1073 if (app.tt_token().IsEmpty()) {
1074 return client_state_key.DeleteValue(kRegValueTTToken);
1075 } else {
1076 return client_state_key.SetValue(kRegValueTTToken, app.tt_token());
1077 }
1078 }
1079
1080 void AppManager::ClearOemInstalled(const AppIdVector& app_ids) {
1081 __mutexScope(registry_access_lock_);
1082
1083 AppIdVector::const_iterator it;
1084 for (it = app_ids.begin(); it != app_ids.end(); ++it) {
1085 ASSERT1(IsAppOemInstalledAndEulaAccepted(*it));
1086 RegKey state_key;
1087
1088 GUID app_guid = GUID_NULL;
1089 HRESULT hr = StringToGuidSafe(*it, &app_guid);
1090 if (FAILED(hr)) {
1091 continue;
1092 }
1093
1094 hr = OpenClientStateKey(app_guid, KEY_ALL_ACCESS, &state_key);
1095 if (FAILED(hr)) {
1096 continue;
1097 }
1098
1099 VERIFY1(SUCCEEDED(state_key.DeleteValue(kRegValueOemInstall)));
1100 }
1101 }
1102
1103 void AppManager::UpdateUpdateAvailableStats(const GUID& app_guid) {
1104 __mutexScope(registry_access_lock_);
1105
1106 RegKey state_key;
1107 HRESULT hr = CreateClientStateKey(app_guid, &state_key);
1108 if (FAILED(hr)) {
1109 ASSERT1(false);
1110 return;
1111 }
1112
1113 DWORD update_available_count(0);
1114 hr = state_key.GetValue(kRegValueUpdateAvailableCount,
1115 &update_available_count);
1116 if (FAILED(hr)) {
1117 update_available_count = 0;
1118 }
1119 ++update_available_count;
1120 VERIFY1(SUCCEEDED(state_key.SetValue(kRegValueUpdateAvailableCount,
1121 update_available_count)));
1122
1123 DWORD64 update_available_since_time(0);
1124 hr = state_key.GetValue(kRegValueUpdateAvailableSince,
1125 &update_available_since_time);
1126 if (FAILED(hr)) {
1127 // There is no existing value, so this must be the first update notice.
1128 VERIFY1(SUCCEEDED(state_key.SetValue(kRegValueUpdateAvailableSince,
1129 GetCurrent100NSTime())));
1130
1131 // TODO(omaha): It would be nice to report the version that we were first
1132 // told to update to. This is available in UpdateResponse but we do not
1133 // currently send it down in update responses. If we start using it, add
1134 // kRegValueFirstUpdateResponseVersion.
1135 }
1136 }
1137
1138 // Returns 0 for any values that are not found.
1139 void AppManager::ReadUpdateAvailableStats(
1140 const GUID& app_guid,
1141 DWORD* update_responses,
1142 DWORD64* time_since_first_response_ms) {
1143 ASSERT1(update_responses);
1144 ASSERT1(time_since_first_response_ms);
1145 *update_responses = 0;
1146 *time_since_first_response_ms = 0;
1147
1148 __mutexScope(registry_access_lock_);
1149
1150 RegKey state_key;
1151 HRESULT hr = OpenClientStateKey(app_guid, KEY_READ, &state_key);
1152 if (FAILED(hr)) {
1153 CORE_LOG(LW, (_T("[App ClientState key does not exist][%s]"),
1154 GuidToString(app_guid)));
1155 return;
1156 }
1157
1158 DWORD update_responses_in_reg(0);
1159 hr = state_key.GetValue(kRegValueUpdateAvailableCount,
1160 &update_responses_in_reg);
1161 if (SUCCEEDED(hr)) {
1162 *update_responses = update_responses_in_reg;
1163 }
1164
1165 DWORD64 update_available_since_time(0);
1166 hr = state_key.GetValue(kRegValueUpdateAvailableSince,
1167 &update_available_since_time);
1168 if (SUCCEEDED(hr)) {
1169 const DWORD64 current_time = GetCurrent100NSTime();
1170 ASSERT1(update_available_since_time <= current_time);
1171 const DWORD64 time_since_first_response_in_100ns =
1172 current_time - update_available_since_time;
1173 *time_since_first_response_ms =
1174 time_since_first_response_in_100ns / kMillisecsTo100ns;
1175 }
1176 }
1177
1178 uint32 AppManager::GetInstallTimeDiffSec(const GUID& app_guid) const {
1179 if (!IsAppRegistered(app_guid) && !IsAppUninstalled(app_guid)) {
1180 return kInitialInstallTimeDiff;
1181 }
1182
1183 RegKey client_state_key;
1184 HRESULT hr = OpenClientStateKey(app_guid, KEY_READ, &client_state_key);
1185 if (FAILED(hr)) {
1186 return 0;
1187 }
1188
1189 DWORD install_time(0);
1190 DWORD install_time_diff_sec(0);
1191 if (SUCCEEDED(client_state_key.GetValue(kRegValueInstallTimeSec,
1192 &install_time))) {
1193 const uint32 now = Time64ToInt32(GetCurrent100NSTime());
1194 if (0 != install_time && now >= install_time) {
1195 install_time_diff_sec = now - install_time;
1196 // TODO(omaha3): Restore this assert. In Omaha 2, this function gets
1197 // called as part of installation verification and Job::UpdateJob(), so
1198 // the value can be 0. This will not be the case in Omaha 3.
1199 // ASSERT1(install_time_diff_sec != 0);
1200 }
1201 }
1202
1203 return install_time_diff_sec;
1204 }
1205
1206 // Clear the Installation ID if at least one of the conditions is true:
1207 // 1) DidRun==yes. First run is the last time we want to use the Installation
1208 // ID. So delete Installation ID if it is present.
1209 // 2) kMaxLifeOfInstallationIDSec has passed since the app was installed. This
1210 // is to ensure that Installation ID is cleared even if DidRun is never set.
1211 // 3) The app is Omaha. Always delete Installation ID if it is present
1212 // because DidRun does not apply.
1213 HRESULT AppManager::ClearInstallationId(const App& app) {
1214 ASSERT1(app.model()->IsLockedByCaller());
1215 __mutexScope(registry_access_lock_);
1216
1217 if (::IsEqualGUID(app.iid(), GUID_NULL)) {
1218 return S_OK;
1219 }
1220
1221 if ((ACTIVE_RUN == app.did_run()) ||
1222 (kMaxLifeOfInstallationIDSec <= app.install_time_diff_sec()) ||
1223 (::IsEqualGUID(kGoopdateGuid, app.app_guid()))) {
1224 CORE_LOG(L1, (_T("[Deleting iid for app][%s]"), app.app_guid_string()));
1225
1226 RegKey client_state_key;
1227 HRESULT hr = CreateClientStateKey(app.app_guid(), &client_state_key);
1228 if (FAILED(hr)) {
1229 return hr;
1230 }
1231
1232 return client_state_key.DeleteValue(kRegValueInstallationId);
1233 }
1234
1235 return S_OK;
1236 }
1237
1238 void AppManager::SetLastPingDayStartTime(const App& app,
1239 int elapsed_seconds_since_day_start) {
1240 ASSERT1(elapsed_seconds_since_day_start >= 0);
1241 ASSERT1(elapsed_seconds_since_day_start < kMaxTimeSinceMidnightSec);
1242 ASSERT1(app.model()->IsLockedByCaller());
1243
1244 __mutexScope(registry_access_lock_);
1245
1246 int now = Time64ToInt32(GetCurrent100NSTime());
1247
1248 RegKey client_state_key;
1249 if (FAILED(CreateClientStateKey(app.app_guid(), &client_state_key))) {
1250 return;
1251 }
1252
1253 bool did_send_active_ping = (app.did_run() == ACTIVE_RUN &&
1254 app.days_since_last_active_ping() != 0);
1255 if (did_send_active_ping) {
1256 VERIFY1(SUCCEEDED(client_state_key.SetValue(
1257 kRegValueActivePingDayStartSec,
1258 static_cast<DWORD>(now - elapsed_seconds_since_day_start))));
1259 }
1260
1261 bool did_send_roll_call = (app.days_since_last_roll_call() != 0);
1262 if (did_send_roll_call) {
1263 VERIFY1(SUCCEEDED(client_state_key.SetValue(
1264 kRegValueRollCallDayStartSec,
1265 static_cast<DWORD>(now - elapsed_seconds_since_day_start))));
1266 }
1267 }
1268
1269 // Writes the day start time when last active ping/roll call happened to
1270 // registry if the corresponding ping has been sent.
1271 // Removes installation id, if did run = true or if goopdate.
1272 // Clears did run.
1273 HRESULT AppManager::PersistUpdateCheckSuccessfullySent(
1274 const App& app,
1275 int elapsed_seconds_since_day_start) {
1276 ASSERT1(app.model()->IsLockedByCaller());
1277
1278 ApplicationUsageData app_usage(app.app_bundle()->is_machine(),
1279 vista_util::IsVistaOrLater());
1280 VERIFY1(SUCCEEDED(app_usage.ResetDidRun(app.app_guid_string())));
1281
1282 SetLastPingDayStartTime(app, elapsed_seconds_since_day_start);
1283
1284 // Handle the installation id.
1285 VERIFY1(SUCCEEDED(ClearInstallationId(app)));
1286
1287 return S_OK;
1288 }
1289
1290 HRESULT AppManager::RemoveClientState(const GUID& app_guid) {
1291 CORE_LOG(L2, (_T("[AppManager::RemoveClientState][%s]"),
1292 GuidToString(app_guid)));
1293 ASSERT1(IsRegistryStableStateLockedByCaller());
1294 __mutexScope(registry_access_lock_);
1295
1296 ASSERT1(!IsAppRegistered(app_guid));
1297
1298 return app_registry_utils::RemoveClientState(is_machine_,
1299 GuidToString(app_guid));
1300 }
1301
1302 // TODO(omaha3): May not need these
1303 #if 0
1304 // Writes 0.0.0.1 to pv. This value avoids any special cases, such as initial
1305 // install rules, for 0.0.0.0, while being unlikely to be higher than the
1306 // product's actual current version.
1307 HRESULT AppManager::RegisterProduct(const GUID& product_guid,
1308 const CString& product_name) {
1309 const TCHAR* const kRegisterProductVersion = _T("0.0.0.1");
1310
1311 __mutexScope(GetRegistryStableStateLock());
1312 RegKey client_key;
1313 HRESULT hr = client_key.Create(GetClientKeyName(GUID_NULL, product_guid));
1314 if (FAILED(hr)) {
1315 return hr;
1316 }
1317
1318 hr = client_key.SetValue(kRegValueProductVersion, kRegisterProductVersion);
1319 if (FAILED(hr)) {
1320 return hr;
1321 }
1322
1323 // AppName is not a required parameter since it's only used for being able to
1324 // easily tell what application is there when reading the registry.
1325 VERIFY1(SUCCEEDED(client_key.SetValue(kRegValueAppName, product_name)));
1326
1327 return S_OK;
1328 }
1329
1330 HRESULT AppManager::UnregisterProduct(const GUID& product_guid) {
1331 __mutexScope(GetRegistryStableStateLock());
1332 return RegKey::DeleteKey(GetClientKeyName(GUID_NULL, product_guid), true);
1333 }
1334 #endif
1335
1336 } // namespace omaha
OLDNEW
« no previous file with comments | « goopdate/app_manager.h ('k') | goopdate/app_manager_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698