chromium/ash/ambient/resources/ambient_dlc_background_installer.cc

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

#include "ash/ambient/resources/ambient_dlc_background_installer.h"

#include "ash/ambient/util/time_of_day_utils.h"
#include "ash/public/cpp/network_config_service.h"
#include "base/check.h"
#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"

namespace ash {

AmbientBackgroundDlcInstaller::AmbientBackgroundDlcInstaller() {
  GetNetworkConfigService(cros_network_config_.BindNewPipeAndPassReceiver());
  cros_network_config_->AddObserver(
      cros_network_config_observer_.BindNewPipeAndPassRemote());
  cros_network_config_->GetNetworkStateList(
      chromeos::network_config::mojom::NetworkFilter::New(
          chromeos::network_config::mojom::FilterType::kActive,
          chromeos::network_config::mojom::NetworkType::kAll,
          chromeos::network_config::mojom::kNoLimit),
      base::BindOnce(
          &AmbientBackgroundDlcInstaller::TryExecuteInstallForAllActiveNetworks,
          weak_factory_.GetWeakPtr()));
}

AmbientBackgroundDlcInstaller::~AmbientBackgroundDlcInstaller() = default;

// TODO(b/220202911): After the linked bug is complete:
// 1) Do the background install at a random delay after the user has logged in
//    and the user has enabled ambient mode.
// 2) Uninstall the DLC if the user disables ambient mode.
// 3) Wait for non-metered/cellular network availability (usually wifi) before
//    performing the background install. This can be done by modifying the
//    `chromeos::network_config::mojom::NetworkFilter` we pass to the
//    `cros_network_config_`.
// The above is currently not done (even though it saves the most disc space)
// because there is currently a corner case where the dlc install can repeatedly
// fail if the user needs to reboot for a pending OS update. Installing the dlc
// immediately after network connectivity reduces the odds of the user hitting
// this case for the time being.
void AmbientBackgroundDlcInstaller::OnNetworkStateChanged(
    chromeos::network_config::mojom::NetworkStatePropertiesPtr network) {
  TryExecuteInstall(std::move(network));
}

void AmbientBackgroundDlcInstaller::TryExecuteInstallForAllActiveNetworks(
    std::vector<chromeos::network_config::mojom::NetworkStatePropertiesPtr>
        active_networks) {
  for (auto& network : active_networks) {
    TryExecuteInstall(std::move(network));
  }
}

void AmbientBackgroundDlcInstaller::TryExecuteInstall(
    chromeos::network_config::mojom::NetworkStatePropertiesPtr network) {
  if (has_executed_install_ || !network ||
      network->connection_state !=
          chromeos::network_config::mojom::ConnectionStateType::kOnline) {
    return;
  }

  has_executed_install_ = true;

  // Stop observing network changes.
  cros_network_config_observer_.reset();

  // Dbus calls for dlc installations must be performed on the main thread or
  // a crash occurs. Post a dummy `BEST_EFFORT` task as a signal that resources
  // are ready for background tasks, and then run the install back on the main
  // thread.
  base::ThreadPool::PostTaskAndReply(
      FROM_HERE, {base::TaskPriority::BEST_EFFORT}, base::DoNothing(),
      base::BindOnce(&InstallAmbientVideoDlcInBackground));
}

}  // namespace ash