chromium/chrome/updater/update_usage_stats_task_win.cc

// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/updater/update_usage_stats_task.h"

#include <string>
#include <vector>

#include "base/logging.h"
#include "base/strings/strcat.h"
#include "base/strings/utf_string_conversions.h"
#include "base/win/registry.h"
#include "base/win/windows_types.h"
#include "chrome/updater/constants.h"
#include "chrome/updater/util/win_util.h"
#include "chrome/updater/win/win_constants.h"

namespace updater {

namespace {

bool AppUsageStatsAllowed(UpdaterScope scope, const std::wstring& app_id) {
  DWORD usagestats = 0;
  if (IsSystemInstall(scope) &&
      base::win::RegKey(UpdaterScopeToHKeyRoot(scope),
                        base::StrCat({CLIENT_STATE_MEDIUM_KEY, app_id}).c_str(),
                        Wow6432(KEY_READ))
              .ReadValueDW(L"usagestats", &usagestats) == ERROR_SUCCESS) {
    return usagestats == 1;
  }

  if (base::win::RegKey(UpdaterScopeToHKeyRoot(scope),
                        GetAppClientStateKey(app_id).c_str(), Wow6432(KEY_READ))
          .ReadValueDW(L"usagestats", &usagestats) == ERROR_SUCCESS) {
    return usagestats == 1;
  }

  return false;
}

}  // namespace

bool OtherAppUsageStatsAllowed(const std::vector<std::string>& app_ids,
                               UpdaterScope scope) {
  for (auto app_id : app_ids) {
    if (base::EqualsCaseInsensitiveASCII(app_id, kUpdaterAppId)) {
      continue;
    }

    if (AppUsageStatsAllowed(scope, base::UTF8ToWide(app_id))) {
      VLOG(2) << "usagestats enabled by app " << app_id;
      return true;
    }
  }

  VLOG(2) << "No app enables usagestats.";
  return false;
}

bool AreRawUsageStatsEnabled(
    UpdaterScope scope,
    const std::vector<std::string>& include_only_these_app_ids) {
  return OtherAppUsageStatsAllowed(
      [&] {
        const HKEY root = UpdaterScopeToHKeyRoot(scope);
        std::vector<std::wstring> subkeys;
        if (IsSystemInstall(scope)) {
          subkeys.push_back(CLIENT_STATE_MEDIUM_KEY);
        }
        subkeys.push_back(CLIENT_STATE_KEY);
        std::vector<std::string> app_ids;
        for (const auto& subkey : subkeys) {
          for (base::win::RegistryKeyIterator it(root, subkey.c_str(),
                                                 KEY_WOW64_32KEY);
               it.Valid(); ++it) {
            const std::string app_id = base::WideToUTF8(it.Name());
            if (include_only_these_app_ids.empty() ||
                base::ranges::find(include_only_these_app_ids, app_id) !=
                    std::end(include_only_these_app_ids)) {
              app_ids.push_back(app_id);
            }
          }
        }

        return app_ids;
      }(),
      scope);
}

}  // namespace updater