mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-16 15:36:12 -04:00
Merge branch 'google3'
Change-Id: Ibebf84b98939ee8e5006beedc34d225e8c2dd413
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
cc_library(
|
||||
name = "api",
|
||||
hdrs = [
|
||||
"atomic_boolean.h",
|
||||
"atomic_reference.h",
|
||||
"ble.h",
|
||||
"ble_v2.h",
|
||||
"bluetooth_adapter.h",
|
||||
"bluetooth_classic.h",
|
||||
"cancelable.h",
|
||||
"condition_variable.h",
|
||||
"count_down_latch.h",
|
||||
"crypto.h",
|
||||
"executor.h",
|
||||
"future.h",
|
||||
"input_file.h",
|
||||
"listenable_future.h",
|
||||
"mutex.h",
|
||||
"output_file.h",
|
||||
"platform.h",
|
||||
"scheduled_executor.h",
|
||||
"server_sync.h",
|
||||
"settable_future.h",
|
||||
"submittable_executor.h",
|
||||
"system_clock.h",
|
||||
"webrtc.h",
|
||||
"wifi.h",
|
||||
"wifi_lan.h",
|
||||
],
|
||||
visibility = [
|
||||
"//platform_v2/base:__pkg__",
|
||||
"//platform_v2/impl:__subpackages__",
|
||||
"//platform_v2/public:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//platform_v2/base",
|
||||
"//absl/base:core_headers",
|
||||
"//absl/strings",
|
||||
"//absl/time",
|
||||
"//absl/types:any",
|
||||
"//webrtc/api:libjingle_peerconnection_api",
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,41 @@
|
||||
add_library(platform_api2 STATIC)
|
||||
|
||||
target_sources(platform_api2
|
||||
PUBLIC
|
||||
atomic_boolean.h
|
||||
atomic_reference.h
|
||||
ble.h
|
||||
ble_v2.h
|
||||
bluetooth_adapter.h
|
||||
bluetooth_classic.h
|
||||
condition_variable.h
|
||||
count_down_latch.h
|
||||
executor.h
|
||||
future.h
|
||||
hash_utils.h
|
||||
input_file.h
|
||||
input_stream.h
|
||||
listenable_future.h
|
||||
multi_thread_executor.h
|
||||
mutex.h
|
||||
output_file.h
|
||||
output_stream.h
|
||||
scheduled_executor.h
|
||||
server_sync.h
|
||||
settable_future.h
|
||||
single_thread_executor.h
|
||||
socket.h
|
||||
submittable_executor.h
|
||||
system_clock.h
|
||||
thread_utils.h
|
||||
webrtc.h
|
||||
wifi.h
|
||||
)
|
||||
|
||||
target_link_libraries(platform_api2
|
||||
PUBLIC
|
||||
absl::strings
|
||||
absl::time
|
||||
platform_types
|
||||
webrtc_api_libjingle_peerconnection_api
|
||||
)
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef PLATFORM_V2_API_ATOMIC_BOOLEAN_H_
|
||||
#define PLATFORM_V2_API_ATOMIC_BOOLEAN_H_
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace api {
|
||||
|
||||
// A boolean value that may be updated atomically.
|
||||
class AtomicBoolean {
|
||||
public:
|
||||
virtual ~AtomicBoolean() = default;
|
||||
|
||||
// Atomically read and return current value.
|
||||
virtual bool Get() const = 0;
|
||||
|
||||
// Atomically exchange original value with a new one. Return previous value.
|
||||
virtual bool Set(bool value) = 0;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_API_ATOMIC_BOOLEAN_H_
|
||||
@@ -0,0 +1,26 @@
|
||||
#ifndef PLATFORM_V2_API_ATOMIC_REFERENCE_H_
|
||||
#define PLATFORM_V2_API_ATOMIC_REFERENCE_H_
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace api {
|
||||
|
||||
// An object reference that may be updated atomically.
|
||||
//
|
||||
// https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/AtomicReference.html
|
||||
template <typename T>
|
||||
class AtomicReference {
|
||||
public:
|
||||
virtual ~AtomicReference() = default;
|
||||
|
||||
virtual T Get() const & = 0;
|
||||
virtual T Get() && = 0;
|
||||
virtual void Set(const T& value) = 0;
|
||||
virtual void Set(T&& value) = 0;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_API_ATOMIC_REFERENCE_H_
|
||||
@@ -0,0 +1,112 @@
|
||||
#ifndef PLATFORM_V2_API_BLE_H_
|
||||
#define PLATFORM_V2_API_BLE_H_
|
||||
|
||||
#include "platform_v2/api/bluetooth_classic.h"
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
#include "platform_v2/base/input_stream.h"
|
||||
#include "platform_v2/base/output_stream.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace api {
|
||||
|
||||
// Opaque wrapper over a BLE peripheral. Must contain enough data about a
|
||||
// particular BLE device to connect to its GATT server.
|
||||
class BlePeripheral {
|
||||
public:
|
||||
virtual ~BlePeripheral() {}
|
||||
|
||||
// The returned reference lifetime matches BlePeripheral object.
|
||||
virtual BluetoothDevice& GetBluetoothDevice() = 0;
|
||||
};
|
||||
|
||||
class BleSocket {
|
||||
public:
|
||||
virtual ~BleSocket() {}
|
||||
|
||||
// Returns the InputStream of the BleSocket.
|
||||
// On error, returned stream will report Exception::kIo on any operation.
|
||||
//
|
||||
// The returned object is not owned by the caller, and can be invalidated once
|
||||
// the BleSocket object is destroyed.
|
||||
virtual InputStream& GetInputStream() = 0;
|
||||
|
||||
// Returns the OutputStream of the BleSocket.
|
||||
// On error, returned stream will report Exception::kIo on any operation.
|
||||
//
|
||||
// The returned object is not owned by the caller, and can be invalidated once
|
||||
// the BleSocket object is destroyed.
|
||||
virtual OutputStream& GetOutputStream() = 0;
|
||||
|
||||
// Conforms to the same contract as
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothSocket.html#close().
|
||||
//
|
||||
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
|
||||
virtual Exception Close() = 0;
|
||||
|
||||
// The returned object is not owned by the caller, and can be invalidated once
|
||||
// the BleSocket object is destroyed.
|
||||
virtual BlePeripheral& GetRemotePeripheral() = 0;
|
||||
};
|
||||
|
||||
// Container of operations that can be performed over the BLE medium.
|
||||
class BleMedium {
|
||||
public:
|
||||
virtual ~BleMedium() {}
|
||||
|
||||
virtual bool StartAdvertising(absl::string_view service_id,
|
||||
const ByteArray& advertisement) = 0;
|
||||
virtual void StopAdvertising(absl::string_view service_id) = 0;
|
||||
|
||||
class DiscoveredPeripheralCallback {
|
||||
public:
|
||||
virtual ~DiscoveredPeripheralCallback() {}
|
||||
|
||||
// The BlePeripheral* is not owned by callbacks.
|
||||
// It is passed to give access to its non-const methods.
|
||||
// It is guaranteed to be valid for the duration of call.
|
||||
virtual void OnPeripheralDiscovered(BlePeripheral* ble_peripheral,
|
||||
absl::string_view service_id,
|
||||
const ByteArray& advertisement) = 0;
|
||||
virtual void OnPeripheralLost(BlePeripheral* ble_peripheral,
|
||||
absl::string_view service_id) = 0;
|
||||
};
|
||||
|
||||
// Returns true once the BLE scan has been initiated.
|
||||
virtual bool StartScanning(
|
||||
absl::string_view service_id,
|
||||
const DiscoveredPeripheralCallback& discovered_peripheral_callback) = 0;
|
||||
|
||||
// Returns true once BLE scanning for service_id is well and truly stopped;
|
||||
// after this returns, there must be no more invocations of the
|
||||
// DiscoveredPeripheralCallback passed in to StartScanning() for service_id.
|
||||
virtual void StopScanning(absl::string_view service_id) = 0;
|
||||
|
||||
// Callback that is invoked when a new connection is accepted.
|
||||
class AcceptedConnectionCallback {
|
||||
public:
|
||||
virtual ~AcceptedConnectionCallback() {}
|
||||
|
||||
virtual void OnConnectionAccepted(std::unique_ptr<BleSocket> socket,
|
||||
absl::string_view service_id) = 0;
|
||||
};
|
||||
|
||||
// Returns true once BLE socket connection requests to service_id can be
|
||||
// accepted.
|
||||
virtual bool StartAcceptingConnections(
|
||||
absl::string_view service_id,
|
||||
const AcceptedConnectionCallback& accepted_connection_callback) = 0;
|
||||
virtual void StopAcceptingConnections(const std::string& service_id) = 0;
|
||||
|
||||
// BlePeripheral* is not owned by this call;
|
||||
// it must remain valid for the duration of a call.
|
||||
virtual std::unique_ptr<BleSocket> Connect(BlePeripheral* ble_peripheral,
|
||||
absl::string_view service_id) = 0;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_API_BLE_H_
|
||||
@@ -0,0 +1,392 @@
|
||||
#ifndef PLATFORM_V2_API_BLE_V2_H_
|
||||
#define PLATFORM_V2_API_BLE_V2_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
#include "platform_v2/base/exception.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace api {
|
||||
namespace ble_v2 {
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/le/AdvertiseData
|
||||
//
|
||||
// Bundle of data found in a BLE advertisement.
|
||||
//
|
||||
// All service UUIDs will conform to the 16-bit Bluetooth base UUID,
|
||||
// 0000xxxx-0000-1000-8000-00805F9B34FB. This makes it possible to store two
|
||||
// byte service UUIDs in the advertisement.
|
||||
struct BleAdvertisementData {
|
||||
using TxPowerLevel = int8_t;
|
||||
|
||||
static const TxPowerLevel kUnspecifiedTxPowerLevel =
|
||||
std::numeric_limits<TxPowerLevel>::min();
|
||||
|
||||
bool is_connectable;
|
||||
// When set to kUnspecifiedTxPowerLevel, TX power should not be included in
|
||||
// the advertisement data.
|
||||
TxPowerLevel tx_power_level;
|
||||
// When set to an empty string, local name should not be included in the
|
||||
// advertisement data.
|
||||
std::string local_name;
|
||||
// When set to an empty vector, the set of 16-bit service class UUIDs should
|
||||
// not be included in the advertisement data.
|
||||
std::set<std::string> service_uuids;
|
||||
// Maps service UUIDs to their service data.
|
||||
std::map<std::string, ByteArray> service_data;
|
||||
};
|
||||
|
||||
// Opaque wrapper over a BLE peripheral. Must be able to uniquely identify a
|
||||
// peripheral so that we can connect to its GATT server.
|
||||
class BlePeripheral {
|
||||
public:
|
||||
virtual ~BlePeripheral() {}
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothDevice#getAddress()
|
||||
//
|
||||
// This should be the MAC address when possible. If the implementation is
|
||||
// unable to retrieve that, any unique identifier should suffice.
|
||||
virtual std::string GetId() const = 0;
|
||||
};
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothGattCharacteristic
|
||||
//
|
||||
// Representation of a GATT characteristic.
|
||||
class GattCharacteristic {
|
||||
public:
|
||||
virtual ~GattCharacteristic() {}
|
||||
|
||||
// Possible permissions of a GATT characteristic.
|
||||
enum class Permission {
|
||||
kUnknown = 0,
|
||||
kRead = 1,
|
||||
kWrite = 2,
|
||||
kLast,
|
||||
};
|
||||
|
||||
// Possible properties of a GATT characteristic.
|
||||
enum class Property {
|
||||
kUnknown = 0,
|
||||
kRead = 1,
|
||||
kWrite = 2,
|
||||
kIndicate = 3,
|
||||
kLast,
|
||||
};
|
||||
|
||||
// Returns the UUID of this characteristic.
|
||||
virtual std::string GetUuid() = 0;
|
||||
|
||||
// Returns the UUID of the containing GATT service.
|
||||
virtual std::string GetServiceUuid() = 0;
|
||||
};
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothGatt
|
||||
//
|
||||
// Representation of a client GATT connection to a remote GATT server.
|
||||
class ClientGattConnection {
|
||||
public:
|
||||
virtual ~ClientGattConnection() {}
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#getDevice()
|
||||
//
|
||||
// Retrieves the BLE peripheral that this connection is tied to.
|
||||
virtual BlePeripheral& GetPeripheral() = 0;
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#discoverServices()
|
||||
//
|
||||
// Discovers all available services and characteristics on this connection.
|
||||
// Returns whether or not discovery finished successfully.
|
||||
//
|
||||
// This function should block until discovery has finished.
|
||||
virtual bool DiscoverServices() = 0;
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#getService(java.util.UUID)
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothGattService.html#getCharacteristic(java.util.UUID)
|
||||
//
|
||||
// Retrieves a GATT characteristic. On error, does not return a value.
|
||||
//
|
||||
// DiscoverServices() should be called before this method to fetch all
|
||||
// available services and characteristics first.
|
||||
//
|
||||
// It is okay for duplicate services to exist, as long as the specified
|
||||
// characteristic UUID is unique among all services of the same UUID.
|
||||
virtual std::optional<GattCharacteristic> GetCharacteristic(
|
||||
absl::string_view service_uuid,
|
||||
absl::string_view characteristic_uuid) = 0;
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#readCharacteristic(android.bluetooth.BluetoothGattCharacteristic)
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothGattCharacteristic.html#getValue()
|
||||
//
|
||||
// Reads a GATT characteristic. No value is returned upon error.
|
||||
virtual std::optional<ByteArray> ReadCharacteristic(
|
||||
const GattCharacteristic& characteristic) = 0;
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothGattCharacteristic.html#setValue(byte[])
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#writeCharacteristic(android.bluetooth.BluetoothGattCharacteristic)
|
||||
//
|
||||
// Sends a remote characteristic write request to the server and returns
|
||||
// whether or not it was successful.
|
||||
virtual bool WriteCharacteristic(const GattCharacteristic& characteristic,
|
||||
const ByteArray& value) = 0;
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#disconnect()
|
||||
//
|
||||
// Disconnects a GATT connection.
|
||||
virtual void Disconnect() = 0;
|
||||
};
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothGattServer
|
||||
//
|
||||
// Representation of a server GATT connection to a remote GATT client.
|
||||
class ServerGattConnection {
|
||||
public:
|
||||
virtual ~ServerGattConnection() {}
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothGattCharacteristic.html#setValue(byte[])
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothGattServer.html#notifyCharacteristicChanged(android.bluetooth.BluetoothDevice,%20android.bluetooth.BluetoothGattCharacteristic,%20boolean)
|
||||
//
|
||||
// Sends a notification (via indication) to the client that a characteristic
|
||||
// has changed with the given value. Returns whether or not it was successful.
|
||||
//
|
||||
// The value sent does not have to reflect the locally stored characteristic
|
||||
// value. To update the local value, call GattServer::UpdateCharacteristic.
|
||||
virtual bool SendCharacteristic(const GattCharacteristic& characteristic,
|
||||
const ByteArray& value) = 0;
|
||||
};
|
||||
|
||||
// Callback for asynchronous events on the client side of a GATT connection.
|
||||
class ClientGattConnectionLifeCycleCallback {
|
||||
public:
|
||||
virtual ~ClientGattConnectionLifeCycleCallback() {}
|
||||
|
||||
// Called when the client is disconnected from the GATT server.
|
||||
virtual void OnDisconnected(ClientGattConnection* connection) = 0;
|
||||
};
|
||||
|
||||
// Callback for asynchronous events on the server side of a GATT connection.
|
||||
class ServerGattConnectionLifeCycleCallback {
|
||||
public:
|
||||
virtual ~ServerGattConnectionLifeCycleCallback() {}
|
||||
|
||||
// Called when a remote peripheral connected to us and subscribed to one of
|
||||
// our characteristics.
|
||||
virtual void OnCharacteristicSubscription(
|
||||
ServerGattConnection* connection,
|
||||
const GattCharacteristic& characteristic) = 0;
|
||||
|
||||
// Called when a remote peripheral unsubscribed from one of our
|
||||
// characteristics.
|
||||
virtual void OnCharacteristicUnsubscription(
|
||||
ServerGattConnection* connection,
|
||||
const GattCharacteristic& characteristic) = 0;
|
||||
};
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothGattServer
|
||||
//
|
||||
// Representation of a BLE GATT server.
|
||||
class GattServer {
|
||||
public:
|
||||
virtual ~GattServer() {}
|
||||
|
||||
// Creates a characteristic and adds it to the GATT server under the given
|
||||
// characteristic and service UUIDs. Returns no value upon error.
|
||||
//
|
||||
// Characteristics of the same service UUID should be put under one
|
||||
// service rather than many services with the same UUID.
|
||||
//
|
||||
// If the INDICATE property is included, the characteristic should include the
|
||||
// official Bluetooth Client Characteristic Configuration descriptor with UUID
|
||||
// 0x2902 and a WRITE permission. This allows remote clients to write to this
|
||||
// descriptor and subscribe for characteristic changes. For more information
|
||||
// about this descriptor, please go to:
|
||||
// https://www.bluetooth.com/specifications/Gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.Gatt.client_characteristic_configuration.xml
|
||||
virtual std::optional<GattCharacteristic> CreateCharacteristic(
|
||||
absl::string_view service_uuid, absl::string_view characteristic_uuid,
|
||||
const std::set<GattCharacteristic::Permission>& permissions,
|
||||
const std::set<GattCharacteristic::Property>& properties) = 0;
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothGattCharacteristic.html#setValue(byte[])
|
||||
//
|
||||
// Locally updates the value of a characteristic and returns whether or not it
|
||||
// was successful.
|
||||
// Takes ownership of (and is responsible for destroying) the passed-in
|
||||
// 'value'.
|
||||
virtual bool UpdateCharacteristic(const GattCharacteristic& characteristic,
|
||||
const ByteArray& value) = 0;
|
||||
|
||||
// Stops a GATT server.
|
||||
virtual void Stop() = 0;
|
||||
};
|
||||
|
||||
// A BLE socket representation.
|
||||
class BleSocket {
|
||||
public:
|
||||
virtual ~BleSocket() {}
|
||||
|
||||
// Returns the remote BLE peripheral tied to this socket.
|
||||
virtual BlePeripheral& GetRemotePeripheral() = 0;
|
||||
|
||||
// Writes a message on the socket and blocks until finished. Returns
|
||||
// Exception::kIo upon error, and Exception::kSuccess otherwise.
|
||||
virtual Exception Write(const ByteArray& message) = 0;
|
||||
|
||||
// Closes the socket and blocks until finished. Returns Exception::kIo upon
|
||||
// error, and Exception::kSuccess otherwise.
|
||||
virtual Exception Close() = 0;
|
||||
};
|
||||
|
||||
// Callback for asynchronous events on a BleSocket object.
|
||||
class BleSocketLifeCycleCallback {
|
||||
public:
|
||||
virtual ~BleSocketLifeCycleCallback() {}
|
||||
|
||||
// Called when a message arrives on a socket.
|
||||
virtual void OnMessageReceived(BleSocket* socket,
|
||||
const ByteArray& message) = 0;
|
||||
|
||||
// Called when a socket gets disconnected.
|
||||
virtual void OnDisconnected(BleSocket* socket) = 0;
|
||||
};
|
||||
|
||||
// Callback for asynchronous events on the server side of a BleSocket object.
|
||||
class ServerBleSocketLifeCycleCallback : public BleSocketLifeCycleCallback {
|
||||
public:
|
||||
~ServerBleSocketLifeCycleCallback() override {}
|
||||
|
||||
// Called when a new incoming socket has been established.
|
||||
virtual void OnSocketEstablished(BleSocket* socket) = 0;
|
||||
};
|
||||
|
||||
// The main BLE medium used inside of Nearby. This serves as the entry point for
|
||||
// all BLE and GATT related operations.
|
||||
class BleMedium {
|
||||
public:
|
||||
using Mtu = uint32_t;
|
||||
|
||||
virtual ~BleMedium() {}
|
||||
|
||||
// Coarse representation of power settings throughout all BLE operations.
|
||||
enum class PowerMode {
|
||||
kUnknown = 0,
|
||||
kLow = 1,
|
||||
kHigh = 2,
|
||||
kLast,
|
||||
};
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/le/BluetoothLeAdvertiser.html#startAdvertising(android.bluetooth.le.AdvertiseSettings,%20android.bluetooth.le.AdvertiseData,%20android.bluetooth.le.AdvertiseData,%20android.bluetooth.le.AdvertiseCallback)
|
||||
//
|
||||
// Starts BLE advertising and returns whether or not it was successful.
|
||||
//
|
||||
// Power mode should be interpreted in the following way:
|
||||
// LOW:
|
||||
// - Advertising interval = ~1000ms
|
||||
// - TX power = low
|
||||
// HIGH:
|
||||
// - Advertising interval = ~100ms
|
||||
// - TX power = high
|
||||
virtual bool StartAdvertising(const BleAdvertisementData& advertisement_data,
|
||||
const BleAdvertisementData& scan_response,
|
||||
PowerMode power_mode) = 0;
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/le/BluetoothLeAdvertiser.html#stopAdvertising(android.bluetooth.le.AdvertiseCallback)
|
||||
//
|
||||
// Stops advertising.
|
||||
virtual void StopAdvertising() = 0;
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/le/ScanCallback
|
||||
//
|
||||
// Callback for BLE scan results.
|
||||
class ScanCallback {
|
||||
public:
|
||||
virtual ~ScanCallback() {}
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/le/ScanCallback.html#onScanResult(int,%20android.bluetooth.le.ScanResult)
|
||||
//
|
||||
// Called when a BLE advertisement is discovered.
|
||||
//
|
||||
// The passed in advertisement_data is the merged combination of both
|
||||
// advertisement data and scan response.
|
||||
//
|
||||
// Every discovery of an advertisement should be reported, even if the
|
||||
// advertisement was discovered before.
|
||||
//
|
||||
// Ownership of the BleAdvertisementData transfers to the caller at this
|
||||
// point.
|
||||
virtual void OnAdvertisementFound(
|
||||
BlePeripheral* peripheral,
|
||||
const BleAdvertisementData& advertisement_data) = 0;
|
||||
};
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/le/BluetoothLeScanner.html#startScan(java.util.List%3Candroid.bluetooth.le.ScanFilter%3E,%20android.bluetooth.le.ScanSettings,%20android.bluetooth.le.ScanCallback)
|
||||
//
|
||||
// Starts scanning and returns whether or not it was successful.
|
||||
//
|
||||
// Power mode should be interpreted in the following way:
|
||||
// LOW:
|
||||
// - Scan window = ~512ms
|
||||
// - Scan interval = ~5120ms
|
||||
// HIGH:
|
||||
// - Scan window = ~4096ms
|
||||
// - Scan interval = ~4096ms
|
||||
virtual bool StartScanning(const std::set<std::string>& service_uuids,
|
||||
PowerMode power_mode,
|
||||
const ScanCallback& scan_callback) = 0;
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/le/BluetoothLeScanner.html#stopScan(android.bluetooth.le.ScanCallback)
|
||||
//
|
||||
// Stops scanning.
|
||||
virtual void StopScanning() = 0;
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothManager#openGattServer(android.content.Context,%20android.bluetooth.BluetoothGattServerCallback)
|
||||
//
|
||||
// Starts a GATT server. Returns a nullptr upon error.
|
||||
virtual std::unique_ptr<GattServer> StartGattServer(
|
||||
const ServerGattConnectionLifeCycleCallback& callback) = 0;
|
||||
|
||||
// Starts listening for incoming BLE sockets and returns false upon error.
|
||||
virtual bool StartListeningForIncomingBleSockets(
|
||||
const ServerBleSocketLifeCycleCallback& callback) = 0;
|
||||
|
||||
// Stops listening for incoming BLE sockets.
|
||||
virtual void StopListeningForIncomingBleSockets() = 0;
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#connectGatt(android.content.Context,%20boolean,%20android.bluetooth.BluetoothGattCallback)
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#requestConnectionPriority(int)
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#requestMtu(int)
|
||||
//
|
||||
// Connects to a GATT server and negotiates the specified connection
|
||||
// parameters. Returns nullptr upon error.
|
||||
//
|
||||
// Both connection interval and MTU can be negotiated on a best-effort basis.
|
||||
//
|
||||
// Power mode should be interpreted in the following way:
|
||||
// LOW:
|
||||
// - Connection interval = ~11.25ms - 15ms
|
||||
// HIGH:
|
||||
// - Connection interval = ~100ms - 125ms
|
||||
virtual std::unique_ptr<ClientGattConnection> ConnectToGattServer(
|
||||
BlePeripheral* peripheral, Mtu mtu, PowerMode power_mode,
|
||||
const ClientGattConnectionLifeCycleCallback& callback) = 0;
|
||||
|
||||
// Establishes a BLE socket to the specified remote peripheral. Returns
|
||||
// nullptr on error.
|
||||
virtual std::unique_ptr<BleSocket> EstablishBleSocket(
|
||||
BlePeripheral* peripheral,
|
||||
const BleSocketLifeCycleCallback& callback) = 0;
|
||||
};
|
||||
|
||||
} // namespace ble_v2
|
||||
} // namespace api
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_API_BLE_V2_H_
|
||||
@@ -0,0 +1,58 @@
|
||||
#ifndef PLATFORM_V2_API_BLUETOOTH_ADAPTER_H_
|
||||
#define PLATFORM_V2_API_BLUETOOTH_ADAPTER_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace api {
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html
|
||||
class BluetoothAdapter {
|
||||
public:
|
||||
virtual ~BluetoothAdapter() = default;
|
||||
|
||||
// Eligible statuses of the BluetoothAdapter.
|
||||
enum class Status {
|
||||
kDisabled,
|
||||
kEnabled,
|
||||
};
|
||||
|
||||
// Synchronously sets the status of the BluetoothAdapter to 'status', and
|
||||
// returns true if the operation was a success.
|
||||
virtual bool SetStatus(Status status) = 0;
|
||||
// Returns true if the BluetoothAdapter's current status is
|
||||
// Status::Value::kEnabled.
|
||||
virtual bool IsEnabled() const = 0;
|
||||
|
||||
// Scan modes of a BluetoothAdapter, as described at
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#getScanMode().
|
||||
enum class ScanMode {
|
||||
kUnknown,
|
||||
kNone,
|
||||
kConnectable,
|
||||
kConnectableDiscoverable,
|
||||
};
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#getScanMode()
|
||||
//
|
||||
// Returns ScanMode::kUnknown on error.
|
||||
virtual ScanMode GetScanMode() const = 0;
|
||||
// Synchronously sets the scan mode of the adapter, and returns true if the
|
||||
// operation was a success.
|
||||
virtual bool SetScanMode(ScanMode scan_mode) = 0;
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#getName()
|
||||
// Returns an empty string on error
|
||||
virtual std::string GetName() const = 0;
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#setName(java.lang.String)
|
||||
virtual bool SetName(absl::string_view name) = 0;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_API_BLUETOOTH_ADAPTER_H_
|
||||
@@ -0,0 +1,126 @@
|
||||
#ifndef PLATFORM_V2_API_BLUETOOTH_CLASSIC_H_
|
||||
#define PLATFORM_V2_API_BLUETOOTH_CLASSIC_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
#include "platform_v2/base/exception.h"
|
||||
#include "platform_v2/base/input_stream.h"
|
||||
#include "platform_v2/base/output_stream.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace api {
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html.
|
||||
class BluetoothDevice {
|
||||
public:
|
||||
virtual ~BluetoothDevice() {}
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#getName()
|
||||
virtual std::string GetName() const = 0;
|
||||
};
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothSocket.html.
|
||||
class BluetoothSocket {
|
||||
public:
|
||||
virtual ~BluetoothSocket() {}
|
||||
|
||||
// Returns the InputStream of the BluetoothSocket.
|
||||
virtual InputStream& GetInputStream() = 0;
|
||||
|
||||
// Returns the OutputStream of the BluetoothSocket.
|
||||
virtual OutputStream& GetOutputStream() = 0;
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothSocket.html#close()
|
||||
//
|
||||
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
|
||||
virtual Exception Close() = 0;
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothSocket.html#getRemoteDevice()
|
||||
virtual BluetoothDevice& GetRemoteDevice() = 0;
|
||||
};
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html.
|
||||
class BluetoothServerSocket {
|
||||
public:
|
||||
virtual ~BluetoothServerSocket() {}
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html#accept()
|
||||
//
|
||||
// returns Exception::kIo on error.
|
||||
virtual ExceptionOr<std::unique_ptr<BluetoothSocket>> Accept() = 0;
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html#close()
|
||||
//
|
||||
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
|
||||
virtual Exception Close() = 0;
|
||||
};
|
||||
|
||||
// Container of operations that can be performed over the Bluetooth Classic
|
||||
// medium.
|
||||
class BluetoothClassicMedium {
|
||||
public:
|
||||
virtual ~BluetoothClassicMedium() {}
|
||||
|
||||
class DiscoveryCallback {
|
||||
public:
|
||||
virtual ~DiscoveryCallback() {}
|
||||
|
||||
// BluetoothDevice* is not owned by callbacks.
|
||||
// Pointer is guaranteed to remain valid for the duration of a call.
|
||||
virtual void OnDeviceDiscovered(BluetoothDevice* device) = 0;
|
||||
virtual void OnDeviceNameChanged(BluetoothDevice* device) = 0;
|
||||
virtual void OnDeviceLost(BluetoothDevice* device) = 0;
|
||||
};
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#startDiscovery()
|
||||
//
|
||||
// Returns true once the process of discovery has been initiated.
|
||||
//
|
||||
// Does not take ownership of the passed-in discovery_callback -- destroying
|
||||
// that is up to the caller.
|
||||
virtual bool StartDiscovery(const DiscoveryCallback& discovery_callback) = 0;
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#cancelDiscovery()
|
||||
//
|
||||
// Returns true once discovery is well and truly stopped; after this returns,
|
||||
// there must be no more invocations of the DiscoveryCallback passed in to
|
||||
// startDiscovery().
|
||||
virtual bool StopDiscovery() = 0;
|
||||
|
||||
// A combination of
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#createInsecureRfcommSocketToServiceRecord
|
||||
// followed by
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothSocket.html#connect().
|
||||
//
|
||||
// service_uuid is the canonical textual representation
|
||||
// (https://en.wikipedia.org/wiki/Universally_unique_identifier#Format) of a
|
||||
// type 3 name-based
|
||||
// (https://en.wikipedia.org/wiki/Universally_unique_identifier#Versions_3_and_5_(namespace_name-based))
|
||||
// UUID.
|
||||
//
|
||||
// On success, returns a new BluetoothSocket, wrapped in a ExceptionOr object.
|
||||
// On error, returns Exception object.
|
||||
virtual ExceptionOr<std::unique_ptr<BluetoothSocket>> ConnectToService(
|
||||
BluetoothDevice* remote_device, absl::string_view service_uuid) = 0;
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#listenUsingInsecureRfcommWithServiceRecord
|
||||
//
|
||||
// service_uuid is the canonical textual representation
|
||||
// (https://en.wikipedia.org/wiki/Universally_unique_identifier#Format) of a
|
||||
// type 3 name-based
|
||||
// (https://en.wikipedia.org/wiki/Universally_unique_identifier#Versions_3_and_5_(namespace_name-based))
|
||||
// UUID.
|
||||
//
|
||||
// Returns Exception::kIo on error.
|
||||
virtual ExceptionOr<std::unique_ptr<BluetoothServerSocket>> ListenForService(
|
||||
absl::string_view service_name, absl::string_view service_uuid) = 0;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_API_BLUETOOTH_CLASSIC_H_
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef PLATFORM_V2_API_CANCELABLE_H_
|
||||
#define PLATFORM_V2_API_CANCELABLE_H_
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace api {
|
||||
|
||||
// An interface to provide a cancellation mechanism for objects that represent
|
||||
// long-running operations.
|
||||
class Cancelable {
|
||||
public:
|
||||
virtual ~Cancelable() = default;
|
||||
|
||||
virtual bool Cancel() = 0;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_API_CANCELABLE_H_
|
||||
@@ -0,0 +1,28 @@
|
||||
#ifndef PLATFORM_V2_API_CONDITION_VARIABLE_H_
|
||||
#define PLATFORM_V2_API_CONDITION_VARIABLE_H_
|
||||
|
||||
#include "platform_v2/base/exception.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace api {
|
||||
|
||||
// The ConditionVariable class is a synchronization primitive that can be used
|
||||
// to block a thread, or multiple threads at the same time, until another thread
|
||||
// both modifies a shared variable (the condition), and notifies the
|
||||
// ConditionVariable.
|
||||
class ConditionVariable {
|
||||
public:
|
||||
virtual ~ConditionVariable() {}
|
||||
|
||||
// https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#notify--
|
||||
virtual void Notify() = 0;
|
||||
// https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#wait--
|
||||
virtual Exception Wait() = 0; // throws Exception::kInterrupted
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_API_CONDITION_VARIABLE_H_
|
||||
@@ -0,0 +1,31 @@
|
||||
#ifndef PLATFORM_V2_API_COUNT_DOWN_LATCH_H_
|
||||
#define PLATFORM_V2_API_COUNT_DOWN_LATCH_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "platform_v2/base/exception.h"
|
||||
#include "absl/time/time.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace api {
|
||||
|
||||
// A synchronization aid that allows one or more threads to wait until a set of
|
||||
// operations being performed in other threads completes.
|
||||
//
|
||||
// https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CountDownLatch.html
|
||||
class CountDownLatch {
|
||||
public:
|
||||
virtual ~CountDownLatch() = default;
|
||||
|
||||
virtual Exception Await() = 0; // throws Exception::kInterrupted
|
||||
virtual ExceptionOr<bool> Await(
|
||||
absl::Duration timeout) = 0; // throws Exception::kInterrupted
|
||||
virtual void CountDown() = 0;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_API_COUNT_DOWN_LATCH_H_
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef PLATFORM_V2_API_CRYPTO_H_
|
||||
#define PLATFORM_V2_API_CRYPTO_H_
|
||||
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
// A provider of standard hashing algorithms.
|
||||
class Crypto {
|
||||
public:
|
||||
// Initialize global crypto state.
|
||||
static void Init();
|
||||
// Return MD5 hash of input.
|
||||
static ByteArray Md5(absl::string_view input);
|
||||
// Return SHA256 hash of input.
|
||||
static ByteArray Sha256(absl::string_view input);
|
||||
};
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_API_CRYPTO_H_
|
||||
@@ -0,0 +1,28 @@
|
||||
#ifndef PLATFORM_V2_API_EXECUTOR_H_
|
||||
#define PLATFORM_V2_API_EXECUTOR_H_
|
||||
|
||||
#include "platform_v2/base/runnable.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace api {
|
||||
|
||||
// This abstract class is the superclass of all classes representing an
|
||||
// Executor.
|
||||
class Executor {
|
||||
public:
|
||||
// Before returning from destructor, executor must wait for all pending
|
||||
// jobs to finish.
|
||||
virtual ~Executor() = default;
|
||||
// https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executor.html#execute-java.lang.Runnable-
|
||||
virtual void Execute(Runnable&& runnable) = 0;
|
||||
|
||||
// https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html#shutdown--
|
||||
virtual void Shutdown() = 0;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_API_EXECUTOR_H_
|
||||
@@ -0,0 +1,32 @@
|
||||
#ifndef PLATFORM_V2_API_FUTURE_H_
|
||||
#define PLATFORM_V2_API_FUTURE_H_
|
||||
|
||||
#include "platform_v2/base/exception.h"
|
||||
#include "absl/time/clock.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace api {
|
||||
|
||||
// A Future represents the result of an asynchronous computation.
|
||||
//
|
||||
// https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Future.html
|
||||
template <typename T>
|
||||
class Future {
|
||||
public:
|
||||
virtual ~Future() = default;
|
||||
|
||||
// throws Exception::kInterrupted, Exception::kExecution
|
||||
virtual ExceptionOr<T> Get() = 0;
|
||||
|
||||
// throws Exception::kInterrupted, Exception::kExecution
|
||||
// throws Exception::kTimeout if timeout is exceeded while waiting for
|
||||
// result.
|
||||
virtual ExceptionOr<T> Get(absl::Duration timeout) = 0;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_API_FUTURE_H_
|
||||
@@ -0,0 +1,26 @@
|
||||
#ifndef PLATFORM_V2_API_INPUT_FILE_H_
|
||||
#define PLATFORM_V2_API_INPUT_FILE_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
#include "platform_v2/base/exception.h"
|
||||
#include "platform_v2/base/input_stream.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace api {
|
||||
|
||||
// An InputFile represents a readable file on the system.
|
||||
class InputFile : public InputStream {
|
||||
public:
|
||||
~InputFile() override = default;
|
||||
virtual std::string GetFilePath() const = 0;
|
||||
virtual std::int64_t GetTotalSize() const = 0;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_API_INPUT_FILE_H_
|
||||
@@ -0,0 +1,32 @@
|
||||
#ifndef PLATFORM_V2_API_LISTENABLE_FUTURE_H_
|
||||
#define PLATFORM_V2_API_LISTENABLE_FUTURE_H_
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include "platform_v2/api/executor.h"
|
||||
#include "platform_v2/api/future.h"
|
||||
#include "platform_v2/base/exception.h"
|
||||
#include "platform_v2/base/runnable.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace api {
|
||||
|
||||
// A Future that accepts completion listeners.
|
||||
//
|
||||
// https://guava.dev/releases/20.0/api/docs/com/google/common/util/concurrent/ListenableFuture.html
|
||||
template <typename T>
|
||||
class ListenableFuture : public Future<T> {
|
||||
public:
|
||||
~ListenableFuture() override = default;
|
||||
|
||||
virtual void AddListener(Runnable runnable,
|
||||
Executor* executor) = 0;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_API_LISTENABLE_FUTURE_H_
|
||||
@@ -0,0 +1,41 @@
|
||||
#ifndef PLATFORM_V2_API_MUTEX_H_
|
||||
#define PLATFORM_V2_API_MUTEX_H_
|
||||
|
||||
#include "absl/base/thread_annotations.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace api {
|
||||
|
||||
// A lock is a tool for controlling access to a shared resource by multiple
|
||||
// threads.
|
||||
//
|
||||
// https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/Lock.html
|
||||
class ABSL_LOCKABLE Mutex {
|
||||
public:
|
||||
// Mode to pass to implementation constructor.
|
||||
// kRegular - produces a regular mutex: disallows multiple locks from
|
||||
// the same thread; optionally, detects double locks in
|
||||
// debug mode.
|
||||
// This is the default option.
|
||||
// kRecursive - produces recursive mutex: allows multiple locks from the
|
||||
// same thread.
|
||||
// kRegularNoCheck - produces a regular mutex: disallows double locks,
|
||||
// but does not check for deadlocks.
|
||||
enum class Mode {
|
||||
kRegular = 0,
|
||||
kRecursive = 1,
|
||||
kRegularNoCheck = 2,
|
||||
};
|
||||
|
||||
virtual ~Mutex() {}
|
||||
|
||||
virtual void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() = 0;
|
||||
virtual void Unlock() ABSL_UNLOCK_FUNCTION() = 0;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_API_MUTEX_H_
|
||||
@@ -0,0 +1,22 @@
|
||||
#ifndef PLATFORM_V2_API_OUTPUT_FILE_H_
|
||||
#define PLATFORM_V2_API_OUTPUT_FILE_H_
|
||||
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
#include "platform_v2/base/exception.h"
|
||||
#include "platform_v2/base/output_stream.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace api {
|
||||
|
||||
// An OutputFile represents a writable file on the system.
|
||||
class OutputFile : public OutputStream {
|
||||
public:
|
||||
~OutputFile() override = default;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_API_OUTPUT_FILE_H_
|
||||
@@ -0,0 +1,78 @@
|
||||
#ifndef PLATFORM_V2_API_PLATFORM_H_
|
||||
#define PLATFORM_V2_API_PLATFORM_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "platform_v2/api/atomic_boolean.h"
|
||||
#include "platform_v2/api/atomic_reference.h"
|
||||
#include "platform_v2/api/ble.h"
|
||||
#include "platform_v2/api/ble_v2.h"
|
||||
#include "platform_v2/api/bluetooth_adapter.h"
|
||||
#include "platform_v2/api/bluetooth_classic.h"
|
||||
#include "platform_v2/api/condition_variable.h"
|
||||
#include "platform_v2/api/count_down_latch.h"
|
||||
#include "platform_v2/api/crypto.h"
|
||||
#include "platform_v2/api/mutex.h"
|
||||
#include "platform_v2/api/scheduled_executor.h"
|
||||
#include "platform_v2/api/server_sync.h"
|
||||
#include "platform_v2/api/settable_future.h"
|
||||
#include "platform_v2/api/submittable_executor.h"
|
||||
#include "platform_v2/api/system_clock.h"
|
||||
#include "platform_v2/api/webrtc.h"
|
||||
#include "platform_v2/api/wifi.h"
|
||||
#include "platform_v2/api/wifi_lan.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/types/any.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace api {
|
||||
|
||||
// API rework notes:
|
||||
// https://docs.google.com/spreadsheets/d/1erZNkX7pX8s5jWTHdxgjntxTMor3BGiY2H_fC_ldtoQ/edit#gid=381357998
|
||||
class ImplementationPlatform {
|
||||
public:
|
||||
// General platform support:
|
||||
// - atomic variables (boolean, and any other copyable type)
|
||||
// - synchronization primitives:
|
||||
// - mutex (regular, and recursive)
|
||||
// - condition variable (must work with regular mutex only)
|
||||
// - Future<T> : to synchronize on Callable<T> schduled to execute.
|
||||
// - CountDownLatch : to ensure at least N threads are waiting.
|
||||
static std::unique_ptr<AtomicReference<absl::any>> CreateAtomicReferenceAny(
|
||||
absl::any initial_value);
|
||||
static std::unique_ptr<SettableFuture<absl::any>> CreateSettableFutureAny();
|
||||
static std::unique_ptr<AtomicBoolean> CreateAtomicBoolean(bool initial_value);
|
||||
static std::unique_ptr<CountDownLatch> CreateCountDownLatch(
|
||||
std::int32_t count);
|
||||
static std::unique_ptr<Mutex> CreateMutex(Mutex::Mode mode);
|
||||
static std::unique_ptr<ConditionVariable> CreateConditionVariable(
|
||||
Mutex* mutex);
|
||||
|
||||
// Java-like Executors
|
||||
static std::unique_ptr<SubmittableExecutor> CreateSingleThreadExecutor();
|
||||
static std::unique_ptr<SubmittableExecutor> CreateMultiThreadExecutor(
|
||||
std::int32_t max_concurrency);
|
||||
static std::unique_ptr<ScheduledExecutor> CreateScheduledExecutor();
|
||||
|
||||
// Protocol implementations, domain-specific support
|
||||
static std::unique_ptr<BluetoothAdapter> CreateBluetoothAdapter();
|
||||
static std::unique_ptr<BluetoothClassicMedium> CreateBluetoothClassicMedium();
|
||||
static std::unique_ptr<BleMedium> CreateBleMedium();
|
||||
static std::unique_ptr<ble_v2::BleMedium> CreateBleV2Medium();
|
||||
static std::unique_ptr<ServerSyncMedium> CreateServerSyncMedium();
|
||||
static std::unique_ptr<WifiMedium> CreateWifiMedium();
|
||||
static std::unique_ptr<WifiLanMedium> CreateWifiLanMedium();
|
||||
static std::unique_ptr<WebRtcSignalingMessenger>
|
||||
CreateWebRtcSignalingMessenger(absl::string_view self_id);
|
||||
static std::string GetDeviceId();
|
||||
static std::string GetPayloadPath(std::int64_t payload_id);
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_API_PLATFORM_H_
|
||||
@@ -0,0 +1,36 @@
|
||||
#ifndef PLATFORM_V2_API_SCHEDULED_EXECUTOR_H_
|
||||
#define PLATFORM_V2_API_SCHEDULED_EXECUTOR_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include "platform_v2/api/cancelable.h"
|
||||
#include "platform_v2/api/executor.h"
|
||||
#include "platform_v2/base/runnable.h"
|
||||
#include "absl/time/time.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace api {
|
||||
|
||||
// An Executor that can schedule commands to run after a given delay, or to
|
||||
// execute periodically.
|
||||
//
|
||||
// https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ScheduledExecutorService.html
|
||||
class ScheduledExecutor : public Executor {
|
||||
public:
|
||||
~ScheduledExecutor() override = default;
|
||||
// Cancelable is kept both in the executor context, and in the caller context.
|
||||
// We want Cancelable to live until both caller and executor are done with it.
|
||||
// Exclusive ownership model does not work for this case;
|
||||
// using std:shared_ptr<> instead if std::unique_ptr<>.
|
||||
virtual std::shared_ptr<Cancelable> Schedule(Runnable&& runnable,
|
||||
absl::Duration duration) = 0;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_API_SCHEDULED_EXECUTOR_H_
|
||||
@@ -0,0 +1,62 @@
|
||||
#ifndef PLATFORM_V2_API_SERVER_SYNC_H_
|
||||
#define PLATFORM_V2_API_SERVER_SYNC_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace api {
|
||||
|
||||
// Abstraction that represents a Nearby endpoint exchanging data through
|
||||
// ServerSync Medium.
|
||||
class ServerSyncDevice {
|
||||
public:
|
||||
virtual ~ServerSyncDevice() = default;
|
||||
|
||||
virtual std::string GetName() const = 0;
|
||||
virtual std::string GetGuid() const = 0;
|
||||
virtual std::string GetOwnGuid() const = 0;
|
||||
};
|
||||
|
||||
// Container of operations that can be performed over the Chrome Sync medium.
|
||||
class ServerSyncMedium {
|
||||
public:
|
||||
virtual ~ServerSyncMedium() = default;
|
||||
|
||||
virtual bool StartAdvertising(absl::string_view service_id,
|
||||
absl::string_view endpoint_id,
|
||||
const ByteArray& endpoint_info) = 0;
|
||||
virtual void StopAdvertising(absl::string_view service_id) = 0;
|
||||
|
||||
class DiscoveredDeviceCallback {
|
||||
public:
|
||||
virtual ~DiscoveredDeviceCallback() = default;
|
||||
|
||||
// Called on a new ServerSyncDevice discovery.
|
||||
virtual void OnDeviceDiscovered(ServerSyncDevice* device,
|
||||
absl::string_view service_id,
|
||||
absl::string_view endpoint_id,
|
||||
const ByteArray& endpoint_info) = 0;
|
||||
// Called when ServerSyncDevice is no longer reachable.
|
||||
virtual void OnDeviceLost(ServerSyncDevice* device,
|
||||
absl::string_view service_id) = 0;
|
||||
};
|
||||
|
||||
// Returns true once the Chrome Sync scan has been initiated.
|
||||
virtual bool StartDiscovery(
|
||||
absl::string_view service_id,
|
||||
const DiscoveredDeviceCallback& discovered_device_callback) = 0;
|
||||
// Returns true once Chrome Sync scan for service_id is well and truly
|
||||
// stopped; after this returns, there must be no more invocations of the
|
||||
// DiscoveredDeviceCallback passed in to startScanning() for service_id.
|
||||
virtual void StopDiscovery(absl::string_view service_id) = 0;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_API_SERVER_SYNC_H_
|
||||
@@ -0,0 +1,28 @@
|
||||
#ifndef PLATFORM_V2_API_SETTABLE_FUTURE_H_
|
||||
#define PLATFORM_V2_API_SETTABLE_FUTURE_H_
|
||||
|
||||
#include "platform_v2/api/listenable_future.h"
|
||||
#include "platform_v2/base/exception.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace api {
|
||||
|
||||
// A SettableFuture is a type of Future whose result can be set.
|
||||
//
|
||||
// https://google.github.io/guava/releases/20.0/api/docs/com/google/common/util/concurrent/SettableFuture.html
|
||||
template <typename T>
|
||||
class SettableFuture : public ListenableFuture<T> {
|
||||
public:
|
||||
~SettableFuture() override = default;
|
||||
|
||||
virtual bool Set(const T& value) = 0;
|
||||
virtual bool Set(T&& value) = 0;
|
||||
virtual bool SetException(Exception exception) = 0;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_API_SETTABLE_FUTURE_H_
|
||||
@@ -0,0 +1,33 @@
|
||||
#ifndef PLATFORM_V2_API_SUBMITTABLE_EXECUTOR_H_
|
||||
#define PLATFORM_V2_API_SUBMITTABLE_EXECUTOR_H_
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include "platform_v2/api/executor.h"
|
||||
#include "platform_v2/api/future.h"
|
||||
#include "platform_v2/base/runnable.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace api {
|
||||
|
||||
// Main interface to be used by platform as a base class for
|
||||
// - MultiThreadExecutorWrapper
|
||||
// - SingleThreadExecutorWrapper
|
||||
// Platform must override bool submit(std::function<void()>) method.
|
||||
class SubmittableExecutor : public Executor {
|
||||
public:
|
||||
~SubmittableExecutor() override = default;
|
||||
|
||||
// Submit a callable (with no delay).
|
||||
// Returns true, if callable was submitted, false otherwise.
|
||||
// Callable is not submitted if shutdown is in progress.
|
||||
virtual bool DoSubmit(Runnable&& wrapped_callable) = 0;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_API_SUBMITTABLE_EXECUTOR_H_
|
||||
@@ -0,0 +1,23 @@
|
||||
#ifndef PLATFORM_V2_API_SYSTEM_CLOCK_H_
|
||||
#define PLATFORM_V2_API_SYSTEM_CLOCK_H_
|
||||
|
||||
#include "platform_v2/base/exception.h"
|
||||
#include "absl/time/clock.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
class SystemClock final {
|
||||
public:
|
||||
// Initialize global system state.
|
||||
static void Init();
|
||||
// Returns current absolute time. It is guaranteed to be monotonic.
|
||||
static absl::Time ElapsedRealtime();
|
||||
// Pauses current thread for the specified duration.
|
||||
static Exception Sleep(absl::Duration duration);
|
||||
};
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_API_SYSTEM_CLOCK_H_
|
||||
@@ -0,0 +1,48 @@
|
||||
#ifndef PLATFORM_V2_API_WEBRTC_H_
|
||||
#define PLATFORM_V2_API_WEBRTC_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
#include "webrtc/api/peer_connection_interface.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace api {
|
||||
|
||||
class WebRtcSignalingMessenger {
|
||||
public:
|
||||
virtual ~WebRtcSignalingMessenger() = default;
|
||||
|
||||
/** Called whenever we receive an inbox message from tachyon. */
|
||||
class SignalingMessageListener {
|
||||
public:
|
||||
virtual ~SignalingMessageListener() = default;
|
||||
|
||||
virtual void OnSignalingMessage(const ByteArray& message) = 0;
|
||||
};
|
||||
|
||||
class IceServersListener {
|
||||
public:
|
||||
virtual ~IceServersListener() = default;
|
||||
|
||||
virtual void OnIceServersFetched(
|
||||
std::vector<webrtc::PeerConnectionInterface::IceServer>
|
||||
ice_servers) = 0;
|
||||
};
|
||||
|
||||
virtual bool RegisterSignaling() = 0;
|
||||
virtual bool UnregisterSignaling() = 0;
|
||||
virtual bool SendMessage(std::string_view peer_id,
|
||||
const ByteArray& message) = 0;
|
||||
virtual bool StartReceivingMessages(
|
||||
const SignalingMessageListener& listener) = 0;
|
||||
virtual void GetIceServers(
|
||||
const IceServersListener& ice_servers_listener) = 0;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_API_WEBRTC_H_
|
||||
@@ -0,0 +1,90 @@
|
||||
#ifndef PLATFORM_V2_API_WIFI_H_
|
||||
#define PLATFORM_V2_API_WIFI_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace api {
|
||||
|
||||
// Possible authentication types for a WiFi network.
|
||||
enum class WifiAuthType {
|
||||
// WiFi Authentication type; either none (non-secured a.k.a. open) link, or
|
||||
// WPA PSK (WiFi Protected Access PreShared Key), or
|
||||
// see https://en.wikipedia.org/wiki/Wi-Fi_Protected_Access
|
||||
// WEP (Wired Equivalent Privacy);
|
||||
// see https://en.wikipedia.org/wiki/Wired_Equivalent_Privacy
|
||||
kUnknown = 0,
|
||||
kOpen = 1,
|
||||
kWpaPsk = 2,
|
||||
kWep = 3,
|
||||
};
|
||||
|
||||
// Possible statuses of a device's connection to a WiFi network.
|
||||
enum class WifiConnectionStatus {
|
||||
kUnknown = 0,
|
||||
kConnected = 1,
|
||||
kConnectionFailure = 2,
|
||||
kAuthFailure = 3,
|
||||
};
|
||||
|
||||
// Represents a WiFi network found during a call to WifiMedium#scan().
|
||||
class WifiScanResult {
|
||||
public:
|
||||
virtual ~WifiScanResult() = default;
|
||||
|
||||
// Gets the SSID of this WiFi network.
|
||||
virtual std::string GetSsid() const = 0;
|
||||
// Gets the signal strength of this WiFi network in dBm.
|
||||
virtual std::int32_t GetSignalStrengthDbm() const = 0;
|
||||
// Gets the frequency band of this WiFi network in MHz.
|
||||
virtual std::int32_t GetFrequencyMhz() const = 0;
|
||||
// Gets the authentication type of this WiFi network.
|
||||
virtual WifiAuthType GetAuthType() const = 0;
|
||||
};
|
||||
|
||||
// Container of operations that can be performed over the WiFi medium.
|
||||
class WifiMedium {
|
||||
public:
|
||||
virtual ~WifiMedium() {}
|
||||
|
||||
class ScanResultCallback {
|
||||
public:
|
||||
virtual ~ScanResultCallback() = default;
|
||||
|
||||
virtual void OnScanResults(
|
||||
const std::vector<WifiScanResult>& scan_results) = 0;
|
||||
};
|
||||
|
||||
// Does not take ownership of the passed-in scan_result_callback -- destroying
|
||||
// that is up to the caller.
|
||||
virtual bool Scan(const ScanResultCallback& scan_result_callback) = 0;
|
||||
|
||||
// If 'password' is an empty string, none has been provided. Returns
|
||||
// WifiConnectionStatus::CONNECTED on success, or the appropriate failure code
|
||||
// otherwise.
|
||||
virtual WifiConnectionStatus ConnectToNetwork(absl::string_view ssid,
|
||||
absl::string_view password,
|
||||
WifiAuthType auth_type) = 0;
|
||||
|
||||
// Blocks until it's certain of there being a connection to the internet, or
|
||||
// returns false if it fails to do so.
|
||||
//
|
||||
// How this method wants to verify said connection is totally up to it (so it
|
||||
// can feel free to ping whatever server, download whatever resource, etc.
|
||||
// that it needs to gain confidence that the internet is reachable hereon in).
|
||||
virtual bool VerifyInternetConnectivity() = 0;
|
||||
|
||||
// Returns the local device's IP address in the IPv4 dotted-quad format.
|
||||
virtual std::string GetIpAddress() = 0;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_API_WIFI_H_
|
||||
@@ -0,0 +1,87 @@
|
||||
#ifndef PLATFORM_V2_API_WIFI_LAN_H_
|
||||
#define PLATFORM_V2_API_WIFI_LAN_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
#include "platform_v2/base/exception.h"
|
||||
#include "platform_v2/base/input_stream.h"
|
||||
#include "platform_v2/base/output_stream.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace api {
|
||||
|
||||
// Opaque wrapper over a WifiLan service which contains encoded service name.
|
||||
class WifiLanService {
|
||||
public:
|
||||
virtual ~WifiLanService() = default;
|
||||
|
||||
virtual std::string GetName() = 0;
|
||||
};
|
||||
|
||||
class WifiLanSocket {
|
||||
public:
|
||||
virtual ~WifiLanSocket() = default;
|
||||
|
||||
// Returns the InputStream of the WifiLanSocket, empty std::unique_ptr<>
|
||||
// on error.
|
||||
virtual std::unique_ptr<InputStream> GetInputStream() = 0;
|
||||
|
||||
// Returns the OutputStream of the WifiLanSocket, empty std::unique_ptr<>
|
||||
// on error.
|
||||
virtual std::unique_ptr<OutputStream> GetOutputStream() = 0;
|
||||
|
||||
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
|
||||
virtual Exception::Value Close() = 0;
|
||||
|
||||
virtual WifiLanService& GetRemoteWifiLanService() = 0;
|
||||
};
|
||||
|
||||
// Container of operations that can be performed over the WifiLan medium.
|
||||
class WifiLanMedium {
|
||||
public:
|
||||
virtual ~WifiLanMedium() = default;
|
||||
|
||||
virtual bool StartAdvertising(
|
||||
absl::string_view service_id,
|
||||
absl::string_view wifi_lan_service_info_name) = 0;
|
||||
virtual void StopAdvertising(absl::string_view service_id) = 0;
|
||||
|
||||
// Callback for WifiLan discover results.
|
||||
class DiscoveredServiceCallback {
|
||||
public:
|
||||
virtual ~DiscoveredServiceCallback() = default;
|
||||
|
||||
virtual void OnServiceDiscovered(WifiLanService* wifi_lan_service) = 0;
|
||||
virtual void OnServiceLost(WifiLanService* wifi_lan_service) = 0;
|
||||
};
|
||||
|
||||
virtual bool StartDiscovery(
|
||||
absl::string_view service_id,
|
||||
DiscoveredServiceCallback* discovered_service_callback) = 0;
|
||||
virtual void StopDiscovery(absl::string_view service_id) = 0;
|
||||
|
||||
class AcceptedConnectionCallback {
|
||||
public:
|
||||
virtual ~AcceptedConnectionCallback() = default;
|
||||
|
||||
virtual void OnConnectionAccepted(WifiLanSocket* socket,
|
||||
absl::string_view service_id) = 0;
|
||||
};
|
||||
|
||||
virtual bool StartAcceptingConnections(
|
||||
absl::string_view service_id,
|
||||
AcceptedConnectionCallback* accepted_connection_callback) = 0;
|
||||
virtual void StopAcceptingConnections(absl::string_view service_id) = 0;
|
||||
|
||||
virtual WifiLanSocket* Connect(WifiLanService* wifi_lan_service,
|
||||
absl::string_view service_id) = 0;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_API_WIFI_LAN_H_
|
||||
@@ -0,0 +1,73 @@
|
||||
load("//ads/util/non_compile:non_compile.bzl", "cc_with_non_compile_test")
|
||||
|
||||
cc_library(
|
||||
name = "base",
|
||||
srcs = [
|
||||
"base64_utils.cc",
|
||||
"prng.cc",
|
||||
],
|
||||
hdrs = [
|
||||
"base64_utils.h",
|
||||
"byte_array.h",
|
||||
"callable.h",
|
||||
"exception.h",
|
||||
"input_stream.h",
|
||||
"listeners.h",
|
||||
"output_stream.h",
|
||||
"prng.h",
|
||||
"runnable.h",
|
||||
"socket.h",
|
||||
],
|
||||
visibility = [
|
||||
"//core_v2:__subpackages__",
|
||||
"//platform_v2:__subpackages__",
|
||||
"//platform_v2/api:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//absl/strings",
|
||||
"//absl/time",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "util",
|
||||
srcs = [
|
||||
"base_pipe.cc",
|
||||
],
|
||||
hdrs = [
|
||||
"base_mutex_lock.h",
|
||||
"base_pipe.h",
|
||||
],
|
||||
visibility = [
|
||||
"//platform_v2/impl:__subpackages__",
|
||||
"//platform_v2/public:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
":base",
|
||||
"//platform_v2/api",
|
||||
"//absl/base:core_headers",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "platform_base_test",
|
||||
srcs = [
|
||||
"byte_array_test.cc",
|
||||
"prng_test.cc",
|
||||
],
|
||||
deps = [
|
||||
":base",
|
||||
"//testing/base/public:gunit_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_with_non_compile_test(
|
||||
name = "exception_test",
|
||||
srcs = [
|
||||
"exception_test.cc",
|
||||
],
|
||||
deps = [
|
||||
":base",
|
||||
"//testing/base/public:gunit_main",
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,27 @@
|
||||
#include "platform_v2/base/base64_utils.h"
|
||||
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
#include "absl/strings/escaping.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
std::string Base64Utils::Encode(const ByteArray& bytes) {
|
||||
std::string base64_string;
|
||||
|
||||
absl::WebSafeBase64Escape(std::string(bytes), &base64_string);
|
||||
|
||||
return base64_string;
|
||||
}
|
||||
|
||||
ByteArray Base64Utils::Decode(absl::string_view base64_string) {
|
||||
std::string decoded_string;
|
||||
if (!absl::WebSafeBase64Unescape(base64_string, &decoded_string)) {
|
||||
return ByteArray();
|
||||
}
|
||||
|
||||
return ByteArray(decoded_string.data(), decoded_string.size());
|
||||
}
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,19 @@
|
||||
#ifndef PLATFORM_V2_BASE_BASE64_UTILS_H_
|
||||
#define PLATFORM_V2_BASE_BASE64_UTILS_H_
|
||||
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
class Base64Utils {
|
||||
public:
|
||||
static std::string Encode(const ByteArray& bytes);
|
||||
static ByteArray Decode(absl::string_view base64_string);
|
||||
};
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_BASE_BASE64_UTILS_H_
|
||||
@@ -0,0 +1,26 @@
|
||||
#ifndef PLATFORM_V2_BASE_BASE_MUTEX_LOCK_H_
|
||||
#define PLATFORM_V2_BASE_BASE_MUTEX_LOCK_H_
|
||||
|
||||
#include "platform_v2/api/mutex.h"
|
||||
#include "absl/base/thread_annotations.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
// An RAII mechanism to acquire a Lock over a block of code.
|
||||
class ABSL_SCOPED_LOCKABLE BaseMutexLock final {
|
||||
public:
|
||||
explicit BaseMutexLock(api::Mutex* mutex) ABSL_EXCLUSIVE_LOCK_FUNCTION(mutex)
|
||||
: mutex_(mutex) {
|
||||
mutex_->Lock();
|
||||
}
|
||||
~BaseMutexLock() ABSL_UNLOCK_FUNCTION() { mutex_->Unlock(); }
|
||||
|
||||
private:
|
||||
api::Mutex* mutex_;
|
||||
};
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_BASE_BASE_MUTEX_LOCK_H_
|
||||
@@ -0,0 +1,96 @@
|
||||
#include "platform_v2/base/base_pipe.h"
|
||||
|
||||
#include "platform_v2/api/platform.h"
|
||||
#include "platform_v2/base/base_mutex_lock.h"
|
||||
#include "platform_v2/base/input_stream.h"
|
||||
#include "platform_v2/base/output_stream.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
ExceptionOr<ByteArray> BasePipe::Read(size_t size) {
|
||||
BaseMutexLock lock(mutex_.get());
|
||||
|
||||
// We're done reading all the chunks that were written before the OutputStream
|
||||
// was closed, so there's nothing to do here other than return an empty chunk
|
||||
// to serve as an EOF indication to callers.
|
||||
if (read_all_chunks_) {
|
||||
return ExceptionOr<ByteArray>{ByteArray{}};
|
||||
}
|
||||
|
||||
while (buffer_.empty() && !input_stream_closed_) {
|
||||
Exception wait_exception = cond_->Wait();
|
||||
|
||||
if (wait_exception.Raised()) {
|
||||
return ExceptionOr<ByteArray>{wait_exception};
|
||||
}
|
||||
}
|
||||
|
||||
if (input_stream_closed_) {
|
||||
return ExceptionOr<ByteArray>{Exception::kIo};
|
||||
}
|
||||
|
||||
ByteArray first_chunk{buffer_.front()};
|
||||
buffer_.pop_front();
|
||||
|
||||
// If we received our sentinel chunk, mark the fact that there cannot
|
||||
// possibly be any more chunks to read here on in, and return an empty chunk
|
||||
// to serve as an EOF indication to callers.
|
||||
if (first_chunk.Empty()) {
|
||||
read_all_chunks_ = true;
|
||||
return ExceptionOr<ByteArray>{ByteArray{}};
|
||||
}
|
||||
|
||||
// If first_chunk is small enough to not overshoot the requested 'size', just
|
||||
// return that.
|
||||
if (first_chunk.size() <= size) {
|
||||
return ExceptionOr<ByteArray>{first_chunk};
|
||||
} else {
|
||||
// Break first_chunk into 2 parts -- the first one of which (next_chunk)
|
||||
// will be 'size' bytes long, and will be returned, and the second one of
|
||||
// which (overflow_chunk) will be re-inserted into buffer_, at the head of
|
||||
// the queue, to be served up in the next call to read().
|
||||
ByteArray next_chunk(first_chunk.data(), size);
|
||||
buffer_.push_front(
|
||||
ByteArray(first_chunk.data() + size, first_chunk.size() - size));
|
||||
return ExceptionOr<ByteArray>{next_chunk};
|
||||
}
|
||||
}
|
||||
|
||||
Exception BasePipe::Write(const ByteArray& data) {
|
||||
BaseMutexLock lock(mutex_.get());
|
||||
|
||||
return WriteLocked(data);
|
||||
}
|
||||
|
||||
void BasePipe::MarkInputStreamClosed() {
|
||||
BaseMutexLock lock(mutex_.get());
|
||||
|
||||
input_stream_closed_ = true;
|
||||
// Trigger cond_ to unblock a potentially-blocked call to read(), and to let
|
||||
// it know to return Exception::IO.
|
||||
cond_->Notify();
|
||||
}
|
||||
|
||||
void BasePipe::MarkOutputStreamClosed() {
|
||||
BaseMutexLock lock(mutex_.get());
|
||||
|
||||
// Write a sentinel null chunk before marking output_stream_closed as true.
|
||||
WriteLocked(ByteArray{});
|
||||
output_stream_closed_ = true;
|
||||
}
|
||||
|
||||
Exception BasePipe::WriteLocked(const ByteArray& data) {
|
||||
if (input_stream_closed_ || output_stream_closed_) {
|
||||
return {Exception::kIo};
|
||||
}
|
||||
|
||||
buffer_.push_back(data);
|
||||
// Trigger cond_ to unblock a potentially-blocked call to read(), now that
|
||||
// there's more data for it to consume.
|
||||
cond_->Notify();
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,128 @@
|
||||
#ifndef PLATFORM_V2_BASE_BASE_PIPE_H_
|
||||
#define PLATFORM_V2_BASE_BASE_PIPE_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
|
||||
#include "platform_v2/api/condition_variable.h"
|
||||
#include "platform_v2/api/mutex.h"
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
#include "platform_v2/base/exception.h"
|
||||
#include "platform_v2/base/input_stream.h"
|
||||
#include "platform_v2/base/output_stream.h"
|
||||
#include "absl/base/thread_annotations.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
// Common Pipe implenentation.
|
||||
// It does not depend on platform implementation, and this allows it to
|
||||
// be used in the platform implementation itself.
|
||||
// Concrete class must be derived from it, as follows:
|
||||
//
|
||||
// class DerivedPipe : public BasePipe {
|
||||
// public:
|
||||
// DerivedPipe() {
|
||||
// auto mutex = /* construct platform-dependent mutex */;
|
||||
// auto cond = /* construct platform-dependent condition variable */;
|
||||
// Setup(std::move(mutex), std::move(cond));
|
||||
// }
|
||||
// ~DerivedPipe() override = default;
|
||||
// DerivedPipe(DerivedPipe&&) = default;
|
||||
// DerivedPipe& operator=(DerivedPipe&&) = default;
|
||||
// };
|
||||
class BasePipe {
|
||||
public:
|
||||
static constexpr const size_t kChunkSize = 64 * 1024;
|
||||
virtual ~BasePipe() = default;
|
||||
|
||||
// Pipe is not copyable or movable, because copy/move will invalidate
|
||||
// references to input and output streams.
|
||||
// If move is required, Pipe could be wrapped with std::unique_ptr<>.
|
||||
BasePipe(BasePipe&&) = delete;
|
||||
BasePipe& operator=(BasePipe&&) = delete;
|
||||
|
||||
// Get...() methods return references to input and output steam facades.
|
||||
// It is safe to call Get...() methods multiple times.
|
||||
InputStream& GetInputStream() { return input_stream_; }
|
||||
OutputStream& GetOutputStream() { return output_stream_; }
|
||||
|
||||
protected:
|
||||
BasePipe() = default;
|
||||
|
||||
void Setup(std::unique_ptr<api::Mutex> mutex,
|
||||
std::unique_ptr<api::ConditionVariable> cond) {
|
||||
mutex_ = std::move(mutex);
|
||||
cond_ = std::move(cond);
|
||||
}
|
||||
|
||||
private:
|
||||
class BasePipeInputStream : public InputStream {
|
||||
public:
|
||||
explicit BasePipeInputStream(BasePipe* pipe) : pipe_(pipe) {}
|
||||
~BasePipeInputStream() override { DoClose(); }
|
||||
|
||||
ExceptionOr<ByteArray> Read(std::int64_t size) override {
|
||||
return pipe_->Read(size);
|
||||
}
|
||||
Exception Close() override {
|
||||
return DoClose();
|
||||
}
|
||||
|
||||
private:
|
||||
Exception DoClose() {
|
||||
pipe_->MarkInputStreamClosed();
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
BasePipe* pipe_;
|
||||
};
|
||||
class BasePipeOutputStream : public OutputStream {
|
||||
public:
|
||||
explicit BasePipeOutputStream(BasePipe* pipe) : pipe_(pipe) {}
|
||||
~BasePipeOutputStream() override { DoClose(); }
|
||||
|
||||
Exception Write(const ByteArray& data) override {
|
||||
return pipe_->Write(data);
|
||||
}
|
||||
Exception Flush() override { return {Exception::kSuccess}; }
|
||||
Exception Close() override {
|
||||
return DoClose();
|
||||
}
|
||||
|
||||
private:
|
||||
Exception DoClose() {
|
||||
pipe_->MarkOutputStreamClosed();
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
BasePipe* pipe_;
|
||||
};
|
||||
|
||||
ExceptionOr<ByteArray> Read(size_t size) ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
Exception Write(const ByteArray& data) ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
void MarkInputStreamClosed() ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
void MarkOutputStreamClosed() ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
Exception WriteLocked(const ByteArray& data)
|
||||
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||
|
||||
// Order of declaration matters:
|
||||
// - mutex must be defined before condvar;
|
||||
// - input & output streams must be after both mutex and condvar.
|
||||
bool input_stream_closed_ ABSL_GUARDED_BY(mutex_) = false;
|
||||
bool output_stream_closed_ ABSL_GUARDED_BY(mutex_) = false;
|
||||
bool read_all_chunks_ ABSL_GUARDED_BY(mutex_) = false;
|
||||
|
||||
std::deque<ByteArray> ABSL_GUARDED_BY(mutex_) buffer_;
|
||||
std::unique_ptr<api::Mutex> mutex_;
|
||||
std::unique_ptr<api::ConditionVariable> cond_;
|
||||
|
||||
BasePipeInputStream input_stream_{this};
|
||||
BasePipeOutputStream output_stream_{this};
|
||||
};
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_BASE_BASE_PIPE_H_
|
||||
@@ -0,0 +1,81 @@
|
||||
#ifndef PLATFORM_V2_BASE_BYTE_ARRAY_H_
|
||||
#define PLATFORM_V2_BASE_BYTE_ARRAY_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
class ByteArray {
|
||||
public:
|
||||
// Create an empty ByteArray
|
||||
ByteArray() = default;
|
||||
ByteArray(const ByteArray&) = default;
|
||||
ByteArray& operator=(const ByteArray&) = default;
|
||||
ByteArray(ByteArray&&) = default;
|
||||
ByteArray& operator=(ByteArray&&) = default;
|
||||
|
||||
// Create ByteArray from string.
|
||||
explicit ByteArray(absl::string_view source) { data_ = source; }
|
||||
|
||||
// Create default-initialized ByteArray of a given size.
|
||||
explicit ByteArray(size_t size) { SetData(size); }
|
||||
|
||||
// Create value-initialized ByteArray of a given size.
|
||||
ByteArray(const char* data, size_t size) { SetData(data, size); }
|
||||
|
||||
// Assign a new value to this ByteArray, as a copy of data, with a given size.
|
||||
void SetData(const char* data, size_t size) {
|
||||
if (data == nullptr) {
|
||||
size = 0;
|
||||
}
|
||||
data_.assign(data, size);
|
||||
}
|
||||
|
||||
// Assign a new value of a given size to this ByteArray
|
||||
// (as a repeated char value).
|
||||
void SetData(size_t size, char value = 0) { data_.assign(size, value); }
|
||||
|
||||
// Returns true, if changes were performed to container, false otherwise.
|
||||
bool CopyAt(size_t offset, const ByteArray& from, size_t source_offset = 0) {
|
||||
if (offset >= size()) return false;
|
||||
if (source_offset >= from.size()) return false;
|
||||
memcpy(data() + offset, from.data() + source_offset,
|
||||
std::min(size() - offset, from.size() - source_offset));
|
||||
return true;
|
||||
}
|
||||
|
||||
char* data() { return &data_[0]; }
|
||||
const char* data() const { return data_.data(); }
|
||||
size_t size() const { return data_.size(); }
|
||||
bool Empty() const { return data_.empty(); }
|
||||
|
||||
friend bool operator==(const ByteArray& lhs, const ByteArray& rhs);
|
||||
friend bool operator!=(const ByteArray& lhs, const ByteArray& rhs);
|
||||
friend bool operator<(const ByteArray& lhs, const ByteArray& rhs);
|
||||
|
||||
explicit operator std::string() const { return data_; }
|
||||
|
||||
private:
|
||||
std::string data_;
|
||||
};
|
||||
|
||||
inline bool operator==(const ByteArray& lhs, const ByteArray& rhs) {
|
||||
return lhs.data_ == rhs.data_;
|
||||
}
|
||||
|
||||
inline bool operator!=(const ByteArray& lhs, const ByteArray& rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
inline bool operator<(const ByteArray& lhs, const ByteArray& rhs) {
|
||||
return lhs.data_ < rhs.data_;
|
||||
}
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_BASE_BYTE_ARRAY_H_
|
||||
@@ -0,0 +1,68 @@
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using location::nearby::ByteArray;
|
||||
|
||||
TEST(ByteArrayTest, DefaultSizeIsZero) {
|
||||
ByteArray bytes;
|
||||
EXPECT_EQ(0, bytes.size());
|
||||
}
|
||||
|
||||
TEST(ByteArrayTest, DefaultIsEmpty) {
|
||||
ByteArray bytes;
|
||||
EXPECT_TRUE(bytes.Empty());
|
||||
}
|
||||
|
||||
TEST(ByteArrayTest, NullArrayIsEmpty) {
|
||||
ByteArray bytes{nullptr, 5};
|
||||
EXPECT_TRUE(bytes.Empty());
|
||||
}
|
||||
|
||||
TEST(ByteArrayTest, CopyAtDoesNotExtendArray) {
|
||||
ByteArray v1("12345");
|
||||
ByteArray v2("ABCDEFGH");
|
||||
EXPECT_TRUE(v2.CopyAt(/*offset=*/5, v1));
|
||||
EXPECT_TRUE(v2.CopyAt(/*offset=*/1, v1, /*source_offset=*/3));
|
||||
EXPECT_EQ(v2, ByteArray("A45DE123"));
|
||||
}
|
||||
|
||||
TEST(ByteArrayTest, CopyAtOutOfBoundsIsIgnored) {
|
||||
ByteArray v1("12345");
|
||||
ByteArray v2("ABCDEFGH");
|
||||
// Try to do an out-of-bounds read.
|
||||
EXPECT_FALSE(v2.CopyAt(/* offset=*/5, v1, /*source_offset=*/10));
|
||||
// Try to do an out-of-bounds write.
|
||||
EXPECT_FALSE(v2.CopyAt(/* offset=*/9, v1));
|
||||
EXPECT_EQ(v2, ByteArray("ABCDEFGH"));
|
||||
}
|
||||
|
||||
TEST(ByteArrayTest, SetFromString) {
|
||||
std::string setup("setup_test");
|
||||
ByteArray bytes{setup}; // array initialized with a copy of string.
|
||||
EXPECT_EQ(setup.size(), bytes.size());
|
||||
EXPECT_EQ(std::string(bytes), setup);
|
||||
}
|
||||
|
||||
TEST(ByteArrayTest, SetExplicitSize) {
|
||||
constexpr size_t kArraySize = 10;
|
||||
char reference[kArraySize]{};
|
||||
ByteArray bytes{kArraySize}; // array of size 10, zero-initialized.
|
||||
EXPECT_EQ(kArraySize, bytes.size());
|
||||
EXPECT_EQ(0, memcmp(bytes.data(), reference, kArraySize));
|
||||
}
|
||||
|
||||
TEST(ByteArrayTest, SetExplicitData) {
|
||||
constexpr static const char message[]{"test_message"};
|
||||
constexpr size_t kMessageSize = sizeof(message);
|
||||
ByteArray bytes{message, kMessageSize};
|
||||
EXPECT_EQ(kMessageSize, bytes.size());
|
||||
EXPECT_NE(message, bytes.data());
|
||||
EXPECT_EQ(0, memcmp(message, bytes.data(), kMessageSize));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,23 @@
|
||||
#ifndef PLATFORM_V2_BASE_CALLABLE_H_
|
||||
#define PLATFORM_V2_BASE_CALLABLE_H_
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "platform_v2/base/exception.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
// The Callable is and object intended to be executed by a thread, that is able
|
||||
// to return a value of specified type T.
|
||||
// It must be invokable without arguments. It must return a value implicitly
|
||||
// convertible to ExceptionOr<T>.
|
||||
//
|
||||
// https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Callable.html
|
||||
template <typename T>
|
||||
using Callable = std::function<ExceptionOr<T>()>;
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_BASE_CALLABLE_H_
|
||||
@@ -0,0 +1,97 @@
|
||||
#ifndef PLATFORM_V2_BASE_EXCEPTION_H_
|
||||
#define PLATFORM_V2_BASE_EXCEPTION_H_
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
struct Exception {
|
||||
enum Value : int {
|
||||
kFailed = -1, // Initial value of Exception; any unknown error.
|
||||
kSuccess = 0, // No exception.
|
||||
kIo = 1, // IO Error happened.
|
||||
kInterrupted = 2, // Operation was interrupted.
|
||||
kInvalidProtocolBuffer = 3, // Couldn't parse.
|
||||
kExecution = 4, // Couldn't execute.
|
||||
kTimeout = 5, // Operarion did not finish within specified time.
|
||||
};
|
||||
bool Ok() const { return value == kSuccess; }
|
||||
bool Raised() const { return !Ok(); }
|
||||
bool Raised(Value value) const { return this->value == value; }
|
||||
Value value{kFailed};
|
||||
};
|
||||
|
||||
constexpr inline bool operator==(const Exception& a, const Exception& b) {
|
||||
return a.value == b.value;
|
||||
}
|
||||
|
||||
constexpr inline bool operator!=(const Exception& a, const Exception& b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
// ExceptionOr provides experience similar to StatusOr<T> used in
|
||||
// Google Cloud API, see:
|
||||
// https://googleapis.github.io/google-cloud-cpp/0.7.0/common/status__or_8h_source.html
|
||||
//
|
||||
// If ok() returns true, result() is a usable return value. Otherwise,
|
||||
// exception() explains why such a value is not present.
|
||||
//
|
||||
// A typical pattern of usage is as follows:
|
||||
//
|
||||
// if (!e.ok()) {
|
||||
// if (Exception::EXCEPTION_TYPE_1 == e.exception()) {
|
||||
// // Handle Exception::EXCEPTION_TYPE_1.
|
||||
// } else if (Exception::EXCEPTION_TYPE_2 == e.exception()) {
|
||||
// // Handle Exception::EXCEPTION_TYPE_2.
|
||||
// }
|
||||
//
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// // Use e.result().
|
||||
template <typename T>
|
||||
class ExceptionOr {
|
||||
public:
|
||||
ExceptionOr() = default;
|
||||
explicit ExceptionOr(T&& result)
|
||||
: result_{std::move(result)},
|
||||
exception_{Exception::kSuccess} {} // NOLINT
|
||||
explicit ExceptionOr(const T& result)
|
||||
: result_{result}, exception_{Exception::kSuccess} {} // NOLINT
|
||||
ExceptionOr(Exception::Value exception) : exception_{exception} {} // NOLINT
|
||||
ExceptionOr(Exception exception) : exception_{exception} {} // NOLINT
|
||||
// If there exists explicit conversion from from U to T,
|
||||
// then allow explicit conversion from ExceptionOr<U> to ExceptionOr<T>.
|
||||
template <typename U, typename = std::void_t<decltype(T{std::declval<U>()})>>
|
||||
explicit ExceptionOr<T>(ExceptionOr<U> value) {
|
||||
if (!value.ok()) {
|
||||
exception_ = value.GetException();
|
||||
} else {
|
||||
result_ = T{std::move(value.result())};
|
||||
exception_ = Exception{Exception::kSuccess};
|
||||
}
|
||||
}
|
||||
|
||||
bool ok() const { return exception_.value == Exception::kSuccess; }
|
||||
|
||||
T& result() & { return result_; }
|
||||
const T& result() const& { return result_; }
|
||||
T&& result() && { return std::move(result_); }
|
||||
const T&& result() const&& { return std::move(result_); }
|
||||
|
||||
Exception::Value exception() const { return exception_.value; }
|
||||
|
||||
T GetResult() const { return result_; }
|
||||
Exception GetException() const { return exception_; }
|
||||
|
||||
private:
|
||||
T result_{};
|
||||
Exception exception_{Exception::kFailed};
|
||||
};
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_BASE_EXCEPTION_H_
|
||||
@@ -0,0 +1,106 @@
|
||||
#include "platform_v2/base/exception.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "platform_v2/base/exception_test.nc.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace location::nearby {
|
||||
|
||||
TEST(ExceptionOr, Result_Copy_NonConst) {
|
||||
ExceptionOr<std::vector<int>> exception_or_vector({1, 2, 3});
|
||||
EXPECT_FALSE(exception_or_vector.result().empty());
|
||||
|
||||
// Expect a copy when not explicitly moving the result.
|
||||
std::vector<int> copy = exception_or_vector.result();
|
||||
EXPECT_FALSE(copy.empty());
|
||||
EXPECT_FALSE(exception_or_vector.result().empty());
|
||||
|
||||
// Modifying |exception_or_vector| should not affect the copy.
|
||||
exception_or_vector.result().clear();
|
||||
EXPECT_FALSE(copy.empty());
|
||||
}
|
||||
|
||||
TEST(ExceptionOr, Result_Copy_Const) {
|
||||
const ExceptionOr<std::vector<int>> exception_or_vector({1, 2, 3});
|
||||
EXPECT_FALSE(exception_or_vector.result().empty());
|
||||
|
||||
// Expect a copy when not explicitly moving the result.
|
||||
std::vector<int> copy = exception_or_vector.result();
|
||||
EXPECT_FALSE(copy.empty());
|
||||
EXPECT_FALSE(exception_or_vector.result().empty());
|
||||
}
|
||||
|
||||
TEST(ExceptionOr, Result_Reference_NonConst) {
|
||||
ExceptionOr<std::vector<int>> exception_or_vector({1, 2, 3});
|
||||
EXPECT_FALSE(exception_or_vector.result().empty());
|
||||
|
||||
// Getting a reference should not modify the source.
|
||||
std::vector<int>& reference = exception_or_vector.result();
|
||||
EXPECT_FALSE(reference.empty());
|
||||
EXPECT_FALSE(exception_or_vector.result().empty());
|
||||
|
||||
// Modifying |exception_or_vector| should reflect in the reference.
|
||||
exception_or_vector.result().clear();
|
||||
EXPECT_TRUE(reference.empty());
|
||||
}
|
||||
|
||||
TEST(ExceptionOr, Result_Reference_Const) {
|
||||
const ExceptionOr<std::vector<int>> exception_or_vector({1, 2, 3});
|
||||
EXPECT_FALSE(exception_or_vector.result().empty());
|
||||
|
||||
// Getting a reference should not modify the source.
|
||||
const std::vector<int>& reference = exception_or_vector.result();
|
||||
EXPECT_FALSE(reference.empty());
|
||||
EXPECT_FALSE(exception_or_vector.result().empty());
|
||||
}
|
||||
|
||||
TEST(ExceptionOr, Result_Move_NonConst) {
|
||||
ExceptionOr<std::vector<int>> exception_or_vector({1, 2, 3});
|
||||
EXPECT_FALSE(exception_or_vector.result().empty());
|
||||
|
||||
// Moving the result should clear the source.
|
||||
std::vector<int> moved = std::move(exception_or_vector).result();
|
||||
EXPECT_FALSE(moved.empty());
|
||||
}
|
||||
|
||||
TEST(ExceptionOr, Result_Move_Const) {
|
||||
const ExceptionOr<std::vector<int>> exception_or_vector({1, 2, 3});
|
||||
EXPECT_FALSE(exception_or_vector.result().empty());
|
||||
|
||||
// Moving const rvalue reference will result in a copy.
|
||||
std::vector<int> moved = std::move(exception_or_vector).result();
|
||||
EXPECT_FALSE(moved.empty());
|
||||
}
|
||||
|
||||
TEST(ExceptionOr, ExplicitConversionWorks) {
|
||||
class A {
|
||||
public:
|
||||
A() = default;
|
||||
};
|
||||
class B {
|
||||
public:
|
||||
B() = default;
|
||||
explicit B(A) {}
|
||||
};
|
||||
ExceptionOr<A> a(A{});
|
||||
ExceptionOr<B> b(a);
|
||||
EXPECT_TRUE(a.ok());
|
||||
EXPECT_TRUE(b.ok());
|
||||
}
|
||||
|
||||
TEST(ExceptionOr, ExplicitConversionFailsToCompile) {
|
||||
class A {
|
||||
public:
|
||||
A() = default;
|
||||
};
|
||||
class B {
|
||||
public:
|
||||
B() = default;
|
||||
};
|
||||
ExceptionOr<A> a(A{});
|
||||
EXPECT_NON_COMPILE("no matching constructor", { ExceptionOr<B> b(a); });
|
||||
}
|
||||
|
||||
} // namespace location::nearby
|
||||
@@ -0,0 +1,28 @@
|
||||
#ifndef PLATFORM_V2_BASE_INPUT_STREAM_H_
|
||||
#define PLATFORM_V2_BASE_INPUT_STREAM_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
#include "platform_v2/base/exception.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
// An InputStream represents an input stream of bytes.
|
||||
//
|
||||
// https://docs.oracle.com/javase/8/docs/api/java/io/InputStream.html
|
||||
class InputStream {
|
||||
public:
|
||||
virtual ~InputStream() = default;
|
||||
|
||||
// throws Exception::kIo
|
||||
virtual ExceptionOr<ByteArray> Read(std::int64_t size) = 0;
|
||||
// throws Exception::kIo
|
||||
virtual Exception Close() = 0;
|
||||
};
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_BASE_INPUT_STREAM_H_
|
||||
@@ -0,0 +1,20 @@
|
||||
#ifndef PLATFORM_V2_BASE_LISTENERS_H_
|
||||
#define PLATFORM_V2_BASE_LISTENERS_H_
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
// Provides default-initialization with a valid empty method,
|
||||
// instead of nullptr. This allows partial initialization
|
||||
// of a set of listeners.
|
||||
template <typename... Args>
|
||||
constexpr std::function<void(Args...)> DefaultCallback() {
|
||||
return std::function<void(Args...)>{[](Args...) {}};
|
||||
}
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_BASE_LISTENERS_H_
|
||||
@@ -0,0 +1,25 @@
|
||||
#ifndef PLATFORM_V2_BASE_OUTPUT_STREAM_H_
|
||||
#define PLATFORM_V2_BASE_OUTPUT_STREAM_H_
|
||||
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
#include "platform_v2/base/exception.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
// An OutputStream represents an output stream of bytes.
|
||||
//
|
||||
// https://docs.oracle.com/javase/8/docs/api/java/io/OutputStream.html
|
||||
class OutputStream {
|
||||
public:
|
||||
virtual ~OutputStream() = default;
|
||||
|
||||
virtual Exception Write(const ByteArray& data) = 0; // throws Exception::kIo
|
||||
virtual Exception Flush() = 0; // throws Exception::kIo
|
||||
virtual Exception Close() = 0; // throws Exception::kIo
|
||||
};
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_BASE_OUTPUT_STREAM_H_
|
||||
@@ -0,0 +1,45 @@
|
||||
#include "platform_v2/base/prng.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "absl/time/clock.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
#define UNSIGNED_INT_BITMASK (std::numeric_limits<unsigned int>::max())
|
||||
|
||||
Prng::Prng() {
|
||||
// absl::GetCurrentTimeNanos() returns 64 bits, but srand() wants an unsigned
|
||||
// int, so we may have to lose some of those 64 bits.
|
||||
//
|
||||
// The lower bits of the current-time-in-nanos are likely to have more entropy
|
||||
// than the upper bits, so choose the former.
|
||||
srand(static_cast<unsigned int>(absl::GetCurrentTimeNanos() &
|
||||
UNSIGNED_INT_BITMASK));
|
||||
}
|
||||
|
||||
Prng::~Prng() {
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
#define RANDOM_BYTE (rand() & 0x0FF) // NOLINT
|
||||
|
||||
std::int32_t Prng::NextInt32() {
|
||||
return (static_cast<std::int32_t>(RANDOM_BYTE) << 24) |
|
||||
(static_cast<std::int32_t>(RANDOM_BYTE) << 16) |
|
||||
(static_cast<std::int32_t>(RANDOM_BYTE) << 8) |
|
||||
(static_cast<std::int32_t>(RANDOM_BYTE));
|
||||
}
|
||||
|
||||
std::uint32_t Prng::NextUint32() {
|
||||
return static_cast<std::uint32_t>(NextInt32());
|
||||
}
|
||||
|
||||
std::int64_t Prng::NextInt64() {
|
||||
return (static_cast<std::int64_t>(NextInt32()) << 32) |
|
||||
(static_cast<std::int64_t>(NextInt32()));
|
||||
}
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,23 @@
|
||||
#ifndef PLATFORM_V2_BASE_PRNG_H_
|
||||
#define PLATFORM_V2_BASE_PRNG_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
// A (non-cryptographic) pseudo-random number generator.
|
||||
class Prng {
|
||||
public:
|
||||
Prng();
|
||||
~Prng();
|
||||
|
||||
std::int32_t NextInt32();
|
||||
std::uint32_t NextUint32();
|
||||
std::int64_t NextInt64();
|
||||
};
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_BASE_PRNG_H_
|
||||
@@ -0,0 +1,27 @@
|
||||
#include "platform_v2/base/prng.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
TEST(PrngTest, NextInt32) {
|
||||
std::int32_t i = Prng().NextInt32();
|
||||
EXPECT_LE(i, std::numeric_limits<std::int32_t>::max());
|
||||
EXPECT_GE(i, std::numeric_limits<std::int32_t>::min());
|
||||
}
|
||||
|
||||
TEST(PrngTest, NextUInt32) {
|
||||
std::uint32_t i = Prng().NextUint32();
|
||||
EXPECT_LE(i, std::numeric_limits<std::uint32_t>::max());
|
||||
EXPECT_GE(i, std::numeric_limits<std::uint32_t>::min());
|
||||
}
|
||||
|
||||
TEST(PrngTest, NextInt64) {
|
||||
std::int64_t i = Prng().NextInt64();
|
||||
EXPECT_LE(i, std::numeric_limits<std::int64_t>::max());
|
||||
EXPECT_GE(i, std::numeric_limits<std::int64_t>::min());
|
||||
}
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,19 @@
|
||||
#ifndef PLATFORM_V2_BASE_RUNNABLE_H_
|
||||
#define PLATFORM_V2_BASE_RUNNABLE_H_
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
// The Runnable is an object intended to be executed by a thread.
|
||||
// It must be invokable without arguments. It must return void.
|
||||
//
|
||||
// https://docs.oracle.com/javase/8/docs/api/java/lang/Runnable.html
|
||||
|
||||
using Runnable = std::function<void()>;
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_BASE_RUNNABLE_H_
|
||||
@@ -0,0 +1,25 @@
|
||||
#ifndef PLATFORM_V2_BASE_SOCKET_H_
|
||||
#define PLATFORM_V2_BASE_SOCKET_H_
|
||||
|
||||
#include "platform_v2/base/input_stream.h"
|
||||
#include "platform_v2/base/output_stream.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
// A socket is an endpoint for communication between two machines.
|
||||
//
|
||||
// https://docs.oracle.com/javase/8/docs/api/java/net/Socket.html
|
||||
class Socket {
|
||||
public:
|
||||
virtual ~Socket() = default;
|
||||
|
||||
virtual InputStream& GetInputStream() = 0;
|
||||
virtual OutputStream& GetOutputStream() = 0;
|
||||
virtual void Close() = 0;
|
||||
};
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_BASE_SOCKET_H_
|
||||
@@ -0,0 +1,21 @@
|
||||
cc_library(
|
||||
name = "config",
|
||||
hdrs = [
|
||||
"config.h",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:private",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "string",
|
||||
hdrs = [
|
||||
"string.h",
|
||||
],
|
||||
visibility = [
|
||||
],
|
||||
deps = [
|
||||
":config",
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,22 @@
|
||||
#ifndef PLATFORM_V2_CONFIG_CONFIG_H_
|
||||
#define PLATFORM_V2_CONFIG_CONFIG_H_
|
||||
|
||||
// Clients can modify this file to customize the Nearby C++ codebase as per
|
||||
// their particular constraints and environments.
|
||||
|
||||
// Note: Every entry in this file should conform to the following format, to
|
||||
// give precedence to command-line options (-D) that set these symbols:
|
||||
//
|
||||
// #ifndef XXX
|
||||
// #define XXX 0/1
|
||||
// #endif
|
||||
|
||||
#ifndef NEARBY_USE_STD_STRING
|
||||
#define NEARBY_USE_STD_STRING 0
|
||||
#endif
|
||||
|
||||
#ifndef NEARBY_USE_RTTI
|
||||
#define NEARBY_USE_RTTI 1
|
||||
#endif
|
||||
|
||||
#endif // PLATFORM_V2_CONFIG_CONFIG_H_
|
||||
@@ -0,0 +1,12 @@
|
||||
#ifndef PLATFORM_V2_CONFIG_STRING_H_
|
||||
#define PLATFORM_V2_CONFIG_STRING_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "platform_v2/config/config.h"
|
||||
|
||||
#if NEARBY_USE_STD_STRING
|
||||
using std::string;
|
||||
#endif
|
||||
|
||||
#endif // PLATFORM_V2_CONFIG_STRING_H_
|
||||
@@ -0,0 +1,57 @@
|
||||
cc_library(
|
||||
name = "g3",
|
||||
srcs = [
|
||||
"atomic_boolean.h",
|
||||
"atomic_reference_any.h",
|
||||
"bluetooth_adapter.cc",
|
||||
"bluetooth_adapter.h",
|
||||
"condition_variable.h",
|
||||
"count_down_latch.h",
|
||||
"medium_environment.cc",
|
||||
"medium_environment.h",
|
||||
"multi_thread_executor.h",
|
||||
"mutex.h",
|
||||
"platform.cc",
|
||||
"scheduled_executor.cc",
|
||||
"scheduled_executor.h",
|
||||
"settable_future_any.h",
|
||||
"single_thread_executor.h",
|
||||
"system_clock.cc",
|
||||
],
|
||||
visibility = [
|
||||
"//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__",
|
||||
"//core_v2:__subpackages__",
|
||||
"//platform_v2:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
":crypto", # build_cleaner: keep
|
||||
"//platform_v2/api",
|
||||
"//platform_v2/base",
|
||||
"//platform_v2/impl/shared:posix_mutex",
|
||||
"//absl/base:core_headers",
|
||||
"//absl/container:flat_hash_map",
|
||||
"//absl/container:flat_hash_set",
|
||||
"//absl/memory",
|
||||
"//absl/strings",
|
||||
"//absl/synchronization",
|
||||
"//absl/time",
|
||||
"//absl/types:any",
|
||||
"//thread",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "crypto",
|
||||
srcs = [
|
||||
"crypto.cc",
|
||||
],
|
||||
visibility = [
|
||||
"//platform_v2/g3:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
"//platform_v2/api",
|
||||
"//platform_v2/base",
|
||||
"//absl/strings",
|
||||
"//openssl:crypto",
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,30 @@
|
||||
#ifndef PLATFORM_V2_IMPL_G3_ATOMIC_BOOLEAN_H_
|
||||
#define PLATFORM_V2_IMPL_G3_ATOMIC_BOOLEAN_H_
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "platform_v2/api/atomic_boolean.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace g3 {
|
||||
|
||||
// See documentation in
|
||||
// https://source.corp.google.com/piper///depot/google3/platform_v2/api/atomic_boolean.h
|
||||
class AtomicBoolean : public api::AtomicBoolean {
|
||||
public:
|
||||
explicit AtomicBoolean(bool initial_value) : value_(initial_value) {}
|
||||
~AtomicBoolean() override = default;
|
||||
|
||||
bool Get() const override { return value_.load(); }
|
||||
bool Set(bool value) override { return value_.exchange(value); }
|
||||
|
||||
private:
|
||||
std::atomic_bool value_;
|
||||
};
|
||||
|
||||
} // namespace g3
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_IMPL_G3_ATOMIC_BOOLEAN_H_
|
||||
@@ -0,0 +1,46 @@
|
||||
#ifndef PLATFORM_V2_IMPL_G3_ATOMIC_REFERENCE_ANY_H_
|
||||
#define PLATFORM_V2_IMPL_G3_ATOMIC_REFERENCE_ANY_H_
|
||||
|
||||
#include "platform_v2/api/atomic_reference.h"
|
||||
#include "absl/base/integral_types.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "absl/types/any.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace g3 {
|
||||
|
||||
// Provide implementation for absl::any.
|
||||
class AtomicReferenceAny : public api::AtomicReference<absl::any> {
|
||||
public:
|
||||
explicit AtomicReferenceAny(absl::any initial_value)
|
||||
: value_(std::move(initial_value)) {}
|
||||
~AtomicReferenceAny() override = default;
|
||||
|
||||
absl::any Get() const & override {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
return value_;
|
||||
}
|
||||
absl::any Get() && override {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
return std::move(value_);
|
||||
}
|
||||
void Set(const absl::any& value) override {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
value_ = value;
|
||||
}
|
||||
void Set(absl::any&& value) override {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
value_ = std::move(value);
|
||||
}
|
||||
|
||||
private:
|
||||
mutable absl::Mutex mutex_;
|
||||
absl::any value_;
|
||||
};
|
||||
|
||||
} // namespace g3
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_IMPL_G3_ATOMIC_REFERENCE_ANY_H_
|
||||
@@ -0,0 +1,65 @@
|
||||
#include "platform_v2/impl/g3/bluetooth_adapter.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "platform_v2/impl/g3/medium_environment.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace g3 {
|
||||
|
||||
BluetoothDevice::BluetoothDevice(BluetoothAdapter* adapter)
|
||||
: adapter_(*adapter) {}
|
||||
|
||||
std::string BluetoothDevice::GetName() const { return adapter_.GetName(); }
|
||||
|
||||
bool BluetoothAdapter::SetStatus(Status status) ABSL_LOCKS_EXCLUDED(mutex_) {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
enabled_ = (status == Status::kEnabled);
|
||||
RunOnCallbackThread([this]() {
|
||||
auto& env = MediumEnvironment::Instance();
|
||||
env.OnBluetoothAdapterChangedState(*this);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BluetoothAdapter::IsEnabled() const {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
return enabled_;
|
||||
}
|
||||
|
||||
BluetoothAdapter::ScanMode BluetoothAdapter::GetScanMode() const {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
return mode_;
|
||||
}
|
||||
|
||||
bool BluetoothAdapter::SetScanMode(BluetoothAdapter::ScanMode mode) {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
if (enabled_) return false;
|
||||
mode_ = mode;
|
||||
RunOnCallbackThread([this]() {
|
||||
auto& env = MediumEnvironment::Instance();
|
||||
env.OnBluetoothAdapterChangedState(*this);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string BluetoothAdapter::GetName() const {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
return name_;
|
||||
}
|
||||
|
||||
bool BluetoothAdapter::SetName(absl::string_view name) {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
if (enabled_) return false;
|
||||
name_ = name;
|
||||
RunOnCallbackThread([this]() {
|
||||
auto& env = MediumEnvironment::Instance();
|
||||
env.OnBluetoothAdapterChangedState(*this);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace g3
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,90 @@
|
||||
#ifndef PLATFORM_V2_IMPL_G3_BLUETOOTH_ADAPTER_H_
|
||||
#define PLATFORM_V2_IMPL_G3_BLUETOOTH_ADAPTER_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "platform_v2/api/bluetooth_adapter.h"
|
||||
#include "platform_v2/api/bluetooth_classic.h"
|
||||
#include "platform_v2/impl/g3/single_thread_executor.h"
|
||||
#include "absl/base/thread_annotations.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace g3 {
|
||||
|
||||
// BluetoothDevice and BluetoothAdapter have a mutual dependency.
|
||||
class BluetoothAdapter;
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html.
|
||||
class BluetoothDevice : public api::BluetoothDevice {
|
||||
public:
|
||||
~BluetoothDevice() override = default;
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#getName()
|
||||
std::string GetName() const override;
|
||||
BluetoothAdapter& GetAdapter();
|
||||
|
||||
private:
|
||||
// Only BluetoothAdapter may instantiate BluetoothDevice.
|
||||
friend class BluetoothAdapter;
|
||||
|
||||
explicit BluetoothDevice(BluetoothAdapter* adapter);
|
||||
|
||||
BluetoothAdapter& adapter_;
|
||||
};
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html
|
||||
class BluetoothAdapter : public api::BluetoothAdapter {
|
||||
public:
|
||||
using Status = api::BluetoothAdapter::Status;
|
||||
using ScanMode = api::BluetoothAdapter::ScanMode;
|
||||
|
||||
BluetoothAdapter() = default;
|
||||
~BluetoothAdapter() override = default;
|
||||
|
||||
// Synchronously sets the status of the BluetoothAdapter to 'status', and
|
||||
// returns true if the operation was a success.
|
||||
bool SetStatus(Status status) override ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
// Returns true if the BluetoothAdapter's current status is
|
||||
// Status::Value::kEnabled.
|
||||
bool IsEnabled() const override ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#getScanMode()
|
||||
//
|
||||
// Returns ScanMode::kUnknown on error.
|
||||
ScanMode GetScanMode() const override ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
// Synchronously sets the scan mode of the adapter, and returns true if the
|
||||
// operation was a success.
|
||||
bool SetScanMode(ScanMode mode) override ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#getName()
|
||||
// Returns an empty string on error
|
||||
std::string GetName() const override ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#setName(java.lang.String)
|
||||
bool SetName(absl::string_view name) override ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
BluetoothDevice& GetDevice() { return device_; }
|
||||
|
||||
private:
|
||||
void RunOnCallbackThread(std::function<void()> runnable) {
|
||||
serial_executor_.Execute(std::move(runnable));
|
||||
}
|
||||
|
||||
mutable absl::Mutex mutex_;
|
||||
BluetoothDevice device_{this};
|
||||
ScanMode mode_ ABSL_GUARDED_BY(mutex_) = ScanMode::kNone;
|
||||
std::string name_ ABSL_GUARDED_BY(mutex_) = "unknown G3 BT device";
|
||||
bool enabled_ ABSL_GUARDED_BY(mutex_) = false;
|
||||
SingleThreadExecutor serial_executor_;
|
||||
};
|
||||
|
||||
} // namespace g3
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_IMPL_G3_BLUETOOTH_ADAPTER_H_
|
||||
@@ -0,0 +1,33 @@
|
||||
#ifndef PLATFORM_V2_IMPL_G3_CONDITION_VARIABLE_H_
|
||||
#define PLATFORM_V2_IMPL_G3_CONDITION_VARIABLE_H_
|
||||
|
||||
#include "platform_v2/api/condition_variable.h"
|
||||
#include "platform_v2/base/exception.h"
|
||||
#include "platform_v2/impl/g3/mutex.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace g3 {
|
||||
|
||||
class ConditionVariable : public api::ConditionVariable {
|
||||
public:
|
||||
explicit ConditionVariable(g3::Mutex* mutex) : mutex_(&mutex->mutex_) {}
|
||||
~ConditionVariable() override = default;
|
||||
|
||||
Exception Wait() override {
|
||||
cond_var_.Wait(mutex_);
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
void Notify() override { cond_var_.SignalAll(); }
|
||||
|
||||
private:
|
||||
absl::Mutex* mutex_;
|
||||
absl::CondVar cond_var_;
|
||||
};
|
||||
|
||||
} // namespace g3
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_IMPL_G3_CONDITION_VARIABLE_H_
|
||||
@@ -0,0 +1,59 @@
|
||||
#ifndef PLATFORM_V2_IMPL_G3_COUNT_DOWN_LATCH_H_
|
||||
#define PLATFORM_V2_IMPL_G3_COUNT_DOWN_LATCH_H_
|
||||
|
||||
#include "platform_v2/api/count_down_latch.h"
|
||||
#include "absl/base/thread_annotations.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "absl/time/clock.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace g3 {
|
||||
|
||||
// A synchronization aid that allows one or more threads to wait until a set of
|
||||
// operations being performed in other threads completes.
|
||||
//
|
||||
// https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CountDownLatch.html
|
||||
class CountDownLatch final : public api::CountDownLatch {
|
||||
public:
|
||||
explicit CountDownLatch(int count) : count_(count) {}
|
||||
CountDownLatch(const CountDownLatch&) = delete;
|
||||
CountDownLatch& operator=(const CountDownLatch&) = delete;
|
||||
CountDownLatch(CountDownLatch&&) = delete;
|
||||
CountDownLatch& operator=(CountDownLatch&&) = delete;
|
||||
ExceptionOr<bool> Await(absl::Duration timeout) override {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
absl::Time deadline = absl::Now() + timeout;
|
||||
while (count_ > 0) {
|
||||
if (cond_.WaitWithDeadline(&mutex_, deadline)) {
|
||||
return ExceptionOr<bool>(false);
|
||||
}
|
||||
}
|
||||
return ExceptionOr<bool>(true);
|
||||
}
|
||||
Exception Await() override {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
while (count_ > 0) {
|
||||
cond_.Wait(&mutex_);
|
||||
}
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
void CountDown() override {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
if (count_ > 0 && --count_ == 0) {
|
||||
cond_.SignalAll();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
absl::Mutex mutex_; // Mutex to be used with cond_.Wait...() method family.
|
||||
absl::CondVar cond_; // Condition to synchronize up to N waiting threads.
|
||||
int count_
|
||||
ABSL_GUARDED_BY(mutex_); // When zero, latch should release all waiters.
|
||||
};
|
||||
|
||||
} // namespace g3
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_IMPL_G3_COUNT_DOWN_LATCH_H_
|
||||
@@ -0,0 +1,39 @@
|
||||
#include "platform_v2/api/crypto.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "openssl/digest.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
// Initialize global crypto state.
|
||||
void Crypto::Init() {}
|
||||
|
||||
static ByteArray Hash(absl::string_view input, const EVP_MD* algo) {
|
||||
unsigned int md_out_size = EVP_MAX_MD_SIZE;
|
||||
uint8_t digest_buffer[EVP_MAX_MD_SIZE];
|
||||
if (input.empty()) return {};
|
||||
|
||||
if (!EVP_Digest(input.data(), input.size(), digest_buffer, &md_out_size, algo,
|
||||
nullptr))
|
||||
return {};
|
||||
|
||||
return ByteArray{reinterpret_cast<char*>(digest_buffer), md_out_size};
|
||||
}
|
||||
|
||||
// Return MD5 hash of input.
|
||||
ByteArray Crypto::Md5(absl::string_view input) {
|
||||
return Hash(input, EVP_md5());
|
||||
}
|
||||
|
||||
// Return SHA256 hash of input.
|
||||
ByteArray Crypto::Sha256(absl::string_view input) {
|
||||
return Hash(input, EVP_sha256());
|
||||
}
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,32 @@
|
||||
#include "platform_v2/impl/g3/medium_environment.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace g3 {
|
||||
|
||||
MediumEnvironment& MediumEnvironment::Instance() {
|
||||
static std::aligned_storage_t<sizeof(MediumEnvironment),
|
||||
alignof(MediumEnvironment)>
|
||||
storage;
|
||||
static MediumEnvironment* env = new (&storage) MediumEnvironment();
|
||||
return *env;
|
||||
}
|
||||
|
||||
void MediumEnvironment::Reset() {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
bluetooth_adapters_.clear();
|
||||
}
|
||||
|
||||
void MediumEnvironment::OnBluetoothAdapterChangedState(
|
||||
BluetoothAdapter& adapter) {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
// We don't care if there is an adapter already since all we store is a
|
||||
// pointer.
|
||||
bluetooth_adapters_.emplace(&adapter);
|
||||
// TODO(apolyudov): Add event propagation code when Medium registration is
|
||||
// implemented.
|
||||
}
|
||||
|
||||
} // namespace g3
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,47 @@
|
||||
#ifndef PLATFORM_V2_IMPL_G3_MEDIUM_ENVIRONMENT_H_
|
||||
#define PLATFORM_V2_IMPL_G3_MEDIUM_ENVIRONMENT_H_
|
||||
|
||||
#include <new>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#include "platform_v2/api/bluetooth_classic.h"
|
||||
#include "platform_v2/impl/g3/bluetooth_adapter.h"
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "absl/container/flat_hash_set.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace g3 {
|
||||
|
||||
// MediumEnvironment is a simulated environment which allowes multiple instances
|
||||
// of simulated HW devices to "work" together as if they are physical.
|
||||
// For each medium type it provides necessary methods to implement
|
||||
// advertising, discovery and establishment of a data link.
|
||||
class MediumEnvironment {
|
||||
public:
|
||||
~MediumEnvironment() = default;
|
||||
// Singleton constructor/accessor.
|
||||
static MediumEnvironment& Instance();
|
||||
|
||||
// Clear state. No notifications are sent.
|
||||
void Reset() ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
// Add an adapter to internal container.
|
||||
// Notify BluetoothClassicMediums if any that adapter state has changed.
|
||||
void OnBluetoothAdapterChangedState(BluetoothAdapter& adapter)
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
private:
|
||||
MediumEnvironment() = default;
|
||||
absl::Mutex mutex_;
|
||||
absl::flat_hash_set<BluetoothAdapter*> bluetooth_adapters_
|
||||
ABSL_GUARDED_BY(mutex_);
|
||||
};
|
||||
|
||||
} // namespace g3
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_IMPL_G3_MEDIUM_ENVIRONMENT_H_
|
||||
@@ -0,0 +1,54 @@
|
||||
#ifndef PLATFORM_V2_IMPL_G3_MULTI_THREAD_EXECUTOR_H_
|
||||
#define PLATFORM_V2_IMPL_G3_MULTI_THREAD_EXECUTOR_H_
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "platform_v2/api/submittable_executor.h"
|
||||
#include "platform_v2/impl/g3/count_down_latch.h"
|
||||
#include "absl/time/clock.h"
|
||||
#include "thread/threadpool.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace g3 {
|
||||
|
||||
// An Executor that reuses a fixed number of threads operating off a shared
|
||||
// unbounded queue.
|
||||
class MultiThreadExecutor : public api::SubmittableExecutor {
|
||||
public:
|
||||
explicit MultiThreadExecutor(int max_parallelism)
|
||||
: thread_pool_(max_parallelism) {
|
||||
thread_pool_.StartWorkers();
|
||||
}
|
||||
void Execute(Runnable&& runnable) override {
|
||||
if (!shutdown_) {
|
||||
thread_pool_.Schedule(std::move(runnable));
|
||||
}
|
||||
}
|
||||
bool DoSubmit(Runnable&& runnable) override {
|
||||
if (shutdown_) return false;
|
||||
thread_pool_.Schedule(std::move(runnable));
|
||||
return true;
|
||||
}
|
||||
void Shutdown() override { DoShutdown(); }
|
||||
~MultiThreadExecutor() override { DoShutdown(); }
|
||||
|
||||
void ScheduleAfter(absl::Duration delay, Runnable&& runnable) {
|
||||
if (shutdown_) return;
|
||||
thread_pool_.ScheduleAt(absl::Now() + delay, std::move(runnable));
|
||||
}
|
||||
bool InShutdown() const { return shutdown_; }
|
||||
|
||||
private:
|
||||
void DoShutdown() {
|
||||
shutdown_ = true;
|
||||
}
|
||||
std::atomic_bool shutdown_ = false;
|
||||
ThreadPool thread_pool_;
|
||||
};
|
||||
|
||||
} // namespace g3
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_IMPL_G3_MULTI_THREAD_EXECUTOR_H_
|
||||
@@ -0,0 +1,47 @@
|
||||
#ifndef PLATFORM_V2_IMPL_G3_MUTEX_H_
|
||||
#define PLATFORM_V2_IMPL_G3_MUTEX_H_
|
||||
|
||||
#include "platform_v2/api/mutex.h"
|
||||
#include "platform_v2/impl/shared/posix_mutex.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace g3 {
|
||||
|
||||
class ABSL_LOCKABLE Mutex : public api::Mutex {
|
||||
public:
|
||||
explicit Mutex(bool check) : check_(check) {}
|
||||
~Mutex() override = default;
|
||||
Mutex(Mutex&&) = delete;
|
||||
Mutex& operator=(Mutex&&) = delete;
|
||||
Mutex(const Mutex&) = delete;
|
||||
Mutex& operator=(const Mutex&) = delete;
|
||||
|
||||
void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() override {
|
||||
mutex_.Lock();
|
||||
if (!check_) mutex_.ForgetDeadlockInfo();
|
||||
}
|
||||
void Unlock() ABSL_UNLOCK_FUNCTION() override { mutex_.Unlock(); }
|
||||
|
||||
private:
|
||||
friend class ConditionVariable;
|
||||
absl::Mutex mutex_;
|
||||
bool check_;
|
||||
};
|
||||
|
||||
class ABSL_LOCKABLE RecursiveMutex : public posix::Mutex {
|
||||
public:
|
||||
~RecursiveMutex() override = default;
|
||||
RecursiveMutex() = default;
|
||||
RecursiveMutex(RecursiveMutex&&) = delete;
|
||||
RecursiveMutex& operator=(RecursiveMutex&&) = delete;
|
||||
RecursiveMutex(const RecursiveMutex&) = delete;
|
||||
RecursiveMutex& operator=(const RecursiveMutex&) = delete;
|
||||
};
|
||||
|
||||
} // namespace g3
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_IMPL_G3_MUTEX_H_
|
||||
@@ -0,0 +1,30 @@
|
||||
#ifndef PLATFORM_V2_IMPL_G3_PIPE_H_
|
||||
#define PLATFORM_V2_IMPL_G3_PIPE_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "platform_v2/base/base_pipe.h"
|
||||
#include "platform_v2/impl/g3/condition_variable.h"
|
||||
#include "platform_v2/impl/g3/mutex.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace g3 {
|
||||
|
||||
class Pipe : public BasePipe {
|
||||
public:
|
||||
Pipe() {
|
||||
auto mutex = std::make_unique<g3::Mutex>(/*check=*/true);
|
||||
auto cond = std::make_unique<g3::ConditionVariable>(mutex.get());
|
||||
Setup(std::move(mutex), std::move(cond));
|
||||
}
|
||||
~Pipe() override = default;
|
||||
Pipe(Pipe &&) = delete;
|
||||
Pipe& operator=(Pipe&&) = delete;
|
||||
};
|
||||
|
||||
} // namespace g3
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_IMPL_G3_PIPE_H_
|
||||
@@ -0,0 +1,136 @@
|
||||
#include "platform_v2/api/platform.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
|
||||
#include "platform_v2/api/atomic_boolean.h"
|
||||
#include "platform_v2/api/atomic_reference.h"
|
||||
#include "platform_v2/api/ble.h"
|
||||
#include "platform_v2/api/ble_v2.h"
|
||||
#include "platform_v2/api/bluetooth_adapter.h"
|
||||
#include "platform_v2/api/bluetooth_classic.h"
|
||||
#include "platform_v2/api/condition_variable.h"
|
||||
#include "platform_v2/api/count_down_latch.h"
|
||||
#include "platform_v2/api/mutex.h"
|
||||
#include "platform_v2/api/scheduled_executor.h"
|
||||
#include "platform_v2/api/server_sync.h"
|
||||
#include "platform_v2/api/settable_future.h"
|
||||
#include "platform_v2/api/submittable_executor.h"
|
||||
#include "platform_v2/api/webrtc.h"
|
||||
#include "platform_v2/api/wifi.h"
|
||||
#include "platform_v2/impl/g3/atomic_boolean.h"
|
||||
#include "platform_v2/impl/g3/atomic_reference_any.h"
|
||||
#include "platform_v2/impl/g3/bluetooth_adapter.h"
|
||||
#include "platform_v2/impl/g3/condition_variable.h"
|
||||
#include "platform_v2/impl/g3/count_down_latch.h"
|
||||
#include "platform_v2/impl/g3/multi_thread_executor.h"
|
||||
#include "platform_v2/impl/g3/mutex.h"
|
||||
#include "platform_v2/impl/g3/scheduled_executor.h"
|
||||
#include "platform_v2/impl/g3/settable_future_any.h"
|
||||
#include "platform_v2/impl/g3/single_thread_executor.h"
|
||||
#include "absl/base/integral_types.h"
|
||||
#include "absl/memory/memory.h"
|
||||
#include "absl/time/time.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace api {
|
||||
|
||||
std::unique_ptr<SubmittableExecutor>
|
||||
ImplementationPlatform::CreateSingleThreadExecutor() {
|
||||
return absl::make_unique<g3::SingleThreadExecutor>();
|
||||
}
|
||||
|
||||
std::unique_ptr<SubmittableExecutor>
|
||||
ImplementationPlatform::CreateMultiThreadExecutor(int max_concurrency) {
|
||||
return absl::make_unique<g3::MultiThreadExecutor>(max_concurrency);
|
||||
}
|
||||
|
||||
std::unique_ptr<ScheduledExecutor>
|
||||
ImplementationPlatform::CreateScheduledExecutor() {
|
||||
return absl::make_unique<g3::ScheduledExecutor>();
|
||||
}
|
||||
|
||||
std::unique_ptr<AtomicReference<absl::any>>
|
||||
ImplementationPlatform::CreateAtomicReferenceAny(absl::any initial_value) {
|
||||
return absl::make_unique<g3::AtomicReferenceAny>(initial_value);
|
||||
}
|
||||
|
||||
std::unique_ptr<SettableFuture<absl::any>>
|
||||
ImplementationPlatform::CreateSettableFutureAny() {
|
||||
return absl::make_unique<g3::SettableFutureAny>();
|
||||
}
|
||||
|
||||
std::unique_ptr<BluetoothAdapter>
|
||||
ImplementationPlatform::CreateBluetoothAdapter() {
|
||||
return absl::make_unique<g3::BluetoothAdapter>();
|
||||
}
|
||||
|
||||
std::unique_ptr<CountDownLatch> ImplementationPlatform::CreateCountDownLatch(
|
||||
std::int32_t count) {
|
||||
return absl::make_unique<g3::CountDownLatch>(count);
|
||||
}
|
||||
|
||||
std::unique_ptr<AtomicBoolean> ImplementationPlatform::CreateAtomicBoolean(
|
||||
bool initial_value) {
|
||||
return absl::make_unique<g3::AtomicBoolean>(initial_value);
|
||||
}
|
||||
|
||||
std::unique_ptr<BluetoothClassicMedium>
|
||||
ImplementationPlatform::CreateBluetoothClassicMedium() {
|
||||
return std::unique_ptr<BluetoothClassicMedium>();
|
||||
}
|
||||
|
||||
std::unique_ptr<BleMedium> ImplementationPlatform::CreateBleMedium() {
|
||||
return std::unique_ptr<BleMedium>();
|
||||
}
|
||||
|
||||
std::unique_ptr<ble_v2::BleMedium> ImplementationPlatform::CreateBleV2Medium() {
|
||||
return std::unique_ptr<ble_v2::BleMedium>();
|
||||
}
|
||||
|
||||
std::unique_ptr<ServerSyncMedium>
|
||||
ImplementationPlatform::CreateServerSyncMedium() {
|
||||
return std::unique_ptr<ServerSyncMedium>(/*new ServerSyncMediumImpl()*/);
|
||||
}
|
||||
|
||||
std::unique_ptr<WifiMedium> ImplementationPlatform::CreateWifiMedium() {
|
||||
return std::unique_ptr<WifiMedium>();
|
||||
}
|
||||
|
||||
std::unique_ptr<WifiLanMedium> ImplementationPlatform::CreateWifiLanMedium() {
|
||||
return std::unique_ptr<WifiLanMedium>();
|
||||
}
|
||||
|
||||
std::unique_ptr<WebRtcSignalingMessenger>
|
||||
ImplementationPlatform::CreateWebRtcSignalingMessenger(
|
||||
absl::string_view self_id) {
|
||||
return std::unique_ptr<WebRtcSignalingMessenger>(
|
||||
/*new FCMSignalingMessenger()*/);
|
||||
}
|
||||
|
||||
std::unique_ptr<Mutex> ImplementationPlatform::CreateMutex(Mutex::Mode mode) {
|
||||
if (mode == Mutex::Mode::kRecursive)
|
||||
return absl::make_unique<g3::RecursiveMutex>();
|
||||
else
|
||||
return absl::make_unique<g3::Mutex>(mode == Mutex::Mode::kRegular);
|
||||
}
|
||||
|
||||
std::unique_ptr<ConditionVariable>
|
||||
ImplementationPlatform::CreateConditionVariable(Mutex* mutex) {
|
||||
return std::unique_ptr<ConditionVariable>(
|
||||
new g3::ConditionVariable(static_cast<g3::Mutex*>(mutex)));
|
||||
}
|
||||
|
||||
std::string ImplementationPlatform::GetDeviceId() {
|
||||
// TODO(alexchau): Get deviceId from base
|
||||
return "google3";
|
||||
}
|
||||
|
||||
std::string ImplementationPlatform::GetPayloadPath(int64_t payload_id) {
|
||||
return "/tmp/" + std::to_string(payload_id);
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,65 @@
|
||||
#include "platform_v2/impl/g3/scheduled_executor.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
|
||||
#include "platform_v2/api/cancelable.h"
|
||||
#include "platform_v2/base/runnable.h"
|
||||
#include "absl/time/clock.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace g3 {
|
||||
|
||||
namespace {
|
||||
|
||||
class ScheduledCancelable : public api::Cancelable {
|
||||
public:
|
||||
bool Cancel() override {
|
||||
Status expected = kNotRun;
|
||||
while (expected == kNotRun) {
|
||||
if (status_.compare_exchange_strong(expected, kCanceled)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool MarkExecuted() {
|
||||
Status expected = kNotRun;
|
||||
while (expected == kNotRun) {
|
||||
if (status_.compare_exchange_strong(expected, kExecuted)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
enum Status {
|
||||
kNotRun,
|
||||
kExecuted,
|
||||
kCanceled,
|
||||
};
|
||||
std::atomic<Status> status_ = kNotRun;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
std::shared_ptr<api::Cancelable> ScheduledExecutor::Schedule(
|
||||
Runnable&& runnable, absl::Duration delay) {
|
||||
auto scheduled_cancelable = std::make_shared<ScheduledCancelable>();
|
||||
if (executor_.InShutdown()) {
|
||||
return scheduled_cancelable;
|
||||
}
|
||||
executor_.ScheduleAfter(
|
||||
delay, [this, scheduled_cancelable, runnable(std::move(runnable))]() {
|
||||
if (!executor_.InShutdown() && scheduled_cancelable->MarkExecuted()) {
|
||||
runnable();
|
||||
}
|
||||
});
|
||||
return scheduled_cancelable;
|
||||
}
|
||||
|
||||
} // namespace g3
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,42 @@
|
||||
#ifndef PLATFORM_V2_IMPL_G3_SCHEDULED_EXECUTOR_H_
|
||||
#define PLATFORM_V2_IMPL_G3_SCHEDULED_EXECUTOR_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
|
||||
#include "platform_v2/api/cancelable.h"
|
||||
#include "platform_v2/api/scheduled_executor.h"
|
||||
#include "platform_v2/base/runnable.h"
|
||||
#include "platform_v2/impl/g3/single_thread_executor.h"
|
||||
#include "absl/time/clock.h"
|
||||
#include "thread/threadpool.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace g3 {
|
||||
|
||||
// An Executor that reuses a fixed number of threads operating off a shared
|
||||
// unbounded queue.
|
||||
class ScheduledExecutor final : public api::ScheduledExecutor {
|
||||
public:
|
||||
ScheduledExecutor() = default;
|
||||
~ScheduledExecutor() override {
|
||||
executor_.Shutdown();
|
||||
}
|
||||
|
||||
void Execute(Runnable&& runnable) override {
|
||||
executor_.Execute(std::move(runnable));
|
||||
}
|
||||
std::shared_ptr<api::Cancelable> Schedule(Runnable&& runnable,
|
||||
absl::Duration delay) override;
|
||||
void Shutdown() override { executor_.Shutdown(); }
|
||||
|
||||
private:
|
||||
SingleThreadExecutor executor_;
|
||||
};
|
||||
|
||||
} // namespace g3
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_IMPL_G3_SCHEDULED_EXECUTOR_H_
|
||||
@@ -0,0 +1,104 @@
|
||||
#ifndef PLATFORM_V2_IMPL_G3_SETTABLE_FUTURE_ANY_H_
|
||||
#define PLATFORM_V2_IMPL_G3_SETTABLE_FUTURE_ANY_H_
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "platform_v2/api/platform.h"
|
||||
#include "platform_v2/api/settable_future.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "absl/time/clock.h"
|
||||
#include "absl/types/any.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace g3 {
|
||||
|
||||
class SettableFutureAny : public api::SettableFuture<absl::any> {
|
||||
public:
|
||||
SettableFutureAny() = default;
|
||||
~SettableFutureAny() override = default;
|
||||
|
||||
bool Set(const absl::any& value) override {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
if (!done_) {
|
||||
value_ = value;
|
||||
done_ = true;
|
||||
exception_ = {Exception::kSuccess};
|
||||
completed_.SignalAll();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Set(absl::any&& value) override {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
if (!done_) {
|
||||
value_ = std::move(value);
|
||||
done_ = true;
|
||||
exception_ = {Exception::kSuccess};
|
||||
completed_.SignalAll();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SetException(Exception exception) override {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
return SetExceptionLocked(exception);
|
||||
}
|
||||
|
||||
void AddListener(Runnable runnable, api::Executor* executor) override {}
|
||||
|
||||
ExceptionOr<std::any> Get() override {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
while (!done_) {
|
||||
completed_.Wait(&mutex_);
|
||||
}
|
||||
return exception_.value != Exception::kSuccess
|
||||
? ExceptionOr<std::any>{exception_.value}
|
||||
: ExceptionOr<std::any>{value_};
|
||||
}
|
||||
|
||||
ExceptionOr<std::any> Get(absl::Duration timeout) override {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
while (!done_) {
|
||||
absl::Time start_time = absl::Now();
|
||||
if (completed_.WaitWithTimeout(&mutex_, timeout)) {
|
||||
SetExceptionLocked({Exception::kTimeout});
|
||||
break;
|
||||
}
|
||||
absl::Duration spent = absl::Now() - start_time;
|
||||
if (spent < timeout) {
|
||||
timeout -= spent;
|
||||
} else if (!done_) {
|
||||
SetExceptionLocked({Exception::kTimeout});
|
||||
break;
|
||||
}
|
||||
}
|
||||
return exception_.value != Exception::kSuccess
|
||||
? ExceptionOr<std::any>{exception_.value}
|
||||
: ExceptionOr<std::any>{value_};
|
||||
}
|
||||
|
||||
private:
|
||||
bool SetExceptionLocked(Exception exception) {
|
||||
if (!done_) {
|
||||
exception_ = exception.value != Exception::kSuccess
|
||||
? exception
|
||||
: Exception{Exception::kFailed};
|
||||
done_ = true;
|
||||
completed_.SignalAll();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
absl::Mutex mutex_;
|
||||
absl::CondVar completed_;
|
||||
bool done_{false};
|
||||
absl::any value_;
|
||||
Exception exception_{Exception::kFailed};
|
||||
};
|
||||
|
||||
} // namespace g3
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_IMPL_G3_SETTABLE_FUTURE_ANY_H_
|
||||
@@ -0,0 +1,22 @@
|
||||
#ifndef PLATFORM_V2_IMPL_G3_SINGLE_THREAD_EXECUTOR_H_
|
||||
#define PLATFORM_V2_IMPL_G3_SINGLE_THREAD_EXECUTOR_H_
|
||||
|
||||
#include "platform_v2/impl/g3/multi_thread_executor.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace g3 {
|
||||
|
||||
// An Executor that uses a single worker thread operating off an unbounded
|
||||
// queue.
|
||||
class SingleThreadExecutor final : public MultiThreadExecutor {
|
||||
public:
|
||||
SingleThreadExecutor() : MultiThreadExecutor(1) {}
|
||||
~SingleThreadExecutor() override = default;
|
||||
};
|
||||
|
||||
} // namespace g3
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_IMPL_G3_SINGLE_THREAD_EXECUTOR_H_
|
||||
@@ -0,0 +1,16 @@
|
||||
#include "platform_v2/api/system_clock.h"
|
||||
|
||||
#include "platform_v2/base/exception.h"
|
||||
#include "absl/time/clock.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
absl::Time SystemClock::ElapsedRealtime() { return absl::Now(); }
|
||||
Exception SystemClock::Sleep(absl::Duration duration) {
|
||||
absl::SleepFor(duration);
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,34 @@
|
||||
cc_library(
|
||||
name = "posix_mutex",
|
||||
srcs = [
|
||||
"posix_mutex.cc",
|
||||
],
|
||||
hdrs = [
|
||||
"posix_mutex.h",
|
||||
],
|
||||
visibility = [
|
||||
"//platform_v2/impl:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//platform_v2/api",
|
||||
"//platform_v2/base",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "posix_condition_variable",
|
||||
srcs = [
|
||||
"posix_condition_variable.cc",
|
||||
],
|
||||
hdrs = [
|
||||
"posix_condition_variable.h",
|
||||
],
|
||||
visibility = [
|
||||
"//platform_v2/impl:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
":posix_mutex",
|
||||
"//platform_v2/api",
|
||||
"//platform_v2/base",
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,30 @@
|
||||
#include "platform_v2/impl/shared/posix_condition_variable.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace posix {
|
||||
|
||||
ConditionVariable::ConditionVariable(Mutex* mutex)
|
||||
: mutex_(mutex), attr_(), cond_() {
|
||||
pthread_condattr_init(&attr_);
|
||||
|
||||
pthread_cond_init(&cond_, &attr_);
|
||||
}
|
||||
|
||||
ConditionVariable::~ConditionVariable() {
|
||||
pthread_cond_destroy(&cond_);
|
||||
|
||||
pthread_condattr_destroy(&attr_);
|
||||
}
|
||||
|
||||
void ConditionVariable::Notify() { pthread_cond_broadcast(&cond_); }
|
||||
|
||||
Exception ConditionVariable::Wait() {
|
||||
pthread_cond_wait(&cond_, &(mutex_->mutex_));
|
||||
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
|
||||
} // namespace posix
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,31 @@
|
||||
#ifndef PLATFORM_V2_IMPL_SHARED_POSIX_CONDITION_VARIABLE_H_
|
||||
#define PLATFORM_V2_IMPL_SHARED_POSIX_CONDITION_VARIABLE_H_
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "platform_v2/api/condition_variable.h"
|
||||
#include "platform_v2/impl/shared/posix_mutex.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace posix {
|
||||
|
||||
class ConditionVariable : public api::ConditionVariable {
|
||||
public:
|
||||
explicit ConditionVariable(Mutex* mutex);
|
||||
~ConditionVariable() override;
|
||||
|
||||
void Notify() override;
|
||||
Exception Wait() override;
|
||||
|
||||
private:
|
||||
Mutex* mutex_;
|
||||
pthread_condattr_t attr_;
|
||||
pthread_cond_t cond_;
|
||||
};
|
||||
|
||||
} // namespace posix
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_IMPL_SHARED_POSIX_CONDITION_VARIABLE_H_
|
||||
@@ -0,0 +1,26 @@
|
||||
#include "platform_v2/impl/shared/posix_mutex.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace posix {
|
||||
|
||||
Mutex::Mutex() : attr_(), mutex_() {
|
||||
pthread_mutexattr_init(&attr_);
|
||||
pthread_mutexattr_settype(&attr_, PTHREAD_MUTEX_RECURSIVE);
|
||||
|
||||
pthread_mutex_init(&mutex_, &attr_);
|
||||
}
|
||||
|
||||
Mutex::~Mutex() {
|
||||
pthread_mutex_destroy(&mutex_);
|
||||
|
||||
pthread_mutexattr_destroy(&attr_);
|
||||
}
|
||||
|
||||
void Mutex::Lock() { pthread_mutex_lock(&mutex_); }
|
||||
|
||||
void Mutex::Unlock() { pthread_mutex_unlock(&mutex_); }
|
||||
|
||||
} // namespace posix
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,31 @@
|
||||
#ifndef PLATFORM_V2_IMPL_SHARED_POSIX_MUTEX_H_
|
||||
#define PLATFORM_V2_IMPL_SHARED_POSIX_MUTEX_H_
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "platform_v2/api/mutex.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace posix {
|
||||
|
||||
class ABSL_LOCKABLE Mutex : public api::Mutex {
|
||||
public:
|
||||
Mutex();
|
||||
~Mutex() override;
|
||||
|
||||
void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() override;
|
||||
void Unlock() ABSL_UNLOCK_FUNCTION() override;
|
||||
|
||||
private:
|
||||
friend class ConditionVariable;
|
||||
|
||||
pthread_mutexattr_t attr_;
|
||||
pthread_mutex_t mutex_;
|
||||
};
|
||||
|
||||
} // namespace posix
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_IMPL_SHARED_POSIX_MUTEX_H_
|
||||
@@ -0,0 +1,86 @@
|
||||
cc_library(
|
||||
name = "public",
|
||||
srcs = [
|
||||
"file.cc",
|
||||
"pipe.cc",
|
||||
],
|
||||
hdrs = [
|
||||
"atomic_boolean.h",
|
||||
"atomic_reference.h",
|
||||
"bluetooth_adapter.h",
|
||||
"cancelable.h",
|
||||
"cancelable_alarm.h",
|
||||
"condition_variable.h",
|
||||
"count_down_latch.h",
|
||||
"crypto.h",
|
||||
"file.h",
|
||||
"future.h",
|
||||
"multi_thread_executor.h",
|
||||
"mutex.h",
|
||||
"mutex_lock.h",
|
||||
"pipe.h",
|
||||
"scheduled_executor.h",
|
||||
"single_thread_executor.h",
|
||||
"submittable_executor.h",
|
||||
"system_clock.h",
|
||||
],
|
||||
visibility = [
|
||||
"//core_v2:__subpackages__",
|
||||
"//platform_v2/impl:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//platform_v2/api",
|
||||
"//platform_v2/base",
|
||||
"//platform_v2/base:util",
|
||||
"//absl/base:core_headers",
|
||||
"//absl/strings",
|
||||
"//absl/time",
|
||||
"//absl/types:any",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "logging",
|
||||
hdrs = [
|
||||
"logging.h",
|
||||
],
|
||||
visibility = [
|
||||
"//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__",
|
||||
"//core_v2:__subpackages__",
|
||||
"//platform_v2:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//platform:logging",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "public_test",
|
||||
srcs = [
|
||||
"atomic_boolean_test.cc",
|
||||
"atomic_reference_test.cc",
|
||||
"bluetooth_adapter_test.cc",
|
||||
"count_down_latch_test.cc",
|
||||
"crypto_test.cc",
|
||||
"file_test.cc",
|
||||
"future_test.cc",
|
||||
"logging_test.cc",
|
||||
"multi_thread_executor_test.cc",
|
||||
"mutex_test.cc",
|
||||
"pipe_test.cc",
|
||||
"scheduled_executor_test.cc",
|
||||
"single_thread_executor_test.cc",
|
||||
],
|
||||
shard_count = 16,
|
||||
deps = [
|
||||
":logging",
|
||||
":public",
|
||||
"//file/util:temp_path",
|
||||
"//platform_v2/base",
|
||||
"//platform_v2/impl/g3",
|
||||
"//testing/base/public:gunit_main",
|
||||
"//absl/strings",
|
||||
"//absl/synchronization",
|
||||
"//absl/time",
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,34 @@
|
||||
#ifndef PLATFORM_V2_PUBLIC_ATOMIC_BOOLEAN_H_
|
||||
#define PLATFORM_V2_PUBLIC_ATOMIC_BOOLEAN_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "platform_v2/api/atomic_boolean.h"
|
||||
#include "platform_v2/api/platform.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
// A boolean value that may be updated atomically.
|
||||
// See documentation in
|
||||
// https://source.corp.google.com/piper///depot/google3/platform_v2/api/atomic_boolean.h
|
||||
class AtomicBoolean final : public api::AtomicBoolean {
|
||||
public:
|
||||
using Platform = api::ImplementationPlatform;
|
||||
explicit AtomicBoolean(bool value = false)
|
||||
: impl_(Platform::CreateAtomicBoolean(value)) {}
|
||||
~AtomicBoolean() override = default;
|
||||
AtomicBoolean(AtomicBoolean&&) = default;
|
||||
AtomicBoolean& operator=(AtomicBoolean&&) = default;
|
||||
|
||||
bool Get() const override { return impl_->Get(); }
|
||||
bool Set(bool value) override { return impl_->Set(value); }
|
||||
|
||||
private:
|
||||
std::unique_ptr<api::AtomicBoolean> impl_;
|
||||
};
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_PUBLIC_ATOMIC_BOOLEAN_H_
|
||||
@@ -0,0 +1,24 @@
|
||||
#include "platform_v2/public/atomic_boolean.h"
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace {
|
||||
|
||||
TEST(AtomicBooleanTest, SetReturnsPrevoiusValue) {
|
||||
AtomicBoolean value(false);
|
||||
EXPECT_FALSE(value.Set(true));
|
||||
EXPECT_TRUE(value.Set(true));
|
||||
}
|
||||
|
||||
TEST(AtomicBooleanTest, GetReturnsWhatWasSet) {
|
||||
AtomicBoolean value(false);
|
||||
EXPECT_FALSE(value.Set(true));
|
||||
EXPECT_TRUE(value.Get());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,40 @@
|
||||
#ifndef PLATFORM_V2_PUBLIC_ATOMIC_REFERENCE_H_
|
||||
#define PLATFORM_V2_PUBLIC_ATOMIC_REFERENCE_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "platform_v2/api/atomic_reference.h"
|
||||
#include "platform_v2/api/platform.h"
|
||||
#include "absl/types/any.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
// An object reference that may be updated atomically.
|
||||
//
|
||||
// https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/AtomicReference.html
|
||||
template <typename T>
|
||||
class AtomicReference final : public api::AtomicReference<T> {
|
||||
public:
|
||||
using Platform = api::ImplementationPlatform;
|
||||
explicit AtomicReference(const T& value)
|
||||
: impl_(Platform::CreateAtomicReferenceAny(value)) {}
|
||||
explicit AtomicReference(T&& value)
|
||||
: impl_(Platform::CreateAtomicReferenceAny(std::move(value))) {}
|
||||
~AtomicReference() override = default;
|
||||
AtomicReference(AtomicReference&&) = default;
|
||||
AtomicReference& operator=(AtomicReference&&) = default;
|
||||
|
||||
T Get() const& override { return absl::any_cast<T>(impl_->Get()); }
|
||||
T Get() && override { return absl::any_cast<T>(std::move(impl_->Get())); }
|
||||
void Set(const T& value) override { impl_->Set(absl::any(value)); }
|
||||
void Set(T&& value) override { impl_->Set(absl::any(value)); }
|
||||
|
||||
private:
|
||||
std::unique_ptr<api::AtomicReference<absl::any>> impl_;
|
||||
};
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_PUBLIC_ATOMIC_REFERENCE_H_
|
||||
@@ -0,0 +1,75 @@
|
||||
#include "platform_v2/public/atomic_reference.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace {
|
||||
|
||||
struct BigSizedStruct {
|
||||
int data[100]{};
|
||||
};
|
||||
|
||||
enum TestEnum {
|
||||
kValue1 = 1,
|
||||
kValue2 = 2,
|
||||
};
|
||||
|
||||
enum class ScopedTestEnum {
|
||||
kValue1 = 1,
|
||||
kValue2 = 2,
|
||||
};
|
||||
|
||||
bool operator==(const BigSizedStruct& a, const BigSizedStruct& b) {
|
||||
return memcmp(a.data, b.data, sizeof(BigSizedStruct::data)) == 0;
|
||||
}
|
||||
|
||||
bool operator!=(const BigSizedStruct& a, const BigSizedStruct& b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(AtomicReferenceTest, SupportIntegralTypes) {
|
||||
AtomicReference<int> atomic_ref({});
|
||||
atomic_ref.Set(5);
|
||||
EXPECT_EQ(atomic_ref.Get(), 5);
|
||||
}
|
||||
|
||||
TEST(AtomicReferenceTest, SupportEnum) {
|
||||
AtomicReference<TestEnum> atomic_ref({});
|
||||
atomic_ref.Set(TestEnum::kValue1);
|
||||
EXPECT_EQ(atomic_ref.Get(), TestEnum::kValue1);
|
||||
}
|
||||
|
||||
TEST(AtomicReferenceTest, SupportScopedEnum) {
|
||||
AtomicReference<ScopedTestEnum> atomic_ref({});
|
||||
atomic_ref.Set(ScopedTestEnum::kValue1);
|
||||
EXPECT_EQ(atomic_ref.Get(), ScopedTestEnum::kValue1);
|
||||
}
|
||||
|
||||
TEST(AtomicReferenceTest, SetTakesCopyOfValue) {
|
||||
// Default constructor is zero-initalizing all data in BigSizedStruct.
|
||||
BigSizedStruct v1;
|
||||
AtomicReference<BigSizedStruct> atomic_ref({});
|
||||
v1.data[0] = 5; // Changing value before calling set() will affect stored
|
||||
v1.data[7] = 3; // value.
|
||||
atomic_ref.Set(v1);
|
||||
v1.data[1] = 6; // Changing value after calling set() will not affect stored
|
||||
v1.data[5] = 4; // value.
|
||||
BigSizedStruct v2 = atomic_ref.Get();
|
||||
EXPECT_NE(v1, v2);
|
||||
v1.data[1] = 0;
|
||||
v1.data[5] = 0;
|
||||
EXPECT_EQ(v2, v1);
|
||||
}
|
||||
|
||||
TEST(AtomicReferenceTest, SupportObjects) {
|
||||
std::string s{"test"};
|
||||
AtomicReference<std::string> atomic_ref({});
|
||||
atomic_ref.Set(s);
|
||||
EXPECT_EQ(s, atomic_ref.Get());
|
||||
}
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,63 @@
|
||||
#ifndef PLATFORM_V2_PUBLIC_BLUETOOTH_ADAPTER_H_
|
||||
#define PLATFORM_V2_PUBLIC_BLUETOOTH_ADAPTER_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "platform_v2/api/bluetooth_adapter.h"
|
||||
#include "platform_v2/api/platform.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html
|
||||
class BluetoothAdapter : public api::BluetoothAdapter {
|
||||
public:
|
||||
using Status = api::BluetoothAdapter::Status;
|
||||
using ScanMode = api::BluetoothAdapter::ScanMode;
|
||||
|
||||
BluetoothAdapter()
|
||||
: impl_(api::ImplementationPlatform::CreateBluetoothAdapter()) {}
|
||||
~BluetoothAdapter() override = default;
|
||||
BluetoothAdapter(BluetoothAdapter&&) = default;
|
||||
BluetoothAdapter& operator=(BluetoothAdapter&&) = default;
|
||||
|
||||
// Synchronously sets the status of the BluetoothAdapter to 'status', and
|
||||
// returns true if the operation was a success.
|
||||
bool SetStatus(Status status) override { return impl_->SetStatus(status); }
|
||||
Status GetStatus() const {
|
||||
return IsEnabled() ? Status::kEnabled : Status::kDisabled;
|
||||
}
|
||||
|
||||
// Returns true if the BluetoothAdapter's current status is
|
||||
// Status::Value::kEnabled.
|
||||
bool IsEnabled() const override { return impl_->IsEnabled(); }
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#getScanMode()
|
||||
//
|
||||
// Returns ScanMode::kUnknown on error.
|
||||
ScanMode GetScanMode() const override { return impl_->GetScanMode(); }
|
||||
|
||||
// Synchronously sets the scan mode of the adapter, and returns true if the
|
||||
// operation was a success.
|
||||
bool SetScanMode(ScanMode scan_mode) override {
|
||||
return impl_->SetScanMode(scan_mode);
|
||||
}
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#getName()
|
||||
// Returns an empty string on error
|
||||
std::string GetName() const override { return impl_->GetName(); }
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#setName(java.lang.String)
|
||||
bool SetName(absl::string_view name) override { return impl_->SetName(name); }
|
||||
|
||||
bool IsValid() const { return impl_ != nullptr; }
|
||||
|
||||
private:
|
||||
std::unique_ptr<api::BluetoothAdapter> impl_;
|
||||
};
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_PUBLIC_BLUETOOTH_ADAPTER_H_
|
||||
@@ -0,0 +1,44 @@
|
||||
#include "platform_v2/public/bluetooth_adapter.h"
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace {
|
||||
|
||||
TEST(BluetoothAdapterTest, ConstructorDestructorWorks) {
|
||||
BluetoothAdapter adapter;
|
||||
EXPECT_TRUE(adapter.IsValid());
|
||||
}
|
||||
|
||||
TEST(BluetoothAdapterTest, CanSetName) {
|
||||
constexpr char kAdapterName[] = "MyBtAdapter";
|
||||
BluetoothAdapter adapter;
|
||||
EXPECT_EQ(adapter.GetStatus(), BluetoothAdapter::Status::kDisabled);
|
||||
EXPECT_TRUE(adapter.SetName(kAdapterName));
|
||||
EXPECT_EQ(adapter.GetName(), std::string(kAdapterName));
|
||||
}
|
||||
|
||||
TEST(BluetoothAdapterTest, CanSetStatus) {
|
||||
BluetoothAdapter adapter;
|
||||
EXPECT_EQ(adapter.GetStatus(), BluetoothAdapter::Status::kDisabled);
|
||||
EXPECT_TRUE(adapter.SetStatus(BluetoothAdapter::Status::kEnabled));
|
||||
EXPECT_EQ(adapter.GetStatus(), BluetoothAdapter::Status::kEnabled);
|
||||
}
|
||||
|
||||
TEST(BluetoothAdapterTest, CanSetMode) {
|
||||
BluetoothAdapter adapter;
|
||||
EXPECT_TRUE(adapter.SetScanMode(BluetoothAdapter::ScanMode::kConnectable));
|
||||
EXPECT_EQ(adapter.GetScanMode(), BluetoothAdapter::ScanMode::kConnectable);
|
||||
EXPECT_TRUE(adapter.SetScanMode(
|
||||
BluetoothAdapter::ScanMode::kConnectableDiscoverable));
|
||||
EXPECT_EQ(adapter.GetScanMode(),
|
||||
BluetoothAdapter::ScanMode::kConnectableDiscoverable);
|
||||
EXPECT_TRUE(adapter.SetScanMode(BluetoothAdapter::ScanMode::kNone));
|
||||
EXPECT_EQ(adapter.GetScanMode(), BluetoothAdapter::ScanMode::kNone);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,36 @@
|
||||
#ifndef PLATFORM_V2_PUBLIC_CANCELABLE_H_
|
||||
#define PLATFORM_V2_PUBLIC_CANCELABLE_H_
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "platform_v2/api/cancelable.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
// An interface to provide a cancellation mechanism for objects that represent
|
||||
// long-running operations.
|
||||
class Cancelable final {
|
||||
public:
|
||||
Cancelable() = default;
|
||||
Cancelable(const Cancelable&) = default;
|
||||
Cancelable& operator=(const Cancelable& other) = default;
|
||||
|
||||
~Cancelable() = default;
|
||||
|
||||
// This constructor is used internally only,
|
||||
// by other classes in "//platform_v2/public/".
|
||||
explicit Cancelable(std::shared_ptr<api::Cancelable> impl)
|
||||
: impl_(std::move(impl)) {}
|
||||
|
||||
bool Cancel() { return impl_->Cancel(); }
|
||||
|
||||
private:
|
||||
std::shared_ptr<api::Cancelable> impl_;
|
||||
};
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_PUBLIC_CANCELABLE_H_
|
||||
@@ -0,0 +1,56 @@
|
||||
#ifndef PLATFORM_V2_PUBLIC_CANCELABLE_ALARM_H_
|
||||
#define PLATFORM_V2_PUBLIC_CANCELABLE_ALARM_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "platform_v2/public/cancelable.h"
|
||||
#include "platform_v2/public/mutex.h"
|
||||
#include "platform_v2/public/mutex_lock.h"
|
||||
#include "platform_v2/public/scheduled_executor.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
/**
|
||||
* A cancelable alarm with a name. This is a simple wrapper around the logic
|
||||
* for posting a Runnable on a ScheduledExecutor and (possibly) later
|
||||
* canceling it.
|
||||
*/
|
||||
class CancelableAlarm {
|
||||
public:
|
||||
CancelableAlarm(absl::string_view name, std::function<void()>&& runnable,
|
||||
absl::Duration delay, ScheduledExecutor* scheduled_executor)
|
||||
: name_(name),
|
||||
cancelable_(scheduled_executor->Schedule(std::move(runnable), delay)) {}
|
||||
~CancelableAlarm() = default;
|
||||
CancelableAlarm(CancelableAlarm&& other) {
|
||||
*this = std::move(other);
|
||||
}
|
||||
CancelableAlarm& operator=(CancelableAlarm&& other) {
|
||||
MutexLock lock(&mutex_);
|
||||
{
|
||||
MutexLock other_lock(&other.mutex_);
|
||||
name_ = std::move(other.name_);
|
||||
cancelable_ = std::move(other.cancelable_);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool Cancel() {
|
||||
MutexLock lock(&mutex_);
|
||||
return cancelable_.Cancel();
|
||||
}
|
||||
|
||||
private:
|
||||
Mutex mutex_;
|
||||
std::string name_;
|
||||
Cancelable cancelable_;
|
||||
};
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_PUBLIC_CANCELABLE_ALARM_H_
|
||||
@@ -0,0 +1,36 @@
|
||||
#ifndef PLATFORM_V2_PUBLIC_CONDITION_VARIABLE_H_
|
||||
#define PLATFORM_V2_PUBLIC_CONDITION_VARIABLE_H_
|
||||
|
||||
#include "platform_v2/api/condition_variable.h"
|
||||
#include "platform_v2/api/platform.h"
|
||||
#include "platform_v2/base/exception.h"
|
||||
#include "platform_v2/public/mutex.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
// The ConditionVariable class is a synchronization primitive that can be used
|
||||
// to block a thread, or multiple threads at the same time, until another thread
|
||||
// both modifies a shared variable (the condition), and notifies the
|
||||
// ConditionVariable.
|
||||
class ConditionVariable final {
|
||||
public:
|
||||
using Platform = api::ImplementationPlatform;
|
||||
explicit ConditionVariable(Mutex* mutex)
|
||||
: impl_(Platform::CreateConditionVariable(mutex->impl_.get())) {}
|
||||
ConditionVariable(ConditionVariable&&) = default;
|
||||
ConditionVariable& operator=(ConditionVariable&&) = default;
|
||||
|
||||
// https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#notify--
|
||||
void Notify() { impl_->Notify(); }
|
||||
// https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#wait--
|
||||
Exception Wait() { return impl_->Wait(); }
|
||||
|
||||
private:
|
||||
std::unique_ptr<api::ConditionVariable> impl_;
|
||||
};
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_PUBLIC_CONDITION_VARIABLE_H_
|
||||
@@ -0,0 +1,40 @@
|
||||
#ifndef PLATFORM_V2_PUBLIC_COUNT_DOWN_LATCH_H_
|
||||
#define PLATFORM_V2_PUBLIC_COUNT_DOWN_LATCH_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "platform_v2/api/count_down_latch.h"
|
||||
#include "platform_v2/api/platform.h"
|
||||
#include "platform_v2/base/exception.h"
|
||||
#include "absl/time/time.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
// A synchronization aid that allows one or more threads to wait until a set of
|
||||
// operations being performed in other threads completes.
|
||||
//
|
||||
// https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CountDownLatch.html
|
||||
class CountDownLatch final {
|
||||
public:
|
||||
using Platform = api::ImplementationPlatform;
|
||||
explicit CountDownLatch(int count)
|
||||
: impl_(Platform::CreateCountDownLatch(count)) {}
|
||||
CountDownLatch(CountDownLatch&&) = default;
|
||||
CountDownLatch& operator=(CountDownLatch&&) = default;
|
||||
~CountDownLatch() = default;
|
||||
|
||||
Exception Await() { return impl_->Await(); }
|
||||
ExceptionOr<bool> Await(absl::Duration timeout) {
|
||||
return impl_->Await(timeout);
|
||||
}
|
||||
void CountDown() { impl_->CountDown(); }
|
||||
|
||||
private:
|
||||
std::unique_ptr<api::CountDownLatch> impl_;
|
||||
};
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_PUBLIC_COUNT_DOWN_LATCH_H_
|
||||
@@ -0,0 +1,48 @@
|
||||
#include "platform_v2/public/count_down_latch.h"
|
||||
|
||||
#include "platform_v2/public/single_thread_executor.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace {
|
||||
|
||||
TEST(CountDownLatch, ConstructorDestructorWorks) { CountDownLatch latch(1); }
|
||||
|
||||
TEST(CountDownLatch, LatchAwaitCanWait) {
|
||||
CountDownLatch latch(1);
|
||||
SingleThreadExecutor executor;
|
||||
std::atomic_bool done = false;
|
||||
executor.Execute([&done, &latch]() {
|
||||
done = true;
|
||||
latch.CountDown();
|
||||
});
|
||||
latch.Await();
|
||||
EXPECT_TRUE(done);
|
||||
}
|
||||
|
||||
TEST(CountDownLatch, LatchExtraCountDownIgnored) {
|
||||
CountDownLatch latch(1);
|
||||
SingleThreadExecutor executor;
|
||||
std::atomic_bool done = false;
|
||||
executor.Execute([&done, &latch]() {
|
||||
done = true;
|
||||
latch.CountDown();
|
||||
latch.CountDown();
|
||||
latch.CountDown();
|
||||
});
|
||||
latch.Await();
|
||||
EXPECT_TRUE(done);
|
||||
}
|
||||
|
||||
TEST(CountDownLatch, LatchAwaitWithTimeoutCanExpire) {
|
||||
CountDownLatch latch(1);
|
||||
SingleThreadExecutor executor;
|
||||
auto response = latch.Await(absl::Milliseconds(100));
|
||||
EXPECT_TRUE(response.ok());
|
||||
EXPECT_FALSE(response.result());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef PLATFORM_V2_PUBLIC_CRYPTO_H_
|
||||
#define PLATFORM_V2_PUBLIC_CRYPTO_H_
|
||||
|
||||
#include "platform_v2/api/crypto.h"
|
||||
|
||||
#endif // PLATFORM_V2_PUBLIC_CRYPTO_H_
|
||||
@@ -0,0 +1,34 @@
|
||||
#include "platform_v2/public/crypto.h"
|
||||
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
TEST(CryptoTest, Md5GeneratesHash) {
|
||||
const ByteArray expected_md5(
|
||||
"\xb4\x5c\xff\xe0\x84\xdd\x3d\x20\xd9\x28\xbe\xe8\x5e\x7b\x0f\x21");
|
||||
ByteArray md5_hash = Crypto::Md5("string");
|
||||
EXPECT_EQ(md5_hash, expected_md5);
|
||||
}
|
||||
|
||||
TEST(CryptoTest, Md5ReturnsEmptyOnError) {
|
||||
EXPECT_EQ(Crypto::Md5(""), ByteArray{});
|
||||
}
|
||||
|
||||
TEST(CryptoTest, Sha256GeneratesHash) {
|
||||
const ByteArray expected_sha256(
|
||||
"\x47\x32\x87\xf8\x29\x8d\xba\x71\x63\xa8\x97\x90\x89\x58\xf7\xc0"
|
||||
"\xea\xe7\x33\xe2\x5d\x2e\x02\x79\x92\xea\x2e\xdc\x9b\xed\x2f\xa8");
|
||||
ByteArray sha256_hash = Crypto::Sha256("string");
|
||||
EXPECT_EQ(sha256_hash, expected_sha256);
|
||||
}
|
||||
|
||||
TEST(CryptoTest, Sha256ReturnsEmptyOnError) {
|
||||
EXPECT_EQ(Crypto::Sha256(""), ByteArray{});
|
||||
}
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,79 @@
|
||||
#include "platform_v2/public/file.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
|
||||
#include "platform_v2/base/exception.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
// InputFile
|
||||
|
||||
InputFile::InputFile(const std::string& path, std::int64_t size)
|
||||
: file_(path), path_(path), total_size_(size) {}
|
||||
|
||||
ExceptionOr<ByteArray> InputFile::Read(std::int64_t size) {
|
||||
if (!file_.is_open()) {
|
||||
return ExceptionOr<ByteArray>{Exception::kIo};
|
||||
}
|
||||
|
||||
if (file_.peek() == EOF) {
|
||||
return ExceptionOr<ByteArray>{ByteArray{}};
|
||||
}
|
||||
|
||||
if (!file_.good()) {
|
||||
return ExceptionOr<ByteArray>{Exception::kIo};
|
||||
}
|
||||
|
||||
ByteArray bytes(size);
|
||||
std::unique_ptr<char[]> read_bytes{new char[size]};
|
||||
file_.read(read_bytes.get(), static_cast<ptrdiff_t>(size));
|
||||
auto num_bytes_read = file_.gcount();
|
||||
if (num_bytes_read == 0) {
|
||||
return ExceptionOr<ByteArray>{Exception::kIo};
|
||||
}
|
||||
|
||||
return ExceptionOr<ByteArray>(ByteArray(read_bytes.get(), num_bytes_read));
|
||||
}
|
||||
|
||||
Exception InputFile::Close() {
|
||||
if (file_.is_open()) {
|
||||
file_.close();
|
||||
}
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
|
||||
// OutputFile
|
||||
|
||||
OutputFile::OutputFile(absl::string_view path) : file_(path) {}
|
||||
|
||||
Exception OutputFile::Write(const ByteArray& data) {
|
||||
if (!file_.is_open()) {
|
||||
return {Exception::kIo};
|
||||
}
|
||||
|
||||
if (!file_.good()) {
|
||||
return {Exception::kIo};
|
||||
}
|
||||
|
||||
file_.write(data.data(), data.size());
|
||||
file_.flush();
|
||||
return {file_.good() ? Exception::kSuccess : Exception::kIo};
|
||||
}
|
||||
|
||||
Exception OutputFile::Flush() {
|
||||
file_.flush();
|
||||
return {file_.good() ? Exception::kSuccess : Exception::kIo};
|
||||
}
|
||||
|
||||
Exception OutputFile::Close() {
|
||||
if (file_.is_open()) {
|
||||
file_.close();
|
||||
}
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,51 @@
|
||||
#ifndef PLATFORM_V2_PUBLIC_FILE_H_
|
||||
#define PLATFORM_V2_PUBLIC_FILE_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
|
||||
#include "platform_v2/api/input_file.h"
|
||||
#include "platform_v2/api/output_file.h"
|
||||
#include "platform_v2/base/exception.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
class InputFile final : public api::InputFile {
|
||||
public:
|
||||
explicit InputFile(const std::string& path, std::int64_t size);
|
||||
~InputFile() override = default;
|
||||
InputFile(InputFile&&) = default;
|
||||
InputFile& operator=(InputFile&&) = default;
|
||||
|
||||
ExceptionOr<ByteArray> Read(std::int64_t size) override;
|
||||
std::string GetFilePath() const override { return path_; }
|
||||
std::int64_t GetTotalSize() const override { return total_size_; }
|
||||
Exception Close() override;
|
||||
|
||||
private:
|
||||
std::ifstream file_;
|
||||
std::string path_;
|
||||
std::int64_t total_size_;
|
||||
};
|
||||
|
||||
class OutputFile final : public api::OutputFile {
|
||||
public:
|
||||
explicit OutputFile(absl::string_view path);
|
||||
~OutputFile() override = default;
|
||||
OutputFile(OutputFile&&) = default;
|
||||
OutputFile& operator=(OutputFile&&) = default;
|
||||
|
||||
Exception Write(const ByteArray& data) override;
|
||||
Exception Flush() override;
|
||||
Exception Close() override;
|
||||
|
||||
private:
|
||||
std::ofstream file_;
|
||||
};
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_PUBLIC_FILE_H_
|
||||
@@ -0,0 +1,131 @@
|
||||
#include "platform_v2/public/file.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
|
||||
#include "file/util/temp_path.h"
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
class FileTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
temp_path_ = std::make_unique<TempPath>(TempPath::Local);
|
||||
path_ = temp_path_->path() + "/file.txt";
|
||||
std::ofstream output_file(path_);
|
||||
file_ = std::fstream(path_, std::fstream::in | std::fstream::out);
|
||||
}
|
||||
|
||||
void WriteToFile(const std::string& text) {
|
||||
file_ << text;
|
||||
file_.flush();
|
||||
size_ += text.size();
|
||||
}
|
||||
|
||||
size_t GetSize() const { return size_; }
|
||||
|
||||
void AssertEquals(const ExceptionOr<ByteArray>& bytes,
|
||||
const std::string& expected) {
|
||||
EXPECT_TRUE(bytes.ok());
|
||||
EXPECT_EQ(std::string(bytes.result()), expected);
|
||||
}
|
||||
|
||||
void AssertEmpty(const ExceptionOr<ByteArray>& bytes) {
|
||||
EXPECT_TRUE(bytes.ok());
|
||||
EXPECT_TRUE(bytes.result().Empty());
|
||||
}
|
||||
|
||||
static constexpr int64_t kMaxSize = 3;
|
||||
|
||||
std::unique_ptr<TempPath> temp_path_;
|
||||
std::string path_;
|
||||
std::fstream file_;
|
||||
size_t size_ = 0;
|
||||
};
|
||||
|
||||
TEST_F(FileTest, InputFile_NonExistentPath) {
|
||||
InputFile input_file("/not/a/valid/path.txt", GetSize());
|
||||
ExceptionOr<ByteArray> read_result = input_file.Read(kMaxSize);
|
||||
EXPECT_FALSE(read_result.ok());
|
||||
EXPECT_TRUE(read_result.GetException().Raised(Exception::kIo));
|
||||
}
|
||||
|
||||
TEST_F(FileTest, InputFile_GetFilePath) {
|
||||
InputFile input_file(path_, GetSize());
|
||||
EXPECT_EQ(input_file.GetFilePath(), path_);
|
||||
}
|
||||
|
||||
TEST_F(FileTest, InputFile_EmptyFileEOF) {
|
||||
InputFile input_file(path_, GetSize());
|
||||
AssertEmpty(input_file.Read(kMaxSize));
|
||||
}
|
||||
|
||||
TEST_F(FileTest, InputFile_ReadWorks) {
|
||||
WriteToFile("abc");
|
||||
InputFile input_file(path_, GetSize());
|
||||
input_file.Read(kMaxSize);
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST_F(FileTest, InputFile_ReadUntilEOF) {
|
||||
WriteToFile("abc");
|
||||
InputFile input_file(path_, GetSize());
|
||||
AssertEquals(input_file.Read(kMaxSize), "abc");
|
||||
AssertEmpty(input_file.Read(kMaxSize));
|
||||
}
|
||||
|
||||
TEST_F(FileTest, InputFile_ReadWithSize) {
|
||||
WriteToFile("abc");
|
||||
InputFile input_file(path_, GetSize());
|
||||
AssertEquals(input_file.Read(2), "ab");
|
||||
AssertEquals(input_file.Read(1), "c");
|
||||
AssertEmpty(input_file.Read(kMaxSize));
|
||||
}
|
||||
|
||||
TEST_F(FileTest, InputFile_GetTotalSize) {
|
||||
WriteToFile("abc");
|
||||
InputFile input_file(path_, GetSize());
|
||||
EXPECT_EQ(input_file.GetTotalSize(), 3);
|
||||
AssertEquals(input_file.Read(1), "a");
|
||||
EXPECT_EQ(input_file.GetTotalSize(), 3);
|
||||
}
|
||||
|
||||
TEST_F(FileTest, InputFile_Close) {
|
||||
WriteToFile("abc");
|
||||
InputFile input_file(path_, GetSize());
|
||||
input_file.Close();
|
||||
ExceptionOr<ByteArray> read_result = input_file.Read(kMaxSize);
|
||||
EXPECT_FALSE(read_result.ok());
|
||||
EXPECT_TRUE(read_result.GetException().Raised(Exception::kIo));
|
||||
}
|
||||
|
||||
TEST_F(FileTest, OutputFile_NonExistentPath) {
|
||||
OutputFile output_file("/not/a/valid/path.txt");
|
||||
ByteArray bytes("a", 1);
|
||||
EXPECT_TRUE(output_file.Write(bytes).Raised(Exception::kIo));
|
||||
}
|
||||
|
||||
TEST_F(FileTest, OutputFile_Write) {
|
||||
OutputFile output_file(path_);
|
||||
ByteArray bytes1("a");
|
||||
ByteArray bytes2("bc");
|
||||
EXPECT_EQ(output_file.Write(bytes1), Exception{Exception::kSuccess});
|
||||
EXPECT_EQ(output_file.Write(bytes2), Exception{Exception::kSuccess});
|
||||
InputFile input_file(path_, GetSize());
|
||||
AssertEquals(input_file.Read(kMaxSize), "abc");
|
||||
}
|
||||
|
||||
TEST_F(FileTest, OutputFile_Close) {
|
||||
OutputFile output_file(path_);
|
||||
output_file.Close();
|
||||
ByteArray bytes("a");
|
||||
EXPECT_EQ(output_file.Write(bytes), Exception{Exception::kIo});
|
||||
}
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,63 @@
|
||||
#ifndef PLATFORM_V2_PUBLIC_FUTURE_H_
|
||||
#define PLATFORM_V2_PUBLIC_FUTURE_H_
|
||||
|
||||
#include "platform_v2/api/executor.h"
|
||||
#include "platform_v2/api/platform.h"
|
||||
#include "platform_v2/api/settable_future.h"
|
||||
#include "platform_v2/base/exception.h"
|
||||
#include "platform_v2/base/runnable.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "absl/types/any.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
template <typename T>
|
||||
class Future final : public api::SettableFuture<T> {
|
||||
public:
|
||||
using Platform = api::ImplementationPlatform;
|
||||
~Future() override = default;
|
||||
Future() : impl_(Platform::CreateSettableFutureAny().release()) {}
|
||||
Future(Future&& other) = default;
|
||||
Future& operator=(Future&& other) = default;
|
||||
|
||||
void AddListener(Runnable runnable, api::Executor* executor) override {
|
||||
impl_->AddListener(runnable, executor);
|
||||
}
|
||||
bool Set(const T& value) override { return impl_->Set(absl::any(value)); }
|
||||
bool Set(T&& value) override { return impl_->Set(absl::any(value)); }
|
||||
bool SetException(Exception exception) override {
|
||||
return impl_->SetException(exception);
|
||||
}
|
||||
// throws Exception::kInterrupted, Exception::kExecution
|
||||
ExceptionOr<T> Get() override {
|
||||
auto ret_val = impl_->Get();
|
||||
if (ret_val.ok()) {
|
||||
T result = std::any_cast<T>(ret_val.result());
|
||||
return ExceptionOr<T>{result};
|
||||
} else {
|
||||
return ExceptionOr<T>{ret_val.exception()};
|
||||
}
|
||||
}
|
||||
|
||||
// throws Exception::kInterrupted, Exception::kExecution
|
||||
// throws Exception::kTimeout if timeout is exceeded while waiting for
|
||||
// result.
|
||||
ExceptionOr<T> Get(absl::Duration timeout) override {
|
||||
auto ret_val = impl_->Get(timeout);
|
||||
if (ret_val.ok()) {
|
||||
T result = std::any_cast<T>(ret_val.result());
|
||||
return ExceptionOr<T>{result};
|
||||
} else {
|
||||
return ExceptionOr<T>{ret_val.exception()};
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<api::SettableFuture<absl::any>> impl_;
|
||||
};
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_PUBLIC_FUTURE_H_
|
||||
@@ -0,0 +1,102 @@
|
||||
#include "platform_v2/public/future.h"
|
||||
|
||||
#include "platform_v2/public/single_thread_executor.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/time/clock.h"
|
||||
#include "absl/time/time.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
namespace {
|
||||
|
||||
enum TestEnum {
|
||||
kValue1 = 1,
|
||||
kValue2 = 2,
|
||||
};
|
||||
|
||||
enum class ScopedTestEnum {
|
||||
kValue1 = 1,
|
||||
kValue2 = 2,
|
||||
};
|
||||
|
||||
struct BigSizedStruct {
|
||||
int data[100]{};
|
||||
};
|
||||
|
||||
bool operator==(const BigSizedStruct& a, const BigSizedStruct& b) {
|
||||
return memcmp(a.data, b.data, sizeof(BigSizedStruct::data)) == 0;
|
||||
}
|
||||
|
||||
bool operator!=(const BigSizedStruct& a, const BigSizedStruct& b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(FutureTest, SupportIntegralTypes) {
|
||||
Future<int> future;
|
||||
future.Set(5);
|
||||
EXPECT_EQ(future.Get().exception(), Exception::kSuccess);
|
||||
EXPECT_EQ(future.Get().result(), 5);
|
||||
}
|
||||
|
||||
TEST(FutureTest, SetExceptionIsPropagated) {
|
||||
Future<int> future;
|
||||
future.SetException({Exception::kIo});
|
||||
EXPECT_EQ(future.Get().exception(), Exception::kIo);
|
||||
}
|
||||
|
||||
TEST(FutureTest, SupportEnum) {
|
||||
Future<TestEnum> future;
|
||||
future.Set(TestEnum::kValue1);
|
||||
EXPECT_EQ(future.Get().exception(), Exception::kSuccess);
|
||||
EXPECT_EQ(future.Get().result(), TestEnum::kValue1);
|
||||
}
|
||||
|
||||
TEST(FutureTest, SupportScopedEnum) {
|
||||
Future<ScopedTestEnum> future;
|
||||
future.Set(ScopedTestEnum::kValue1);
|
||||
EXPECT_EQ(future.Get().exception(), Exception::kSuccess);
|
||||
EXPECT_EQ(future.Get().result(), ScopedTestEnum::kValue1);
|
||||
}
|
||||
|
||||
TEST(FutureTest, SetTakesCopyOfValue) {
|
||||
// Default constructor is zero-initalizing all data in BigSizedStruct.
|
||||
BigSizedStruct v1;
|
||||
Future<BigSizedStruct> future;
|
||||
v1.data[0] = 5; // Changing value before calling Set() will affect stored
|
||||
v1.data[7] = 3; // value.
|
||||
future.Set(v1);
|
||||
v1.data[1] = 6; // Changing value after calling Set() will not affect stored
|
||||
v1.data[5] = 4; // value.
|
||||
EXPECT_EQ(future.Get().exception(), Exception::kSuccess);
|
||||
BigSizedStruct v2 = future.Get().result();
|
||||
EXPECT_NE(v1, v2);
|
||||
v1.data[1] = 0;
|
||||
v1.data[5] = 0;
|
||||
EXPECT_EQ(v2, v1);
|
||||
}
|
||||
|
||||
TEST(FutureTest, SetsExceptionOnTimeout) {
|
||||
Future<int> future;
|
||||
EXPECT_EQ(future.Get(absl::Milliseconds(100)).exception(),
|
||||
Exception::kTimeout);
|
||||
}
|
||||
|
||||
TEST(FutureTest, GetBlocksWhenNotReady) {
|
||||
Future<int> future;
|
||||
SingleThreadExecutor executor;
|
||||
absl::Time start = absl::Now();
|
||||
executor.Execute([&future](){
|
||||
absl::SleepFor(absl::Milliseconds(500));
|
||||
future.Set(10);
|
||||
});
|
||||
auto response = future.Get();
|
||||
absl::Duration blocked_duration = absl::Now() - start;
|
||||
EXPECT_EQ(response.result(), 10);
|
||||
EXPECT_GE(blocked_duration, absl::Milliseconds(500));
|
||||
}
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef PLATFORM_V2_PUBLIC_LOGGING_H_
|
||||
#define PLATFORM_V2_PUBLIC_LOGGING_H_
|
||||
|
||||
#include "platform/logging.h"
|
||||
|
||||
#endif // PLATFORM_V2_PUBLIC_LOGGING_H_
|
||||
@@ -0,0 +1,12 @@
|
||||
#include "platform_v2/public/logging.h"
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace {
|
||||
|
||||
TEST(LoggingTest, CanLog) {
|
||||
NEARBY_LOG(INFO, "message");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#ifndef PLATFORM_V2_PUBLIC_MULTI_THREAD_EXECUTOR_H_
|
||||
#define PLATFORM_V2_PUBLIC_MULTI_THREAD_EXECUTOR_H_
|
||||
|
||||
#include "platform_v2/api/platform.h"
|
||||
#include "platform_v2/public/submittable_executor.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
// An Executor that reuses a fixed number of threads operating off a shared
|
||||
// unbounded queue.
|
||||
//
|
||||
// https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html#newFixedThreadPool-int-
|
||||
class MultiThreadExecutor final : public SubmittableExecutor {
|
||||
public:
|
||||
using Platform = api::ImplementationPlatform;
|
||||
explicit MultiThreadExecutor(int max_parallelism)
|
||||
: SubmittableExecutor(
|
||||
Platform::CreateMultiThreadExecutor(max_parallelism)) {}
|
||||
MultiThreadExecutor(MultiThreadExecutor&&) = default;
|
||||
MultiThreadExecutor& operator=(MultiThreadExecutor&&) = default;
|
||||
~MultiThreadExecutor() override = default;
|
||||
};
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_PUBLIC_MULTI_THREAD_EXECUTOR_H_
|
||||
@@ -0,0 +1,94 @@
|
||||
#include "platform_v2/public/multi_thread_executor.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
|
||||
#include "platform_v2/base/exception.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "absl/time/clock.h"
|
||||
#include "absl/time/time.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
namespace {
|
||||
const int kMaxThreads = 5;
|
||||
}
|
||||
|
||||
TEST(MultiThreadExecutorTest, ConsructorDestructorWorks) {
|
||||
MultiThreadExecutor executor(kMaxThreads);
|
||||
}
|
||||
|
||||
TEST(MultiThreadExecutorTest, CanExecute) {
|
||||
absl::CondVar cond;
|
||||
std::atomic_bool done = false;
|
||||
MultiThreadExecutor executor(kMaxThreads);
|
||||
executor.Execute([&done, &cond]() {
|
||||
done = true;
|
||||
cond.SignalAll();
|
||||
});
|
||||
absl::Mutex mutex;
|
||||
{
|
||||
absl::MutexLock lock(&mutex);
|
||||
if (!done) {
|
||||
cond.WaitWithTimeout(&mutex, absl::Seconds(1));
|
||||
}
|
||||
}
|
||||
EXPECT_TRUE(done);
|
||||
}
|
||||
|
||||
TEST(MultiThreadExecutorTest, JobsExecuteInParallel) {
|
||||
absl::Mutex mutex;
|
||||
absl::CondVar thread_cond;
|
||||
absl::CondVar test_cond;
|
||||
MultiThreadExecutor executor(kMaxThreads);
|
||||
int count = 0;
|
||||
|
||||
for (int i = 0; i < kMaxThreads; ++i) {
|
||||
executor.Execute([&count, &mutex, &test_cond, &thread_cond]() {
|
||||
absl::MutexLock lock(&mutex);
|
||||
count++;
|
||||
test_cond.Signal();
|
||||
thread_cond.Wait(&mutex);
|
||||
count--;
|
||||
test_cond.Signal();
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
absl::Duration duration = absl::Milliseconds(kMaxThreads * 100);
|
||||
absl::MutexLock lock(&mutex);
|
||||
while (count < kMaxThreads) {
|
||||
absl::Time start = absl::Now();
|
||||
if (test_cond.WaitWithTimeout(&mutex, duration)) break;
|
||||
duration -= absl::Now() - start;
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_EQ(count, kMaxThreads);
|
||||
thread_cond.SignalAll();
|
||||
|
||||
{
|
||||
absl::Duration duration = absl::Milliseconds(kMaxThreads * 100);
|
||||
absl::MutexLock lock(&mutex);
|
||||
while (count > 0) {
|
||||
absl::Time start = absl::Now();
|
||||
if (test_cond.WaitWithTimeout(&mutex, duration)) break;
|
||||
duration -= absl::Now() - start;
|
||||
}
|
||||
}
|
||||
EXPECT_EQ(count, 0);
|
||||
}
|
||||
|
||||
TEST(MultiThreadExecutorTest, CanSubmit) {
|
||||
MultiThreadExecutor executor(kMaxThreads);
|
||||
Future<bool> future;
|
||||
bool submitted =
|
||||
executor.Submit<bool>([]() { return ExceptionOr<bool>{true}; }, &future);
|
||||
EXPECT_TRUE(submitted);
|
||||
EXPECT_TRUE(future.Get().result());
|
||||
}
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,64 @@
|
||||
#ifndef PLATFORM_V2_PUBLIC_MUTEX_H_
|
||||
#define PLATFORM_V2_PUBLIC_MUTEX_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "platform_v2/api/mutex.h"
|
||||
#include "platform_v2/api/platform.h"
|
||||
#include "absl/base/thread_annotations.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
// This is a classic mutex can be acquired at most once.
|
||||
// Atttempt to acuire mutex from the same thread that is holding it will likely
|
||||
// cause a deadlock.
|
||||
class ABSL_LOCKABLE Mutex final {
|
||||
public:
|
||||
using Platform = api::ImplementationPlatform;
|
||||
using Mode = api::Mutex::Mode;
|
||||
|
||||
explicit Mutex(bool check = true)
|
||||
: impl_(Platform::CreateMutex(check ? Mode::kRegular
|
||||
: Mode::kRegularNoCheck)) {}
|
||||
Mutex(Mutex&&) = default;
|
||||
Mutex& operator=(Mutex&&) = default;
|
||||
~Mutex() = default;
|
||||
|
||||
void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() { impl_->Lock(); }
|
||||
void Unlock() ABSL_UNLOCK_FUNCTION() { impl_->Unlock(); }
|
||||
|
||||
private:
|
||||
friend class ConditionVariable;
|
||||
friend class MutexLock;
|
||||
std::unique_ptr<api::Mutex> impl_;
|
||||
};
|
||||
|
||||
// This mutex is compatible with Java definition:
|
||||
// https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/Lock.html
|
||||
// This mutex may be acuired multiple times by a thread that is already holding
|
||||
// it without blocking.
|
||||
// It needs to be released equal number of times before any other thread could
|
||||
// successfully acquire it.
|
||||
class ABSL_LOCKABLE RecursiveMutex final {
|
||||
public:
|
||||
using Platform = api::ImplementationPlatform;
|
||||
using Mode = api::Mutex::Mode;
|
||||
|
||||
RecursiveMutex() : impl_(Platform::CreateMutex(Mode::kRecursive)) {}
|
||||
RecursiveMutex(RecursiveMutex&&) = default;
|
||||
RecursiveMutex& operator=(RecursiveMutex&&) = default;
|
||||
~RecursiveMutex() = default;
|
||||
|
||||
void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() { impl_->Lock(); }
|
||||
void Unlock() ABSL_UNLOCK_FUNCTION() { impl_->Unlock(); }
|
||||
|
||||
private:
|
||||
friend class MutexLock;
|
||||
std::unique_ptr<api::Mutex> impl_;
|
||||
};
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_PUBLIC_MUTEX_H_
|
||||
@@ -0,0 +1,31 @@
|
||||
#ifndef PLATFORM_V2_PUBLIC_MUTEX_LOCK_H_
|
||||
#define PLATFORM_V2_PUBLIC_MUTEX_LOCK_H_
|
||||
|
||||
#include "platform_v2/api/mutex.h"
|
||||
#include "platform_v2/public/mutex.h"
|
||||
#include "absl/base/thread_annotations.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
// An RAII mechanism to acquire a Lock over a block of code.
|
||||
class ABSL_SCOPED_LOCKABLE MutexLock final {
|
||||
public:
|
||||
explicit MutexLock(Mutex* mutex) ABSL_EXCLUSIVE_LOCK_FUNCTION(mutex)
|
||||
: mutex_(mutex->impl_.get()) {
|
||||
mutex_->Lock();
|
||||
}
|
||||
explicit MutexLock(RecursiveMutex* mutex) ABSL_EXCLUSIVE_LOCK_FUNCTION(mutex)
|
||||
: mutex_(mutex->impl_.get()) {
|
||||
mutex_->Lock();
|
||||
}
|
||||
~MutexLock() ABSL_UNLOCK_FUNCTION() { mutex_->Unlock(); }
|
||||
|
||||
private:
|
||||
api::Mutex* mutex_;
|
||||
};
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_PUBLIC_MUTEX_LOCK_H_
|
||||
@@ -0,0 +1,103 @@
|
||||
#include "platform_v2/public/mutex.h"
|
||||
|
||||
#include "platform_v2/public/condition_variable.h"
|
||||
#include "platform_v2/public/single_thread_executor.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "absl/time/clock.h"
|
||||
#include "absl/time/time.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace {
|
||||
|
||||
class MutexTest : public testing::Test {
|
||||
public:
|
||||
void VerifyStepReached(int expected) {
|
||||
absl::MutexLock lock(&step_mutex_);
|
||||
absl::Time deadline = absl::Now() + kTimeToWait;
|
||||
while (step_ != expected) {
|
||||
if (step_cond_.WaitWithDeadline(&step_mutex_, deadline)) break;
|
||||
}
|
||||
EXPECT_EQ(step_, expected);
|
||||
// Make sure we are not progressing further.
|
||||
absl::SleepFor(kTimeToWait);
|
||||
EXPECT_EQ(step_, expected);
|
||||
}
|
||||
|
||||
protected:
|
||||
SingleThreadExecutor executor_;
|
||||
const absl::Duration kTimeToWait = absl::Milliseconds(200);
|
||||
std::atomic_int step_ = 0;
|
||||
absl::Mutex step_mutex_;
|
||||
absl::CondVar step_cond_;
|
||||
};
|
||||
|
||||
TEST_F(MutexTest, ConstructorDestructorWorks) {
|
||||
Mutex test_mutex;
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST_F(MutexTest, BasicLockingWorks) {
|
||||
Mutex test_mutex;
|
||||
test_mutex.Lock();
|
||||
executor_.Execute([this, &test_mutex]() {
|
||||
step_ = 1;
|
||||
step_cond_.Signal();
|
||||
test_mutex.Lock();
|
||||
test_mutex.Unlock();
|
||||
step_ = 2;
|
||||
step_cond_.Signal();
|
||||
});
|
||||
VerifyStepReached(1);
|
||||
test_mutex.Unlock();
|
||||
VerifyStepReached(2);
|
||||
}
|
||||
|
||||
#ifdef THREAD_SANITIZER
|
||||
TEST_F(MutexTest, DISABLED_DoubleLockIsDeadlock)
|
||||
ABSL_NO_THREAD_SAFETY_ANALYSIS {
|
||||
#else
|
||||
TEST_F(MutexTest, DoubleLockIsDeadlock) ABSL_NO_THREAD_SAFETY_ANALYSIS {
|
||||
#endif
|
||||
Mutex test_mutex{/*check=*/false}; // Disable run-time deadlock detection.
|
||||
test_mutex.Lock();
|
||||
executor_.Execute([this, &test_mutex]() ABSL_NO_THREAD_SAFETY_ANALYSIS {
|
||||
step_ = 1;
|
||||
step_cond_.Signal(); // We entered executor.
|
||||
test_mutex.Lock();
|
||||
step_ = 2;
|
||||
step_cond_.Signal(); // We acquired the test lock.
|
||||
test_mutex.Lock(); // Deadlock. (Main thread should save us).
|
||||
step_ = 3;
|
||||
step_cond_.Signal(); // We are done.
|
||||
});
|
||||
VerifyStepReached(1);
|
||||
test_mutex.Unlock(); // Let executor proceed to step 2.
|
||||
VerifyStepReached(2);
|
||||
test_mutex.Unlock(); // Bring executor out of deadlock.
|
||||
VerifyStepReached(3);
|
||||
test_mutex.Unlock(); // Unlock before shutdown.
|
||||
}
|
||||
|
||||
TEST_F(MutexTest, DoubleLockIsNotDeadlock) {
|
||||
RecursiveMutex test_mutex;
|
||||
test_mutex.Lock();
|
||||
executor_.Execute([this, &test_mutex]() ABSL_NO_THREAD_SAFETY_ANALYSIS {
|
||||
step_ = 1;
|
||||
step_cond_.Signal(); // We entered executor.
|
||||
test_mutex.Lock();
|
||||
test_mutex.Lock();
|
||||
test_mutex.Unlock();
|
||||
test_mutex.Unlock();
|
||||
step_ = 2;
|
||||
step_cond_.Signal(); // We are done.
|
||||
});
|
||||
VerifyStepReached(1);
|
||||
test_mutex.Unlock(); // Let executor continue.
|
||||
VerifyStepReached(2);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,21 @@
|
||||
#include "platform_v2/public/pipe.h"
|
||||
|
||||
#include "platform_v2/api/condition_variable.h"
|
||||
#include "platform_v2/api/mutex.h"
|
||||
#include "platform_v2/api/platform.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
namespace {
|
||||
using Platform = api::ImplementationPlatform;
|
||||
}
|
||||
|
||||
Pipe::Pipe() {
|
||||
auto mutex = Platform::CreateMutex(api::Mutex::Mode::kRegular);
|
||||
auto cond = Platform::CreateConditionVariable(mutex.get());
|
||||
Setup(std::move(mutex), std::move(cond));
|
||||
}
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user