Index: goopdate/app_manager.cc |
diff --git a/goopdate/app_manager.cc b/goopdate/app_manager.cc |
deleted file mode 100644 |
index a517354a804b9923cdf13ce26c3846bd5c9c3efc..0000000000000000000000000000000000000000 |
--- a/goopdate/app_manager.cc |
+++ /dev/null |
@@ -1,1336 +0,0 @@ |
-// Copyright 2007-2010 Google Inc. |
-// |
-// Licensed under the Apache License, Version 2.0 (the "License"); |
-// you may not use this file except in compliance with the License. |
-// You may obtain a copy of the License at |
-// |
-// http://www.apache.org/licenses/LICENSE-2.0 |
-// |
-// Unless required by applicable law or agreed to in writing, software |
-// distributed under the License is distributed on an "AS IS" BASIS, |
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
-// See the License for the specific language governing permissions and |
-// limitations under the License. |
-// ======================================================================== |
- |
-#include "omaha/goopdate/app_manager.h" |
-#include <algorithm> |
-#include <cstdlib> |
-#include <functional> |
-#include <map> |
-#include "base/scoped_ptr.h" |
-#include "omaha/base/const_object_names.h" |
-#include "omaha/base/error.h" |
-#include "omaha/base/reg_key.h" |
-#include "omaha/base/scoped_ptr_address.h" |
-#include "omaha/base/time.h" |
-#include "omaha/base/utils.h" |
-#include "omaha/base/vistautil.h" |
-#include "omaha/common/app_registry_utils.h" |
-#include "omaha/common/config_manager.h" |
-#include "omaha/common/const_goopdate.h" |
-#include "omaha/common/oem_install_utils.h" |
-#include "omaha/goopdate/application_usage_data.h" |
-#include "omaha/goopdate/model.h" |
-#include "omaha/goopdate/server_resource.h" |
-#include "omaha/goopdate/string_formatter.h" |
- |
-namespace omaha { |
- |
-namespace { |
- |
-const uint32 kInitialInstallTimeDiff = static_cast<uint32>(-1 * kSecondsPerDay); |
- |
-// Returns the number of days haven been passed since the given time. |
-// The parameter time is in the same format as C time() returns. |
-int GetNumberOfDaysSince(int time) { |
- ASSERT1(time >= 0); |
- const int now = Time64ToInt32(GetCurrent100NSTime()); |
- ASSERT1(now >= time); |
- |
- if (now < time) { |
- // In case the client computer clock is adjusted in between. |
- return 0; |
- } |
- return (now - time) / kSecondsPerDay; |
-} |
- |
-// Determines if an application is registered with Omaha. |
-class IsAppRegisteredFunc |
- : public std::unary_function<const CString&, HRESULT> { |
- public: |
- explicit IsAppRegisteredFunc(const CString& guid) |
- : is_registered_(false), |
- guid_(guid) {} |
- |
- bool is_registered() const { return is_registered_; } |
- |
- HRESULT operator() (const CString& guid) { |
- if (guid.CompareNoCase(guid_) == 0) { |
- is_registered_ = true; |
- } |
- return S_OK; |
- } |
- private: |
- CString guid_; |
- bool is_registered_; |
-}; |
- |
-// Enumerates all sub keys of the key and calls the functor for each of them, |
-// ignoring errors to ensure all keys are processed. |
-template <typename T> |
-HRESULT EnumerateSubKeys(const TCHAR* key_name, T* functor) { |
- RegKey client_key; |
- HRESULT hr = client_key.Open(key_name, KEY_READ); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- |
- int num_sub_keys = client_key.GetSubkeyCount(); |
- for (int i = 0; i < num_sub_keys; ++i) { |
- CString sub_key_name; |
- hr = client_key.GetSubkeyNameAt(i, &sub_key_name); |
- if (SUCCEEDED(hr)) { |
- (*functor)(sub_key_name); |
- } |
- } |
- |
- return S_OK; |
-} |
- |
-} // namespace |
- |
-typedef bool (*AppPredictFunc)(const AppManager& app_manager, |
- const CString& app_id); |
- |
-bool IsUninstalledAppPredicate(const AppManager& app_manager, |
- const CString& app_id) { |
- return app_manager.IsAppUninstalled(app_id); |
-} |
- |
-bool IsAppOemInstalledAndEulaAcceptedPredicate(const AppManager& app_manager, |
- const CString& app_id) { |
- return app_manager.IsAppOemInstalledAndEulaAccepted(app_id); |
-} |
- |
-bool IsRegisteredAppPredicate(const AppManager& app_manager, |
- const CString& app_id) { |
- return app_manager.IsAppRegistered(app_id); |
-} |
- |
-// Accumulates app IDs for apps that satisfies the predicate. |
-class CollectProductsFunc |
- : public std::unary_function<const CString&, HRESULT> { |
- public: |
- CollectProductsFunc(const AppPredictFunc predicate, |
- const AppManager& app_manager, |
- AppIdVector* app_ids) |
- : predicate_(predicate), |
- app_manager_(app_manager), |
- app_ids_(app_ids) { |
- ASSERT1(app_ids); |
- } |
- |
- // Ignores errors and accumulates as many applications as possible. |
- HRESULT operator() (const CString& app_id) const { |
- if ((*predicate_)(app_manager_, app_id)) { |
- app_ids_->push_back(app_id); |
- } |
- |
- return S_OK; |
- } |
- |
- private: |
- const AppPredictFunc predicate_; |
- const AppManager& app_manager_; |
- AppIdVector* const app_ids_; |
- |
- DISALLOW_IMPLICIT_CONSTRUCTORS(CollectProductsFunc); |
-}; |
- |
-// Runs application registration hooks registered under Omaha AppIds. |
-// Reads the Hook Clsid entry under Clients\{AppID}. CoCreates the CLSID. Calls |
-// IRegistrationUpdateHook::UpdateRegistry(). |
-class RunRegistrationUpdateHooksFunc |
- : public std::unary_function<const CString&, HRESULT> { |
- public: |
- explicit RunRegistrationUpdateHooksFunc(const AppManager& app_manager) |
- : app_manager_(app_manager) { |
- } |
- |
- HRESULT operator() (const CString& app_id) { |
- GUID app_guid = GUID_NULL; |
- HRESULT hr = StringToGuidSafe(app_id, &app_guid); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- RegKey client_key; |
- hr = app_manager_.OpenClientKey(app_guid, &client_key); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- |
- CString hook_clsid_str; |
- hr = client_key.GetValue(kRegValueUpdateHookClsid, &hook_clsid_str); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- GUID hook_clsid = GUID_NULL; |
- hr = StringToGuidSafe(hook_clsid_str, &hook_clsid); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- |
- CORE_LOG(L3, (_T("[Update Hook Clsid][%s][%s]"), app_id, hook_clsid_str)); |
- |
- CComPtr<IRegistrationUpdateHook> registration_hook; |
- hr = registration_hook.CoCreateInstance(hook_clsid); |
- if (FAILED(hr)) { |
- CORE_LOG(LE, (_T("[IRegistrationUpdateHook CoCreate failed][0x%x]"), hr)); |
- return hr; |
- } |
- |
- hr = registration_hook->UpdateRegistry(CComBSTR(app_id), |
- app_manager_.is_machine_); |
- if (FAILED(hr)) { |
- CORE_LOG(LE, (_T("[registration_hook UpdateRegistry failed][0x%x]"), hr)); |
- return hr; |
- } |
- |
- return S_OK; |
- } |
- |
- private: |
- const AppManager& app_manager_; |
-}; |
- |
-AppManager* AppManager::instance_ = NULL; |
- |
-// We do not worry about contention on creation because only the Worker should |
-// create AppManager during its initialization. |
-HRESULT AppManager::CreateInstance(bool is_machine) { |
- ASSERT1(!instance_); |
- if (instance_) { |
- return S_OK; |
- } |
- |
- AppManager* instance(new AppManager(is_machine)); |
- if (!instance->InitializeRegistryLock()) { |
- HRESULT hr(HRESULTFromLastError()); |
- delete instance; |
- return hr; |
- } |
- |
- instance_ = instance; |
- return S_OK; |
-} |
- |
-void AppManager::DeleteInstance() { |
- delete instance_; |
- instance_ = NULL; |
-} |
- |
-AppManager* AppManager::Instance() { |
- ASSERT1(instance_); |
- return instance_; |
-} |
- |
-HRESULT AppManager::ReadAppVersionNoLock(bool is_machine, const GUID& app_guid, |
- CString* version) { |
- ASSERT1(version); |
- CORE_LOG(L2, (_T("[ReadAppVersionNoLock][%s]"), GuidToString(app_guid))); |
- |
- AppManager app_manager(is_machine); |
- RegKey client_key; |
- HRESULT hr = app_manager.OpenClientKey(app_guid, &client_key); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- |
- hr = client_key.GetValue(kRegValueProductVersion, version); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- |
- CORE_LOG(L3, (_T("[kRegValueProductVersion][%s]"), *version)); |
- return S_OK; |
-} |
- |
-AppManager::AppManager(bool is_machine) |
- : is_machine_(is_machine) { |
- CORE_LOG(L3, (_T("[AppManager::AppManager][is_machine=%d]"), is_machine)); |
-} |
- |
-// App installers should use similar code to create a lock to acquire while |
-// modifying Omaha registry. |
-bool AppManager::InitializeRegistryLock() { |
- NamedObjectAttributes lock_attr; |
- GetNamedObjectAttributes(kRegistryAccessMutex, is_machine_, &lock_attr); |
- return registry_access_lock_.InitializeWithSecAttr(lock_attr.name, |
- &lock_attr.sa); |
-} |
- |
-// Vulnerable to a race condition with installers. To prevent this, acquire |
-// GetRegistryStableStateLock(). |
-bool AppManager::IsAppRegistered(const GUID& app_guid) const { |
- return IsAppRegistered(GuidToString(app_guid)); |
-} |
- |
-// Vulnerable to a race condition with installers. To prevent this, acquire |
-// GetRegistryStableStateLock(). |
-bool AppManager::IsAppRegistered(const CString& app_id) const { |
- IsAppRegisteredFunc func(app_id); |
- HRESULT hr = EnumerateSubKeys( |
- ConfigManager::Instance()->registry_clients(is_machine_), |
- &func); |
- if (FAILED(hr)) { |
- return false; |
- } |
- |
- return func.is_registered(); |
-} |
- |
-bool AppManager::IsAppUninstalled(const CString& app_id) const { |
- GUID app_guid = {0}; |
- if (FAILED(StringToGuidSafe(app_id, &app_guid))) { |
- ASSERT1(false); |
- return false; |
- } |
- return IsAppUninstalled(app_guid); |
-} |
- |
-// An app is considered uninstalled if: |
-// * The app's Clients key does not exist AND |
-// * The app's ClientState key exists and contains the pv value. |
-// We check for the pv key value in the ClientState to prevent Omaha from |
-// detecting the key created in the following scenarios as an uninstalled app. |
-// * Per-machine apps may write dr to per-user Omaha's key. Per-user Omaha |
-// must not detect this as an uninstalled app. |
-// * Omaha may create the app's ClientState key and write values from the |
-// metainstaller tag before running the installer, which creates the |
-// Clients key. |
-bool AppManager::IsAppUninstalled(const GUID& app_guid) const { |
- if (IsAppRegistered(app_guid)) { |
- return false; |
- } |
- |
- return RegKey::HasValue(GetClientStateKeyName(app_guid), |
- kRegValueProductVersion); |
-} |
- |
-bool AppManager::IsAppOemInstalledAndEulaAccepted(const CString& app_id) const { |
- GUID app_guid = GUID_NULL; |
- if (FAILED(StringToGuidSafe(app_id, &app_guid))) { |
- ASSERT1(false); |
- return false; |
- } |
- |
- if (IsAppUninstalled(app_guid)) { |
- return false; |
- } |
- |
- if (!app_registry_utils::IsAppEulaAccepted(is_machine_, app_id, false)) { |
- CORE_LOG(L3, (_T("[EULA not accepted for app %s, its OEM ping not sent.]"), |
- app_id.GetString())); |
- return false; |
- } |
- |
- return RegKey::HasValue(GetClientStateKeyName(app_guid), kRegValueOemInstall); |
-} |
- |
-// Vulnerable to a race condition with installers. To prevent this, hold |
-// GetRegistryStableStateLock() while calling this function and related |
-// functions, such as ReadAppPersistentData(). |
-HRESULT AppManager::GetRegisteredApps(AppIdVector* app_ids) const { |
- ASSERT1(app_ids); |
- |
- CollectProductsFunc func(IsRegisteredAppPredicate, *this, app_ids); |
- |
- return EnumerateSubKeys( |
- ConfigManager::Instance()->registry_clients(is_machine_), |
- &func); |
-} |
- |
-// Vulnerable to a race condition with installers. To prevent this, acquire |
-// GetRegistryStableStateLock(). |
-HRESULT AppManager::GetUninstalledApps(AppIdVector* app_ids) const { |
- ASSERT1(app_ids); |
- |
- CollectProductsFunc func(IsUninstalledAppPredicate, *this, app_ids); |
- |
- return EnumerateSubKeys( |
- ConfigManager::Instance()->registry_client_state(is_machine_), |
- &func); |
-} |
- |
-HRESULT AppManager::GetOemInstalledAndEulaAcceptedApps( |
- AppIdVector* app_ids) const { |
- ASSERT1(app_ids); |
- |
- CollectProductsFunc func(IsAppOemInstalledAndEulaAcceptedPredicate, |
- *this, |
- app_ids); |
- |
- return EnumerateSubKeys( |
- ConfigManager::Instance()->registry_client_state(is_machine_), |
- &func); |
-} |
- |
-HRESULT AppManager::RunRegistrationUpdateHook(const CString& app_id) const { |
- return RunRegistrationUpdateHooksFunc(*this)(app_id); |
-} |
- |
-// Vulnerable to a race condition with installers. We think this is acceptable. |
-// If there is a future requirement for greater consistency, acquire |
-// GetRegistryStableStateLock(). |
-HRESULT AppManager::RunAllRegistrationUpdateHooks() const { |
- RunRegistrationUpdateHooksFunc func(*this); |
- const TCHAR* key(ConfigManager::Instance()->registry_clients(is_machine_)); |
- return EnumerateSubKeys(key, &func); |
-} |
- |
-CString AppManager::GetClientKeyName(const GUID& app_guid) const { |
- return app_registry_utils::GetAppClientsKey(is_machine_, |
- GuidToString(app_guid)); |
-} |
- |
-CString AppManager::GetClientStateKeyName(const GUID& app_guid) const { |
- return app_registry_utils::GetAppClientStateKey(is_machine_, |
- GuidToString(app_guid)); |
-} |
- |
-CString AppManager::GetClientStateMediumKeyName(const GUID& app_guid) const { |
- ASSERT1(is_machine_); |
- return app_registry_utils::GetAppClientStateMediumKey(is_machine_, |
- GuidToString(app_guid)); |
-} |
- |
-// Assumes the registry access lock is held. |
-HRESULT AppManager::OpenClientKey(const GUID& app_guid, |
- RegKey* client_key) const { |
- ASSERT1(client_key); |
- return client_key->Open(GetClientKeyName(app_guid), KEY_READ); |
-} |
- |
-// Assumes the registry access lock is held. |
-HRESULT AppManager::OpenClientStateKey(const GUID& app_guid, |
- REGSAM sam_desired, |
- RegKey* client_state_key) const { |
- ASSERT1(client_state_key); |
- CString key_name = GetClientStateKeyName(app_guid); |
- return client_state_key->Open(key_name, sam_desired); |
-} |
- |
-// Also creates the ClientStateMedium key for machine apps, ensuring it exists |
-// whenever ClientState exists. Does not create ClientStateMedium for Omaha. |
-// This function is called for self-updates, so it must explicitly avoid this. |
-// Assumes the registry access lock is held. |
-HRESULT AppManager::CreateClientStateKey(const GUID& app_guid, |
- RegKey* client_state_key) { |
- ASSERT1(client_state_key); |
- // TODO(omaha3): Add GetOwner() to GLock & add this to Open() functions too. |
- // ASSERT1(::GetCurrentThreadId() == registry_access_lock_.GetOwner()); |
- |
- const CString key_name = GetClientStateKeyName(app_guid); |
- HRESULT hr = client_state_key->Create(key_name); |
- if (FAILED(hr)) { |
- CORE_LOG(L3, (_T("[RegKey::Create failed][0x%08x]"), hr)); |
- return hr; |
- } |
- |
- if (!is_machine_) { |
- return S_OK; |
- } |
- |
- if (::IsEqualGUID(kGoopdateGuid, app_guid)) { |
- return S_OK; |
- } |
- |
- const CString medium_key_name = GetClientStateMediumKeyName(app_guid); |
- hr = RegKey::CreateKey(medium_key_name); |
- if (FAILED(hr)) { |
- CORE_LOG(L3, (_T("[RegKey::Create ClientStateMedium failed][0x%08x]"), hr)); |
- return hr; |
- } |
- |
- return S_OK; |
-} |
- |
-// Reads the following values from the registry: |
-// Clients key |
-// pv |
-// lang |
-// name |
-// ClientState key |
-// lang (if not present in Clients) |
-// ap |
-// tttoken |
-// iid |
-// brand |
-// client |
-// experiment |
-// (referral is intentionally not read) |
-// InstallTime (converted to diff) |
-// oeminstall |
-// ClientState and ClientStateMedium key |
-// eulaaccepted |
-// ClientState key in HKCU/HKLM/Low integrity |
-// did run |
-// |
-// app_guid_ is set to the app_guid argument. |
-// Note: pv is not read from ClientState into app_data. It's |
-// presence is checked for an uninstall |
-// TODO(omaha3): We will need to get ClientState's pv when reporting uninstalls. |
-// Note: If the application is uninstalled, the Clients key may not exist. |
-HRESULT AppManager::ReadAppPersistentData(App* app) { |
- ASSERT1(app); |
- |
- const GUID& app_guid = app->app_guid(); |
- const CString& app_guid_string = app->app_guid_string(); |
- |
- CORE_LOG(L2, (_T("[AppManager::ReadAppPersistentData][%s]"), |
- app_guid_string)); |
- |
- ASSERT1(app->model()->IsLockedByCaller()); |
- |
- __mutexScope(registry_access_lock_); |
- |
- const bool is_eula_accepted = |
- app_registry_utils::IsAppEulaAccepted(is_machine_, |
- app_guid_string, |
- false); |
- app->is_eula_accepted_ = is_eula_accepted ? TRISTATE_TRUE : TRISTATE_FALSE; |
- |
- bool client_key_exists = false; |
- RegKey client_key; |
- HRESULT hr = OpenClientKey(app_guid, &client_key); |
- if (SUCCEEDED(hr)) { |
- client_key_exists = true; |
- |
- CString version; |
- hr = client_key.GetValue(kRegValueProductVersion, &version); |
- CORE_LOG(L3, (_T("[AppManager::ReadAppPersistentData]") |
- _T("[%s][version=%s]"), app_guid_string, version)); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- |
- app->current_version()->set_version(version); |
- |
- // Language and name might not be written by installer, so ignore failures. |
- client_key.GetValue(kRegValueLanguage, &app->language_); |
- client_key.GetValue(kRegValueAppName, &app->display_name_); |
- } |
- |
- // Ensure there is a valid display name. |
- if (app->display_name_.IsEmpty()) { |
- StringFormatter formatter(app->app_bundle()->display_language()); |
- |
- CString company_name; |
- VERIFY1(SUCCEEDED(formatter.LoadString(IDS_FRIENDLY_COMPANY_NAME, |
- &company_name))); |
- |
- VERIFY1(SUCCEEDED(formatter.FormatMessage(&app->display_name_, |
- IDS_DEFAULT_APP_DISPLAY_NAME, |
- company_name))); |
- } |
- |
- // If ClientState registry key doesn't exist, the function could return. |
- // Before opening the key, set days_since_last* to -1, which is the |
- // default value if reg key doesn't exist. If later we find that the values |
- // are readable, new values will overwrite current ones. |
- app->set_days_since_last_active_ping(-1); |
- app->set_days_since_last_roll_call(-1); |
- |
- // The following do not rely on client_state_key, so check them before |
- // possibly returning if OpenClientStateKey fails. |
- |
- // Reads the did run value. |
- ApplicationUsageData app_usage(is_machine_, vista_util::IsVistaOrLater()); |
- app_usage.ReadDidRun(app_guid_string); |
- |
- // Sets did_run regardless of the return value of ReadDidRun above. If read |
- // fails, active_state() should return ACTIVE_UNKNOWN which is intented. |
- app->did_run_ = app_usage.active_state(); |
- |
- // TODO(omaha3): Consider moving GetInstallTimeDiffSec() up here. Be careful |
- // that the results when ClientState does not exist are desirable. See the |
- // comments near that function and above set_days_since_last_active_ping call. |
- |
- RegKey client_state_key; |
- hr = OpenClientStateKey(app_guid, KEY_READ, &client_state_key); |
- if (FAILED(hr)) { |
- // It is possible that the client state key has not yet been populated. |
- // In this case just return the information that we have gathered thus far. |
- // However if both keys do not exist, then we are doing something wrong. |
- CORE_LOG(LW, (_T("[AppManager::ReadAppPersistentData - No ClientState]"))); |
- if (client_key_exists) { |
- return S_OK; |
- } else { |
- return hr; |
- } |
- } |
- |
- // Read language from ClientState key if it was not found in the Clients key. |
- if (app->language().IsEmpty()) { |
- client_state_key.GetValue(kRegValueLanguage, &app->language_); |
- } |
- |
- client_state_key.GetValue(kRegValueAdditionalParams, &app->ap_); |
- client_state_key.GetValue(kRegValueTTToken, &app->tt_token_); |
- |
- CString iid; |
- client_state_key.GetValue(kRegValueInstallationId, &iid); |
- GUID iid_guid; |
- if (SUCCEEDED(StringToGuidSafe(iid, &iid_guid))) { |
- app->iid_ = iid_guid; |
- } |
- |
- client_state_key.GetValue(kRegValueBrandCode, &app->brand_code_); |
- ASSERT1(app->brand_code_.GetLength() <= kBrandIdLength); |
- client_state_key.GetValue(kRegValueClientId, &app->client_id_); |
- |
- // We do not need the referral_id. |
- |
- DWORD last_active_ping_sec(0); |
- if (SUCCEEDED(client_state_key.GetValue(kRegValueActivePingDayStartSec, |
- &last_active_ping_sec))) { |
- int days_since_last_active_ping = |
- GetNumberOfDaysSince(static_cast<int32>(last_active_ping_sec)); |
- app->set_days_since_last_active_ping(days_since_last_active_ping); |
- } |
- |
- DWORD last_roll_call_sec(0); |
- if (SUCCEEDED(client_state_key.GetValue(kRegValueRollCallDayStartSec, |
- &last_roll_call_sec))) { |
- int days_since_last_roll_call = |
- GetNumberOfDaysSince(static_cast<int32>(last_roll_call_sec)); |
- app->set_days_since_last_roll_call(days_since_last_roll_call); |
- } |
- |
- app->install_time_diff_sec_ = GetInstallTimeDiffSec(app_guid); |
- // Generally GetInstallTimeDiffSec() shouldn't return kInitialInstallTimeDiff |
- // here. The only exception is in the unexpected case when ClientState exists |
- // without a pv. |
- ASSERT1((app->install_time_diff_sec_ != kInitialInstallTimeDiff) || |
- !RegKey::HasValue(GetClientStateKeyName(app_guid), |
- kRegValueProductVersion)); |
- |
- return S_OK; |
-} |
- |
-void AppManager::ReadAppInstallTimeDiff(App* app) { |
- ASSERT1(app); |
- app->install_time_diff_sec_ = GetInstallTimeDiffSec(app->app_guid()); |
-} |
- |
-// Calls ReadAppPersistentData() to populate app and adds the following values |
-// specific to uninstalled apps: |
-// ClientState key |
-// pv: set as current_version()->version |
-// |
-// Since this is an uninstalled app, values from the Clients key should not be |
-// populated. |
-HRESULT AppManager::ReadUninstalledAppPersistentData(App* app) { |
- ASSERT1(app); |
- ASSERT1(!IsAppRegistered(app->app_guid_string())); |
- |
- HRESULT hr = ReadAppPersistentData(app); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- |
- ASSERT1(app->current_version()->version().IsEmpty()); |
- |
- RegKey client_state_key; |
- hr = OpenClientStateKey(app->app_guid(), KEY_READ, &client_state_key); |
- ASSERT(SUCCEEDED(hr), (_T("Uninstalled apps have a ClientState key."))); |
- |
- CString version; |
- hr = client_state_key.GetValue(kRegValueProductVersion, &version); |
- CORE_LOG(L3, (_T("[AppManager::ReadAppPersistentData]") |
- _T("[%s][uninstalled version=%s]"), |
- app->app_guid_string(), version)); |
- ASSERT(SUCCEEDED(hr), (_T("Uninstalled apps have a pv."))); |
- app->current_version()->set_version(version); |
- |
- return S_OK; |
-} |
- |
-// Sets the following values in the app's ClientState, to make them available to |
-// the installer: |
-// lang |
-// ap |
-// brand (in SetAppBranding) |
-// client (in SetAppBranding) |
-// experiment |
-// referral (in SetAppBranding) |
-// InstallTime (in SetAppBranding; converted from diff) |
-// oeminstall (if appropriate) |
-// eulaaccepted (set/deleted) |
-// browser |
-// usagestats |
-// Sets eulaaccepted=0 if the app is not already registered and the app's EULA |
-// has not been accepted. Deletes eulaaccepted if the EULA has been accepted. |
-// Only call for initial or over-installs. Do not call for updates to avoid |
-// mistakenly replacing data, such as the application's language, and causing |
-// unexpected changes to the app during a silent update. |
-HRESULT AppManager::WritePreInstallData(const App& app) { |
- CORE_LOG(L2, (_T("[AppManager::WritePreInstallData][%s]"), |
- app.app_guid_string())); |
- |
- ASSERT1(app.app_bundle()->is_machine() == is_machine_); |
- |
- ASSERT1(IsRegistryStableStateLockedByCaller()); |
- __mutexScope(registry_access_lock_); |
- |
- RegKey client_state_key; |
- HRESULT hr = CreateClientStateKey(app.app_guid(), &client_state_key); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- |
- if (app.is_eula_accepted()) { |
- hr = app_registry_utils::ClearAppEulaNotAccepted(is_machine_, |
- app.app_guid_string()); |
- } else { |
- if (!IsAppRegistered(app.app_guid())) { |
- hr = app_registry_utils::SetAppEulaNotAccepted(is_machine_, |
- app.app_guid_string()); |
- } |
- } |
- if (FAILED(hr)) { |
- return hr; |
- } |
- |
- if (!app.language().IsEmpty()) { |
- VERIFY1(SUCCEEDED(client_state_key.SetValue(kRegValueLanguage, |
- app.language()))); |
- } |
- |
- if (app.ap().IsEmpty()) { |
- VERIFY1(SUCCEEDED(client_state_key.DeleteValue(kRegValueAdditionalParams))); |
- } else { |
- VERIFY1(SUCCEEDED(client_state_key.SetValue(kRegValueAdditionalParams, |
- app.ap()))); |
- } |
- |
- CString state_key_path = GetClientStateKeyName(app.app_guid()); |
- VERIFY1(SUCCEEDED(app_registry_utils::SetAppBranding(state_key_path, |
- app.brand_code(), |
- app.client_id(), |
- app.referral_id()))); |
- |
- if (app.GetExperimentLabels().IsEmpty()) { |
- VERIFY1(SUCCEEDED(client_state_key.DeleteValue(kRegValueExperimentLabels))); |
- } else { |
- VERIFY1(SUCCEEDED(client_state_key.SetValue(kRegValueExperimentLabels, |
- app.GetExperimentLabels()))); |
- } |
- |
- if (oem_install_utils::IsOemInstalling(is_machine_)) { |
- ASSERT1(is_machine_); |
- VERIFY1(SUCCEEDED(client_state_key.SetValue(kRegValueOemInstall, _T("1")))); |
- } |
- |
- if (BROWSER_UNKNOWN == app.browser_type()) { |
- VERIFY1(SUCCEEDED(client_state_key.DeleteValue(kRegValueBrowser))); |
- } else { |
- DWORD browser_type = app.browser_type(); |
- VERIFY1(SUCCEEDED(client_state_key.SetValue(kRegValueBrowser, |
- browser_type))); |
- } |
- |
- if (TRISTATE_NONE != app.usage_stats_enable()) { |
- VERIFY1(SUCCEEDED(app_registry_utils::SetUsageStatsEnable( |
- is_machine_, |
- app.app_guid_string(), |
- app.usage_stats_enable()))); |
- } |
- |
- return S_OK; |
-} |
- |
-// All values are optional. |
-void AppManager::ReadInstallerResultApiValues( |
- const GUID& app_guid, |
- InstallerResult* installer_result, |
- DWORD* installer_error, |
- DWORD* installer_extra_code1, |
- CString* installer_result_uistring, |
- CString* installer_success_launch_cmd) { |
- ASSERT1(installer_result); |
- ASSERT1(installer_error); |
- ASSERT1(installer_extra_code1); |
- ASSERT1(installer_result_uistring); |
- ASSERT1(installer_success_launch_cmd); |
- |
- __mutexScope(registry_access_lock_); |
- |
- RegKey client_state_key; |
- HRESULT hr = OpenClientStateKey(app_guid, KEY_READ, &client_state_key); |
- if (FAILED(hr)) { |
- return; |
- } |
- |
- if (SUCCEEDED(client_state_key.GetValue( |
- kRegValueInstallerResult, |
- reinterpret_cast<DWORD*>(installer_result)))) { |
- CORE_LOG(L1, (_T("[InstallerResult in registry][%u]"), *installer_result)); |
- } |
- if (*installer_result >= INSTALLER_RESULT_MAX) { |
- CORE_LOG(LW, (_T("[Unsupported InstallerResult value]"))); |
- *installer_result = INSTALLER_RESULT_DEFAULT; |
- } |
- |
- if (SUCCEEDED(client_state_key.GetValue(kRegValueInstallerError, |
- installer_error))) { |
- CORE_LOG(L1, (_T("[InstallerError in registry][%u]"), *installer_error)); |
- } |
- |
- if (SUCCEEDED(client_state_key.GetValue(kRegValueInstallerExtraCode1, |
- installer_extra_code1))) { |
- CORE_LOG(L1, (_T("[InstallerExtraCode1 in registry][%u]"), |
- *installer_extra_code1)); |
- } |
- |
- if (SUCCEEDED(client_state_key.GetValue(kRegValueInstallerResultUIString, |
- installer_result_uistring))) { |
- CORE_LOG(L1, (_T("[InstallerResultUIString in registry][%s]"), |
- *installer_result_uistring)); |
- } |
- |
- if (SUCCEEDED(client_state_key.GetValue( |
- kRegValueInstallerSuccessLaunchCmdLine, |
- installer_success_launch_cmd))) { |
- CORE_LOG(L1, (_T("[InstallerSuccessLaunchCmdLine in registry][%s]"), |
- *installer_success_launch_cmd)); |
- } |
- |
- ClearInstallerResultApiValues(app_guid); |
-} |
- |
-void AppManager::ClearInstallerResultApiValues(const GUID& app_guid) { |
- const CString client_state_key_name = GetClientStateKeyName(app_guid); |
- const CString update_key_name = |
- ConfigManager::Instance()->registry_update(is_machine_); |
- |
- ASSERT1(IsRegistryStableStateLockedByCaller()); |
- __mutexScope(registry_access_lock_); |
- |
- // Delete the old LastXXX values. These may not exist, so don't care if they |
- // fail. |
- RegKey::DeleteValue(client_state_key_name, |
- kRegValueLastInstallerResult); |
- RegKey::DeleteValue(client_state_key_name, |
- kRegValueLastInstallerResultUIString); |
- RegKey::DeleteValue(client_state_key_name, |
- kRegValueLastInstallerError); |
- RegKey::DeleteValue(client_state_key_name, |
- kRegValueLastInstallerExtraCode1); |
- RegKey::DeleteValue(client_state_key_name, |
- kRegValueLastInstallerSuccessLaunchCmdLine); |
- |
- // Also delete any values from Google\Update. |
- // TODO(Omaha): This is a temporary fix for bug 1539293. See TODO below. |
- RegKey::DeleteValue(update_key_name, |
- kRegValueLastInstallerResult); |
- RegKey::DeleteValue(update_key_name, |
- kRegValueLastInstallerResultUIString); |
- RegKey::DeleteValue(update_key_name, |
- kRegValueLastInstallerError); |
- RegKey::DeleteValue(update_key_name, |
- kRegValueLastInstallerExtraCode1); |
- RegKey::DeleteValue(update_key_name, |
- kRegValueLastInstallerSuccessLaunchCmdLine); |
- |
- // Rename current InstallerResultXXX values to LastXXX. |
- RegKey::RenameValue(client_state_key_name, |
- kRegValueInstallerResult, |
- kRegValueLastInstallerResult); |
- RegKey::RenameValue(client_state_key_name, |
- kRegValueInstallerError, |
- kRegValueLastInstallerError); |
- RegKey::RenameValue(client_state_key_name, |
- kRegValueInstallerExtraCode1, |
- kRegValueLastInstallerExtraCode1); |
- RegKey::RenameValue(client_state_key_name, |
- kRegValueInstallerResultUIString, |
- kRegValueLastInstallerResultUIString); |
- RegKey::RenameValue(client_state_key_name, |
- kRegValueInstallerSuccessLaunchCmdLine, |
- kRegValueLastInstallerSuccessLaunchCmdLine); |
- |
- // Copy over to the Google\Update key. |
- // TODO(Omaha3): This is a temporary fix for bug 1539293. Once Pack V2 is |
- // deprecated (Pack stops taking offline installers for new versions of |
- // Omaha apps), remove this. (It might be useful to leave the CopyValue calls |
- // in DEBUG builds only.) |
- RegKey::CopyValue(client_state_key_name, |
- update_key_name, |
- kRegValueLastInstallerResult); |
- RegKey::CopyValue(client_state_key_name, |
- update_key_name, |
- kRegValueLastInstallerError); |
- RegKey::CopyValue(client_state_key_name, |
- update_key_name, |
- kRegValueLastInstallerExtraCode1); |
- RegKey::CopyValue(client_state_key_name, |
- update_key_name, |
- kRegValueLastInstallerResultUIString); |
- RegKey::CopyValue(client_state_key_name, |
- update_key_name, |
- kRegValueLastInstallerSuccessLaunchCmdLine); |
-} |
- |
-// Reads the following values from Clients: |
-// pv |
-// lang (if present) |
-// name is not read. TODO(omaha3): May change if we persist name in registry. |
-HRESULT AppManager::ReadInstallerRegistrationValues(App* app) { |
- ASSERT1(app); |
- |
- const CString& app_guid_string = app->app_guid_string(); |
- |
- CORE_LOG(L2, (_T("[AppManager::ReadInstallerRegistrationValues][%s]"), |
- app_guid_string)); |
- |
- ASSERT1(app->model()->IsLockedByCaller()); |
- |
- __mutexScope(registry_access_lock_); |
- |
- RegKey client_key; |
- if (FAILED(OpenClientKey(app->app_guid(), &client_key))) { |
- OPT_LOG(LE, (_T("[Installer did not create key][%s]"), app_guid_string)); |
- return GOOPDATEINSTALL_E_INSTALLER_DID_NOT_WRITE_CLIENTS_KEY; |
- } |
- |
- CString version; |
- if (FAILED(client_key.GetValue(kRegValueProductVersion, &version))) { |
- OPT_LOG(LE, (_T("[Installer did not register][%s]"), app_guid_string)); |
- return GOOPDATEINSTALL_E_INSTALLER_DID_NOT_WRITE_CLIENTS_KEY; |
- } |
- |
- if (version.IsEmpty()) { |
- OPT_LOG(LE, (_T("[Installer did not write version][%s]"), app_guid_string)); |
- return GOOPDATEINSTALL_E_INSTALLER_DID_NOT_WRITE_CLIENTS_KEY; |
- } |
- |
- app->next_version()->set_version(version); |
- |
- CString language; |
- if (SUCCEEDED(client_key.GetValue(kRegValueLanguage, &language))) { |
- app->language_ = language; |
- } |
- |
- return S_OK; |
-} |
- |
-// Writes tttoken and updates relevant stats. |
-void AppManager::PersistSuccessfulUpdateCheckResponse( |
- const App& app, |
- bool is_update_available) { |
- CORE_LOG(L2, (_T("[AppManager::PersistSuccessfulUpdateCheckResponse]") |
- _T("[%s][%d]"), app.app_guid_string(), is_update_available)); |
- __mutexScope(registry_access_lock_); |
- |
- VERIFY1(SUCCEEDED(SetTTToken(app))); |
- |
- const CString client_state_key = GetClientStateKeyName(app.app_guid()); |
- |
- if (is_update_available) { |
- if (app.error_code() == GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY) { |
- // The error indicates is_update and updates are disabled by policy. |
- ASSERT1(app.is_update()); |
- app_registry_utils::ClearUpdateAvailableStats(client_state_key); |
- } else if (app.is_update()) { |
- // Only record an update available event for updates. |
- // We have other mechanisms, including IID, to track install success. |
- UpdateUpdateAvailableStats(app.app_guid()); |
- } |
- } else { |
- app_registry_utils::ClearUpdateAvailableStats(client_state_key); |
- app_registry_utils::PersistSuccessfulUpdateCheck(client_state_key); |
- } |
-} |
- |
-// Writes the following values to the ClientState key: |
-// pv (should be value written by installer in Clients key) |
-// lang (should be value written by installer in Clients key) |
-// iid (set/deleted) |
-// |
-// Does not write the following values because they were set by |
-// WritePreInstallData() and would not have changed during installation unless |
-// modified directly by the app installer. |
-// ap |
-// brand |
-// client |
-// experiment |
-// referral |
-// InstallTime (converted from diff) |
-// oeminstall |
-// eulaaccepted |
-// browser |
-// usagestats |
-// TODO(omaha3): Maybe we should delete referral at this point. Ask Chrome. |
-// |
-// Other values, such as tttoken were set after the update check. |
-// |
-// The caller is responsible for modifying the values in app_data as |
-// appropriate, including: |
-// * Updating values in app_data to reflect installer's values (pv and lang) |
-// * Clearing iid if appropriate. |
-// * Clearing the did run value. TODO(omaha3): Depends on TODO below. |
-void AppManager::PersistSuccessfulInstall(const App& app) { |
- CORE_LOG(L2, (_T("[AppManager::PersistSuccessfulInstall][%s]"), |
- app.app_guid_string())); |
- |
- ASSERT1(IsRegistryStableStateLockedByCaller()); |
- __mutexScope(registry_access_lock_); |
- |
- ASSERT1(!::IsEqualGUID(kGoopdateGuid, app.app_guid())); |
- |
- RegKey client_state_key; |
- VERIFY1(SUCCEEDED(CreateClientStateKey(app.app_guid(), &client_state_key))); |
- |
- VERIFY1(SUCCEEDED(client_state_key.SetValue(kRegValueProductVersion, |
- app.next_version()->version()))); |
- |
- if (!app.language().IsEmpty()) { |
- VERIFY1(SUCCEEDED(client_state_key.SetValue(kRegValueLanguage, |
- app.language()))); |
- } |
- |
- if (::IsEqualGUID(app.iid(), GUID_NULL)) { |
- VERIFY1(SUCCEEDED(client_state_key.DeleteValue(kRegValueInstallationId))); |
- } else { |
- VERIFY1(SUCCEEDED(client_state_key.SetValue( |
- kRegValueInstallationId, |
- GuidToString(app.iid())))); |
- } |
- |
- const CString client_state_key_path = GetClientStateKeyName(app.app_guid()); |
- app_registry_utils::PersistSuccessfulInstall(client_state_key_path, |
- app.is_update(), |
- false); // TODO(omaha3): offline |
-} |
- |
-HRESULT AppManager::SynchronizeClientState(const GUID& app_guid) { |
- __mutexScope(registry_access_lock_); |
- |
- RegKey client_key; |
- HRESULT hr = OpenClientKey(app_guid, &client_key); |
- if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) { |
- return S_OK; |
- } |
- if (FAILED(hr)) { |
- return hr; |
- } |
- |
- RegKey client_state_key; |
- hr = CreateClientStateKey(app_guid, &client_state_key); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- |
- CString version; |
- client_key.GetValue(kRegValueProductVersion, &version); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- hr = client_state_key.SetValue(kRegValueProductVersion, version); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- |
- CString language; |
- client_key.GetValue(kRegValueLanguage, &language); |
- if (!language.IsEmpty()) { |
- return client_state_key.SetValue(kRegValueLanguage, language); |
- } |
- |
- return S_OK; |
-} |
- |
-// TODO(omaha3): tttoken is not currently read from the server response. |
-// TODO(omaha3): When implementing offline, we must make sure that the tttoken |
-// is not deleted by the offline response processing. |
-// TODO(omaha3): Having the parser write the server's token to the same member |
-// that is used for the value from the tag exposes this value to the COM setter. |
-// It would be nice to avoid that, possibly by only allowing that setter to work |
-// in certain states. |
-HRESULT AppManager::SetTTToken(const App& app) { |
- CORE_LOG(L3, (_T("[AppManager::SetTTToken][token=%s]"), app.tt_token())); |
- |
- __mutexScope(registry_access_lock_); |
- |
- RegKey client_state_key; |
- HRESULT hr = CreateClientStateKey(app.app_guid(), &client_state_key); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- |
- if (app.tt_token().IsEmpty()) { |
- return client_state_key.DeleteValue(kRegValueTTToken); |
- } else { |
- return client_state_key.SetValue(kRegValueTTToken, app.tt_token()); |
- } |
-} |
- |
-void AppManager::ClearOemInstalled(const AppIdVector& app_ids) { |
- __mutexScope(registry_access_lock_); |
- |
- AppIdVector::const_iterator it; |
- for (it = app_ids.begin(); it != app_ids.end(); ++it) { |
- ASSERT1(IsAppOemInstalledAndEulaAccepted(*it)); |
- RegKey state_key; |
- |
- GUID app_guid = GUID_NULL; |
- HRESULT hr = StringToGuidSafe(*it, &app_guid); |
- if (FAILED(hr)) { |
- continue; |
- } |
- |
- hr = OpenClientStateKey(app_guid, KEY_ALL_ACCESS, &state_key); |
- if (FAILED(hr)) { |
- continue; |
- } |
- |
- VERIFY1(SUCCEEDED(state_key.DeleteValue(kRegValueOemInstall))); |
- } |
-} |
- |
-void AppManager::UpdateUpdateAvailableStats(const GUID& app_guid) { |
- __mutexScope(registry_access_lock_); |
- |
- RegKey state_key; |
- HRESULT hr = CreateClientStateKey(app_guid, &state_key); |
- if (FAILED(hr)) { |
- ASSERT1(false); |
- return; |
- } |
- |
- DWORD update_available_count(0); |
- hr = state_key.GetValue(kRegValueUpdateAvailableCount, |
- &update_available_count); |
- if (FAILED(hr)) { |
- update_available_count = 0; |
- } |
- ++update_available_count; |
- VERIFY1(SUCCEEDED(state_key.SetValue(kRegValueUpdateAvailableCount, |
- update_available_count))); |
- |
- DWORD64 update_available_since_time(0); |
- hr = state_key.GetValue(kRegValueUpdateAvailableSince, |
- &update_available_since_time); |
- if (FAILED(hr)) { |
- // There is no existing value, so this must be the first update notice. |
- VERIFY1(SUCCEEDED(state_key.SetValue(kRegValueUpdateAvailableSince, |
- GetCurrent100NSTime()))); |
- |
- // TODO(omaha): It would be nice to report the version that we were first |
- // told to update to. This is available in UpdateResponse but we do not |
- // currently send it down in update responses. If we start using it, add |
- // kRegValueFirstUpdateResponseVersion. |
- } |
-} |
- |
-// Returns 0 for any values that are not found. |
-void AppManager::ReadUpdateAvailableStats( |
- const GUID& app_guid, |
- DWORD* update_responses, |
- DWORD64* time_since_first_response_ms) { |
- ASSERT1(update_responses); |
- ASSERT1(time_since_first_response_ms); |
- *update_responses = 0; |
- *time_since_first_response_ms = 0; |
- |
- __mutexScope(registry_access_lock_); |
- |
- RegKey state_key; |
- HRESULT hr = OpenClientStateKey(app_guid, KEY_READ, &state_key); |
- if (FAILED(hr)) { |
- CORE_LOG(LW, (_T("[App ClientState key does not exist][%s]"), |
- GuidToString(app_guid))); |
- return; |
- } |
- |
- DWORD update_responses_in_reg(0); |
- hr = state_key.GetValue(kRegValueUpdateAvailableCount, |
- &update_responses_in_reg); |
- if (SUCCEEDED(hr)) { |
- *update_responses = update_responses_in_reg; |
- } |
- |
- DWORD64 update_available_since_time(0); |
- hr = state_key.GetValue(kRegValueUpdateAvailableSince, |
- &update_available_since_time); |
- if (SUCCEEDED(hr)) { |
- const DWORD64 current_time = GetCurrent100NSTime(); |
- ASSERT1(update_available_since_time <= current_time); |
- const DWORD64 time_since_first_response_in_100ns = |
- current_time - update_available_since_time; |
- *time_since_first_response_ms = |
- time_since_first_response_in_100ns / kMillisecsTo100ns; |
- } |
-} |
- |
-uint32 AppManager::GetInstallTimeDiffSec(const GUID& app_guid) const { |
- if (!IsAppRegistered(app_guid) && !IsAppUninstalled(app_guid)) { |
- return kInitialInstallTimeDiff; |
- } |
- |
- RegKey client_state_key; |
- HRESULT hr = OpenClientStateKey(app_guid, KEY_READ, &client_state_key); |
- if (FAILED(hr)) { |
- return 0; |
- } |
- |
- DWORD install_time(0); |
- DWORD install_time_diff_sec(0); |
- if (SUCCEEDED(client_state_key.GetValue(kRegValueInstallTimeSec, |
- &install_time))) { |
- const uint32 now = Time64ToInt32(GetCurrent100NSTime()); |
- if (0 != install_time && now >= install_time) { |
- install_time_diff_sec = now - install_time; |
- // TODO(omaha3): Restore this assert. In Omaha 2, this function gets |
- // called as part of installation verification and Job::UpdateJob(), so |
- // the value can be 0. This will not be the case in Omaha 3. |
- // ASSERT1(install_time_diff_sec != 0); |
- } |
- } |
- |
- return install_time_diff_sec; |
-} |
- |
-// Clear the Installation ID if at least one of the conditions is true: |
-// 1) DidRun==yes. First run is the last time we want to use the Installation |
-// ID. So delete Installation ID if it is present. |
-// 2) kMaxLifeOfInstallationIDSec has passed since the app was installed. This |
-// is to ensure that Installation ID is cleared even if DidRun is never set. |
-// 3) The app is Omaha. Always delete Installation ID if it is present |
-// because DidRun does not apply. |
-HRESULT AppManager::ClearInstallationId(const App& app) { |
- ASSERT1(app.model()->IsLockedByCaller()); |
- __mutexScope(registry_access_lock_); |
- |
- if (::IsEqualGUID(app.iid(), GUID_NULL)) { |
- return S_OK; |
- } |
- |
- if ((ACTIVE_RUN == app.did_run()) || |
- (kMaxLifeOfInstallationIDSec <= app.install_time_diff_sec()) || |
- (::IsEqualGUID(kGoopdateGuid, app.app_guid()))) { |
- CORE_LOG(L1, (_T("[Deleting iid for app][%s]"), app.app_guid_string())); |
- |
- RegKey client_state_key; |
- HRESULT hr = CreateClientStateKey(app.app_guid(), &client_state_key); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- |
- return client_state_key.DeleteValue(kRegValueInstallationId); |
- } |
- |
- return S_OK; |
-} |
- |
-void AppManager::SetLastPingDayStartTime(const App& app, |
- int elapsed_seconds_since_day_start) { |
- ASSERT1(elapsed_seconds_since_day_start >= 0); |
- ASSERT1(elapsed_seconds_since_day_start < kMaxTimeSinceMidnightSec); |
- ASSERT1(app.model()->IsLockedByCaller()); |
- |
- __mutexScope(registry_access_lock_); |
- |
- int now = Time64ToInt32(GetCurrent100NSTime()); |
- |
- RegKey client_state_key; |
- if (FAILED(CreateClientStateKey(app.app_guid(), &client_state_key))) { |
- return; |
- } |
- |
- bool did_send_active_ping = (app.did_run() == ACTIVE_RUN && |
- app.days_since_last_active_ping() != 0); |
- if (did_send_active_ping) { |
- VERIFY1(SUCCEEDED(client_state_key.SetValue( |
- kRegValueActivePingDayStartSec, |
- static_cast<DWORD>(now - elapsed_seconds_since_day_start)))); |
- } |
- |
- bool did_send_roll_call = (app.days_since_last_roll_call() != 0); |
- if (did_send_roll_call) { |
- VERIFY1(SUCCEEDED(client_state_key.SetValue( |
- kRegValueRollCallDayStartSec, |
- static_cast<DWORD>(now - elapsed_seconds_since_day_start)))); |
- } |
-} |
- |
-// Writes the day start time when last active ping/roll call happened to |
-// registry if the corresponding ping has been sent. |
-// Removes installation id, if did run = true or if goopdate. |
-// Clears did run. |
-HRESULT AppManager::PersistUpdateCheckSuccessfullySent( |
- const App& app, |
- int elapsed_seconds_since_day_start) { |
- ASSERT1(app.model()->IsLockedByCaller()); |
- |
- ApplicationUsageData app_usage(app.app_bundle()->is_machine(), |
- vista_util::IsVistaOrLater()); |
- VERIFY1(SUCCEEDED(app_usage.ResetDidRun(app.app_guid_string()))); |
- |
- SetLastPingDayStartTime(app, elapsed_seconds_since_day_start); |
- |
- // Handle the installation id. |
- VERIFY1(SUCCEEDED(ClearInstallationId(app))); |
- |
- return S_OK; |
-} |
- |
-HRESULT AppManager::RemoveClientState(const GUID& app_guid) { |
- CORE_LOG(L2, (_T("[AppManager::RemoveClientState][%s]"), |
- GuidToString(app_guid))); |
- ASSERT1(IsRegistryStableStateLockedByCaller()); |
- __mutexScope(registry_access_lock_); |
- |
- ASSERT1(!IsAppRegistered(app_guid)); |
- |
- return app_registry_utils::RemoveClientState(is_machine_, |
- GuidToString(app_guid)); |
-} |
- |
-// TODO(omaha3): May not need these |
-#if 0 |
-// Writes 0.0.0.1 to pv. This value avoids any special cases, such as initial |
-// install rules, for 0.0.0.0, while being unlikely to be higher than the |
-// product's actual current version. |
-HRESULT AppManager::RegisterProduct(const GUID& product_guid, |
- const CString& product_name) { |
- const TCHAR* const kRegisterProductVersion = _T("0.0.0.1"); |
- |
- __mutexScope(GetRegistryStableStateLock()); |
- RegKey client_key; |
- HRESULT hr = client_key.Create(GetClientKeyName(GUID_NULL, product_guid)); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- |
- hr = client_key.SetValue(kRegValueProductVersion, kRegisterProductVersion); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- |
- // AppName is not a required parameter since it's only used for being able to |
- // easily tell what application is there when reading the registry. |
- VERIFY1(SUCCEEDED(client_key.SetValue(kRegValueAppName, product_name))); |
- |
- return S_OK; |
-} |
- |
-HRESULT AppManager::UnregisterProduct(const GUID& product_guid) { |
- __mutexScope(GetRegistryStableStateLock()); |
- return RegKey::DeleteKey(GetClientKeyName(GUID_NULL, product_guid), true); |
-} |
-#endif |
- |
-} // namespace omaha |