blob: fccc79e885d9da2f521f50b06039f003a40277e5 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MEDIA_CAPTURE_VIDEO_CHROMEOS_CAMERA_HAL_DISPATCHER_IMPL_H_
#define MEDIA_CAPTURE_VIDEO_CHROMEOS_CAMERA_HAL_DISPATCHER_IMPL_H_
#include <memory>
#include <set>
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/containers/unique_ptr_adapters.h"
#include "base/files/scoped_file.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/singleton.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list_threadsafe.h"
#include "base/observer_list_types.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
#include "base/thread_annotations.h"
#include "base/threading/thread.h"
#include "base/unguessable_token.h"
#include "components/chromeos_camera/common/jpeg_encode_accelerator.mojom.h"
#include "components/chromeos_camera/common/mjpeg_decode_accelerator.mojom.h"
#include "media/capture/capture_export.h"
#include "media/capture/video/chromeos/mojom/cros_camera_service.mojom.h"
#include "media/capture/video/chromeos/token_manager.h"
#include "media/capture/video/chromeos/video_capture_device_factory_chromeos.h"
#include "media/capture/video/video_capture_device_factory.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/platform/platform_channel_server_endpoint.h"
namespace base {
class SingleThreadTaskRunner;
class WaitableEvent;
} // namespace base
namespace media {
using MojoJpegEncodeAcceleratorFactoryCB = base::RepeatingCallback<void(
mojo::PendingReceiver<chromeos_camera::mojom::JpegEncodeAccelerator>)>;
class CAPTURE_EXPORT CameraClientObserver {
public:
CameraClientObserver(cros::mojom::CameraClientType type,
base::UnguessableToken auth_token)
: type_(type), auth_token_(auth_token) {}
virtual ~CameraClientObserver();
virtual void OnChannelCreated(
mojo::PendingRemote<cros::mojom::CameraModule> camera_module) = 0;
cros::mojom::CameraClientType GetType() { return type_; }
const base::UnguessableToken GetAuthToken() { return auth_token_; }
bool Authenticate(TokenManager* token_manager);
private:
cros::mojom::CameraClientType type_;
base::UnguessableToken auth_token_;
};
class CAPTURE_EXPORT CameraActiveClientObserver : public base::CheckedObserver {
public:
virtual void OnActiveClientChange(cros::mojom::CameraClientType type,
bool is_active) = 0;
};
// A class to provide a no-op remote to CameraHalServer that failed
// registration. When CameraHalServer calls
// CameraHalDispatcher::RegisterServerWithToken to register itself, a
// PendingRemote<CameraHalServerCallbacks> is returned. Returning an unbound
// pending remote would crash CameraHalServer immediately, and thus disallows
// it from handling authentication failures.
// TODO(b/170075468): Modify RegisterServerWithToken to return an optional
// CameraHalServerCallbacks instead.
class FailedCameraHalServerCallbacks final
: public cros::mojom::CameraHalServerCallbacks {
private:
friend class CameraHalDispatcherImpl;
FailedCameraHalServerCallbacks();
~FailedCameraHalServerCallbacks() override;
mojo::PendingRemote<cros::mojom::CameraHalServerCallbacks> GetRemote();
// CameraHalServerCallbacks implementations.
void CameraDeviceActivityChange(int32_t camera_id,
bool opened,
cros::mojom::CameraClientType type) override;
void CameraPrivacySwitchStateChange(
cros::mojom::CameraPrivacySwitchState state) override;
mojo::Receiver<cros::mojom::CameraHalServerCallbacks> callbacks_;
};
class CAPTURE_EXPORT CameraPrivacySwitchObserver
: public base::CheckedObserver {
public:
virtual void OnCameraPrivacySwitchStatusChanged(
cros::mojom::CameraPrivacySwitchState state) = 0;
protected:
~CameraPrivacySwitchObserver() override = default;
};
// The CameraHalDispatcherImpl hosts and waits on the unix domain socket
// /var/run/camera3.sock. CameraHalServer and CameraHalClients connect to the
// unix domain socket to create the initial Mojo connections with the
// CameraHalDisptcherImpl, and CameraHalDispatcherImpl then creates and
// dispatches the Mojo channels between CameraHalServer and CameraHalClients to
// establish direct Mojo connections between the CameraHalServer and the
// CameraHalClients.
//
// For general documentation about the CameraHalDispater Mojo interface see the
// comments in mojo/cros_camera_service.mojom.
//
// On ChromeOS the video capture service must run in the browser process,
// because parts of the code depend on global objects that are only available in
// the Browser process. Therefore, CameraHalDispatcherImpl must run in the
// browser process as well.
// See https://crbug.com/891961.
class CAPTURE_EXPORT CameraHalDispatcherImpl final
: public cros::mojom::CameraHalDispatcher,
public cros::mojom::CameraHalServerCallbacks,
public base::trace_event::TraceLog::EnabledStateObserver {
public:
static CameraHalDispatcherImpl* GetInstance();
bool Start(MojoMjpegDecodeAcceleratorFactoryCB jda_factory,
MojoJpegEncodeAcceleratorFactoryCB jea_factory);
void AddClientObserver(std::unique_ptr<CameraClientObserver> observer,
base::OnceCallback<void(int32_t)> result_callback);
bool IsStarted();
// Adds an observer that watches for active camera client changes. Observer
// would be immediately notified of the current list of active clients.
void AddActiveClientObserver(CameraActiveClientObserver* observer);
// Removes the observer. A previously-added observer must be removed before
// being destroyed.
void RemoveActiveClientObserver(CameraActiveClientObserver* observer);
// Adds an observer to get notified when the camera privacy switch status
// changed. Please note that for some devices, the signal will only be
// detectable when the camera is currently on due to hardware limitations.
// Returns the current state of the camera privacy switch.
cros::mojom::CameraPrivacySwitchState AddCameraPrivacySwitchObserver(
CameraPrivacySwitchObserver* observer);
// Removes the observer. A previously-added observer must be removed before
// being destroyed.
void RemoveCameraPrivacySwitchObserver(CameraPrivacySwitchObserver* observer);
// Called by vm_permission_service to register the token used for pluginvm.
void RegisterPluginVmToken(const base::UnguessableToken& token);
void UnregisterPluginVmToken(const base::UnguessableToken& token);
// CameraHalDispatcher implementations.
void RegisterServer(
mojo::PendingRemote<cros::mojom::CameraHalServer> server) final;
void RegisterServerWithToken(
mojo::PendingRemote<cros::mojom::CameraHalServer> server,
const base::UnguessableToken& token,
RegisterServerWithTokenCallback callback) final;
void RegisterClient(
mojo::PendingRemote<cros::mojom::CameraHalClient> client) final;
void RegisterClientWithToken(
mojo::PendingRemote<cros::mojom::CameraHalClient> client,
cros::mojom::CameraClientType type,
const base::UnguessableToken& auth_token,
RegisterClientWithTokenCallback callback) final;
void GetMjpegDecodeAccelerator(
mojo::PendingReceiver<chromeos_camera::mojom::MjpegDecodeAccelerator>
jda_receiver) final;
void GetJpegEncodeAccelerator(
mojo::PendingReceiver<chromeos_camera::mojom::JpegEncodeAccelerator>
jea_receiver) final;
void RegisterSensorClientWithToken(
mojo::PendingRemote<chromeos::sensors::mojom::SensorHalClient> client,
const base::UnguessableToken& auth_token,
RegisterSensorClientWithTokenCallback callback) final;
// CameraHalServerCallbacks implementations.
void CameraDeviceActivityChange(int32_t camera_id,
bool opened,
cros::mojom::CameraClientType type) final;
void CameraPrivacySwitchStateChange(
cros::mojom::CameraPrivacySwitchState state) final;
base::UnguessableToken GetTokenForTrustedClient(
cros::mojom::CameraClientType type);
// base::trace_event::TraceLog::EnabledStateObserver implementation.
void OnTraceLogEnabled() final;
void OnTraceLogDisabled() final;
private:
friend struct base::DefaultSingletonTraits<CameraHalDispatcherImpl>;
// Allow the test to construct the class directly.
friend class CameraHalDispatcherImplTest;
CameraHalDispatcherImpl();
~CameraHalDispatcherImpl() final;
bool StartThreads();
// Creates the unix domain socket for the camera client processes and the
// camera HALv3 adapter process to connect.
void CreateSocket(base::WaitableEvent* started);
// Waits for incoming connections (from HAL process or from client processes).
// Runs on |blocking_io_thread_|.
void StartServiceLoop(base::ScopedFD socket_fd, base::WaitableEvent* started);
void RegisterClientWithTokenOnProxyThread(
mojo::PendingRemote<cros::mojom::CameraHalClient> client,
cros::mojom::CameraClientType type,
base::UnguessableToken token,
RegisterClientWithTokenCallback callback);
void AddClientObserverOnProxyThread(
std::unique_ptr<CameraClientObserver> observer,
base::OnceCallback<void(int32_t)> result_callback);
void EstablishMojoChannel(CameraClientObserver* client_observer);
// Handler for incoming Mojo connection on the unix domain socket.
void OnPeerConnected(mojo::ScopedMessagePipeHandle message_pipe);
// Mojo connection error handlers.
void OnCameraHalServerConnectionError();
void OnCameraHalClientConnectionError(CameraClientObserver* client);
void RegisterSensorClientWithTokenOnUIThread(
mojo::PendingRemote<chromeos::sensors::mojom::SensorHalClient> client,
const base::UnguessableToken& auth_token,
RegisterSensorClientWithTokenCallback callback);
void StopOnProxyThread();
void OnTraceLogEnabledOnProxyThread();
void OnTraceLogDisabledOnProxyThread();
TokenManager* GetTokenManagerForTesting();
base::ScopedFD proxy_fd_;
base::ScopedFD cancel_pipe_;
base::Thread proxy_thread_;
base::Thread blocking_io_thread_;
scoped_refptr<base::SequencedTaskRunner> main_task_runner_;
scoped_refptr<base::SingleThreadTaskRunner> proxy_task_runner_;
scoped_refptr<base::SingleThreadTaskRunner> blocking_io_task_runner_;
mojo::ReceiverSet<cros::mojom::CameraHalDispatcher> receiver_set_;
mojo::Remote<cros::mojom::CameraHalServer> camera_hal_server_;
mojo::Receiver<cros::mojom::CameraHalServerCallbacks>
camera_hal_server_callbacks_;
FailedCameraHalServerCallbacks failed_camera_hal_server_callbacks_;
std::set<std::unique_ptr<CameraClientObserver>, base::UniquePtrComparator>
client_observers_;
MojoMjpegDecodeAcceleratorFactoryCB jda_factory_;
MojoJpegEncodeAcceleratorFactoryCB jea_factory_;
TokenManager token_manager_;
base::Lock opened_camera_id_map_lock_;
base::flat_map<cros::mojom::CameraClientType, base::flat_set<int32_t>>
opened_camera_id_map_ GUARDED_BY(opened_camera_id_map_lock_);
scoped_refptr<base::ObserverListThreadSafe<CameraActiveClientObserver>>
active_client_observers_;
base::Lock privacy_switch_state_lock_;
cros::mojom::CameraPrivacySwitchState current_privacy_switch_state_
GUARDED_BY(privacy_switch_state_lock_);
scoped_refptr<base::ObserverListThreadSafe<CameraPrivacySwitchObserver>>
privacy_switch_observers_;
base::WeakPtrFactory<CameraHalDispatcherImpl> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(CameraHalDispatcherImpl);
};
} // namespace media
#endif // MEDIA_CAPTURE_VIDEO_CHROMEOS_CAMERA_HAL_DISPATCHER_IMPL_H_