chromium/chrome/browser/ash/nearby/nearby_process_manager_impl.h

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

#ifndef CHROME_BROWSER_ASH_NEARBY_NEARBY_PROCESS_MANAGER_IMPL_H_
#define CHROME_BROWSER_ASH_NEARBY_NEARBY_PROCESS_MANAGER_IMPL_H_

#include <memory>

#include "base/containers/flat_map.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/timer/timer.h"
#include "base/unguessable_token.h"
#include "chromeos/ash/services/nearby/public/cpp/nearby_process_manager.h"
#include "chromeos/ash/services/nearby/public/mojom/quick_start_decoder.mojom.h"
#include "mojo/public/cpp/bindings/shared_remote.h"

namespace ash {
namespace nearby {

class NearbyDependenciesProvider;

// NearbyProcessManager implementation, which is implemented as a KeyedService
// because its dependencies are associated with the current user.
//
// This class starts up the utility process when at least one client holds a
// NearbyReferenceImpl object. When the first client requests a reference, this
// class creates a Mojo connection to the Sharing interface, which causes the
// process to start up. Once the last remaining client deletes its reference,
// this class invokes the asynchronous shutdown flow, then disconnects the
// Mojo connection, which results in the process getting killed.
class NearbyProcessManagerImpl : public NearbyProcessManager {
 public:
  class Factory {
   public:
    static std::unique_ptr<NearbyProcessManager> Create(
        NearbyDependenciesProvider* nearby_dependencies_provider,
        std::unique_ptr<base::OneShotTimer> timer =
            std::make_unique<base::OneShotTimer>());
    static void SetFactoryForTesting(Factory* factory);
    virtual ~Factory() = default;

   private:
    virtual std::unique_ptr<NearbyProcessManager> BuildInstance(
        NearbyDependenciesProvider* nearby_dependencies_provider,
        std::unique_ptr<base::OneShotTimer> timer) = 0;
  };

  ~NearbyProcessManagerImpl() override;

 private:
  friend class NearbyProcessManagerImplTest;

  class NearbyReferenceImpl
      : public NearbyProcessManager::NearbyProcessReference {
   public:
    NearbyReferenceImpl(
        const mojo::SharedRemote<
            ::nearby::connections::mojom::NearbyConnections>& connections,
        const mojo::SharedRemote<
            ::ash::nearby::presence::mojom::NearbyPresence>& presence,
        const mojo::SharedRemote<sharing::mojom::NearbySharingDecoder>& decoder,
        const mojo::SharedRemote<quick_start::mojom::QuickStartDecoder>&
            quick_start_decoder,
        base::OnceClosure destructor_callback);
    ~NearbyReferenceImpl() override;

   private:
    // NearbyProcessManager::NearbyProcessReference:
    const mojo::SharedRemote<::nearby::connections::mojom::NearbyConnections>&
    GetNearbyConnections() const override;
    const mojo::SharedRemote<::ash::nearby::presence::mojom::NearbyPresence>&
    GetNearbyPresence() const override;
    const mojo::SharedRemote<sharing::mojom::NearbySharingDecoder>&
    GetNearbySharingDecoder() const override;
    const mojo::SharedRemote<quick_start::mojom::QuickStartDecoder>&
    GetQuickStartDecoder() const override;

    mojo::SharedRemote<::nearby::connections::mojom::NearbyConnections>
        connections_;
    mojo::SharedRemote<::ash::nearby::presence::mojom::NearbyPresence>
        presence_;
    mojo::SharedRemote<sharing::mojom::NearbySharingDecoder> decoder_;
    mojo::SharedRemote<quick_start::mojom::QuickStartDecoder>
        quick_start_decoder_;
    base::OnceClosure destructor_callback_;
  };

  NearbyProcessManagerImpl(
      NearbyDependenciesProvider* nearby_dependencies_provider,
      std::unique_ptr<base::OneShotTimer> timer,
      const base::RepeatingCallback<
          mojo::PendingRemote<sharing::mojom::Sharing>()>& sharing_binder);

  // NearbyProcessManagerImpl:
  std::unique_ptr<NearbyProcessReference> GetNearbyProcessReference(
      NearbyProcessStoppedCallback on_process_stopped_callback) override;
  void ShutDownProcess() override;

  // KeyedService:
  void Shutdown() override;

  // Returns whether the process was successfully bound.
  bool AttemptToBindToUtilityProcess();

  void OnSharingProcessCrash();
  void OnMojoPipeDisconnect(NearbyProcessShutdownReason shutdown_reason);
  void OnReferenceDeleted(const base::UnguessableToken& reference_id);
  void DoShutDownProcess(NearbyProcessShutdownReason shutdown_reason);
  void NotifyProcessStopped(NearbyProcessShutdownReason shutdown_reason);

  raw_ptr<NearbyDependenciesProvider> nearby_dependencies_provider_;
  std::unique_ptr<base::OneShotTimer> shutdown_debounce_timer_;
  base::RepeatingCallback<mojo::PendingRemote<sharing::mojom::Sharing>()>
      sharing_binder_;

  // Connection to the Nearby Connections utility process. If bound, the
  // process is active and running.
  mojo::Remote<sharing::mojom::Sharing> sharing_;

  // Implemented as SharedRemote because copies of these are intended to be used
  // by multiple clients.
  mojo::SharedRemote<::nearby::connections::mojom::NearbyConnections>
      connections_;
  mojo::SharedRemote<::ash::nearby::presence::mojom::NearbyPresence> presence_;
  mojo::SharedRemote<sharing::mojom::NearbySharingDecoder> decoder_;
  mojo::SharedRemote<quick_start::mojom::QuickStartDecoder>
      quick_start_decoder_;

  // Map which stores callbacks to be invoked if the Nearby process shuts down
  // unexpectedly, before clients release their references.
  base::flat_map<base::UnguessableToken, NearbyProcessStoppedCallback>
      id_to_process_stopped_callback_map_;

  bool shut_down_ = false;

  base::WeakPtrFactory<NearbyProcessManagerImpl> weak_ptr_factory_{this};
};

}  // namespace nearby
}  // namespace ash

#endif  // CHROME_BROWSER_ASH_NEARBY_NEARBY_PROCESS_MANAGER_IMPL_H_