Merge branch 'google3'

Change-Id: I674779bb692da84fd8718bb59ffa3eecf9011a3f
This commit is contained in:
Alexey Polyudov
2020-10-22 11:07:51 -07:00
551 changed files with 13692 additions and 42984 deletions
-92
View File
@@ -1,92 +0,0 @@
cc_library(
name = "utils",
srcs = [
"base64_utils.cc",
"cancelable_alarm.cc",
"pipe.cc",
"prng.cc",
"reliability_utils.cc",
],
hdrs = [
"base64_utils.h",
"cancelable_alarm.h",
"pipe.h",
"prng.h",
"reliability_utils.h",
"synchronized.h",
],
visibility = [
"//core:__subpackages__",
"//platform/impl:__subpackages__",
"//location/nearby/setup/core/internal:__subpackages__",
],
deps = [
":types",
"//platform/api",
"//platform/port:string",
"//absl/strings",
"//absl/time",
],
)
cc_library(
name = "types",
hdrs = [
"byte_array.h",
"callable.h",
"cancelable.h",
"container_of.h",
"exception.h",
"ptr.h",
"runnable.h",
],
visibility = [
"//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__",
"//core:__subpackages__",
"//platform:__subpackages__",
"//location/nearby/setup/core:__subpackages__",
],
deps = [
":logging",
"//platform/port:down_cast",
"//platform/port:string",
],
)
cc_library(
name = "logging",
hdrs = [
"logging.h",
],
visibility = [
"//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__",
"//core:__subpackages__",
],
deps = [
"//absl/base",
"//absl/base:raw_logging_internal",
],
)
cc_test(
name = "platform_test",
timeout = "short",
srcs = [
"atomic_reference_test.cc",
"byte_array_test.cc",
"container_of_test.cc",
"pipe_test.cc",
"prng_test.cc",
"ptr_test.cc",
"settable_future_test.cc",
],
deps = [
":utils",
"//platform:types",
"//platform/api",
"//platform/impl/g3",
"//platform/port:string",
"//testing/base/public:gunit_main",
"//absl/time",
],
)
-81
View File
@@ -1,81 +0,0 @@
add_library(platform_utils STATIC
)
target_sources(platform_utils
PRIVATE
base64_utils.cc
cancelable_alarm.cc
pipe.cc
prng.cc
reliability_utils.cc
PUBLIC
base64_utils.h
cancelable_alarm.h
pipe.h
prng.h
reliability_utils.h
synchronized.h
)
target_link_libraries(platform_utils
PUBLIC
platform_api
platform_types
platform_impl_g3
platform_impl_shared_posix_lock
platform_impl_shared_posix_condition_variable
absl::strings
)
add_library(platform_types STATIC)
target_sources(platform_types
PUBLIC
byte_array.h
callable.h
cancelable.h
container_of.h
exception.h
logging.h
ptr.h
runnable.h
)
target_link_libraries(platform_types
PUBLIC
absl::base
absl::strings
)
add_executable(platform_test
byte_array_test.cc
container_of_test.cc
exception_test.cc
pipe_test.cc
prng_test.cc
ptr_test.cc
)
target_link_libraries(platform_test
PUBLIC
absl::base
absl::strings
absl::time
gmock
gtest
gtest_main
platform_api
platform_impl_g3
platform_types
platform_utils
)
add_test(
NAME platform_test
COMMAND platform_test
)
add_subdirectory(api)
add_subdirectory(impl/g3)
add_subdirectory(impl/shared)
add_subdirectory(port)
+54 -46
View File
@@ -1,69 +1,77 @@
package(default_visibility = [
"//core:__subpackages__",
"//platform:__subpackages__",
"//location/nearby/setup/core:__subpackages__",
])
cc_library(
name = "api",
name = "types",
hdrs = [
"atomic_boolean.h",
"atomic_reference.h",
"atomic_reference_def.h",
"cancelable.h",
"condition_variable.h",
"count_down_latch.h",
"crypto.h",
"executor.h",
"future.h",
"input_file.h",
"listenable_future.h",
"log_message.h",
"mutex.h",
"output_file.h",
"scheduled_executor.h",
"settable_future.h",
"submittable_executor.h",
"system_clock.h",
],
visibility = [
"//platform/base:__pkg__",
"//platform/impl:__subpackages__",
"//platform/public:__pkg__",
],
deps = [
"//platform/base",
"//absl/base:core_headers",
"//absl/strings",
"//absl/time",
],
)
cc_library(
name = "comm",
hdrs = [
"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",
"lock.h",
"multi_thread_executor.h",
"output_file.h",
"output_stream.h",
"platform.h",
"scheduled_executor.h",
"server_sync.h",
"settable_future.h",
"settable_future_def.h",
"single_thread_executor.h",
"socket.h",
"submittable_executor.h",
"submittable_executor_def.h",
"system_clock.h",
"thread_utils.h",
"webrtc.h",
"wifi.h",
"wifi_lan.h",
],
visibility = [
"//platform/base:__pkg__",
"//platform/impl:__subpackages__",
"//platform/public:__pkg__",
],
deps = [
"//platform:types",
"//platform/port:down_cast",
"//platform/port:string",
"//proto/connections:offline_wire_formats_portable_proto",
"//platform/base",
"//absl/strings",
"//absl/types:any",
"//absl/types:optional",
"//webrtc/api:libjingle_peerconnection_api",
],
)
cc_library(
name = "lock",
hdrs = ["lock.h"],
name = "platform",
hdrs = [
"platform.h",
],
visibility = [
"//platform:__subpackages__",
"//platform/base:__pkg__",
"//platform/impl:__subpackages__",
"//platform/public:__pkg__",
],
deps = [
":comm",
":types",
"//platform/base",
"//absl/strings",
],
)
cc_library(
name = "condition_variable",
hdrs = ["condition_variable.h"],
visibility = [
"//platform:__subpackages__",
],
deps = ["//platform:types"],
)
-36
View File
@@ -1,36 +0,0 @@
add_library(platform_api STATIC
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
lock.h
multi_thread_executor.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
wifi_lan.h
)
target_link_libraries(platform_api
PUBLIC
platform_types
)
+8 -5
View File
@@ -3,18 +3,21 @@
namespace location {
namespace nearby {
namespace api {
// A boolean value that may be updated atomically.
//
// https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicBoolean.html
class AtomicBoolean {
public:
virtual ~AtomicBoolean() {}
virtual ~AtomicBoolean() = default;
virtual bool get() = 0;
virtual void set(bool value) = 0;
// 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
+10 -33
View File
@@ -1,48 +1,25 @@
#ifndef PLATFORM_API_ATOMIC_REFERENCE_H_
#define PLATFORM_API_ATOMIC_REFERENCE_H_
#include "platform/api/atomic_reference_def.h"
#include "platform/api/platform.h"
#include "platform/ptr.h"
#include "absl/types/any.h"
#include <cstdint>
namespace location {
namespace nearby {
namespace api {
// "Common" part of implementation.
// Placed here for textual compatibility to minimize scope of changes.
// Can be (and should be) moved to a separate file outside "api" folder.
// TODO(apolyudov): for API v2.0
namespace platform {
namespace impl {
template <typename T>
class AtomicReferenceImpl : public AtomicReference<T> {
// Type that allows 32-bit atomic reads and writes.
class AtomicUint32 {
public:
explicit AtomicReferenceImpl(T initial_value) {
atomic_ = platform::ImplementationPlatform::createAtomicReferenceAny(
absl::any(initial_value));
}
virtual ~AtomicUint32() = default;
~AtomicReferenceImpl() override = default;
// Atomically reads and returns stored value.
virtual std::uint32_t Get() const = 0;
void set(T new_value) override { atomic_->set(absl::any(new_value)); }
T get() override { return absl::any_cast<T>(atomic_->get()); }
private:
Ptr<AtomicReference<absl::any>> atomic_;
// Atomically stores value.
virtual void Set(std::uint32_t value) = 0;
};
} // namespace impl
template <typename T>
Ptr<AtomicReference<T>> ImplementationPlatform::createAtomicReference(
T initial_value) {
return Ptr<AtomicReference<T>>(
new impl::AtomicReferenceImpl<T>{initial_value});
}
} // namespace platform
} // namespace api
} // namespace nearby
} // namespace location
-27
View File
@@ -1,27 +0,0 @@
#ifndef PLATFORM_API_ATOMIC_REFERENCE_DEF_H_
#define PLATFORM_API_ATOMIC_REFERENCE_DEF_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
//
// Platform must implentent non-template static member functions
// Ptr<AtomicReference<size_t>> CreateAtomicReferenceSizeT()
// Ptr<AtomicReference<std::shared_ptr<void>>> CreateAtomicReferencePtr()
// in the location::nearby::platform::ImplementationPlatform class.
template <typename T>
class AtomicReference {
public:
virtual ~AtomicReference() = default;
virtual T get() = 0;
virtual void set(T value) = 0;
};
} // namespace nearby
} // namespace location
#endif // PLATFORM_API_ATOMIC_REFERENCE_DEF_H_
+61 -76
View File
@@ -2,122 +2,107 @@
#define PLATFORM_API_BLE_H_
#include "platform/api/bluetooth_classic.h"
#include "platform/api/input_stream.h"
#include "platform/api/output_stream.h"
#include "platform/byte_array.h"
#include "platform/ptr.h"
#include "platform/base/byte_array.h"
#include "platform/base/input_stream.h"
#include "platform/base/output_stream.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 {
class BlePeripheral {
public:
virtual ~BLEPeripheral() {}
virtual ~BlePeripheral() = default;
// The returned Ptr is not owned by the caller, and can be invalidated once
// the corresponding BLEPeripheral object is destroyed.
virtual Ptr<BluetoothDevice> getBluetoothDevice() = 0;
virtual std::string GetName() const = 0;
virtual ByteArray GetAdvertisementBytes(
const std::string& service_id) const = 0;
};
class BLESocket {
class BleSocket {
public:
virtual ~BLESocket() {}
virtual ~BleSocket() = default;
// Returns the InputStream of the BLESocket, or a null Ptr<InputStream>
// on error.
// Returns the InputStream of the BleSocket.
// On error, returned stream will report Exception::kIo on any operation.
//
// The returned Ptr is not owned by the caller, and can be invalidated once
// the BLESocket object is destroyed.
virtual Ptr<InputStream> getInputStream() = 0;
// 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, or a null
// Ptr<OutputStream> on error.
// Returns the OutputStream of the BleSocket.
// On error, returned stream will report Exception::kIo on any operation.
//
// The returned Ptr is not owned by the caller, and can be invalidated once
// the BLESocket object is destroyed.
virtual Ptr<OutputStream> getOutputStream() = 0;
// 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::IO on error, Exception::NONE otherwise.
virtual Exception::Value close() = 0;
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
virtual Exception Close() = 0;
// The returned Ptr is not owned by the caller, and can be invalidated once
// the BLESocket object is destroyed.
virtual Ptr<BLEPeripheral> getRemotePeripheral() = 0;
// Returns valid BlePeripheral pointer if there is a connection, and
// nullptr otherwise.
virtual BlePeripheral* GetRemotePeripheral() = 0;
};
// Container of operations that can be performed over the BLE medium.
class BLEMedium {
class BleMedium {
public:
virtual ~BLEMedium() {}
virtual ~BleMedium() = default;
// Takes ownership of (and is responsible for destroying) the passed-in
// 'advertisement'.
virtual bool startAdvertising(const std::string& service_id,
ConstPtr<ByteArray> advertisement) = 0;
virtual void stopAdvertising(const std::string& service_id) = 0;
virtual bool StartAdvertising(
const std::string& service_id, const ByteArray& advertisement_bytes,
const std::string& fast_advertisement_service_uuid) = 0;
virtual bool StopAdvertising(const std::string& service_id) = 0;
class DiscoveredPeripheralCallback {
public:
virtual ~DiscoveredPeripheralCallback() {}
// The Ptrs provided in these callback methods will be owned (and
// destroyed) by the recipient of the callback methods (i.e. the creator of
// the concrete DiscoveredPeripheralCallback object).
virtual void onPeripheralDiscovered(Ptr<BLEPeripheral> ble_peripheral,
const std::string& service_id,
ConstPtr<ByteArray> advertisement) = 0;
virtual void onPeripheralLost(Ptr<BLEPeripheral> ble_peripheral,
const std::string& service_id) = 0;
// Callback that is invoked when a discovered peripheral is found or lost.
struct DiscoveredPeripheralCallback {
std::function<void(BlePeripheral& peripheral, const std::string& service_id,
bool fast_advertisement)>
peripheral_discovered_cb =
DefaultCallback<BlePeripheral&, const std::string&, bool>();
std::function<void(BlePeripheral& peripheral,
const std::string& service_id)>
peripheral_lost_cb =
DefaultCallback<BlePeripheral&, const std::string&>();
};
// Returns true once the BLE scan has been initiated.
//
// Does not take ownership of the passed-in discovered_peripheral_callback --
// destroying that is up to the caller.
virtual bool startScanning(
const std::string& service_id,
Ptr<DiscoveredPeripheralCallback> discovered_peripheral_callback) = 0;
virtual bool StartScanning(const std::string& service_id,
const std::string& fast_advertisement_service_uuid,
DiscoveredPeripheralCallback 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.
//
// Does not need to bother with destroying the DiscoveredPeripheralCallback
// passed in to startScanning() -- that's the job of the caller.
virtual void stopScanning(const std::string& service_id) = 0;
// DiscoveredPeripheralCallback passed in to StartScanning() for service_id.
virtual bool StopScanning(const std::string& service_id) = 0;
// Callback that is invoked when a new connection is accepted.
class AcceptedConnectionCallback {
public:
virtual ~AcceptedConnectionCallback() {}
// The Ptr provided in this callback method will be owned (and
// destroyed) by the recipient of the callback methods (i.e. the creator of
// the concrete AcceptedConnectionCallback object).
virtual void onConnectionAccepted(Ptr<BLESocket> socket,
const std::string& service_id) = 0;
struct AcceptedConnectionCallback {
std::function<void(BleSocket& socket, const std::string& service_id)>
accepted_cb = DefaultCallback<BleSocket&, const std::string&>();
};
// Returns true once BLE socket connection requests to service_id can be
// accepted.
//
// Does not take ownership of the passed-in accepted_connection_callback --
// destroying that is up to the caller.
virtual bool startAcceptingConnections(
const std::string& service_id,
Ptr<AcceptedConnectionCallback> accepted_connection_callback) = 0;
virtual void stopAcceptingConnections(const std::string& service_id) = 0;
virtual bool StartAcceptingConnections(
const std::string& service_id, AcceptedConnectionCallback callback) = 0;
virtual bool StopAcceptingConnections(const std::string& service_id) = 0;
// The returned Ptr will be owned (and destroyed) by the caller. Returns
// a null Ptr<BleSocket> on error.
virtual Ptr<BLESocket> connect(Ptr<BLEPeripheral> ble_peripheral,
const std::string& service_id) = 0;
// Connects to a BLE peripheral.
// On success, returns a new BleSocket.
// On error, returns nullptr.
virtual std::unique_ptr<BleSocket> Connect(BlePeripheral& peripheral,
const std::string& service_id) = 0;
};
} // namespace api
} // namespace nearby
} // namespace location
+130 -142
View File
@@ -4,15 +4,19 @@
#include <cstdint>
#include <limits>
#include <map>
#include <memory>
#include <set>
#include <string>
#include "platform/byte_array.h"
#include "platform/exception.h"
#include "platform/port/string.h"
#include "platform/ptr.h"
#include "platform/base/byte_array.h"
#include "platform/base/exception.h"
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
namespace location {
namespace nearby {
namespace api {
namespace ble_v2 {
// https://developer.android.com/reference/android/bluetooth/le/AdvertiseData
//
@@ -21,16 +25,16 @@ namespace nearby {
// 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 {
typedef std::int8_t TXPowerLevel;
struct BleAdvertisementData {
using TxPowerLevel = int8_t;
static constexpr TXPowerLevel UNSPECIFIED_TX_POWER_LEVEL =
std::numeric_limits<TXPowerLevel>::min();
static const TxPowerLevel kUnspecifiedTxPowerLevel =
std::numeric_limits<TxPowerLevel>::min();
bool is_connectable;
// When set to UNSPECIFIED_TX_POWER_LEVEL, TX power should not be included in
// When set to kUnspecifiedTxPowerLevel, TX power should not be included in
// the advertisement data.
TXPowerLevel tx_power_level;
TxPowerLevel tx_power_level;
// When set to an empty string, local name should not be included in the
// advertisement data.
std::string local_name;
@@ -38,75 +42,64 @@ struct BLEAdvertisementData {
// not be included in the advertisement data.
std::set<std::string> service_uuids;
// Maps service UUIDs to their service data.
// Ownership of the map values is tied to ownership of BLEAdvertisementData.
std::map<std::string, ConstPtr<ByteArray>> 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.
//
// BLEPeripheralV2 should always be created as a RefCountedPtr because ownership
// is shared between the per-platform implementation and the internals of Nearby
// Connections.
class BLEPeripheralV2 {
class BlePeripheral {
public:
virtual ~BLEPeripheralV2() {}
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() = 0;
virtual std::string GetId() const = 0;
};
// https://developer.android.com/reference/android/bluetooth/BluetoothGattCharacteristic
//
// Representation of a GATT characteristic.
//
// GATTCharacteristics are RefCounted so that ownership can be shared between
// the per-platform implementation and C++ internals. All GATTCharacteristics
// should be created with MakeRefCountedPtr().
class GATTCharacteristic {
class GattCharacteristic {
public:
virtual ~GATTCharacteristic() {}
virtual ~GattCharacteristic() {}
// Possible permissions of a GATT characteristic.
struct Permission {
enum Value {
UNKNOWN = 0,
READ = 1,
WRITE = 2,
};
enum class Permission {
kUnknown = 0,
kRead = 1,
kWrite = 2,
kLast,
};
// Possible properties of a GATT characteristic.
struct Property {
enum Value {
UNKNOWN = 0,
READ = 1,
WRITE = 2,
INDICATE = 3,
};
enum class Property {
kUnknown = 0,
kRead = 1,
kWrite = 2,
kIndicate = 3,
kLast,
};
// Returns the UUID of this characteristic.
virtual std::string getUUID() = 0;
virtual std::string GetUuid() = 0;
// Returns the UUID of the containing GATT service.
virtual std::string getServiceUUID() = 0;
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 {
class ClientGattConnection {
public:
virtual ~ClientGATTConnection() {}
virtual ~ClientGattConnection() {}
// https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#getDevice()
//
// Retrieves the BLE peripheral that this connection is tied to.
virtual Ptr<BLEPeripheralV2> getPeripheral() = 0;
virtual BlePeripheral& GetPeripheral() = 0;
// https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#discoverServices()
//
@@ -114,49 +107,49 @@ class ClientGATTConnection {
// Returns whether or not discovery finished successfully.
//
// This function should block until discovery has finished.
virtual bool discoverServices() = 0;
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. A null Ptr is returned upon error.
// Retrieves a GATT characteristic. On error, does not return a value.
//
// discoverServices() should be called before this method to fetch all
// 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 Ptr<GATTCharacteristic> getCharacteristic(
const std::string& service_uuid,
const std::string& characteristic_uuid) = 0;
virtual absl::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. A null ConstPtr is returned upon error.
virtual ConstPtr<ByteArray> readCharacteristic(
Ptr<GATTCharacteristic> characteristic) = 0;
// Reads a GATT characteristic. No value is returned upon error.
virtual absl::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(Ptr<GATTCharacteristic> characteristic,
ConstPtr<ByteArray> value) = 0;
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;
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 {
class ServerGattConnection {
public:
virtual ~ServerGATTConnection() {}
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)
@@ -165,47 +158,47 @@ class ServerGATTConnection {
// 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(Ptr<GATTCharacteristic> characteristic,
ConstPtr<ByteArray> value) = 0;
// 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 {
class ClientGattConnectionLifeCycleCallback {
public:
virtual ~ClientGATTConnectionLifecycleCallback() {}
virtual ~ClientGattConnectionLifeCycleCallback() {}
// Called when the client is disconnected from the GATT server.
virtual void onDisconnected(Ptr<ClientGATTConnection> connection) = 0;
virtual void OnDisconnected(ClientGattConnection* connection) = 0;
};
// Callback for asynchronous events on the server side of a GATT connection.
class ServerGATTConnectionLifecycleCallback {
class ServerGattConnectionLifeCycleCallback {
public:
virtual ~ServerGATTConnectionLifecycleCallback() {}
virtual ~ServerGattConnectionLifeCycleCallback() {}
// Called when a remote peripheral connected to us and subscribed to one of
// our characteristics.
virtual void onCharacteristicSubscription(
Ptr<ServerGATTConnection> connection,
Ptr<GATTCharacteristic> characteristic) = 0;
virtual void OnCharacteristicSubscription(
ServerGattConnection* connection,
const GattCharacteristic& characteristic) = 0;
// Called when a remote peripheral unsubscribed from one of our
// characteristics.
virtual void onCharacteristicUnsubscription(
Ptr<ServerGATTConnection> connection,
Ptr<GATTCharacteristic> characteristic) = 0;
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 {
class GattServer {
public:
virtual ~GATTServer() {}
virtual ~GattServer() {}
// Creates a characteristic and adds it to the GATT server under the given
// characteristic and service UUIDs. Returns a null Ptr upon error.
// 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.
@@ -215,12 +208,11 @@ class GATTServer {
// 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 Ptr<GATTCharacteristic> createCharacteristic(
const std::string& service_uuid,
const std::string& characteristic_uuid,
const std::set<GATTCharacteristic::Permission::Value>& permissions,
const std::set<GATTCharacteristic::Property::Value>& properties) = 0;
// https://www.bluetooth.com/specifications/Gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.Gatt.client_characteristic_configuration.xml
virtual absl::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[])
//
@@ -228,67 +220,66 @@ class GATTServer {
// was successful.
// Takes ownership of (and is responsible for destroying) the passed-in
// 'value'.
virtual bool updateCharacteristic(Ptr<GATTCharacteristic> characteristic,
ConstPtr<ByteArray> value) = 0;
virtual bool UpdateCharacteristic(const GattCharacteristic& characteristic,
const ByteArray& value) = 0;
// Stops a GATT server.
virtual void stop() = 0;
virtual void Stop() = 0;
};
// A BLE socket representation.
class BLESocketV0 {
class BleSocket {
public:
virtual ~BLESocketV0() {}
virtual ~BleSocket() {}
// Returns the remote BLE peripheral tied to this socket.
virtual Ptr<BLEPeripheralV2> getRemotePeripheral() = 0;
virtual BlePeripheral& GetRemotePeripheral() = 0;
// Writes a message on the socket and blocks until finished. Returns
// Exception::IO upon error, and Exception::NONE otherwise.
virtual Exception::Value write(ConstPtr<ByteArray> message) = 0;
// Exception::kIo upon error, and Exception::kSuccess otherwise.
virtual Exception Write(const ByteArray& message) = 0;
// Closes the socket and blocks until finished. Returns Exception::IO upon
// error, and Exception::NONE otherwise.
virtual Exception::Value close() = 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 BLESocketV0 object.
class BLESocketLifecycleCallback {
// Callback for asynchronous events on a BleSocket object.
class BleSocketLifeCycleCallback {
public:
virtual ~BLESocketLifecycleCallback() {}
virtual ~BleSocketLifeCycleCallback() {}
// Called when a message arrives on a socket.
virtual void onMessageReceived(Ptr<BLESocketV0> socket,
ConstPtr<ByteArray> message) = 0;
virtual void OnMessageReceived(BleSocket* socket,
const ByteArray& message) = 0;
// Called when a socket gets disconnected.
virtual void onDisconnected(Ptr<BLESocketV0> socket) = 0;
virtual void OnDisconnected(BleSocket* socket) = 0;
};
// Callback for asynchronous events on the server side of a BLESocketV0 object.
class ServerBLESocketLifecycleCallback : public BLESocketLifecycleCallback {
// Callback for asynchronous events on the server side of a BleSocket object.
class ServerBleSocketLifeCycleCallback : public BleSocketLifeCycleCallback {
public:
~ServerBLESocketLifecycleCallback() override {}
~ServerBleSocketLifeCycleCallback() override {}
// Called when a new incoming socket has been established.
virtual void onSocketEstablished(Ptr<BLESocketV0> socket) = 0;
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 BLEMediumV2 {
class BleMedium {
public:
virtual ~BLEMediumV2() {}
using Mtu = uint32_t;
typedef std::uint32_t MTU;
virtual ~BleMedium() {}
// Coarse representation of power settings throughout all BLE operations.
struct PowerMode {
enum Value {
UNKNOWN = 0,
LOW = 1,
HIGH = 2,
};
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)
@@ -302,15 +293,14 @@ class BLEMediumV2 {
// HIGH:
// - Advertising interval = ~100ms
// - TX power = high
virtual bool startAdvertising(
ConstPtr<BLEAdvertisementData> advertisement_data,
ConstPtr<BLEAdvertisementData> scan_response,
PowerMode::Value power_mode) = 0;
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;
virtual void StopAdvertising() = 0;
// https://developer.android.com/reference/android/bluetooth/le/ScanCallback
//
@@ -329,11 +319,11 @@ class BLEMediumV2 {
// 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
// Ownership of the BleAdvertisementData transfers to the caller at this
// point.
virtual void onAdvertisementFound(
Ptr<BLEPeripheralV2> peripheral,
ConstPtr<BLEAdvertisementData> advertisement_data) = 0;
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)
@@ -347,35 +337,34 @@ class BLEMediumV2 {
// HIGH:
// - Scan window = ~4096ms
// - Scan interval = ~4096ms
virtual bool startScanning(const std::set<std::string>& service_uuids,
PowerMode::Value power_mode,
Ptr<ScanCallback> scan_callback) = 0;
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;
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 null Ptr upon error.
virtual Ptr<GATTServer> startGATTServer(
Ptr<ServerGATTConnectionLifecycleCallback>
connection_lifecycle_callback) = 0;
// 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(
Ptr<ServerBLESocketLifecycleCallback> socket_lifecycle_callback) = 0;
virtual bool StartListeningForIncomingBleSockets(
const ServerBleSocketLifeCycleCallback& callback) = 0;
// Stops listening for incoming BLE sockets.
virtual void stopListeningForIncomingBLESockets() = 0;
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 a null Ptr upon error.
// parameters. Returns nullptr upon error.
//
// Both connection interval and MTU can be negotiated on a best-effort basis.
//
@@ -384,20 +373,19 @@ class BLEMediumV2 {
// - Connection interval = ~11.25ms - 15ms
// HIGH:
// - Connection interval = ~100ms - 125ms
virtual Ptr<ClientGATTConnection> connectToGATTServer(
Ptr<BLEPeripheralV2> peripheral,
MTU mtu,
PowerMode::Value power_mode,
Ptr<ClientGATTConnectionLifecycleCallback>
connection_lifecycle_callback) = 0;
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 a null
// Ptr on error.
virtual Ptr<BLESocketV0> establishBLESocket(
Ptr<BLEPeripheralV2> ble_peripheral,
Ptr<BLESocketLifecycleCallback> socket_lifecycle_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
+26 -23
View File
@@ -1,57 +1,60 @@
#ifndef PLATFORM_API_BLUETOOTH_ADAPTER_H_
#define PLATFORM_API_BLUETOOTH_ADAPTER_H_
#include "platform/port/string.h"
#include "platform/ptr.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() {}
virtual ~BluetoothAdapter() = default;
// Eligible statuses of the BluetoothAdapter.
struct Status {
enum Value {
DISABLED,
ENABLED,
};
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::Value status) = 0;
virtual bool SetStatus(Status status) = 0;
// Returns true if the BluetoothAdapter's current status is
// Status::Value::ENABLED.
virtual bool isEnabled() = 0;
// 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().
struct ScanMode {
enum Value {
UNKNOWN,
CONNECTABLE_DISCOVERABLE,
};
enum class ScanMode {
kUnknown,
kNone,
kConnectable,
kConnectableDiscoverable,
};
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#getScanMode()
//
// Returns ScanMode::UNKNOWN on error.
virtual ScanMode::Value getScanMode() = 0;
// 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::Value scan_mode) = 0;
virtual bool SetScanMode(ScanMode scan_mode) = 0;
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#getName()
//
// Returns a null Ptr<string> on error.
virtual Ptr<std::string> getName() = 0;
// 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(const std::string& name) = 0;
virtual bool SetName(absl::string_view name) = 0;
// Returns BT MAC address assigned to this adapter.
virtual std::string GetMacAddress() const = 0;
};
} // namespace api
} // namespace nearby
} // namespace location
+70 -65
View File
@@ -1,107 +1,112 @@
#ifndef PLATFORM_API_BLUETOOTH_CLASSIC_H_
#define PLATFORM_API_BLUETOOTH_CLASSIC_H_
#include "platform/api/input_stream.h"
#include "platform/api/output_stream.h"
#include "platform/byte_array.h"
#include "platform/exception.h"
#include "platform/port/string.h"
#include "platform/ptr.h"
#include <memory>
#include <string>
#include "platform/base/byte_array.h"
#include "platform/base/exception.h"
#include "platform/base/input_stream.h"
#include "platform/base/listeners.h"
#include "platform/base/output_stream.h"
namespace location {
namespace nearby {
namespace api {
// https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html.
class BluetoothDevice {
public:
virtual ~BluetoothDevice() {}
virtual ~BluetoothDevice() = default;
// https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#getName()
virtual std::string getName() = 0;
virtual std::string GetName() const = 0;
// Returns BT MAC address assigned to this device.
virtual std::string GetMacAddress() const = 0;
};
// https://developer.android.com/reference/android/bluetooth/BluetoothSocket.html.
class BluetoothSocket {
public:
virtual ~BluetoothSocket() {}
virtual ~BluetoothSocket() = default;
// Returns the InputStream of the BluetoothSocket, or a null Ptr<InputStream>
// on error.
//
// The returned Ptr is not owned by the caller, and can be invalidated once
// the BluetoothSocket object is destroyed.
virtual Ptr<InputStream> getInputStream() = 0;
// NOTE:
// It is an undefined behavior if GetInputStream() or GetOutputStream() is
// called for a not-connected BluetoothSocket, i.e. any object that is not
// returned by BluetoothClassicMedium::ConnectToService() for client side or
// BluetoothServerSocket::Accept() for server side of connection.
// Returns the OutputStream of the BluetoothSocket, or a null
// Ptr<OutputStream> on error.
//
// The returned Ptr is not owned by the caller, and can be invalidated once
// the BluetoothSocket object is destroyed.
virtual Ptr<OutputStream> getOutputStream() = 0;
// Returns the InputStream of this connected BluetoothSocket.
virtual InputStream& GetInputStream() = 0;
// https://developer.android.com/reference/android/bluetooth/BluetoothSocket.html#close()
//
// Returns Exception::IO on error, Exception::NONE otherwise.
virtual Exception::Value close() = 0;
// Returns the OutputStream of this connected BluetoothSocket.
virtual OutputStream& GetOutputStream() = 0;
// Closes both input and output streams, marks Socket as closed.
// After this call object should be treated as not connected.
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
virtual Exception Close() = 0;
// https://developer.android.com/reference/android/bluetooth/BluetoothSocket.html#getRemoteDevice()
//
// The returned Ptr is not owned by the caller, and can be invalidated once
// the BluetoothSocket object is destroyed.
virtual Ptr<BluetoothDevice> getRemoteDevice() = 0;
// Returns valid BluetoothDevice pointer if there is a connection, and
// nullptr otherwise.
virtual BluetoothDevice* GetRemoteDevice() = 0;
};
// https://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html.
class BluetoothServerSocket {
public:
virtual ~BluetoothServerSocket() {}
virtual ~BluetoothServerSocket() = default;
// https://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html#accept()
//
// The returned Ptr will be owned (and destroyed) by the caller. Returns
// Exception::IO on error.
virtual ExceptionOr<Ptr<BluetoothSocket>> accept() = 0;
// Blocks until either:
// - at least one incoming connection request is available, or
// - ServerSocket is closed.
// On success, returns connected socket, ready to exchange data.
// Returns nullptr on error.
// Once error is reported, it is permanent, and ServerSocket has to be closed.
virtual std::unique_ptr<BluetoothSocket> Accept() = 0;
// https://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html#close()
//
// Returns Exception::IO on error, Exception::NONE otherwise.
virtual Exception::Value close() = 0;
// 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() {}
virtual ~BluetoothClassicMedium() = default;
class DiscoveryCallback {
public:
virtual ~DiscoveryCallback() {}
// The Ptrs provided in these callback methods will be owned (and
// destroyed) by the recipient of the callback methods (i.e. the creator of
// the concrete DiscoveryCallback object).
virtual void onDeviceDiscovered(Ptr<BluetoothDevice> device) = 0;
virtual void onDeviceNameChanged(Ptr<BluetoothDevice> device) = 0;
virtual void onDeviceLost(Ptr<BluetoothDevice> device) = 0;
struct DiscoveryCallback {
// BluetoothDevice is a proxy object created as a result of BT discovery.
// Its lifetime spans between calls to device_discovered_cb and
// device_lost_cb.
// It is safe to use BluetoothDevice in device_discovered_cb() callback
// and at any time afterwards, until device_lost_cb() is called.
// It is not safe to use BluetoothDevice after returning from
// device_lost_cb() callback.
std::function<void(BluetoothDevice& device)> device_discovered_cb =
DefaultCallback<BluetoothDevice&>();
std::function<void(BluetoothDevice& device)> device_name_changed_cb =
DefaultCallback<BluetoothDevice&>();
std::function<void(BluetoothDevice& device)> device_lost_cb =
DefaultCallback<BluetoothDevice&>();
};
// 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(Ptr<DiscoveryCallback> discovery_callback) = 0;
virtual bool StartDiscovery(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().
//
// Does not need to bother with destroying the DiscoveryCallback passed in to
// startDiscovery() -- that's the job of the caller.
virtual bool stopDiscovery() = 0;
// StartDiscovery().
virtual bool StopDiscovery() = 0;
// A combination of
// https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#createInsecureRfcommSocketToServiceRecord
@@ -114,11 +119,10 @@ class BluetoothClassicMedium {
// (https://en.wikipedia.org/wiki/Universally_unique_identifier#Versions_3_and_5_(namespace_name-based))
// UUID.
//
// The returned Ptr will be owned (and destroyed) by the caller. Returns
// Exception::IO on error.
virtual ExceptionOr<Ptr<BluetoothSocket>> connectToService(
Ptr<BluetoothDevice> remote_device,
const std::string& service_uuid) = 0;
// On success, returns a new BluetoothSocket.
// On error, returns nullptr.
virtual std::unique_ptr<BluetoothSocket> ConnectToService(
BluetoothDevice& remote_device, const std::string& service_uuid) = 0;
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#listenUsingInsecureRfcommWithServiceRecord
//
@@ -128,13 +132,14 @@ class BluetoothClassicMedium {
// (https://en.wikipedia.org/wiki/Universally_unique_identifier#Versions_3_and_5_(namespace_name-based))
// UUID.
//
// The returned Ptr will be owned (and destroyed) by the caller. Returns
// Exception::IO on error.
virtual ExceptionOr<Ptr<BluetoothServerSocket>> listenForService(
const std::string& service_name,
const std::string& service_uuid) = 0;
// Returns nullptr error.
virtual std::unique_ptr<BluetoothServerSocket> ListenForService(
const std::string& service_name, const std::string& service_uuid) = 0;
virtual BluetoothDevice* GetRemoteDevice(const std::string& mac_address) = 0;
};
} // namespace api
} // namespace nearby
} // namespace location
@@ -1,19 +1,21 @@
#ifndef PLATFORM_CANCELABLE_H_
#define PLATFORM_CANCELABLE_H_
#ifndef PLATFORM_API_CANCELABLE_H_
#define PLATFORM_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() {}
virtual ~Cancelable() = default;
virtual bool cancel() = 0;
virtual bool Cancel() = 0;
};
} // namespace api
} // namespace nearby
} // namespace location
#endif // PLATFORM_CANCELABLE_H_
#endif // PLATFORM_API_CANCELABLE_H_
+16 -5
View File
@@ -1,10 +1,12 @@
#ifndef PLATFORM_API_CONDITION_VARIABLE_H_
#define PLATFORM_API_CONDITION_VARIABLE_H_
#include "platform/exception.h"
#include "platform/base/exception.h"
#include "absl/time/clock.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
@@ -14,12 +16,21 @@ 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::Value wait() = 0; // throws Exception::INTERRUPTED
// Notifies all the waiters that condition state has changed.
virtual void Notify() = 0;
// Waits indefinitely for Notify to be called.
// May return prematurely in case of interrupt, if supported by platform.
// Returns kSuccess, or kInterrupted on interrupt.
virtual Exception Wait() = 0;
// Waits while timeout has not expired for Notify to be called.
// May return prematurely in case of interrupt, if supported by platform.
// Returns kSuccess, or kInterrupted on interrupt.
virtual Exception Wait(absl::Duration timeout) = 0;
};
} // namespace api
} // namespace nearby
} // namespace location
+9 -6
View File
@@ -3,10 +3,12 @@
#include <cstdint>
#include "platform/exception.h"
#include "platform/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.
@@ -14,14 +16,15 @@ namespace nearby {
// https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CountDownLatch.html
class CountDownLatch {
public:
virtual ~CountDownLatch() {}
virtual ~CountDownLatch() = default;
virtual Exception::Value await() = 0; // throws Exception::INTERRUPTED
virtual ExceptionOr<bool> await(
std::int32_t timeout_millis) = 0; // throws Exception::INTERRUPTED
virtual void countDown() = 0;
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
+24
View File
@@ -0,0 +1,24 @@
#ifndef PLATFORM_API_CRYPTO_H_
#define PLATFORM_API_CRYPTO_H_
#include "platform/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_API_CRYPTO_H_
+12 -6
View File
@@ -1,25 +1,31 @@
#ifndef PLATFORM_API_EXECUTOR_H_
#define PLATFORM_API_EXECUTOR_H_
#include "platform/ptr.h"
#include "platform/runnable.h"
#include "platform/base/runnable.h"
namespace location {
namespace nearby {
namespace api {
int GetCurrentTid();
// This abstract class is the superclass of all classes representing an
// Executor.
class Executor {
public:
virtual ~Executor() {}
// 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;
virtual void Shutdown() = 0;
// https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executor.html#execute-java.lang.Runnable-
virtual void execute(Ptr<Runnable> runnable) = 0;
virtual int GetTid(int index) const = 0;
};
} // namespace api
} // namespace nearby
} // namespace location
+10 -9
View File
@@ -1,12 +1,12 @@
#ifndef PLATFORM_API_FUTURE_H_
#define PLATFORM_API_FUTURE_H_
#include <cstdint>
#include "platform/exception.h"
#include "platform/base/exception.h"
#include "absl/time/clock.h"
namespace location {
namespace nearby {
namespace api {
// A Future represents the result of an asynchronous computation.
//
@@ -14,17 +14,18 @@ namespace nearby {
template <typename T>
class Future {
public:
virtual ~Future() {}
virtual ~Future() = default;
virtual ExceptionOr<T>
get() = 0; // throws Exception::INTERRUPTED, Exception::EXECUTION
// throws Exception::kInterrupted, Exception::kExecution
virtual ExceptionOr<T> Get() = 0;
// throws Exception::INTERRUPTED, Exception::EXECUTION
// throws Exception::TIMEOUT if |timeout_ms| is exceeded while waiting for
// throws Exception::kInterrupted, Exception::kExecution
// throws Exception::kTimeout if timeout is exceeded while waiting for
// result.
virtual ExceptionOr<T> get(std::int64_t timeout_ms) = 0;
virtual ExceptionOr<T> Get(absl::Duration timeout) = 0;
};
} // namespace api
} // namespace nearby
} // namespace location
-23
View File
@@ -1,23 +0,0 @@
#ifndef PLATFORM_API_HASH_UTILS_H_
#define PLATFORM_API_HASH_UTILS_H_
#include "platform/byte_array.h"
#include "platform/port/string.h"
#include "platform/ptr.h"
namespace location {
namespace nearby {
// A provider of standard hashing algorithms.
class HashUtils {
public:
virtual ~HashUtils() {}
virtual ConstPtr<ByteArray> md5(const std::string& input) = 0;
virtual ConstPtr<ByteArray> sha256(const std::string& input) = 0;
};
} // namespace nearby
} // namespace location
#endif // PLATFORM_API_HASH_UTILS_H_
+11 -15
View File
@@ -1,29 +1,25 @@
#ifndef PLATFORM_API_INPUT_FILE_H_
#define PLATFORM_API_INPUT_FILE_H_
#include "platform/byte_array.h"
#include "platform/exception.h"
#include "platform/ptr.h"
#include <cstdint>
#include "platform/base/byte_array.h"
#include "platform/base/exception.h"
#include "platform/base/input_stream.h"
namespace location {
namespace nearby {
namespace api {
// An InputFile represents a readable file on the system.
class InputFile {
class InputFile : public InputStream {
public:
virtual ~InputFile() {}
// The returned ConstPtr will be owned (and destroyed) by the caller.
// When we have exhausted reading the file and no bytes remain, read will
// always return an empty ConstPtr for which isNull() is true.
virtual ExceptionOr<ConstPtr<ByteArray>> read(
std::int64_t size) = 0; // throws Exception::IO when the file cannot be
// opened or read.
virtual std::string getFilePath() const = 0;
virtual std::int64_t getTotalSize() const = 0;
virtual void close() = 0;
~InputFile() override = default;
virtual std::string GetFilePath() const = 0;
virtual std::int64_t GetTotalSize() const = 0;
};
} // namespace api
} // namespace nearby
} // namespace location
-31
View File
@@ -1,31 +0,0 @@
#ifndef PLATFORM_API_INPUT_STREAM_H_
#define PLATFORM_API_INPUT_STREAM_H_
#include <cstdint>
#include "platform/byte_array.h"
#include "platform/exception.h"
#include "platform/ptr.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() {}
// The returned ConstPtr will be owned (and destroyed) by the caller.
virtual ExceptionOr<ConstPtr<ByteArray>> read() = 0; // throws Exception::IO
// The returned ConstPtr will be owned (and destroyed) by the caller.
virtual ExceptionOr<ConstPtr<ByteArray>> read(
std::int64_t size) = 0; // throws Exception::IO
virtual Exception::Value close() = 0; // throws Exception::IO
};
} // namespace nearby
} // namespace location
#endif // PLATFORM_API_INPUT_STREAM_H_
+10 -6
View File
@@ -1,14 +1,17 @@
#ifndef PLATFORM_API_LISTENABLE_FUTURE_H_
#define PLATFORM_API_LISTENABLE_FUTURE_H_
#include <functional>
#include <memory>
#include "platform/api/executor.h"
#include "platform/api/future.h"
#include "platform/exception.h"
#include "platform/ptr.h"
#include "platform/runnable.h"
#include "platform/base/exception.h"
#include "platform/base/runnable.h"
namespace location {
namespace nearby {
namespace api {
// A Future that accepts completion listeners.
//
@@ -16,12 +19,13 @@ namespace nearby {
template <typename T>
class ListenableFuture : public Future<T> {
public:
~ListenableFuture() override {}
~ListenableFuture() override = default;
// Executor is shared among multiple runnables. It is not owned by any future.
virtual void addListener(Ptr<Runnable> runnable, Executor* executor) = 0;
virtual void AddListener(Runnable runnable,
Executor* executor) = 0;
};
} // namespace api
} // namespace nearby
} // namespace location
-22
View File
@@ -1,22 +0,0 @@
#ifndef PLATFORM_API_LOCK_H_
#define PLATFORM_API_LOCK_H_
namespace location {
namespace nearby {
// 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 Lock {
public:
virtual ~Lock() {}
virtual void lock() = 0;
virtual void unlock() = 0;
};
} // namespace nearby
} // namespace location
#endif // PLATFORM_API_LOCK_H_
+41
View File
@@ -0,0 +1,41 @@
#ifndef PLATFORM_API_LOG_MESSAGE_H_
#define PLATFORM_API_LOG_MESSAGE_H_
#include <iostream>
namespace location {
namespace nearby {
namespace api {
// A log message that prints to appropraite destination when ~LogMessage() is
// called.
class LogMessage {
public:
enum class Severity {
kInfo = 0,
kWarning = 1,
kError = 2,
kFatal = 3, // Terminates the process after logging
};
// Configures minimum severity to be logged.
static void SetMinLogSeverity(Severity severity);
// Returns if a log with |severity| should be logged based on
// SetMinLogSeverity and additional platform requirements.
static bool ShouldCreateLogMessage(Severity severity);
virtual ~LogMessage() = default;
// Printf like logging.
virtual void Print(const char* format, ...) = 0;
// Returns a stream for std::cout like logging.
virtual std::ostream& Stream() = 0;
};
} // namespace api
} // namespace nearby
} // namespace location
#endif // PLATFORM_API_LOG_MESSAGE_H_
-21
View File
@@ -1,21 +0,0 @@
#ifndef PLATFORM_API_MULTI_THREAD_EXECUTOR_H_
#define PLATFORM_API_MULTI_THREAD_EXECUTOR_H_
#include "platform/api/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 : public SubmittableExecutor {
public:
~MultiThreadExecutor() override = default;
};
} // namespace nearby
} // namespace location
#endif // PLATFORM_API_MULTI_THREAD_EXECUTOR_H_
+41
View File
@@ -0,0 +1,41 @@
#ifndef PLATFORM_API_MUTEX_H_
#define PLATFORM_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_API_MUTEX_H_
+7 -11
View File
@@ -1,25 +1,21 @@
#ifndef PLATFORM_API_OUTPUT_FILE_H_
#define PLATFORM_API_OUTPUT_FILE_H_
#include "platform/byte_array.h"
#include "platform/exception.h"
#include "platform/ptr.h"
#include "platform/base/byte_array.h"
#include "platform/base/exception.h"
#include "platform/base/output_stream.h"
namespace location {
namespace nearby {
namespace api {
// An OutputFile represents a writable file on the system.
class OutputFile {
class OutputFile : public OutputStream {
public:
virtual ~OutputFile() {}
// Takes ownership of the passed-in ConstPtr, and ensures that it is destroyed
// even upon error (i.e. when the return value is not Exception::NONE).
virtual Exception::Value write(
ConstPtr<ByteArray> data) = 0; // throws Exception::IO
virtual void close() = 0;
~OutputFile() override = default;
};
} // namespace api
} // namespace nearby
} // namespace location
-29
View File
@@ -1,29 +0,0 @@
#ifndef PLATFORM_API_OUTPUT_STREAM_H_
#define PLATFORM_API_OUTPUT_STREAM_H_
#include "platform/byte_array.h"
#include "platform/exception.h"
#include "platform/ptr.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() {}
// Takes ownership of the passed-in ConstPtr, and ensures that it is destroyed
// even upon error (i.e. when the return value is not Exception::NONE).
virtual Exception::Value write(
ConstPtr<ByteArray> data) = 0; // throws Exception::IO
virtual Exception::Value flush() = 0; // throws Exception::IO
virtual Exception::Value close() = 0; // throws Exception::IO
};
} // namespace nearby
} // namespace location
#endif // PLATFORM_API_OUTPUT_STREAM_H_
+56 -69
View File
@@ -2,108 +2,95 @@
#define PLATFORM_API_PLATFORM_H_
#include <cstdint>
#include <memory>
#include <string>
#include "platform/api/atomic_boolean.h"
#include "platform/api/atomic_reference_def.h"
#include "platform/api/atomic_reference.h"
#include "platform/api/ble.h"
#include "platform/api/ble_v2.h"
#include "platform/api/bluetooth_adapter.h"
#include "platform/api/bluetooth_classic.h"
#include "platform/api/condition_variable.h"
#include "platform/api/count_down_latch.h"
#include "platform/api/hash_utils.h"
#include "platform/api/crypto.h"
#include "platform/api/input_file.h"
#include "platform/api/lock.h"
#include "platform/api/log_message.h"
#include "platform/api/mutex.h"
#include "platform/api/output_file.h"
#include "platform/api/scheduled_executor.h"
#include "platform/api/server_sync.h"
#include "platform/api/settable_future_def.h"
#include "platform/api/submittable_executor_def.h"
#include "platform/api/settable_future.h"
#include "platform/api/submittable_executor.h"
#include "platform/api/system_clock.h"
#include "platform/api/thread_utils.h"
//#include "platform/api/webrtc.h"
#include "platform/api/webrtc.h"
#include "platform/api/wifi.h"
#include "platform/api/wifi_lan.h"
// Project-specific basic types, that are not part of API.
// TODO(apolyudov): replace with c++ standard types.
#include "platform/port/string.h"
#include "platform/ptr.h"
#include "absl/types/any.h"
#include "platform/base/payload_id.h"
#include "absl/strings/string_view.h"
namespace location {
namespace nearby {
namespace platform {
namespace api {
// API rework notes:
// https://docs.google.com/spreadsheets/d/1erZNkX7pX8s5jWTHdxgjntxTMor3BGiY2H_fC_ldtoQ/edit#gid=381357998
class ImplementationPlatform {
public:
// Class Templates in platform code.
//
// Platform interface does not support templates directly.
// This is a design decision. The purpose is to have type isolation
// between platform library (or simply platform) and core library.
// Another goal is to make a platform implementation a black box,
// which does not leak implementation details in any form, be that types,
// methods, or variables.
//
// Core library code does provide platform-specific class templates
// on top of (a non-templated) platform support.
//
// For every common library template that needs platform support,
// platform must provide an absl::any specialization of class template:
template <typename T>
static Ptr<AtomicReference<T>> createAtomicReference(T initial_value = T{});
template <typename T>
static Ptr<SettableFuture<T>> createSettableFuture();
// 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> scheduled to execute.
// - CountDownLatch : to ensure at least N threads are waiting.
// - file I/O
// - Logging
// AtomicReference<T>
static Ptr<AtomicReference<absl::any>> createAtomicReferenceAny(
absl::any initial_value);
// Atomics:
// =======
// SettableFuture<T>
static Ptr<SettableFuture<absl::any>> createSettableFutureAny();
// Atomic boolean: special case. Uses native platform atomics.
// Does not use locking.
// Does not use dynamic memory allocations in operations.
static std::unique_ptr<AtomicBoolean> CreateAtomicBoolean(bool initial_value);
// Non-template methods: general platform support.
static Ptr<AtomicBoolean> createAtomicBoolean(bool initial_value);
static Ptr<CountDownLatch> createCountDownLatch(std::int32_t count);
static Ptr<Lock> createLock();
static Ptr<ConditionVariable> createConditionVariable(Ptr<Lock> lock);
static Ptr<HashUtils> createHashUtils();
static Ptr<ThreadUtils> createThreadUtils();
static Ptr<SystemClock> createSystemClock();
static Ptr<InputFile> createInputFile(std::int64_t payload_id,
std::int64_t total_size);
static Ptr<OutputFile> createOutputFile(std::int64_t payload_id);
// Supports enums and integers up to 32-bit.
// Does not use locking, if platform supports 32-bit atimics natively.
// Does not use dynamic memory allocations in operations.
static std::unique_ptr<AtomicUint32> CreateAtomicUint32(std::uint32_t 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);
static std::unique_ptr<InputFile> CreateInputFile(PayloadId payload_id,
std::int64_t total_size);
static std::unique_ptr<OutputFile> CreateOutputFile(PayloadId payload_id);
static std::unique_ptr<LogMessage> CreateLogMessage(
const char* file, int line, LogMessage::Severity severity);
// Java-like Executors
// Type aliases used to API 1.0 compatibility.
// They will be retired soon.
// TODO(apolyudov): cleanup.
using SingleThreadExecutorType = SubmittableExecutor;
using MultiThreadExecutorType = SubmittableExecutor;
using ScheduledExecutorType = ScheduledExecutor;
static Ptr<SubmittableExecutor> createSingleThreadExecutor();
static Ptr<SubmittableExecutor> createMultiThreadExecutor(
static std::unique_ptr<SubmittableExecutor> CreateSingleThreadExecutor();
static std::unique_ptr<SubmittableExecutor> CreateMultiThreadExecutor(
std::int32_t max_concurrency);
static Ptr<ScheduledExecutor> createScheduledExecutor();
static std::unique_ptr<ScheduledExecutor> CreateScheduledExecutor();
// Protocol implementations, domain-specific support
static Ptr<BluetoothAdapter> createBluetoothAdapter();
static Ptr<WifiMedium> createWifiMedium();
static Ptr<BluetoothClassicMedium> createBluetoothClassicMedium();
static Ptr<BLEMedium> createBLEMedium();
static Ptr<BLEMediumV2> createBLEMediumV2();
static Ptr<ServerSyncMedium> createServerSyncMedium();
static Ptr<WifiLanMedium> createWifiLanMedium();
// static Ptr<WebRtcSignalingMessenger> createWebRtcSignalingMessenger(
// const std::string& self_id);
static std::string getDeviceId();
static std::unique_ptr<BluetoothAdapter> CreateBluetoothAdapter();
static std::unique_ptr<BluetoothClassicMedium> CreateBluetoothClassicMedium(
BluetoothAdapter&);
static std::unique_ptr<BleMedium> CreateBleMedium(BluetoothAdapter&);
static std::unique_ptr<ble_v2::BleMedium> CreateBleV2Medium(
BluetoothAdapter&);
static std::unique_ptr<ServerSyncMedium> CreateServerSyncMedium();
static std::unique_ptr<WifiMedium> CreateWifiMedium();
static std::unique_ptr<WifiLanMedium> CreateWifiLanMedium();
static std::unique_ptr<WebRtcMedium> CreateWebRtcMedium();
};
} // namespace platform
} // namespace api
} // namespace nearby
} // namespace location
+15 -8
View File
@@ -2,27 +2,34 @@
#define PLATFORM_API_SCHEDULED_EXECUTOR_H_
#include <cstdint>
#include <functional>
#include <memory>
#include "platform/api/submittable_executor_def.h"
#include "platform/cancelable.h"
#include "platform/ptr.h"
#include "platform/runnable.h"
#include "platform/api/cancelable.h"
#include "platform/api/executor.h"
#include "platform/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 SubmittableExecutor {
class ScheduledExecutor : public Executor {
public:
~ScheduledExecutor() override = default;
virtual Ptr<Cancelable> schedule(Ptr<Runnable> runnable,
std::int64_t delay_millis) = 0;
// 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
+25 -27
View File
@@ -3,61 +3,59 @@
#include <string>
#include "platform/byte_array.h"
#include "platform/ptr.h"
#include "platform/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() {}
virtual ~ServerSyncDevice() = default;
virtual std::string getName() = 0;
virtual std::string getGuid() = 0;
virtual std::string getOwnGuid() = 0;
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 Server Sync medium.
// Container of operations that can be performed over the Chrome Sync medium.
class ServerSyncMedium {
public:
virtual ~ServerSyncMedium() {}
virtual ~ServerSyncMedium() = default;
// Takes ownership of (and is responsible for destroying) the passed-in
// 'endpoint_info'.
virtual bool startAdvertising(const std::string& service_id,
const std::string& endpoint_id,
ConstPtr<ByteArray> endpoint_info) = 0;
virtual void stopAdvertising(const std::string& service_id) = 0;
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() {}
virtual ~DiscoveredDeviceCallback() = default;
// Called on a new ServerSyncDevice discovery.
virtual void onDeviceDiscovered(Ptr<ServerSyncDevice> device,
const std::string& service_id,
const std::string& endpoint_id,
ConstPtr<ByteArray> endpoint_info) = 0;
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(Ptr<ServerSyncDevice> device,
const std::string& service_id) = 0;
virtual void OnDeviceLost(ServerSyncDevice* device,
absl::string_view service_id) = 0;
};
// Returns true once the Chrome Sync scan has been initiated.
virtual bool startDiscovery(
const std::string& service_id,
Ptr<DiscoveredDeviceCallback> discovered_device_callback) = 0;
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(const std::string& service_id) = 0;
virtual void StopDiscovery(absl::string_view service_id) = 0;
};
} // namespace api
} // namespace nearby
} // namespace location
+18 -49
View File
@@ -1,65 +1,34 @@
#ifndef PLATFORM_API_SETTABLE_FUTURE_H_
#define PLATFORM_API_SETTABLE_FUTURE_H_
#include "platform/api/platform.h"
#include "platform/api/settable_future_def.h"
#include "platform/exception.h"
#include "platform/ptr.h"
#include "platform/runnable.h"
#include "absl/types/any.h"
#include "platform/api/listenable_future.h"
#include "platform/base/exception.h"
namespace location {
namespace nearby {
namespace api {
// "Common" part of implementation.
// Placed here for textual compatibility to minimize scope of changes.
// Can be (and should be) moved to a separate file outside "api" folder.
// TODO(apolyudov): for API v2.0
namespace platform {
namespace impl {
// 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 SettableFutureImpl : public SettableFuture<T> {
class SettableFuture : public ListenableFuture<T> {
public:
SettableFutureImpl() {
future_ = platform::ImplementationPlatform::createSettableFutureAny();
}
~SettableFuture() override = default;
~SettableFutureImpl() override = default;
// Completes the future successfully. The value is returned to any waiters.
// Returns true, if value was set.
// Returns false, if Future is already in "done" state.
virtual bool Set(T value) = 0;
bool set(T value) override { return future_->set(absl::any(value)); }
bool setException(Exception exception) override {
return future_->setException(exception);
}
void addListener(Ptr<Runnable> runnable, Executor* executor) override {
future_->addListener(runnable, executor);
}
ExceptionOr<T> get() override { return CommonGet(future_->get()); }
ExceptionOr<T> get(std::int64_t timeout_ms) override {
return CommonGet(future_->get(timeout_ms));
}
private:
ExceptionOr<T> CommonGet(ExceptionOr<absl::any> ret_val) {
if (ret_val.exception() != Exception::kSuccess) {
return ExceptionOr<T>{ret_val.exception()};
}
return ExceptionOr<T>{absl::any_cast<T>(ret_val.result())};
}
Ptr<SettableFuture<absl::any>> future_;
// Completes the future unsuccessfully. The exception value is returned to any
// waiters.
// Returns true, if exception was set.
// Returns false, if Future is already in "done" state.
virtual bool SetException(Exception exception) = 0;
};
} // namespace impl
template <typename T>
Ptr<SettableFuture<T>> ImplementationPlatform::createSettableFuture() {
return Ptr<SettableFuture<T>>(new impl::SettableFutureImpl<T>{});
}
} // namespace platform
} // namespace api
} // namespace nearby
} // namespace location
-31
View File
@@ -1,31 +0,0 @@
#ifndef PLATFORM_API_SETTABLE_FUTURE_DEF_H_
#define PLATFORM_API_SETTABLE_FUTURE_DEF_H_
#include "platform/api/listenable_future.h"
#include "platform/exception.h"
namespace location {
namespace nearby {
// 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
//
// Platform must implentent non-template static member functions
// Ptr<SettableFuture<size_t>> CreateSettableFutureSizeT()
// Ptr<SettableFuture<std::shared_ptr<void>>> CreateSettableFuturePtr()
// in the location::nearby::platform::ImplementationPlatform class.
template <typename T>
class SettableFuture : public ListenableFuture<T> {
public:
~SettableFuture() override = default;
virtual bool set(T value) = 0;
virtual bool setException(Exception exception) = 0;
};
} // namespace nearby
} // namespace location
#endif // PLATFORM_API_SETTABLE_FUTURE_DEF_H_
-21
View File
@@ -1,21 +0,0 @@
#ifndef PLATFORM_API_SINGLE_THREAD_EXECUTOR_H_
#define PLATFORM_API_SINGLE_THREAD_EXECUTOR_H_
#include "platform/api/submittable_executor.h"
namespace location {
namespace nearby {
// An Executor that uses a single worker thread operating off an unbounded
// queue.
//
// https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html#newSingleThreadExecutor--
class SingleThreadExecutor : public SubmittableExecutor {
public:
~SingleThreadExecutor() override = default;
};
} // namespace nearby
} // namespace location
#endif // PLATFORM_API_SINGLE_THREAD_EXECUTOR_H_
-26
View File
@@ -1,26 +0,0 @@
#ifndef PLATFORM_API_SOCKET_H_
#define PLATFORM_API_SOCKET_H_
#include "platform/api/input_stream.h"
#include "platform/api/output_stream.h"
#include "platform/ptr.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() {}
virtual Ptr<InputStream> getInputStream() = 0;
virtual Ptr<OutputStream> getOutputStream() = 0;
virtual void close() = 0;
};
} // namespace nearby
} // namespace location
#endif // PLATFORM_API_SOCKET_H_
+17 -26
View File
@@ -2,40 +2,31 @@
#define PLATFORM_API_SUBMITTABLE_EXECUTOR_H_
#include <functional>
#include <memory>
#include "platform/api/executor.h"
#include "platform/api/future.h"
#include "platform/api/platform.h"
#include "platform/api/settable_future.h"
#include "platform/api/submittable_executor_def.h"
#include "platform/exception.h"
#include "platform/base/runnable.h"
namespace location {
namespace nearby {
namespace api {
// "Common" part of implementation.
// Placed here for textual compatibility to minimize scope of changes.
// Can be (and should be) moved to a separate file outside "api" folder.
// TODO(apolyudov): for API v2.0
template <typename T>
Ptr<Future<T>> SubmittableExecutor::submit(Ptr<Callable<T>> callable) {
using Platform = platform::ImplementationPlatform;
Ptr<SettableFuture<T>> future{Platform::createSettableFuture<T>()};
bool submitted = DoSubmit([callable, future]() {
ExceptionOr<T> result = callable->call();
if (result.ok()) {
future->set(std::move(result.result()));
} else {
future->setException({result.exception()});
}
});
if (!submitted) {
// Raise Exception::kExecution if we are shutting down.
future->setException({Exception::kExecution});
}
return future;
}
// 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
@@ -1,35 +0,0 @@
#ifndef PLATFORM_API_SUBMITTABLE_EXECUTOR_DEF_H_
#define PLATFORM_API_SUBMITTABLE_EXECUTOR_DEF_H_
#include <functional>
#include "platform/api/executor.h"
#include "platform/api/future.h"
#include "platform/callable.h"
#include "platform/ptr.h"
namespace location {
namespace nearby {
// 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;
template <typename T>
Ptr<Future<T>> submit(Ptr<Callable<T>> callable);
protected:
// 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(std::function<void()> wrapped_callable) = 0;
};
} // namespace nearby
} // namespace location
#endif // PLATFORM_API_SUBMITTABLE_EXECUTOR_DEF_H_
+9 -8
View File
@@ -1,19 +1,20 @@
#ifndef PLATFORM_API_SYSTEM_CLOCK_H_
#define PLATFORM_API_SYSTEM_CLOCK_H_
#include <cstdint>
#include "platform/base/exception.h"
#include "absl/time/clock.h"
namespace location {
namespace nearby {
class SystemClock {
class SystemClock final {
public:
virtual ~SystemClock() {}
// Returns the time (in milliseconds) since the system was booted, and
// includes deep sleep. This clock should be guaranteed to be monotonic, and
// should continue to tick even when the CPU is in power saving modes.
virtual std::int64_t elapsedRealtime() = 0;
// 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
-23
View File
@@ -1,23 +0,0 @@
#ifndef PLATFORM_API_THREAD_UTILS_H_
#define PLATFORM_API_THREAD_UTILS_H_
#include <cstdint>
#include "platform/exception.h"
namespace location {
namespace nearby {
class ThreadUtils {
public:
virtual ~ThreadUtils() {}
// https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#sleep(long)
virtual Exception::Value sleep(
std::int64_t millis) = 0; // throws Exception::INTERRUPTED
};
} // namespace nearby
} // namespace location
#endif // PLATFORM_API_THREAD_UTILS_H_
+33 -29
View File
@@ -1,46 +1,50 @@
#ifndef PLATFORM_API_WEBRTC_H_
#define PLATFORM_API_WEBRTC_H_
#include <vector>
#include <memory>
#include "platform/byte_array.h"
#include "platform/ptr.h"
//#include "webrtc/api/peer_connection_interface.h"
#include "proto/connections/offline_wire_formats.pb.h"
#include "proto/connections/offline_wire_formats.pb.h"
#include "platform/base/byte_array.h"
#include "absl/strings/string_view.h"
#include "webrtc/api/peer_connection_interface.h"
namespace location {
namespace nearby {
#if 0
namespace api {
class WebRtcSignalingMessenger {
public:
using OnSignalingMessageCallback = std::function<void(const ByteArray&)>;
virtual ~WebRtcSignalingMessenger() = default;
/** Called whenever we receive an inbox message from tachyon. */
class SignalingMessageListener {
public:
virtual ~SignalingMessageListener() = default;
virtual bool SendMessage(absl::string_view peer_id,
const ByteArray& message) = 0;
virtual void onSignalingMessage(ConstPtr<ByteArray> message) = 0;
};
class IceServersListener {
public:
virtual ~IceServersListener() = default;
virtual void OnIceServersFetched(
std::vector<Ptr<webrtc::PeerConnectionInterface::IceServer>>
ice_servers) = 0;
};
virtual bool registerSignaling() = 0;
virtual bool unregisterSignaling() = 0;
virtual bool sendMessage(const std::string& peer_id,
ConstPtr<ByteArray> message) = 0;
virtual bool startReceivingMessages(
Ptr<SignalingMessageListener> listener) = 0;
virtual void getIceServers(Ptr<IceServersListener> ice_servers_listener) = 0;
virtual bool StartReceivingMessages(OnSignalingMessageCallback listener) = 0;
virtual void StopReceivingMessages() = 0;
};
#endif
class WebRtcMedium {
public:
using PeerConnectionCallback =
std::function<void(rtc::scoped_refptr<webrtc::PeerConnectionInterface>)>;
virtual ~WebRtcMedium() = default;
// Creates and returns a new webrtc::PeerConnectionInterface object via
// |callback|.
virtual void CreatePeerConnection(webrtc::PeerConnectionObserver* observer,
PeerConnectionCallback callback) = 0;
// Returns a signaling messenger for sending WebRTC signaling messages.
virtual std::unique_ptr<WebRtcSignalingMessenger> GetSignalingMessenger(
absl::string_view self_id,
const connections::LocationHint& location_hint) = 0;
};
} // namespace api
} // namespace nearby
} // namespace location
+33 -34
View File
@@ -2,47 +2,49 @@
#define PLATFORM_API_WIFI_H_
#include <cstdint>
#include <string>
#include <vector>
#include "platform/port/string.h"
#include "platform/ptr.h"
#include "absl/strings/string_view.h"
namespace location {
namespace nearby {
namespace api {
// Possible authentication types for a WiFi network.
struct WifiAuthType {
enum Value {
UNKNOWN = 0,
OPEN = 1,
WPA_PSK = 2,
WEP = 3,
};
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.
struct WifiConnectionStatus {
enum Value {
UNKNOWN = 0,
CONNECTED = 1,
CONNECTION_FAILURE = 2,
AUTH_FAILURE = 3,
};
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() {}
virtual ~WifiScanResult() = default;
// Gets the SSID of this WiFi network.
virtual std::string getSSID() const = 0;
virtual std::string GetSsid() const = 0;
// Gets the signal strength of this WiFi network in dBm.
virtual std::int32_t getSignalStrengthDbm() const = 0;
virtual std::int32_t GetSignalStrengthDbm() const = 0;
// Gets the frequency band of this WiFi network in MHz.
virtual std::int32_t getFrequencyMhz() const = 0;
virtual std::int32_t GetFrequencyMhz() const = 0;
// Gets the authentication type of this WiFi network.
virtual WifiAuthType::Value getAuthType() const = 0;
virtual WifiAuthType GetAuthType() const = 0;
};
// Container of operations that can be performed over the WiFi medium.
@@ -52,26 +54,22 @@ class WifiMedium {
class ScanResultCallback {
public:
virtual ~ScanResultCallback() {}
virtual ~ScanResultCallback() = default;
// The ConstPtr<WifiScanResult> objects contained in scan_results will be
// owned (and destroyed) by the recipient of the callback methods (i.e. the
// creator of the concrete ScanResultCallback object).
virtual void onScanResults(
const std::vector<ConstPtr<WifiScanResult>>& scan_results) = 0;
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(Ptr<ScanResultCallback> scan_result_callback) = 0;
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::Value connectToNetwork(
const std::string& ssid,
const std::string& password,
WifiAuthType::Value auth_type) = 0;
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.
@@ -79,12 +77,13 @@ class WifiMedium {
// 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;
virtual bool VerifyInternetConnectivity() = 0;
// Returns the local device's IP address in the IPv4 dotted-quad format.
virtual std::string getIPAddress() = 0;
virtual std::string GetIpAddress() = 0;
};
} // namespace api
} // namespace nearby
} // namespace location
+71 -48
View File
@@ -1,49 +1,61 @@
#ifndef PLATFORM_API_WIFI_LAN_H_
#define PLATFORM_API_WIFI_LAN_H_
#include "platform/api/input_stream.h"
#include "platform/api/output_stream.h"
#include "platform/byte_array.h"
#include "platform/exception.h"
#include "platform/port/string.h"
#include "platform/ptr.h"
#include <string>
#include "platform/base/byte_array.h"
#include "platform/base/input_stream.h"
#include "platform/base/listeners.h"
#include "platform/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.
// Opaque wrapper over a WifiLan service which contains packed
// |WifiLanServiceInfo| string name.
class WifiLanService {
public:
virtual ~WifiLanService() = default;
virtual std::string GetName() = 0;
// Returns the packed string of |WifiLanServiceInfo|. Note that the packed
// string would not include TXTRecord, which inheritor should save it in
// another store.
virtual std::string GetServiceName() const = 0;
// Returns the packed string of endpoint info with named key.
virtual std::string GetTxtRecord(const std::string& key) const = 0;
// Returns the local device's <IP address, port> as a pair.
// IP address is in byte sequence, in network order.
virtual std::pair<std::string, int> GetServiceAddress() const = 0;
};
class WifiLanSocket {
public:
virtual ~WifiLanSocket() = default;
// Returns the InputStream of the WifiLanSocket, or a null Ptr<InputStream>
// on error.
// Returns the InputStream of the WifiLanSocket.
// On error, returned stream will report Exception::kIo on any operation.
//
// The returned Ptr is not owned by the caller, and can be invalidated once
// The returned object is not owned by the caller, and can be invalidated once
// the WifiLanSocket object is destroyed.
virtual Ptr<InputStream> GetInputStream() = 0;
virtual InputStream& GetInputStream() = 0;
// Returns the OutputStream of the WifiLanSocket, or a null
// Ptr<OutputStream> on error.
// Returns the OutputStream of the WifiLanSocket.
// On error, returned stream will report Exception::kIo on any operation.
//
// The returned Ptr is not owned by the caller, and can be invalidated once
// The returned object is not owned by the caller, and can be invalidated once
// the WifiLanSocket object is destroyed.
virtual Ptr<OutputStream> GetOutputStream() = 0;
virtual OutputStream& GetOutputStream() = 0;
// Returns Exception::IO on error, Exception::NONE otherwise.
virtual Exception::Value Close() = 0;
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
virtual Exception Close() = 0;
// The returned Ptr is not owned by the caller, and can be invalidated once
// the WifiLanSocket object is destroyed.
virtual Ptr<WifiLanService> GetRemoteWifiLanService() = 0;
// Returns valid WifiLanService pointer if there is a connection, and
// nullptr otherwise.
virtual WifiLanService* GetRemoteWifiLanService() = 0;
};
// Container of operations that can be performed over the WifiLan medium.
@@ -52,44 +64,55 @@ class WifiLanMedium {
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;
const std::string& service_id,
const std::string& wifi_lan_service_info_name,
const std::string& endpoint_info_name) = 0;
virtual bool StopAdvertising(const std::string& service_id) = 0;
// Callback for WifiLan discover results.
class DiscoveredServiceCallback {
public:
virtual ~DiscoveredServiceCallback() = default;
virtual void OnServiceDiscovered(Ptr<WifiLanService> wifi_lan_service) = 0;
virtual void OnServiceLost(Ptr<WifiLanService> wifi_lan_service) = 0;
// Callback that is invoked when a discovered service is found or lost.
struct DiscoveredServiceCallback {
std::function<void(WifiLanService& wifi_lan_service,
const std::string& service_id)>
service_discovered_cb =
DefaultCallback<WifiLanService&, const std::string&>();
std::function<void(WifiLanService& wifi_lan_service,
const std::string& service_id)>
service_lost_cb =
DefaultCallback<WifiLanService&, const std::string&>();
};
virtual bool StartDiscovery(
absl::string_view service_id,
Ptr<DiscoveredServiceCallback> discovered_service_callback) = 0;
virtual void StopDiscovery(absl::string_view service_id) = 0;
// Returns true once the WifiLan discovery has been initiated.
virtual bool StartDiscovery(const std::string& service_id,
DiscoveredServiceCallback callback) = 0;
class AcceptedConnectionCallback {
public:
virtual ~AcceptedConnectionCallback() = default;
// Returns true once WifiLan discovery for service_id is well and truly
// stopped; after this returns, there must be no more invocations of the
// DiscoveredServiceCallback passed in to StartDiscovery() for service_id.
virtual bool StopDiscovery(const std::string& service_id) = 0;
// The Ptr provided in this callback method will be owned (and
// destroyed) by the recipient of the callback methods (i.e. the creator of
// the concrete AcceptedConnectionCallback object).
virtual void OnConnectionAccepted(Ptr<WifiLanSocket> socket,
absl::string_view service_id) = 0;
// Callback that is invoked when a new connection is accepted.
struct AcceptedConnectionCallback {
std::function<void(WifiLanSocket& socket, const std::string& service_id)>
accepted_cb = DefaultCallback<WifiLanSocket&, const std::string&>();
};
// Returns true once WifiLan socket connection requests to service_id can be
// accepted.
virtual bool StartAcceptingConnections(
absl::string_view service_id,
Ptr<AcceptedConnectionCallback> accepted_connection_callback) = 0;
virtual void StopAcceptingConnections(absl::string_view service_id) = 0;
const std::string& service_id, AcceptedConnectionCallback callback) = 0;
virtual bool StopAcceptingConnections(const std::string& service_id) = 0;
virtual Ptr<WifiLanSocket> Connect(Ptr<WifiLanService> wifi_lan_service,
absl::string_view service_id) = 0;
// Connects to a WifiLan service.
// On success, returns a new WifiLanSocket.
// On error, returns nullptr.
virtual std::unique_ptr<WifiLanSocket> Connect(
WifiLanService& service, const std::string& service_id) = 0;
virtual WifiLanService* FindRemoteService(const std::string& ip_address,
int port) = 0;
};
} // namespace api
} // namespace nearby
} // namespace location
+124
View File
@@ -0,0 +1,124 @@
load("//ads/util/non_compile:non_compile.bzl", "cc_with_non_compile_test")
cc_library(
name = "base",
srcs = [
"base64_utils.cc",
"bluetooth_utils.cc",
"prng.cc",
],
hdrs = [
"base64_utils.h",
"bluetooth_utils.h",
"byte_array.h",
"callable.h",
"exception.h",
"input_stream.h",
"listeners.h",
"output_stream.h",
"payload_id.h",
"prng.h",
"runnable.h",
"socket.h",
"types.h",
],
visibility = [
"//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__",
"//core:__subpackages__",
"//platform:__subpackages__",
"//platform/api:__subpackages__",
],
deps = [
"//absl/meta:type_traits",
"//absl/strings",
"//absl/strings:str_format",
"//absl/time",
],
)
cc_library(
name = "util",
srcs = [
"base_input_stream.cc",
"base_pipe.cc",
],
hdrs = [
"base_input_stream.h",
"base_mutex_lock.h",
"base_pipe.h",
],
visibility = [
"//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__",
"//core:__subpackages__",
"//platform/impl:__subpackages__",
"//platform/public:__pkg__",
],
deps = [
":base",
"//platform/api:types",
"//absl/base:core_headers",
],
)
cc_library(
name = "logging",
hdrs = [
"logging.h",
],
visibility = [
"//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__",
"//platform:__subpackages__",
],
deps = [
"//platform/api:platform",
"//platform/api:types",
],
)
cc_library(
name = "test_util",
testonly = True,
srcs = [
"medium_environment.cc",
],
hdrs = [
"medium_environment.h",
],
visibility = [
"//core:__subpackages__",
"//platform/impl:__subpackages__",
"//platform/public:__pkg__",
],
deps = [
":base",
":logging",
"//platform/api:comm",
"//platform/public:types",
"//absl/container:flat_hash_map",
"//absl/strings",
],
)
cc_test(
name = "platform_base_test",
srcs = [
"bluetooth_utils_test.cc",
"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",
],
)
+27
View File
@@ -0,0 +1,27 @@
#include "platform/base/base64_utils.h"
#include "platform/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
+19
View File
@@ -0,0 +1,19 @@
#ifndef PLATFORM_BASE_BASE64_UTILS_H_
#define PLATFORM_BASE_BASE64_UTILS_H_
#include "platform/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_BASE_BASE64_UTILS_H_
+85
View File
@@ -0,0 +1,85 @@
#include "platform/base/base_input_stream.h"
namespace location {
namespace nearby {
ExceptionOr<ByteArray> BaseInputStream::Read(std::int64_t size) {
if (!IsAvailable(size)) {
return ExceptionOr<ByteArray>{Exception::kIo};
}
ByteArray read_bytes{static_cast<size_t>(size)};
if (read_bytes.CopyAt(/*offset=*/0, buffer_,
/*source_offset=*/position_)) {
position_ += size;
return ExceptionOr<ByteArray>{read_bytes};
} else {
return ExceptionOr<ByteArray>{Exception::kIo};
}
}
std::uint8_t BaseInputStream::ReadUint8() {
constexpr int byte_size = sizeof(std::uint8_t);
ByteArray read_bytes = ReadBytes(byte_size);
if (read_bytes.Empty() || read_bytes.size() != byte_size) {
return -1;
}
return read_bytes.data()[0];
}
std::uint16_t BaseInputStream::ReadUint16() {
constexpr int byte_size = sizeof(std::uint16_t);
ByteArray read_bytes = ReadBytes(byte_size);
if (read_bytes.Empty() || read_bytes.size() != byte_size) {
return -1;
}
// Convert from network order.
const char *data = read_bytes.data();
return static_cast<uint16_t>(data[0]) << 8 | static_cast<uint16_t>(data[1]);
}
std::uint32_t BaseInputStream::ReadUint32() {
constexpr int byte_size = sizeof(std::uint32_t);
ByteArray read_bytes = ReadBytes(byte_size);
if (read_bytes.Empty() || read_bytes.size() != byte_size) {
return -1;
}
// Convert from network order.
const char *data = read_bytes.data();
return static_cast<uint32_t>(data[0]) << 24 |
static_cast<uint32_t>(data[1]) << 16 |
static_cast<uint32_t>(data[2]) << 8 | static_cast<uint32_t>(data[3]);
}
std::uint64_t BaseInputStream::ReadUint64() {
constexpr int byte_size = sizeof(std::uint64_t);
ByteArray read_bytes = ReadBytes(byte_size);
if (read_bytes.Empty() || read_bytes.size() != byte_size) {
return -1;
}
// Convert from network order.
const char *data = read_bytes.data();
return static_cast<uint64_t>(data[0]) << 56 |
static_cast<uint64_t>(data[1]) << 48 |
static_cast<uint64_t>(data[2]) << 40 |
static_cast<uint64_t>(data[3]) << 32 |
static_cast<uint64_t>(data[4]) << 24 |
static_cast<uint64_t>(data[5]) << 16 |
static_cast<uint64_t>(data[6]) << 8 | static_cast<uint64_t>(data[7]);
}
ByteArray BaseInputStream::ReadBytes(int size) {
ExceptionOr<ByteArray> read_bytes_result = Read(size);
if (!read_bytes_result.ok()) {
return ByteArray{};
}
return read_bytes_result.GetResult();
}
} // namespace nearby
} // namespace location
+43
View File
@@ -0,0 +1,43 @@
#ifndef PLATFORM_BASE_BASE_INPUT_STREAM_H_
#define PLATFORM_BASE_BASE_INPUT_STREAM_H_
#include "platform/base/byte_array.h"
#include "platform/base/exception.h"
#include "platform/base/input_stream.h"
namespace location {
namespace nearby {
// A base {@link InputStream } for reading the contents of a byte array.
class BaseInputStream : public InputStream {
public:
explicit BaseInputStream(ByteArray &buffer) : buffer_{buffer} {}
BaseInputStream(const BaseInputStream &) = delete;
BaseInputStream &operator=(const BaseInputStream &) = delete;
~BaseInputStream() override { Close(); }
ExceptionOr<ByteArray> Read(std::int64_t size) override;
Exception Close() override {
// Do nothing.
return {Exception::kSuccess};
}
std::uint8_t ReadUint8();
std::uint16_t ReadUint16();
std::uint32_t ReadUint32();
std::uint64_t ReadUint64();
ByteArray ReadBytes(int size);
bool IsAvailable(int size) const {
return buffer_.size() - position_ >= size;
}
private:
ByteArray &buffer_;
int position_{0};
};
} // namespace nearby
} // namespace location
#endif // PLATFORM_BASE_BASE_INPUT_STREAM_H_
+26
View File
@@ -0,0 +1,26 @@
#ifndef PLATFORM_BASE_BASE_MUTEX_LOCK_H_
#define PLATFORM_BASE_BASE_MUTEX_LOCK_H_
#include "platform/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_BASE_BASE_MUTEX_LOCK_H_
+95
View File
@@ -0,0 +1,95 @@
#include "platform/base/base_pipe.h"
#include "platform/base/base_mutex_lock.h"
#include "platform/base/input_stream.h"
#include "platform/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
+128
View File
@@ -0,0 +1,128 @@
#ifndef PLATFORM_BASE_BASE_PIPE_H_
#define PLATFORM_BASE_BASE_PIPE_H_
#include <cstdint>
#include <deque>
#include <memory>
#include "platform/api/condition_variable.h"
#include "platform/api/mutex.h"
#include "platform/base/byte_array.h"
#include "platform/base/exception.h"
#include "platform/base/input_stream.h"
#include "platform/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_BASE_BASE_PIPE_H_
+61
View File
@@ -0,0 +1,61 @@
#include "platform/base/bluetooth_utils.h"
#include "absl/strings/escaping.h"
#include "absl/strings/str_format.h"
namespace location {
namespace nearby {
std::string BluetoothUtils::ToString(const ByteArray& bluetooth_mac_address) {
std::string colon_delimited_string;
if (bluetooth_mac_address.size() != kBluetoothMacAddressLength)
return colon_delimited_string;
if (IsBluetoothMacAddressUnset(bluetooth_mac_address))
return colon_delimited_string;
for (auto byte : std::string(bluetooth_mac_address)) {
if (!colon_delimited_string.empty())
absl::StrAppend(&colon_delimited_string, ":");
absl::StrAppend(&colon_delimited_string, absl::StrFormat("%02X", byte));
}
return colon_delimited_string;
}
ByteArray BluetoothUtils::FromString(absl::string_view bluetooth_mac_address) {
std::string bt_mac_address(bluetooth_mac_address);
// Remove the colon delimiters.
bt_mac_address.erase(
std::remove(bt_mac_address.begin(), bt_mac_address.end(), ':'),
bt_mac_address.end());
// If the bluetooth mac address is invalid (wrong size), return a null byte
// array.
if (bt_mac_address.length() != kBluetoothMacAddressLength * 2) {
return ByteArray();
}
// Convert to bytes. If MAC Address bytes are unset, return a null byte array.
auto bt_mac_address_string(absl::HexStringToBytes(bt_mac_address));
auto bt_mac_address_bytes =
ByteArray(bt_mac_address_string.data(), bt_mac_address_string.size());
if (IsBluetoothMacAddressUnset(bt_mac_address_bytes)) {
return ByteArray();
}
return bt_mac_address_bytes;
}
bool BluetoothUtils::IsBluetoothMacAddressUnset(
const ByteArray& bluetooth_mac_address_bytes) {
for (int i = 0; i < bluetooth_mac_address_bytes.size(); i++) {
if (bluetooth_mac_address_bytes.data()[i] != 0) {
return false;
}
}
return true;
}
} // namespace nearby
} // namespace location
+32
View File
@@ -0,0 +1,32 @@
#ifndef PLATFORM_BASE_BLUETOOTH_UTILS_H_
#define PLATFORM_BASE_BLUETOOTH_UTILS_H_
#include "platform/base/byte_array.h"
#include "absl/strings/string_view.h"
namespace location {
namespace nearby {
class BluetoothUtils {
public:
static constexpr int kBluetoothMacAddressLength = 6;
// Converts a Bluetooth MAC address from byte array to String format. Returns
// empty if input byte array is not of correct format.
// e.g. {-84, 55, 67, -68, -87, 40} -> "AC:37:43:BC:A9:28".
static std::string ToString(const ByteArray& bluetooth_mac_address);
// Converts a Bluetooth MAC address from String format to byte array. Returns
// empty if input string is not of correct format.
// e.g. "AC:37:43:BC:A9:28" -> {-84, 55, 67, -68, -87, 40}.
static ByteArray FromString(absl::string_view bluetooth_mac_address);
// Checks if a Bluetooth MAC address is zero for every byte.
static bool IsBluetoothMacAddressUnset(
const ByteArray& bluetooth_mac_address);
};
} // namespace nearby
} // namespace location
#endif // PLATFORM_BASE_BLUETOOTH_UTILS_H_
+75
View File
@@ -0,0 +1,75 @@
#include "platform/base/bluetooth_utils.h"
#include "gtest/gtest.h"
namespace location {
namespace nearby {
constexpr absl::string_view kBluetoothMacAddress{"00:00:E6:88:64:13"};
constexpr char kBluetoothMacAddressBytes[] = {0x00, 0x00, 0xe6,
0x88, 0x64, 0x13};
TEST(BluetoothUtilsTest, ToStringWorks) {
ByteArray bt_mac_address_bytes{
kBluetoothMacAddressBytes, sizeof(kBluetoothMacAddressBytes)};
auto bt_mac_address = BluetoothUtils::ToString(bt_mac_address_bytes);
EXPECT_EQ(kBluetoothMacAddress, bt_mac_address);
}
TEST(BluetoothUtilsTest, FromStringWorks) {
ByteArray bt_mac_address_bytes{
kBluetoothMacAddressBytes, sizeof(kBluetoothMacAddressBytes)};
auto bt_mac_address_bytes_result =
BluetoothUtils::FromString(kBluetoothMacAddress);
EXPECT_EQ(bt_mac_address_bytes, bt_mac_address_bytes_result);
}
TEST(BluetoothUtilsTest, InvalidBytesReturnsEmptyString) {
std::string string_result;
char bad_bt_mac_address_1[] = {0x02, 0x20, 0x00};
ByteArray bad_bt_mac_address_bytes_1{bad_bt_mac_address_1,
sizeof(bad_bt_mac_address_1)};
string_result = BluetoothUtils::ToString(bad_bt_mac_address_bytes_1);
EXPECT_TRUE(string_result.empty());
char bad_bt_mac_address_2[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
ByteArray bad_bt_mac_address_bytes_2{bad_bt_mac_address_2,
sizeof(bad_bt_mac_address_2)};
string_result = BluetoothUtils::ToString(bad_bt_mac_address_bytes_2);
EXPECT_TRUE(string_result.empty());
char bad_bt_mac_address_3[] = {0x11, 0x22, 0x33, 0x44, 0x55,
0x66, 0x77, 0x88, 0x99};
ByteArray bad_bt_mac_address_bytes_3{bad_bt_mac_address_3,
sizeof(bad_bt_mac_address_3)};
string_result = BluetoothUtils::ToString(bad_bt_mac_address_bytes_3);
EXPECT_TRUE(string_result.empty());
}
TEST(BluetoothUtilsTest, InvalidStringReturnsEmptyByteArray) {
ByteArray bytes_result;
std::string bad_bt_mac_address_1 = "022:00";
bytes_result = BluetoothUtils::FromString(bad_bt_mac_address_1);
EXPECT_TRUE(bytes_result.Empty());
std::string bad_bt_mac_address_2 = "22:00:11:33:77:aa::bb::99";
bytes_result = BluetoothUtils::FromString(bad_bt_mac_address_2);
EXPECT_TRUE(bytes_result.Empty());
std::string bad_bt_mac_address_3 = "00:00:00:00:00:00";
bytes_result = BluetoothUtils::FromString(bad_bt_mac_address_3);
EXPECT_TRUE(bytes_result.Empty());
std::string bad_bt_mac_address_4 = "BLUETOOTHCHIP";
bytes_result = BluetoothUtils::FromString(bad_bt_mac_address_4);
EXPECT_TRUE(bytes_result.Empty());
}
} // namespace nearby
} // namespace location
+98
View File
@@ -0,0 +1,98 @@
#ifndef PLATFORM_BASE_BYTE_ARRAY_H_
#define PLATFORM_BASE_BYTE_ARRAY_H_
#include <array>
#include <cstdint>
#include <string>
#include <type_traits>
#include <utility>
namespace location {
namespace nearby {
class ByteArray {
public:
// Create an empty ByteArray
ByteArray() = default;
template <size_t N>
explicit ByteArray(const std::array<char, N>& data) {
SetData(data.data(), data.size());
}
ByteArray(const ByteArray&) = default;
ByteArray& operator=(const ByteArray&) = default;
ByteArray(ByteArray&&) = default;
ByteArray& operator=(ByteArray&&) = default;
// Moves string out of temporary, allowing for a zero-copy constructions.
// This is an optimization for very large strings.
explicit ByteArray(std::string&& source) : data_(std::move(source)) {}
// Create ByteArray by copy of a std::string. This can't be a string_view,
// because it will conflict with std::string&& version of constructor.
explicit ByteArray(const std::string& source) {
SetData(source.data(), source.size());
}
// 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);
// Returns a copy of internal representation as std::string.
explicit operator std::string() const& { return data_; }
// Moves string out of temporary ByteArray, allowing for a zero-copy
// operation.
explicit operator std::string() && { return std::move(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_BASE_BYTE_ARRAY_H_
+76
View File
@@ -0,0 +1,76 @@
#include "platform/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));
}
TEST(ByteArrayTest, CreateFromNonNullTerminatedStdArray) {
constexpr static const std::array data{'a', '\x00', 'b'};
ByteArray bytes{data};
EXPECT_EQ(bytes.size(), 3);
EXPECT_EQ(bytes.size(), std::string(bytes).size());
EXPECT_EQ(std::string(bytes), std::string(data.data(), data.size()));
}
} // namespace
+23
View File
@@ -0,0 +1,23 @@
#ifndef PLATFORM_BASE_CALLABLE_H_
#define PLATFORM_BASE_CALLABLE_H_
#include <functional>
#include "platform/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_BASE_CALLABLE_H_
+98
View File
@@ -0,0 +1,98 @@
#ifndef PLATFORM_BASE_EXCEPTION_H_
#define PLATFORM_BASE_EXCEPTION_H_
#include <utility>
#include "absl/meta/type_traits.h"
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 = absl::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_BASE_EXCEPTION_H_
@@ -1,7 +1,8 @@
#include "platform/exception.h"
#include "platform/base/exception.h"
#include <vector>
#include "platform/base/exception_test.nc.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
@@ -57,20 +58,49 @@ TEST(ExceptionOr, Result_Reference_Const) {
TEST(ExceptionOr, Result_Move_NonConst) {
ExceptionOr<std::vector<int>> exception_or_vector({1, 2, 3});
ASSERT_FALSE(exception_or_vector.result().empty());
EXPECT_FALSE(exception_or_vector.result().empty());
// Moving the result should clear the source.
std::vector<int> moved = std::move(exception_or_vector).result();
ASSERT_FALSE(moved.empty());
EXPECT_FALSE(moved.empty());
}
TEST(ExceptionOr, Result_Move_Const) {
const ExceptionOr<std::vector<int>> exception_or_vector({1, 2, 3});
ASSERT_FALSE(exception_or_vector.result().empty());
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();
ASSERT_FALSE(moved.empty());
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
+28
View File
@@ -0,0 +1,28 @@
#ifndef PLATFORM_BASE_INPUT_STREAM_H_
#define PLATFORM_BASE_INPUT_STREAM_H_
#include <cstdint>
#include "platform/base/byte_array.h"
#include "platform/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_BASE_INPUT_STREAM_H_
+20
View File
@@ -0,0 +1,20 @@
#ifndef PLATFORM_BASE_LISTENERS_H_
#define PLATFORM_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_BASE_LISTENERS_H_
+65
View File
@@ -0,0 +1,65 @@
#ifndef PLATFORM_BASE_LOGGING_H_
#define PLATFORM_BASE_LOGGING_H_
#include "platform/api/log_message.h"
#include "platform/api/platform.h"
namespace location {
namespace nearby {
// This class is used to explicitly ignore values in the conditional
// logging macros. This avoids compiler warnings like "value computed
// is not used" and "statement has no effect".
class LogMessageVoidify {
public:
LogMessageVoidify() = default;
// This has to be an operator with a precedence lower than << but
// higher than ?:
void operator&(std::ostream&) {}
};
} // namespace nearby
} // namespace location
// Severity enum conversion
#define NEARBY_SEVERITY_INFO location::nearby::api::LogMessage::Severity::kInfo
#define NEARBY_SEVERITY_WARNING \
location::nearby::api::LogMessage::Severity::kWarning
#define NEARBY_SEVERITY_ERROR \
location::nearby::api::LogMessage::Severity::kError
#define NEARBY_SEVERITY_FATAL \
location::nearby::api::LogMessage::Severity::kFatal
#if defined(_WIN32)
// wingdi.h defines ERROR to be 0. When we call LOG(ERROR), it gets substituted
// with 0, and it expands to NEARBY_SEVERITY_0. To allow us to keep using this
// syntax, we define this macro to do the same thing as NEARBY_SEVERITY_ERROR.
#define NEARBY_SEVERITY_0 location::nearby::api::LogMessage::Severity::kError
#endif // defined(_WIN32)
#define NEARBY_SEVERITY(severity) NEARBY_SEVERITY_##severity
// Log enabling
#define NEARBY_LOG_IS_ON(severity) \
location::nearby::api::LogMessage::ShouldCreateLogMessage( \
NEARBY_SEVERITY(severity))
#define NEARBY_LOG_SET_SEVERITY(severity) \
location::nearby::api::LogMessage::SetMinLogSeverity( \
NEARBY_SEVERITY(severity))
// Log message creation
#define NEARBY_LOG_MESSAGE(severity) \
location::nearby::api::ImplementationPlatform::CreateLogMessage( \
__FILE__, __LINE__, NEARBY_SEVERITY(severity))
// Public APIs
// The stream statement must come last or otherwise it won't compile.
#define NEARBY_LOGS(severity) \
!(NEARBY_LOG_IS_ON(severity)) ? (void)0 \
: location::nearby::LogMessageVoidify() & \
NEARBY_LOG_MESSAGE(severity)->Stream()
#define NEARBY_LOG(severity, ...) \
NEARBY_LOG_IS_ON(severity) \
? NEARBY_LOG_MESSAGE(severity)->Print(__VA_ARGS__) : (void)0
#endif // PLATFORM_BASE_LOGGING_H_
+647
View File
@@ -0,0 +1,647 @@
#include "platform/base/medium_environment.h"
#include <atomic>
#include <cinttypes>
#include <new>
#include <type_traits>
#include "platform/api/ble.h"
#include "platform/api/bluetooth_adapter.h"
#include "platform/api/bluetooth_classic.h"
#include "platform/api/wifi_lan.h"
#include "platform/base/logging.h"
#include "platform/public/count_down_latch.h"
namespace location {
namespace nearby {
MediumEnvironment& MediumEnvironment::Instance() {
static std::aligned_storage_t<sizeof(MediumEnvironment),
alignof(MediumEnvironment)>
storage;
static MediumEnvironment* env = new (&storage) MediumEnvironment();
return *env;
}
void MediumEnvironment::Start(EnvironmentConfig config) {
if (!enabled_.exchange(true)) {
NEARBY_LOG(INFO, "MediumEnvironment::Start()");
config_ = std::move(config);
Reset();
}
}
void MediumEnvironment::Stop() {
if (enabled_.exchange(false)) {
NEARBY_LOG(INFO, "MediumEnvironment::Stop()");
Sync(false);
}
}
void MediumEnvironment::Reset() {
RunOnMediumEnvironmentThread([this]() {
NEARBY_LOG(INFO, "MediumEnvironment::Reset()");
bluetooth_adapters_.clear();
bluetooth_mediums_.clear();
ble_mediums_.clear();
wifi_lan_mediums_.clear();
});
Sync();
}
void MediumEnvironment::Sync(bool enable_notifications) {
enable_notifications_ = enable_notifications;
NEARBY_LOG(INFO, "MediumEnvironment::sync(%d)", enable_notifications);
int count = 0;
do {
CountDownLatch latch(1);
count = job_count_ + 1;
// We are about to schedule one last job.
// When it is done, counter must be equal to count.
// However, if pending jobs schedule anything else,
// it will be pending after us.
// If we want to ensure we are completely idle, then we have to
// repeat sync, until this becomes true.
RunOnMediumEnvironmentThread([&latch]() { latch.CountDown(); });
latch.Await();
} while (count < job_count_);
NEARBY_LOG(INFO, "MediumEnvironment::Sync(): done [count=%d]", count);
}
const EnvironmentConfig& MediumEnvironment::GetEnvironmentConfig() {
return config_;
}
void MediumEnvironment::OnBluetoothAdapterChangedState(
api::BluetoothAdapter& adapter, api::BluetoothDevice& adapter_device,
std::string name, bool enabled, api::BluetoothAdapter::ScanMode mode) {
if (!enabled_) return;
RunOnMediumEnvironmentThread([this, &adapter, &adapter_device,
name = std::move(name), enabled, mode]() {
NEARBY_LOG(INFO,
"[adapter=%p, device=%p] update: name=%s, enabled=%d, mode=%d",
&adapter, &adapter_device, name.c_str(), enabled, mode);
for (auto& medium_info : bluetooth_mediums_) {
auto& info = medium_info.second;
// Do not send notification to medium that owns this adapter.
if (info.adapter == &adapter) continue;
NEARBY_LOG(INFO, "[adapter=%p, device=%p] notify: adapter=%p", &adapter,
&adapter_device, info.adapter);
OnBluetoothDeviceStateChanged(info, adapter_device, name, mode, enabled);
}
// We don't care if there is an adapter already since all we store is a
// pointer. Pointer must remain valid for the duration of a Core session
// (since it is owned by the correspoinding Medium, and mediums lifetime
// matches Core lifetime).
bluetooth_adapters_.emplace(&adapter, &adapter_device);
});
}
void MediumEnvironment::OnBluetoothDeviceStateChanged(
BluetoothMediumContext& info, api::BluetoothDevice& device,
const std::string& name, api::BluetoothAdapter::ScanMode mode,
bool enabled) {
if (!enabled_) return;
auto item = info.devices.find(&device);
if (item == info.devices.end()) {
NEARBY_LOG(INFO,
"G3 OnBluetoothDeviceStateChanged [device impl=%p]: new device; "
"notify=%d",
&device, enable_notifications_.load());
if (mode == api::BluetoothAdapter::ScanMode::kConnectableDiscoverable &&
enabled) {
// New device is turned on, and is in discoverable state.
// Store device name, and report it as discovered.
info.devices.emplace(&device, name);
if (enable_notifications_) {
RunOnMediumEnvironmentThread(
[&info, &device]() { info.callback.device_discovered_cb(device); });
}
}
} else {
NEARBY_LOG(INFO,
"G3 OnBluetoothDeviceStateChanged [device impl=%p]: exisitng "
"device; notify=%d",
&device, enable_notifications_.load());
auto& discovered_name = item->second;
if (mode == api::BluetoothAdapter::ScanMode::kConnectableDiscoverable &&
enabled) {
if (name != discovered_name) {
// Known device is turned on, and is in discoverable state.
// Store device name, and report it as renamed.
item->second = name;
if (enable_notifications_) {
RunOnMediumEnvironmentThread([&info, &device]() {
info.callback.device_name_changed_cb(device);
});
}
} else {
// Device is in discovery mode, so we are reporting it anyway.
if (enable_notifications_) {
RunOnMediumEnvironmentThread([&info, &device]() {
info.callback.device_discovered_cb(device);
});
}
}
}
if (!enabled) {
// Known device is turned off.
// Erase it from the map, and report as lost.
if (enable_notifications_) {
RunOnMediumEnvironmentThread(
[&info, &device]() { info.callback.device_lost_cb(device); });
}
info.devices.erase(item);
}
}
}
api::BluetoothDevice* MediumEnvironment::FindBluetoothDevice(
const std::string& mac_address) {
api::BluetoothDevice* device = nullptr;
CountDownLatch latch(1);
RunOnMediumEnvironmentThread([this, &device, &latch, &mac_address]() {
for (auto& item : bluetooth_mediums_) {
auto* adapter = item.second.adapter;
if (!adapter) continue;
if (adapter->GetMacAddress() == mac_address) {
device = bluetooth_adapters_[adapter];
break;
}
}
latch.CountDown();
});
latch.Await();
return device;
}
void MediumEnvironment::OnBlePeripheralStateChanged(
BleMediumContext& info, api::BlePeripheral& peripheral,
const std::string& service_id, bool fast_advertisement, bool enabled) {
if (!enabled_) return;
NEARBY_LOG(INFO,
"G3 OnBleServiceStateChanged [peripheral impl=%p]; context=%p; "
"service_id=%s; notify=%d",
&peripheral, &info, service_id.c_str(),
enable_notifications_.load());
if (!enable_notifications_) return;
RunOnMediumEnvironmentThread([&info, enabled, &peripheral, service_id,
fast_advertisement]() {
NEARBY_LOG(INFO,
"G3 [Run] OnBlePeripheralStateChanged [peripheral impl=%p]; "
"context=%p; service_id=%s; enabled=%d",
&peripheral, &info, service_id.c_str(), enabled);
if (enabled) {
info.discovery_callback.peripheral_discovered_cb(peripheral, service_id,
fast_advertisement);
} else {
info.discovery_callback.peripheral_lost_cb(peripheral, service_id);
}
});
}
void MediumEnvironment::OnWifiLanServiceStateChanged(
WifiLanMediumContext& info, api::WifiLanService& service,
const std::string& service_id, bool enabled) {
if (!enabled_) return;
NEARBY_LOG(INFO,
"G3 OnWifiLanServiceStateChanged [service impl=%p]; context=%p; "
"service_id=%s; notify=%d",
&service, &info, service_id.c_str(), enable_notifications_.load());
if (!enable_notifications_) return;
RunOnMediumEnvironmentThread([&info, enabled, &service, service_id]() {
NEARBY_LOG(INFO,
"G3 [Run] OnWifiLanServiceStateChanged [service impl=%p]; "
"context=%p; service_id=%s; enabled=%d",
&service, &info, service_id.c_str(), enabled);
auto service_id_context = info.services.find(service_id);
if (service_id_context == info.services.end()) return;
if (enabled) {
service_id_context->second.discovery_callback.service_discovered_cb(
service, service_id);
} else {
service_id_context->second.discovery_callback.service_lost_cb(service,
service_id);
}
});
}
void MediumEnvironment::RunOnMediumEnvironmentThread(
std::function<void()> runnable) {
job_count_++;
executor_.Execute(std::move(runnable));
}
void MediumEnvironment::RegisterBluetoothMedium(
api::BluetoothClassicMedium& medium,
api::BluetoothAdapter& medium_adapter) {
if (!enabled_) return;
RunOnMediumEnvironmentThread([this, &medium, &medium_adapter]() {
auto& context = bluetooth_mediums_
.insert({&medium,
BluetoothMediumContext{
.adapter = &medium_adapter,
}})
.first->second;
auto* owned_adapter = context.adapter;
NEARBY_LOG(INFO, "Registered: medium=%p; adapter=%p", &medium,
owned_adapter);
for (auto& adapter_device : bluetooth_adapters_) {
auto& adapter = adapter_device.first;
auto& device = adapter_device.second;
if (adapter == nullptr) continue;
OnBluetoothDeviceStateChanged(context, *device, adapter->GetName(),
adapter->GetScanMode(),
adapter->IsEnabled());
}
});
}
void MediumEnvironment::UpdateBluetoothMedium(
api::BluetoothClassicMedium& medium, BluetoothDiscoveryCallback callback) {
if (!enabled_) return;
RunOnMediumEnvironmentThread([this, &medium,
callback = std::move(callback)]() {
auto item = bluetooth_mediums_.find(&medium);
if (item == bluetooth_mediums_.end()) return;
auto& context = item->second;
context.callback = std::move(callback);
auto* owned_adapter = context.adapter;
NEARBY_LOG(
INFO,
"Updated: this=%p; medium=%p; adapter=%p; name=%s; enabled=%d; mode=%d",
this, &medium, owned_adapter, owned_adapter->GetName().c_str(),
owned_adapter->IsEnabled(), owned_adapter->GetScanMode());
for (auto& adapter_device : bluetooth_adapters_) {
auto& adapter = adapter_device.first;
auto& device = adapter_device.second;
if (adapter == nullptr) continue;
OnBluetoothDeviceStateChanged(context, *device, adapter->GetName(),
adapter->GetScanMode(),
adapter->IsEnabled());
}
});
}
void MediumEnvironment::UnregisterBluetoothMedium(
api::BluetoothClassicMedium& medium) {
if (!enabled_) return;
RunOnMediumEnvironmentThread([this, &medium]() {
auto item = bluetooth_mediums_.extract(&medium);
if (item.empty()) return;
auto& context = item.mapped();
NEARBY_LOG(INFO, "Unregistered medium for device=%s",
context.adapter->GetName().c_str());
});
}
void MediumEnvironment::RegisterBleMedium(api::BleMedium& medium) {
if (!enabled_) return;
RunOnMediumEnvironmentThread([this, &medium]() {
ble_mediums_.insert({&medium, BleMediumContext{}});
NEARBY_LOG(INFO, "Registered: medium=%p", &medium);
});
}
void MediumEnvironment::UpdateBleMediumForAdvertising(
api::BleMedium& medium, api::BlePeripheral& peripheral,
const std::string& service_id, bool fast_advertisement, bool enabled) {
if (!enabled_) return;
RunOnMediumEnvironmentThread(
[this, &medium, &peripheral, service_id, fast_advertisement, enabled]() {
auto item = ble_mediums_.find(&medium);
if (item == ble_mediums_.end()) {
NEARBY_LOG(INFO,
"UpdateBleMediumForAdvertising failed. There is no medium "
"registered.");
return;
}
auto& context = item->second;
context.ble_peripheral = &peripheral;
context.advertising = enabled;
context.fast_advertisement = fast_advertisement;
NEARBY_LOG(
INFO,
"Update Ble medium for advertising: this=%p; medium=%p; "
"service_id=%s; name=%s; fast_advertisement=%d; enabled=%d; ",
this, &medium, service_id.c_str(), peripheral.GetName().c_str(),
fast_advertisement, enabled);
for (auto& medium_info : ble_mediums_) {
auto& local_medium = medium_info.first;
auto& info = medium_info.second;
// Do not send notification to the same medium.
if (local_medium == &medium) continue;
OnBlePeripheralStateChanged(info, peripheral, service_id,
fast_advertisement, enabled);
}
});
}
void MediumEnvironment::UpdateBleMediumForScanning(
api::BleMedium& medium, const std::string& service_id,
const std::string& fast_advertisement_service_uuid,
BleDiscoveredPeripheralCallback callback, bool enabled) {
if (!enabled_) return;
RunOnMediumEnvironmentThread(
[this, &medium, service_id, fast_advertisement_service_uuid,
callback = std::move(callback), enabled]() {
auto item = ble_mediums_.find(&medium);
if (item == ble_mediums_.end()) {
NEARBY_LOG(INFO,
"UpdateBleMediumFoScanning failed. There is no medium "
"registered.");
return;
}
auto& context = item->second;
context.discovery_callback = std::move(callback);
NEARBY_LOG(
INFO,
"Update Ble medium for scanning: this=%p; medium=%p; "
"service_id=%s; fast_advertisement_service_uuid=%s; enabled=%d ;",
this, &medium, service_id.c_str(),
fast_advertisement_service_uuid.c_str(), enabled);
for (auto& medium_info : ble_mediums_) {
auto& local_medium = medium_info.first;
auto& info = medium_info.second;
// Do not send notification to the same medium.
if (local_medium == &medium) continue;
// Search advertising mediums and send notification.
if (info.advertising && enabled) {
OnBlePeripheralStateChanged(context, *(info.ble_peripheral),
service_id, info.fast_advertisement,
enabled);
}
}
});
}
void MediumEnvironment::UpdateBleMediumForAcceptedConnection(
api::BleMedium& medium, const std::string& service_id,
BleAcceptedConnectionCallback callback) {
if (!enabled_) return;
RunOnMediumEnvironmentThread(
[this, &medium, service_id, callback = std::move(callback)]() {
auto item = ble_mediums_.find(&medium);
if (item == ble_mediums_.end()) {
NEARBY_LOG(
INFO, "Update Ble medium failed. There is no medium registered.");
return;
}
auto& context = item->second;
context.accepted_connection_callback = std::move(callback);
NEARBY_LOG(INFO,
"Update Ble medium for accepted callback: this=%p; "
"medium=%p; service_id=%s; ",
this, &medium, service_id.c_str());
});
}
void MediumEnvironment::UnregisterBleMedium(api::BleMedium& medium) {
if (!enabled_) return;
RunOnMediumEnvironmentThread([this, &medium]() {
auto item = ble_mediums_.extract(&medium);
if (item.empty()) return;
NEARBY_LOG(INFO, "Unregistered Ble medium");
});
}
void MediumEnvironment::CallBleAcceptedConnectionCallback(
api::BleMedium& medium, api::BleSocket& socket,
const std::string& service_id) {
if (!enabled_) return;
RunOnMediumEnvironmentThread([this, &medium, &socket, service_id]() {
auto item = ble_mediums_.find(&medium);
if (item == ble_mediums_.end()) {
NEARBY_LOG(INFO,
"Call AcceptedConnectionCallback failed.. There is no medium "
"registered.");
return;
}
auto& info = item->second;
info.accepted_connection_callback.accepted_cb(socket, service_id);
});
}
void MediumEnvironment::RegisterWebRtcSignalingMessenger(
absl::string_view self_id, OnSignalingMessageCallback callback) {
if (!enabled_) return;
RunOnMediumEnvironmentThread(
[this, self_id{std::string(self_id)}, callback{std::move(callback)}]() {
webrtc_signaling_callback_[self_id] = std::move(callback);
NEARBY_LOG(INFO, "Registered signaling message callback for id = %s",
self_id.c_str());
});
}
void MediumEnvironment::UnregisterWebRtcSignalingMessenger(
absl::string_view self_id) {
if (!enabled_) return;
RunOnMediumEnvironmentThread([this, self_id{std::string(self_id)}]() {
auto item = webrtc_signaling_callback_.extract(self_id);
if (item.empty()) return;
NEARBY_LOG(INFO, "Unregistered signaling message callback for id = %s",
self_id.c_str());
});
}
void MediumEnvironment::SendWebRtcSignalingMessage(absl::string_view peer_id,
const ByteArray& message) {
if (!enabled_) return;
RunOnMediumEnvironmentThread(
[this, peer_id{std::string(peer_id)}, message]() {
auto item = webrtc_signaling_callback_.find(peer_id);
if (item == webrtc_signaling_callback_.end()) {
NEARBY_LOG(WARNING, "No callback registered for peer id = %s",
peer_id.c_str());
return;
}
item->second(message);
});
}
void MediumEnvironment::SetUseValidPeerConnection(
bool use_valid_peer_connection) {
use_valid_peer_connection_ = use_valid_peer_connection;
}
bool MediumEnvironment::GetUseValidPeerConnection() {
return use_valid_peer_connection_;
}
void MediumEnvironment::RegisterWifiLanMedium(api::WifiLanMedium& medium) {
if (!enabled_) return;
RunOnMediumEnvironmentThread([this, &medium]() {
wifi_lan_mediums_.insert({&medium, WifiLanMediumContext{}});
NEARBY_LOG(INFO, "Registered: medium=%p", &medium);
});
}
void MediumEnvironment::UpdateWifiLanMediumForAdvertising(
api::WifiLanMedium& medium, api::WifiLanService& service,
const std::string& service_id, bool enabled) {
if (!enabled_) return;
RunOnMediumEnvironmentThread([this, &medium, &service, service_id,
enabled]() {
auto item = wifi_lan_mediums_.find(&medium);
if (item == wifi_lan_mediums_.end()) {
NEARBY_LOG(INFO,
"UpdateWifiLanMediumForAdvertising failed. There is no medium "
"registered.");
return;
}
auto& context = item->second;
context.wifi_lan_service = &service;
auto service_id_context = context.services.find(service_id);
if (service_id_context == context.services.end()) {
WifiLanServiceIdContext id_context{
.advertising = enabled,
};
context.services.emplace(service_id, std::move(id_context));
} else {
service_id_context->second.advertising = enabled;
}
NEARBY_LOG(INFO,
"Update WifiLan medium for advertising: this=%p; medium=%p; "
"service_id=%s; name=%s; enabled=%d",
this, &medium, service_id.c_str(),
service.GetServiceName().c_str(), enabled);
for (auto& medium_info : wifi_lan_mediums_) {
auto& local_medium = medium_info.first;
auto& info = medium_info.second;
// Do not send notification to the same medium.
if (local_medium == &medium) continue;
OnWifiLanServiceStateChanged(info, service, service_id, enabled);
}
});
}
void MediumEnvironment::UpdateWifiLanMediumForDiscovery(
api::WifiLanMedium& medium, const std::string& service_id,
WifiLanDiscoveredServiceCallback callback, bool enabled) {
if (!enabled_) return;
RunOnMediumEnvironmentThread([this, &medium, service_id,
callback = std::move(callback), enabled]() {
auto item = wifi_lan_mediums_.find(&medium);
if (item == wifi_lan_mediums_.end()) {
NEARBY_LOG(INFO,
"UpdateWifiLanMediumForDiscovery failed. There is no medium "
"registered.");
return;
}
auto& context = item->second;
auto service_id_context = context.services.find(service_id);
if (service_id_context == context.services.end()) {
WifiLanServiceIdContext id_context{
.discovery_callback = std::move(callback),
};
context.services.emplace(service_id, std::move(id_context));
} else {
service_id_context->second.discovery_callback = std::move(callback);
}
NEARBY_LOG(INFO,
"Update WifiLan medium for discovery: this=%p; medium=%p; "
"service_id=%s; enabled=%d; ",
this, &medium, service_id.c_str(), enabled);
for (auto& medium_info : wifi_lan_mediums_) {
auto& local_medium = medium_info.first;
auto& info = medium_info.second;
// Do not send notification to the same medium.
if (local_medium == &medium) continue;
// Search advertising mediums and send notification.
for (auto& service_id_context : info.services) {
auto& service_id = service_id_context.first;
auto& id_context = service_id_context.second;
if (id_context.advertising && enabled) {
OnWifiLanServiceStateChanged(context, *(info.wifi_lan_service),
service_id, enabled);
}
}
}
});
}
void MediumEnvironment::UpdateWifiLanMediumForAcceptedConnection(
api::WifiLanMedium& medium, const std::string& service_id,
WifiLanAcceptedConnectionCallback callback) {
if (!enabled_) return;
RunOnMediumEnvironmentThread([this, &medium, service_id,
callback = std::move(callback)]() {
auto item = wifi_lan_mediums_.find(&medium);
if (item == wifi_lan_mediums_.end()) {
NEARBY_LOG(
INFO, "Update WifiLan medium failed. There is no medium registered.");
return;
}
auto& context = item->second;
auto service_id_context = context.services.find(service_id);
if (service_id_context == context.services.end()) {
WifiLanServiceIdContext id_context{
.accepted_connection_callback = std::move(callback),
};
context.services.emplace(service_id, std::move(id_context));
} else {
service_id_context->second.accepted_connection_callback =
std::move(callback);
}
NEARBY_LOG(INFO,
"Update WifiLan medium for accepted callback: this=%p; "
"medium=%p; service_id=%s; ",
this, &medium, service_id.c_str());
});
}
void MediumEnvironment::UnregisterWifiLanMedium(api::WifiLanMedium& medium) {
if (!enabled_) return;
RunOnMediumEnvironmentThread([this, &medium]() {
auto item = wifi_lan_mediums_.extract(&medium);
if (item.empty()) return;
NEARBY_LOG(INFO, "Unregistered WifiLan medium");
});
}
void MediumEnvironment::CallWifiLanAcceptedConnectionCallback(
api::WifiLanMedium& medium, api::WifiLanSocket& socket,
const std::string& service_id) {
if (!enabled_) return;
RunOnMediumEnvironmentThread([this, &medium, &socket, service_id]() {
auto item = wifi_lan_mediums_.find(&medium);
if (item == wifi_lan_mediums_.end()) {
NEARBY_LOG(INFO,
"Call AcceptedConnectionCallback failed.. There is no medium "
"registered.");
return;
}
auto& info = item->second;
auto service_id_context = info.services.find(service_id);
if (service_id_context != info.services.end()) {
service_id_context->second.accepted_connection_callback.accepted_cb(
socket, service_id);
}
});
}
api::WifiLanService* MediumEnvironment::FindWifiLanService(
const std::string& ip_address, int port) {
api::WifiLanService* remote_service = nullptr;
CountDownLatch latch(1);
RunOnMediumEnvironmentThread(
[this, &remote_service, &ip_address, port, &latch]() {
for (auto& item : wifi_lan_mediums_) {
auto* service = item.second.wifi_lan_service;
if (!service) continue;
auto addr = remote_service->GetServiceAddress();
if (addr.first == ip_address && addr.second == port) {
remote_service = service;
break;
}
}
latch.CountDown();
});
latch.Await();
return remote_service;
}
} // namespace nearby
} // namespace location
+298
View File
@@ -0,0 +1,298 @@
#ifndef PLATFORM_BASE_MEDIUM_ENVIRONMENT_H_
#define PLATFORM_BASE_MEDIUM_ENVIRONMENT_H_
#include <atomic>
#include "platform/api/bluetooth_adapter.h"
#include "platform/api/bluetooth_classic.h"
#include "platform/api/webrtc.h"
#include "platform/base/byte_array.h"
#include "platform/base/listeners.h"
#include "platform/public/single_thread_executor.h"
#include "absl/container/flat_hash_map.h"
#include "absl/strings/string_view.h"
namespace location {
namespace nearby {
// Environment config that can control availability of certain mediums for
// testing.
struct EnvironmentConfig {
// Control whether WEB_RTC medium is enabled in the environment.
// This is currently set to false, due to http://b/139734036 that would lead
// to flaky tests.
bool webrtc_enabled = false;
};
// MediumEnvironment is a simulated environment which allows 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.
// NOTE: this code depends on public:types target.
class MediumEnvironment {
public:
using BluetoothDiscoveryCallback =
api::BluetoothClassicMedium::DiscoveryCallback;
using BleDiscoveredPeripheralCallback =
api::BleMedium::DiscoveredPeripheralCallback;
using BleAcceptedConnectionCallback =
api::BleMedium::AcceptedConnectionCallback;
using OnSignalingMessageCallback =
api::WebRtcSignalingMessenger::OnSignalingMessageCallback;
using WifiLanDiscoveredServiceCallback =
api::WifiLanMedium::DiscoveredServiceCallback;
using WifiLanAcceptedConnectionCallback =
api::WifiLanMedium::AcceptedConnectionCallback;
MediumEnvironment(const MediumEnvironment&) = delete;
MediumEnvironment& operator=(const MediumEnvironment&) = delete;
// Creates and returns a reference to the global test environment instance.
static MediumEnvironment& Instance();
// Global ON/OFF switch for medium environment.
// Start & Stop work as On/Off switch for this object.
// Default state (after creation) is ON, to make it compatible with early
// tests that are already using it and relying on it being ON.
// Enables Medium environment.
void Start(EnvironmentConfig config = EnvironmentConfig());
// Disables Medium environment.
void Stop();
// Clears state. No notifications are sent.
void Reset();
// Waits for all previously scheduled jobs to finish.
// This method works as a barrier that guarantees that after it returns, all
// the activities that started before it was called, or while it was running
// are ended. This means that system is at the state of relaxation when this
// code returns. It requires external stimulus to get out of relaxation state.
//
// If enable_notifications is true (default), simulation environment
// will send all future notification events to all registered objects,
// whenever protocol requires that. This is expected behavior.
// If enabled_notifications is false, future event notifications will not be
// sent to registered instances. This is useful for protocol shutdown,
// where we no longer care about notifications, and where notifications may
// otherwise be delivered after the notification source or target lifeteme has
// ended, and cause undefined behavior.
void Sync(bool enable_notifications = true);
// Adds an adapter to internal container.
// Notify BluetoothClassicMediums if any that adapter state has changed.
void OnBluetoothAdapterChangedState(api::BluetoothAdapter& adapter,
api::BluetoothDevice& adapter_device,
std::string name, bool enabled,
api::BluetoothAdapter::ScanMode mode);
// Adds medium-related info to allow for adapter discovery to work.
// This provides acccess to this medium from other mediums, when protocol
// expects they should communicate.
void RegisterBluetoothMedium(api::BluetoothClassicMedium& medium,
api::BluetoothAdapter& medium_adapter);
// Updates callback info to allow for dispatch of discovery events.
//
// Invokes callback asynchronously when any changes happen to discoverable
// devices, or if the defice is turned off, whether or not it is discoverable,
// if it was ever reported as discoverable.
//
// This should be called when discoverable state changes.
// with user-specified callback when discovery is enabled, and with default
// (empty) callback otherwise.
void UpdateBluetoothMedium(api::BluetoothClassicMedium& medium,
BluetoothDiscoveryCallback callback);
// Removes medium-related info. This should correspond to device power off.
void UnregisterBluetoothMedium(api::BluetoothClassicMedium& medium);
// Returns a Bluetooth Device object matching given mac address to nullptr.
api::BluetoothDevice* FindBluetoothDevice(const std::string& mac_address);
const EnvironmentConfig& GetEnvironmentConfig();
// Registers |callback| to receive messages sent to device with id |self_id|.
void RegisterWebRtcSignalingMessenger(absl::string_view self_id,
OnSignalingMessageCallback callback);
// Unregisters the callback listening to incoming messages for |self_id|.
void UnregisterWebRtcSignalingMessenger(absl::string_view self_id);
// Simulates sending a signaling message |message| to device with id
// |peer_id|.
void SendWebRtcSignalingMessage(absl::string_view peer_id,
const ByteArray& message);
// Used to set if WebRtcMedium should use a valid peer connection or nullptr
// in tests.
void SetUseValidPeerConnection(bool use_valid_peer_connection);
bool GetUseValidPeerConnection();
// Adds medium-related info to allow for scanning/advertising to work.
// This provides acccess to this medium from other mediums, when protocol
// expects they should communicate.
void RegisterBleMedium(api::BleMedium& medium);
// Updates advertising info to indicate the current medium is exposing
// advertising event.
void UpdateBleMediumForAdvertising(api::BleMedium& medium,
api::BlePeripheral& peripheral,
const std::string& service_id,
bool fast_advertisement, bool enabled);
// Updates discovery callback info to allow for dispatch of discovery events.
//
// Invokes callback asynchronously when any changes happen to discoverable
// devices, or if the defice is turned off, whether or not it is discoverable,
// if it was ever reported as discoverable.
//
// This should be called when discoverable state changes.
// with user-specified callback when discovery is enabled, and with default
// (empty) callback otherwise.
void UpdateBleMediumForScanning(
api::BleMedium& medium, const std::string& service_id,
const std::string& fast_advertisement_service_uuid,
BleDiscoveredPeripheralCallback callback, bool enabled);
// Updates Accepted connection callback info to allow for dispatch of
// advertising events.
void UpdateBleMediumForAcceptedConnection(
api::BleMedium& medium, const std::string& service_id,
BleAcceptedConnectionCallback callback);
// Removes medium-related info. This should correspond to device power off.
void UnregisterBleMedium(api::BleMedium& medium);
// Call back when advertising has created the server socket and is ready for
// connect.
void CallBleAcceptedConnectionCallback(api::BleMedium& medium,
api::BleSocket& socket,
const std::string& service_id);
// Adds medium-related info to allow for discovery/advertising to work.
// This provides acccess to this medium from other mediums, when protocol
// expects they should communicate.
void RegisterWifiLanMedium(api::WifiLanMedium& medium);
// Updates advertising info to indicate the current medium is exposing
// advertising event.
void UpdateWifiLanMediumForAdvertising(api::WifiLanMedium& medium,
api::WifiLanService& service,
const std::string& service_id,
bool enabled);
// Updates discovery callback info to allow for dispatch of discovery events.
//
// Invokes callback asynchronously when any changes happen to discoverable
// devices, or if the defice is turned off, whether or not it is discoverable,
// if it was ever reported as discoverable.
//
// This should be called when discoverable state changes.
// with user-specified callback when discovery is enabled, and with default
// (empty) callback otherwise.
void UpdateWifiLanMediumForDiscovery(
api::WifiLanMedium& medium, const std::string& service_id,
WifiLanDiscoveredServiceCallback callback, bool enabled);
// Updates Accepted connection callback info to allow for dispatch of
// advertising events.
void UpdateWifiLanMediumForAcceptedConnection(
api::WifiLanMedium& medium, const std::string& service_id,
WifiLanAcceptedConnectionCallback callback);
// Removes medium-related info. This should correspond to device power off.
void UnregisterWifiLanMedium(api::WifiLanMedium& medium);
// Call back when advertising has created the server socket and is ready for
// connect.
void CallWifiLanAcceptedConnectionCallback(api::WifiLanMedium& medium,
api::WifiLanSocket& socket,
const std::string& service_id);
// Returns WiFi LAN service matching IP address and port, or nullptr.
api::WifiLanService* FindWifiLanService(const std::string& ip_address,
int port);
private:
struct BluetoothMediumContext {
BluetoothDiscoveryCallback callback;
api::BluetoothAdapter* adapter = nullptr;
// discovered device vs device name map.
absl::flat_hash_map<api::BluetoothDevice*, std::string> devices;
};
struct BleMediumContext {
BleDiscoveredPeripheralCallback discovery_callback;
BleAcceptedConnectionCallback accepted_connection_callback;
api::BlePeripheral* ble_peripheral = nullptr;
bool advertising = false;
bool fast_advertisement = false;
};
struct WifiLanServiceIdContext {
WifiLanDiscoveredServiceCallback discovery_callback;
WifiLanAcceptedConnectionCallback accepted_connection_callback;
bool advertising = false;
};
struct WifiLanMediumContext {
api::WifiLanService* wifi_lan_service = nullptr;
absl::flat_hash_map<std::string, WifiLanServiceIdContext> services;
};
// This is a singleton object, for which destructor will never be called.
// Constructor will be invoked once from Instance() static method.
// Object is create in-place (with a placement new) to guarantee that
// destructor is not scheduled for execution at exit.
MediumEnvironment() = default;
~MediumEnvironment() = default;
void OnBluetoothDeviceStateChanged(BluetoothMediumContext& info,
api::BluetoothDevice& device,
const std::string& name,
api::BluetoothAdapter::ScanMode mode,
bool enabled);
void OnBlePeripheralStateChanged(BleMediumContext& info,
api::BlePeripheral& peripheral,
const std::string& service_id,
bool fast_advertisement, bool enabled);
void OnWifiLanServiceStateChanged(WifiLanMediumContext& info,
api::WifiLanService& service,
const std::string& service_id,
bool enabled);
void RunOnMediumEnvironmentThread(std::function<void()> runnable);
std::atomic_bool enabled_ = true;
std::atomic_int job_count_ = 0;
std::atomic_bool enable_notifications_ = false;
SingleThreadExecutor executor_;
EnvironmentConfig config_;
// The following data members are accessed in the context of a private
// executor_ thread.
absl::flat_hash_map<api::BluetoothAdapter*, api::BluetoothDevice*>
bluetooth_adapters_;
absl::flat_hash_map<api::BluetoothClassicMedium*, BluetoothMediumContext>
bluetooth_mediums_;
absl::flat_hash_map<api::BleMedium*, BleMediumContext> ble_mediums_;
// Maps peer id to callback for receiving signaling messages.
absl::flat_hash_map<std::string, OnSignalingMessageCallback>
webrtc_signaling_callback_;
absl::flat_hash_map<api::WifiLanMedium*, WifiLanMediumContext>
wifi_lan_mediums_;
bool use_valid_peer_connection_ = true;
};
} // namespace nearby
} // namespace location
#endif // PLATFORM_BASE_MEDIUM_ENVIRONMENT_H_
+25
View File
@@ -0,0 +1,25 @@
#ifndef PLATFORM_BASE_OUTPUT_STREAM_H_
#define PLATFORM_BASE_OUTPUT_STREAM_H_
#include "platform/base/byte_array.h"
#include "platform/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_BASE_OUTPUT_STREAM_H_
+14
View File
@@ -0,0 +1,14 @@
#ifndef PLATFORM_BASE_PAYLOAD_ID_H_
#define PLATFORM_BASE_PAYLOAD_ID_H_
#include <cstdint>
namespace location {
namespace nearby {
using PayloadId = std::int64_t;
} // namespace nearby
} // namespace location
#endif // PLATFORM_BASE_PAYLOAD_ID_H_
@@ -1,4 +1,4 @@
#include "platform/prng.h"
#include "platform/base/prng.h"
#include <limits>
@@ -25,20 +25,20 @@ Prng::~Prng() {
#define RANDOM_BYTE (rand() & 0x0FF) // NOLINT
std::int32_t Prng::nextInt32() {
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::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()));
std::int64_t Prng::NextInt64() {
return (static_cast<std::int64_t>(NextInt32()) << 32) |
(static_cast<std::int64_t>(NextUint32()));
}
} // namespace nearby
@@ -1,5 +1,5 @@
#ifndef PLATFORM_PRNG_H_
#define PLATFORM_PRNG_H_
#ifndef PLATFORM_BASE_PRNG_H_
#define PLATFORM_BASE_PRNG_H_
#include <cstdint>
@@ -12,12 +12,12 @@ class Prng {
Prng();
~Prng();
std::int32_t nextInt32();
std::uint32_t nextUInt32();
std::int64_t nextInt64();
std::int32_t NextInt32();
std::uint32_t NextUint32();
std::int64_t NextInt64();
};
} // namespace nearby
} // namespace location
#endif // PLATFORM_PRNG_H_
#endif // PLATFORM_BASE_PRNG_H_
+77
View File
@@ -0,0 +1,77 @@
#include "platform/base/prng.h"
#include "gtest/gtest.h"
namespace location {
namespace nearby {
enum class TestMode {
kUpperHalfOfInt64,
kLowerHalfOfInt64,
kInt32,
kUint32,
};
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());
}
void ValidateRandom(TestMode mode) {
int count_all_zeros = 0;
int count_all_ones = 0;
std::uint32_t i;
Prng prng;
for (int count = 0; count < 100; ++count) {
switch (mode) {
case TestMode::kUpperHalfOfInt64:
i = static_cast<std::uint32_t>(prng.NextInt64() >> 32);
break;
case TestMode::kLowerHalfOfInt64:
i = static_cast<std::uint32_t>(prng.NextInt64());
break;
case TestMode::kInt32:
i = static_cast<std::uint32_t>(prng.NextInt32());
break;
case TestMode::kUint32:
i = static_cast<std::uint32_t>(prng.NextUint32());
break;
}
if (!i) count_all_zeros++;
if (i == 0xFFFFFFFF) count_all_ones++;
}
EXPECT_LE(count_all_zeros, 1);
EXPECT_LE(count_all_ones, 1);
}
TEST(PrngTest, ValidateUpperHalfOfInt64) {
ValidateRandom(TestMode::kUpperHalfOfInt64);
}
TEST(PrngTest, ValidateLowerHalfOfInt64) {
ValidateRandom(TestMode::kLowerHalfOfInt64);
}
TEST(PrngTest, ValidateInt32) {
ValidateRandom(TestMode::kInt32);
}
TEST(PrngTest, ValidateUint32) {
ValidateRandom(TestMode::kUint32);
}
} // namespace nearby
} // namespace location
+19
View File
@@ -0,0 +1,19 @@
#ifndef PLATFORM_BASE_RUNNABLE_H_
#define PLATFORM_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_BASE_RUNNABLE_H_
+25
View File
@@ -0,0 +1,25 @@
#ifndef PLATFORM_BASE_SOCKET_H_
#define PLATFORM_BASE_SOCKET_H_
#include "platform/base/input_stream.h"
#include "platform/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_BASE_SOCKET_H_
+30
View File
@@ -0,0 +1,30 @@
#ifndef PLATFORM_BASE_TYPES_H_
#define PLATFORM_BASE_TYPES_H_
#include <type_traits>
namespace location {
namespace nearby {
// Similar to static_cast, but will assert that Derived is a derived type of
// Base.
// Usage:
// class A {};
// class B : public A {};
// class C {};
// B b;
// A* a = &b;
// B* b2 = down_cast<B*>(a); // This is OK.
// C* c = down_cast<C*>(a); // This will fail to compile.
template <typename Derived, typename Base>
inline Derived down_cast(Base* value) {
using DerivedType = typename std::remove_pointer<Derived>::type;
static_assert(std::is_base_of<Base, DerivedType>::value,
"incompatible casting");
return static_cast<Derived>(value);
}
} // namespace nearby
} // namespace location
#endif // PLATFORM_BASE_TYPES_H_
-57
View File
@@ -1,57 +0,0 @@
#include "platform/base64_utils.h"
#include "absl/strings/escaping.h"
namespace location {
namespace nearby {
std::string Base64Utils::encode(ConstPtr<ByteArray> bytes) {
std::string base64_string;
if (!bytes.isNull()) {
absl::WebSafeBase64Escape(bytes->asString(), &base64_string);
}
return base64_string;
}
std::string Base64Utils::encode(const ByteArray& bytes) {
std::string base64_string;
absl::WebSafeBase64Escape(bytes.asString(), &base64_string);
return base64_string;
}
std::string Base64Utils::encode(absl::string_view input) {
std::string base64_string;
absl::WebSafeBase64Escape(input, &base64_string);
return base64_string;
}
template<>
Ptr<ByteArray> Base64Utils::decode(absl::string_view base64_string) {
std::string decoded_string;
if (!absl::WebSafeBase64Unescape(base64_string, &decoded_string)) {
return Ptr<ByteArray>();
}
return MakePtr(new ByteArray(decoded_string));
}
template<>
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);
}
Ptr<ByteArray> Base64Utils::decode(absl::string_view base64_string) {
return decode<Ptr<ByteArray>>(base64_string);
}
} // namespace nearby
} // namespace location
-26
View File
@@ -1,26 +0,0 @@
#ifndef PLATFORM_BASE64_UTILS_H_
#define PLATFORM_BASE64_UTILS_H_
#include "platform/byte_array.h"
#include "platform/port/string.h"
#include "platform/ptr.h"
#include "absl/strings/string_view.h"
namespace location {
namespace nearby {
class Base64Utils {
public:
static std::string encode(absl::string_view input);
static std::string encode(const ByteArray& bytes);
static std::string encode(ConstPtr<ByteArray> bytes);
template <typename T>
static T decode(absl::string_view base64_string);
static Ptr<ByteArray> decode(absl::string_view base64_string);
};
} // namespace nearby
} // namespace location
#endif // PLATFORM_BASE64_UTILS_H_
-62
View File
@@ -1,62 +0,0 @@
#ifndef PLATFORM_BYTE_ARRAY_H_
#define PLATFORM_BYTE_ARRAY_H_
#include "platform/port/string.h"
namespace location {
namespace nearby {
class ByteArray {
public:
// Create an empty ByteArray
ByteArray() {}
// Create ByteArray from string.
explicit ByteArray(const std::string& 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) {
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);
}
char* getData() { return &data_[0]; }
const char* getData() const { return data_.data(); }
size_t size() const { return data_.size(); }
// Operator overloads when comparing ConstPtr<ByteArray>.
bool operator==(const ByteArray& rhs) const {
return this->data_ == rhs.data_;
}
bool operator!=(const ByteArray& rhs) const { return !(*this == rhs); }
bool operator<(const ByteArray& rhs) const {
return this->data_ < rhs.data_;
}
// TODO(b/149869249) : rename according to go/c-style
std::string asString() const { return data_; }
private:
std::string data_;
};
} // namespace nearby
} // namespace location
#endif // PLATFORM_BYTE_ARRAY_H_
-39
View File
@@ -1,39 +0,0 @@
#include "platform/byte_array.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
namespace {
using location::nearby::ByteArray;
TEST(ByteArrayTest, DefaultSizeIsZero) {
ByteArray bytes;
ASSERT_EQ(0, bytes.size());
}
TEST(ByteArrayTest, SetFromString) {
std::string setup("setup_test");
ByteArray bytes{setup}; // array initialized with a copy of string.
ASSERT_EQ(setup.size(), bytes.size());
ASSERT_EQ(bytes.asString(), setup);
}
TEST(ByteArrayTest, SetExplicitSize) {
constexpr size_t kArraySize = 10;
char reference[kArraySize]{};
ByteArray bytes{kArraySize}; // array of size 10, zero-initialized.
ASSERT_EQ(kArraySize, bytes.size());
ASSERT_EQ(0, memcmp(bytes.getData(), reference, kArraySize));
}
TEST(ByteArrayTest, SetExplicitData) {
constexpr static const char message[] {"test_message"};
constexpr size_t kMessageSize = sizeof(message);
ByteArray bytes{message, kMessageSize};
ASSERT_EQ(kMessageSize, bytes.size());
ASSERT_NE(message, bytes.getData());
ASSERT_EQ(0, memcmp(message, bytes.getData(), kMessageSize));
}
} // namespace
-26
View File
@@ -1,26 +0,0 @@
#ifndef PLATFORM_CALLABLE_H_
#define PLATFORM_CALLABLE_H_
#include "platform/exception.h"
namespace location {
namespace nearby {
// The Callable interface should be implemented by any class whose instances are
// intended to be executed by a thread, and need to return a result. The class
// must define a method named call() with no arguments and a specific return
// type.
//
// https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Callable.html
template <typename T>
class Callable {
public:
virtual ~Callable() {}
virtual ExceptionOr<T> call() = 0;
};
} // namespace nearby
} // namespace location
#endif // PLATFORM_CALLABLE_H_
-39
View File
@@ -1,39 +0,0 @@
#include "platform/cancelable_alarm.h"
#include "platform/api/platform.h"
#include "platform/api/scheduled_executor.h"
#include "platform/synchronized.h"
namespace location {
namespace nearby {
namespace {
using Platform = platform::ImplementationPlatform;
}
CancelableAlarm::CancelableAlarm(const std::string &name,
Ptr<Runnable> runnable,
std::int64_t delay_millis,
Ptr<ScheduledExecutor> scheduled_executor)
: name_(name),
lock_(Platform::createLock()),
cancelable_(scheduled_executor->schedule(runnable, delay_millis)) {}
CancelableAlarm::~CancelableAlarm() { cancelable_.destroy(); }
bool CancelableAlarm::cancel() {
Synchronized s(lock_.get());
if (cancelable_.isNull()) {
// TODO(tracyzhou): Add logging
return false;
}
bool canceled = cancelable_->cancel();
// TODO(tracyzhou): Add logging
cancelable_.destroy();
return canceled;
}
} // namespace nearby
} // namespace location
-39
View File
@@ -1,39 +0,0 @@
#ifndef PLATFORM_CANCELABLE_ALARM_H_
#define PLATFORM_CANCELABLE_ALARM_H_
#include <cstdint>
#include "platform/api/lock.h"
#include "platform/api/scheduled_executor.h"
#include "platform/cancelable.h"
#include "platform/port/string.h"
#include "platform/ptr.h"
#include "platform/runnable.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(const std::string& name, Ptr<Runnable> runnable,
std::int64_t delay_millis,
Ptr<ScheduledExecutor> scheduled_executor);
~CancelableAlarm();
bool cancel();
private:
std::string name_;
ScopedPtr<Ptr<Lock> > lock_;
Ptr<Cancelable> cancelable_;
};
} // namespace nearby
} // namespace location
#endif // PLATFORM_CANCELABLE_ALARM_H_
+21
View File
@@ -0,0 +1,21 @@
cc_library(
name = "config",
hdrs = [
"config.h",
],
visibility = [
"//visibility:private",
],
)
cc_library(
name = "string",
hdrs = [
"string.h",
],
visibility = [
],
deps = [
":config",
],
)
@@ -1,5 +1,5 @@
#ifndef PLATFORM_PORT_CONFIG_H_
#define PLATFORM_PORT_CONFIG_H_
#ifndef PLATFORM_CONFIG_CONFIG_H_
#define PLATFORM_CONFIG_CONFIG_H_
// Clients can modify this file to customize the Nearby C++ codebase as per
// their particular constraints and environments.
@@ -12,11 +12,11 @@
// #endif
#ifndef NEARBY_USE_STD_STRING
#define NEARBY_USE_STD_STRING 1
#define NEARBY_USE_STD_STRING 0
#endif
#ifndef NEARBY_USE_RTTI
#define NEARBY_USE_RTTI 0
#define NEARBY_USE_RTTI 1
#endif
#endif // PLATFORM_PORT_CONFIG_H_
#endif // PLATFORM_CONFIG_CONFIG_H_
+12
View File
@@ -0,0 +1,12 @@
#ifndef PLATFORM_CONFIG_STRING_H_
#define PLATFORM_CONFIG_STRING_H_
#include <string>
#include "platform/config/config.h"
#if NEARBY_USE_STD_STRING
using std::string;
#endif
#endif // PLATFORM_CONFIG_STRING_H_
-71
View File
@@ -1,71 +0,0 @@
#ifndef PLATFORM_CONTAINER_OF_H_
#define PLATFORM_CONTAINER_OF_H_
#include <cstddef>
#include <type_traits>
namespace location::nearby {
// Similar to offsetof() macro, but implemented in a type-safe way,
// OffsetOf(<pointer-to-member>) returns the byte offset of a given data
// member in the ClassType.
// Behavior is undefined if member is not a direct, non-static data member of
// type ClassType.
// usage example:
// struct S { int x; double y; };
// size_t y_offset = OffsetOf(&S::y);
// CHECK(y_offset >= sizeof(int));
//
// the following is not guaranteed to work:
// struct S1 { int x; };
// struct S2 { double y; };
// struct S : public S1, S2 { char t; };
// size_t y_offset_bad = OffsetOf(&S::y);
// because S::y is not a direct member of S; it is a member by inheritance.
// To make sure OffsetOf works with inherited members, it must be called
// with explicitly defined template parameters, as follows:
// size_t y_offset_ok = OffsetOf<double,S>(&S::y);
//
// However, the following is guaranteed to work:
// struct S1 { int x; };
// struct S2 { double y; };
// struct S3 { double z; };
// struct S : public S1, S2 { S3 s3; char t; };
// size_t s3_offset = OffsetOf(&S::s3);
template <typename ValueType, typename ClassType>
constexpr size_t OffsetOf(const ValueType ClassType::*member) {
std::aligned_storage_t<sizeof(ClassType), alignof(ClassType)> obj_memory;
ClassType* obj = reinterpret_cast<ClassType*>(&obj_memory);
return reinterpret_cast<size_t>(&(obj->*member)) -
reinterpret_cast<size_t>(obj);
}
// Similar to Linux containerof() macro, this function returns pointer to
// the type instance that contains the specified member;
// ContainerOf(<pointer to variable instance of type ValueType, which is member
// of ClassType>, <pointer-to-ClassType-member>);
// usage example:
// struct S { int x; double y; } a;
// S *b = ContainerOf(&a.y, &S::y);
// CHECK(b == &a);
template <typename ValueType, typename ClassType>
ClassType* ContainerOf(ValueType* ptr, ValueType ClassType::*member) {
using BaseValueType = std::remove_volatile_t<ValueType>;
return reinterpret_cast<ClassType*>(
reinterpret_cast<char*>(const_cast<BaseValueType*>(ptr)) -
OffsetOf(member));
}
template <typename ValueType, typename ClassType>
const ClassType* ContainerOf(const ValueType* ptr,
ValueType ClassType::*member) {
using BaseValueType = std::remove_volatile_t<ValueType>;
return reinterpret_cast<const ClassType*>(
reinterpret_cast<const char*>(const_cast<BaseValueType*>(ptr)) -
OffsetOf(member));
}
} // namespace location::nearby
#endif // PLATFORM_CONTAINER_OF_H_
-47
View File
@@ -1,47 +0,0 @@
#include "platform/container_of.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
namespace location::nearby {
TEST(OffsetOf, OffsetOfTest) {
struct [[gnu::packed]] S {
char x;
double y;
};
EXPECT_EQ(OffsetOf(&S::x), 0U);
EXPECT_EQ(OffsetOf(&S::y), sizeof(S::x));
}
TEST(OffsetOf, ExplicitOffsetOfTest) {
struct [[gnu::packed]] S1 { int x; };
struct [[gnu::packed]] S2 { double y; };
struct [[gnu::packed]] S : public S1, S2 { char t; };
EXPECT_EQ((OffsetOf<decltype(std::declval<S>().x), S>(&S::x)), 0U);
EXPECT_EQ((OffsetOf<decltype(std::declval<S>().y), S>(&S::y)), sizeof(S::x));
}
TEST(ContainerOf, ContainerOfTest) {
struct [[gnu::packed]] S {
char x;
double y;
} s;
char* p = &s.x;
double* q = &s.y;
EXPECT_EQ(ContainerOf(p, &S::x), &s);
EXPECT_EQ(ContainerOf(q, &S::y), &s);
}
TEST(ContainerOf, ContainerOfTestConst) {
struct [[gnu::packed]] S {
char x;
double y;
} s;
const char* p = &s.x;
const double* q = &s.y;
EXPECT_EQ(ContainerOf(p, &S::x), &s);
EXPECT_EQ(ContainerOf(q, &S::y), &s);
}
} // namespace location::nearby
-79
View File
@@ -1,79 +0,0 @@
#ifndef PLATFORM_EXCEPTION_H_
#define PLATFORM_EXCEPTION_H_
#include <utility>
namespace location {
namespace nearby {
struct Exception {
enum Value : int {
NONE,
IO,
INTERRUPTED,
INVALID_PROTOCOL_BUFFER,
EXECUTION,
// New code should use the kConstants.
// Old CONSTANTS are deprecated, and should not be used.
kFailed = -1, // Initial value of Exception; any unknown error.
kSuccess = NONE, // No exception.
kIo = IO, // IO Error happened.
kInterrupted = INTERRUPTED, // Operation was interrupted.
kInvalidProtocolBuffer = INVALID_PROTOCOL_BUFFER, // Couldn't parse.
kExecution = EXECUTION, // Couldn't execute.
kTimeout, // Operation did not finish within specified time.
};
Value value {kFailed};
};
// 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;
ExceptionOr(T&& result) : result_{std::move(result)}, // NOLINT
exception_{Exception::kSuccess} {}
ExceptionOr(const T& result) : result_{result}, // NOLINT
exception_{Exception::kSuccess} {}
ExceptionOr(Exception::Value exception) : exception_{exception} {} // NOLINT
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;
Exception GetException() const;
private:
T result_;
Exception exception_ {Exception::kFailed};
};
} // namespace nearby
} // namespace location
#endif // PLATFORM_EXCEPTION_H_
+95 -11
View File
@@ -1,26 +1,110 @@
cc_library(
name = "types",
testonly = True,
srcs = [
"log_message.cc",
"scheduled_executor.cc",
"system_clock.cc",
],
hdrs = [
"atomic_boolean.h",
"atomic_reference.h",
"condition_variable.h",
"count_down_latch.h",
"log_message.h",
"multi_thread_executor.h",
"mutex.h",
"pipe.h",
"scheduled_executor.h",
"single_thread_executor.h",
],
visibility = ["//visibility:private"],
deps = [
"//base",
"//platform/api:platform",
"//platform/api:types",
"//platform/base",
"//platform/base:util",
"//platform/impl/shared:posix_mutex",
"//absl/base:core_headers",
"//absl/synchronization",
"//absl/time",
"//thread",
],
)
cc_library(
name = "comm",
testonly = True,
srcs = [
"ble.cc",
"bluetooth_adapter.cc",
"bluetooth_classic.cc",
"webrtc.cc",
"wifi_lan.cc",
],
hdrs = [
"ble.h",
"bluetooth_adapter.h",
"bluetooth_classic.h",
"webrtc.h",
"wifi_lan.h",
],
visibility = ["//visibility:private"],
deps = [
":types",
"//platform/api:comm",
"//platform/base",
"//platform/base:logging",
"//platform/base:test_util",
"//absl/base:core_headers",
"//absl/container:flat_hash_map",
"//absl/container:flat_hash_set",
"//absl/strings",
"//absl/synchronization",
"//webrtc/api:create_peerconnection_factory", #buildcleaner: keep
"//webrtc/api:libjingle_peerconnection_api",
"//webrtc/api/task_queue:default_task_queue_factory",
],
)
cc_library(
name = "crypto",
testonly = True,
srcs = [
"crypto.cc",
],
visibility = ["//visibility:private"],
deps = [
"//platform/api:types",
"//platform/base",
"//absl/strings",
"//openssl:crypto",
],
)
cc_library(
name = "g3",
testonly = True,
srcs = [
"atomic_reference_impl.h",
"platform.cc",
"settable_future_impl.h",
"system_clock_impl.h",
],
visibility = [
"//core:__subpackages__",
"//platform:__subpackages__",
],
deps = [
"//platform:types",
"//platform/api",
"//platform/impl/shared:atomic_boolean",
":comm",
":crypto", # build_cleaner: keep
":types",
"//platform/api:comm",
"//platform/api:platform",
"//platform/api:types",
"//platform/base:test_util",
"//platform/impl/shared:file",
"//platform/impl/shared:posix_condition_variable",
"//platform/impl/shared:posix_lock",
"//platform/port:string",
"//absl/base:core_headers",
"//absl/synchronization",
"//absl/memory",
"//absl/strings",
"//absl/time",
"//absl/types:any",
],
)
-28
View File
@@ -1,28 +0,0 @@
add_library(platform_impl_g3 STATIC)
target_sources(platform_impl_g3
PRIVATE
"atomic_reference_impl.h"
"platform.cc"
"settable_future_impl.h"
"system_clock_impl.h"
)
target_include_directories(platform_impl_g3
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
)
target_link_libraries(platform_impl_g3
PUBLIC
"platform_types"
"platform_api"
"platform_impl_shared_atomic_boolean"
"platform_impl_shared_file"
"platform_impl_shared_posix_condition_variable"
"platform_impl_shared_posix_lock"
"platform_port_string"
"absl::base"
"absl::synchronization"
"absl::time"
)
+30
View File
@@ -0,0 +1,30 @@
#ifndef PLATFORM_IMPL_G3_ATOMIC_BOOLEAN_H_
#define PLATFORM_IMPL_G3_ATOMIC_BOOLEAN_H_
#include <atomic>
#include "platform/api/atomic_boolean.h"
namespace location {
namespace nearby {
namespace g3 {
// See documentation in
// https://source.corp.google.com/piper///depot/google3/platform/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_IMPL_G3_ATOMIC_BOOLEAN_H_
+33
View File
@@ -0,0 +1,33 @@
#ifndef PLATFORM_IMPL_G3_ATOMIC_REFERENCE_H_
#define PLATFORM_IMPL_G3_ATOMIC_REFERENCE_H_
#include <atomic>
#include <cstdint>
#include "platform/api/atomic_reference.h"
namespace location {
namespace nearby {
namespace g3 {
class AtomicUint32 : public api::AtomicUint32 {
public:
explicit AtomicUint32(std::int32_t value) : value_(value) {}
~AtomicUint32() override = default;
std::uint32_t Get() const override {
return value_;
}
void Set(std::uint32_t value) override {
value_ = value;
}
private:
std::atomic<std::uint32_t> value_;
};
} // namespace g3
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_G3_ATOMIC_REFERENCE_H_
@@ -1,38 +0,0 @@
#ifndef PLATFORM_IMPL_G3_ATOMIC_REFERENCE_IMPL_H_
#define PLATFORM_IMPL_G3_ATOMIC_REFERENCE_IMPL_H_
#include "platform/api/atomic_reference.h"
#include "platform/ptr.h"
#include "absl/synchronization/mutex.h"
#include "absl/types/any.h"
namespace location {
namespace nearby {
namespace platform {
// Provide implementation for absl::any.
class AtomicReferenceImpl : public AtomicReference<absl::any> {
public:
explicit AtomicReferenceImpl(absl::any initial_value)
: value_(std::move(initial_value)) {}
~AtomicReferenceImpl() override = default;
absl::any get() override {
absl::MutexLock lock(&mutex_);
return value_;
}
void set(absl::any value) override {
absl::MutexLock lock(&mutex_);
value_ = std::move(value);
}
private:
absl::Mutex mutex_;
absl::any value_;
};
} // namespace platform
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_G3_ATOMIC_REFERENCE_IMPL_H_
+351
View File
@@ -0,0 +1,351 @@
#include "platform/impl/g3/ble.h"
#include <iostream>
#include <memory>
#include <string>
#include "platform/api/ble.h"
#include "platform/base/logging.h"
#include "platform/base/medium_environment.h"
#include "absl/synchronization/mutex.h"
namespace location {
namespace nearby {
namespace g3 {
BleSocket::~BleSocket() {
absl::MutexLock lock(&mutex_);
DoClose();
}
void BleSocket::Connect(BleSocket& other) {
absl::MutexLock lock(&mutex_);
remote_socket_ = &other;
input_ = other.output_;
}
InputStream& BleSocket::GetInputStream() {
auto* remote_socket = GetRemoteSocket();
CHECK(remote_socket != nullptr);
return remote_socket->GetLocalInputStream();
}
OutputStream& BleSocket::GetOutputStream() {
return GetLocalOutputStream();
}
BleSocket* BleSocket::GetRemoteSocket() {
absl::MutexLock lock(&mutex_);
return remote_socket_;
}
bool BleSocket::IsConnected() const {
absl::MutexLock lock(&mutex_);
return IsConnectedLocked();
}
bool BleSocket::IsClosed() const {
absl::MutexLock lock(&mutex_);
return closed_;
}
Exception BleSocket::Close() {
absl::MutexLock lock(&mutex_);
DoClose();
return {Exception::kSuccess};
}
BlePeripheral* BleSocket::GetRemotePeripheral() {
absl::MutexLock lock(&mutex_);
return peripheral_;
}
void BleSocket::DoClose() {
if (!closed_) {
remote_socket_ = nullptr;
output_->GetOutputStream().Close();
output_->GetInputStream().Close();
if (IsConnectedLocked()) {
input_->GetOutputStream().Close();
input_->GetInputStream().Close();
}
closed_ = true;
}
}
bool BleSocket::IsConnectedLocked() const { return input_ != nullptr; }
InputStream& BleSocket::GetLocalInputStream() {
absl::MutexLock lock(&mutex_);
return output_->GetInputStream();
}
OutputStream& BleSocket::GetLocalOutputStream() {
absl::MutexLock lock(&mutex_);
return output_->GetOutputStream();
}
std::unique_ptr<api::BleSocket> BleServerSocket::Accept(
BlePeripheral* peripheral) {
absl::MutexLock lock(&mutex_);
if (closed_) return {};
while (pending_sockets_.empty()) {
cond_.Wait(&mutex_);
if (closed_) break;
}
if (closed_) return {};
auto* remote_socket =
pending_sockets_.extract(pending_sockets_.begin()).value();
CHECK(remote_socket);
auto local_socket = std::make_unique<BleSocket>(peripheral);
local_socket->Connect(*remote_socket);
remote_socket->Connect(*local_socket);
cond_.SignalAll();
return local_socket;
}
bool BleServerSocket::Connect(BleSocket& socket) {
absl::MutexLock lock(&mutex_);
if (closed_) return false;
if (socket.IsConnected()) {
NEARBY_LOG(ERROR,
"Failed to connect to Ble server socket: already connected");
return true; // already connected.
}
// add client socket to the pending list
pending_sockets_.emplace(&socket);
cond_.SignalAll();
while (!socket.IsConnected()) {
cond_.Wait(&mutex_);
if (closed_) return false;
}
return true;
}
void BleServerSocket::SetCloseNotifier(std::function<void()> notifier) {
absl::MutexLock lock(&mutex_);
close_notifier_ = std::move(notifier);
}
BleServerSocket::~BleServerSocket() {
absl::MutexLock lock(&mutex_);
DoClose();
}
Exception BleServerSocket::Close() {
absl::MutexLock lock(&mutex_);
return DoClose();
}
Exception BleServerSocket::DoClose() {
bool should_notify = !closed_;
closed_ = true;
if (should_notify) {
cond_.SignalAll();
if (close_notifier_) {
auto notifier = std::move(close_notifier_);
mutex_.Unlock();
// Notifier may contain calls to public API, and may cause deadlock, if
// mutex_ is held during the call.
notifier();
mutex_.Lock();
}
}
return {Exception::kSuccess};
}
BleMedium::BleMedium(api::BluetoothAdapter& adapter)
: adapter_(static_cast<BluetoothAdapter*>(&adapter)) {
adapter_->SetBleMedium(this);
auto& env = MediumEnvironment::Instance();
env.RegisterBleMedium(*this);
}
BleMedium::~BleMedium() {
adapter_->SetBleMedium(nullptr);
auto& env = MediumEnvironment::Instance();
env.UnregisterBleMedium(*this);
StopAdvertising(advertising_info_.service_id);
StopScanning(scanning_info_.service_id);
accept_loops_runner_.Shutdown();
NEARBY_LOG(INFO, "BleMedium dtor advertising_accept_thread_running_ = %d",
acceptance_thread_running_.load());
// If acceptance thread is still running, wait to finish.
if (acceptance_thread_running_) {
while (acceptance_thread_running_) {
CountDownLatch latch(1);
close_accept_loops_runner_.Execute([&latch]() { latch.CountDown(); });
latch.Await();
}
}
}
bool BleMedium::StartAdvertising(
const std::string& service_id, const ByteArray& advertisement_bytes,
const std::string& fast_advertisement_service_uuid) {
NEARBY_LOGS(INFO) << "G3 Ble StartAdvertising: service_id=" << service_id
<< ", advertisement bytes=" << advertisement_bytes.data()
<< "(" << advertisement_bytes.size() << "),"
<< " fast advertisement service uuid="
<< fast_advertisement_service_uuid;
auto& env = MediumEnvironment::Instance();
auto& peripheral = adapter_->GetPeripheral();
peripheral.SetAdvertisementBytes(service_id, advertisement_bytes);
bool fast_advertisement = !fast_advertisement_service_uuid.empty();
env.UpdateBleMediumForAdvertising(*this, peripheral, service_id,
fast_advertisement, true);
absl::MutexLock lock(&mutex_);
if (server_socket_ != nullptr) server_socket_.release();
server_socket_ = std::make_unique<BleServerSocket>();
acceptance_thread_running_.exchange(true);
accept_loops_runner_.Execute([&env, this, service_id]() mutable {
if (!accept_loops_runner_.InShutdown()) {
while (true) {
auto client_socket =
server_socket_->Accept(&(this->adapter_->GetPeripheral()));
if (client_socket == nullptr) break;
env.CallBleAcceptedConnectionCallback(*this, *(client_socket.release()),
service_id);
}
}
acceptance_thread_running_.exchange(false);
});
advertising_info_.service_id = service_id;
return true;
}
bool BleMedium::StopAdvertising(const std::string& service_id) {
NEARBY_LOGS(INFO) << "G3 Ble StopAdvertising: service_id=" << service_id;
{
absl::MutexLock lock(&mutex_);
if (advertising_info_.Empty()) {
NEARBY_LOGS(INFO) << "G3 Ble StopAdvertising: Can't stop advertising "
"because we never started advertising.";
return false;
}
advertising_info_.Clear();
}
auto& env = MediumEnvironment::Instance();
env.UpdateBleMediumForAdvertising(*this, adapter_->GetPeripheral(),
service_id, /*fast_advertisement=*/false,
/*enabled=*/false);
accept_loops_runner_.Shutdown();
if (server_socket_ == nullptr) {
NEARBY_LOGS(ERROR) << "G3 Ble StopAdvertising: Failed to find Ble Server "
"socket: service_id="
<< service_id;
// Fall through for server socket not found.
return true;
}
if (!server_socket_->Close().Ok()) {
NEARBY_LOGS(INFO)
<< "G3 Ble StopAdvertising: Failed to close Ble server socket for "
<< service_id;
return false;
}
return true;
}
bool BleMedium::StartScanning(
const std::string& service_id,
const std::string& fast_advertisement_service_uuid,
DiscoveredPeripheralCallback callback) {
NEARBY_LOGS(INFO) << "G3 Ble StartScanning: service_id=" << service_id;
auto& env = MediumEnvironment::Instance();
env.UpdateBleMediumForScanning(*this, service_id,
fast_advertisement_service_uuid,
std::move(callback), true);
{
absl::MutexLock lock(&mutex_);
scanning_info_.service_id = service_id;
}
return true;
}
bool BleMedium::StopScanning(const std::string& service_id) {
NEARBY_LOGS(INFO) << "G3 Ble StopScanning: service_id=" << service_id;
{
absl::MutexLock lock(&mutex_);
if (scanning_info_.Empty()) {
NEARBY_LOGS(INFO) << "G3 Ble StopDiscovery: Can't stop scanning because "
"we never started scanning.";
return false;
}
scanning_info_.Clear();
}
auto& env = MediumEnvironment::Instance();
env.UpdateBleMediumForScanning(*this, service_id, {}, {}, false);
return true;
}
bool BleMedium::StartAcceptingConnections(const std::string& service_id,
AcceptedConnectionCallback callback) {
NEARBY_LOGS(INFO) << "G3 Ble StartAcceptingConnections: service_id="
<< service_id;
auto& env = MediumEnvironment::Instance();
env.UpdateBleMediumForAcceptedConnection(*this, service_id, callback);
return true;
}
bool BleMedium::StopAcceptingConnections(const std::string& service_id) {
NEARBY_LOGS(INFO) << "G3 Ble StopAcceptingConnections: service_id="
<< service_id;
auto& env = MediumEnvironment::Instance();
env.UpdateBleMediumForAcceptedConnection(*this, service_id, {});
return true;
}
std::unique_ptr<api::BleSocket> BleMedium::Connect(
api::BlePeripheral& remote_peripheral, const std::string& service_id) {
NEARBY_LOG(INFO,
"G3 Ble Connect [self]: medium=%p, adapter=%p, peripheral=%p, "
"service_id=%s",
this, &GetAdapter(), &GetAdapter().GetPeripheral(),
service_id.c_str());
// First, find an instance of remote medium, that exposed this peripheral.
auto& adapter = static_cast<BlePeripheral&>(remote_peripheral).GetAdapter();
auto* medium = static_cast<BleMedium*>(adapter.GetBleMedium());
if (!medium) return {}; // Can't find medium. Bail out.
BleServerSocket* remote_server_socket = nullptr;
NEARBY_LOG(INFO,
"G3 Ble Connect [peer]: medium=%p, adapter=%p, peripheral=%p, "
"service_id=%s",
medium, &adapter, &remote_peripheral, service_id.c_str());
// Then, find our server socket context in this medium.
{
absl::MutexLock medium_lock(&medium->mutex_);
remote_server_socket = medium->server_socket_.get();
if (remote_server_socket == nullptr) {
NEARBY_LOGS(ERROR)
<< "G3 Ble Connect: Failed to find Ble Server socket: service_id="
<< service_id;
return {};
}
}
BlePeripheral peripheral = static_cast<BlePeripheral&>(remote_peripheral);
auto socket = std::make_unique<BleSocket>(&peripheral);
// Finally, Request to connect to this socket.
if (!remote_server_socket->Connect(*socket)) {
NEARBY_LOGS(ERROR) << "G3 Ble Connect: Failed to connect to existing Ble "
"Server socket: service_id="
<< service_id;
return {};
}
NEARBY_LOG(INFO, "G3 Ble Connect: connected: socket=%p", socket.get());
return socket;
}
} // namespace g3
} // namespace nearby
} // namespace location
+215
View File
@@ -0,0 +1,215 @@
#ifndef PLATFORM_IMPL_G3_BLE_H_
#define PLATFORM_IMPL_G3_BLE_H_
#include <memory>
#include <string>
#include "platform/api/ble.h"
#include "platform/base/byte_array.h"
#include "platform/base/input_stream.h"
#include "platform/base/output_stream.h"
#include "platform/impl/g3/bluetooth_adapter.h"
#include "platform/impl/g3/bluetooth_classic.h"
#include "platform/impl/g3/multi_thread_executor.h"
#include "platform/impl/g3/pipe.h"
#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_set.h"
#include "absl/strings/escaping.h"
#include "absl/synchronization/mutex.h"
namespace location {
namespace nearby {
namespace g3 {
class BleMedium;
class BleSocket : public api::BleSocket {
public:
BleSocket() = default;
explicit BleSocket(BlePeripheral* peripheral) : peripheral_(peripheral) {}
~BleSocket() override;
// Connect to another BleSocket, to form a functional low-level channel.
// from this point on, and until Close is called, connection exists.
void Connect(BleSocket& other) ABSL_LOCKS_EXCLUDED(mutex_);
// Returns the InputStream of this connected BleSocket.
InputStream& GetInputStream() override ABSL_LOCKS_EXCLUDED(mutex_);
// Returns the OutputStream of this connected BleSocket.
// This stream is for local side to write.
OutputStream& GetOutputStream() override ABSL_LOCKS_EXCLUDED(mutex_);
// Returns address of a remote BleSocket or nullptr.
BleSocket* GetRemoteSocket() ABSL_LOCKS_EXCLUDED(mutex_);
// Returns true if connection exists to the (possibly closed) remote socket.
bool IsConnected() const ABSL_LOCKS_EXCLUDED(mutex_);
// Returns true if socket is closed.
bool IsClosed() const ABSL_LOCKS_EXCLUDED(mutex_);
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
Exception Close() override ABSL_LOCKS_EXCLUDED(mutex_);
// Returns valid BlePeripheral pointer if there is a connection, and
// nullptr otherwise.
BlePeripheral* GetRemotePeripheral() override
ABSL_LOCKS_EXCLUDED(mutex_);
private:
void DoClose() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Returns true if connection exists to the (possibly closed) remote socket.
bool IsConnectedLocked() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Returns InputStream of our side of a connection.
// This is what the remote side is supposed to read from.
// This is a helper for GetInputStream() method.
InputStream& GetLocalInputStream() ABSL_LOCKS_EXCLUDED(mutex_);
// Returns OutputStream of our side of a connection.
// This is what the local size is supposed to write to.
// This is a helper for GetOutputStream() method.
OutputStream& GetLocalOutputStream() ABSL_LOCKS_EXCLUDED(mutex_);
// Output pipe is initialized by constructor, it remains always valid, until
// it is closed. it represents output part of a local socket. Input part of a
// local socket comes from the peer socket, after connection.
std::shared_ptr<Pipe> output_ {new Pipe};
std::shared_ptr<Pipe> input_;
mutable absl::Mutex mutex_;
BlePeripheral* peripheral_;
BleSocket* remote_socket_ ABSL_GUARDED_BY(mutex_) = nullptr;
bool closed_ ABSL_GUARDED_BY(mutex_) = false;
};
class BleServerSocket {
public:
~BleServerSocket();
// Blocks until either:
// - at least one incoming connection request is available, or
// - ServerSocket is closed.
// On success, returns connected socket, ready to exchange data.
// Returns nullptr on error.
// Once error is reported, it is permanent, and ServerSocket has to be closed.
//
// Called by the server side of a connection.
// Returns BleSocket to the server side.
// If not null, returned socket is connected to its remote (client-side) peer.
std::unique_ptr<api::BleSocket> Accept(BlePeripheral* peripheral)
ABSL_LOCKS_EXCLUDED(mutex_);
// Blocks until either:
// - connection is available, or
// - server socket is closed, or
// - error happens.
//
// Called by the client side of a connection.
// Returns true, if socket is successfully connected.
bool Connect(BleSocket& socket) ABSL_LOCKS_EXCLUDED(mutex_);
// Called by the server side of a connection before passing ownership of
// BleServerSocker to user, to track validity of a pointer to this
// server socket,
void SetCloseNotifier(std::function<void()> notifier)
ABSL_LOCKS_EXCLUDED(mutex_);
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
// Calls close_notifier if it was previously set, and marks socket as closed.
Exception Close() ABSL_LOCKS_EXCLUDED(mutex_);
private:
Exception DoClose() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
absl::Mutex mutex_;
absl::CondVar cond_;
absl::flat_hash_set<BleSocket*> pending_sockets_ ABSL_GUARDED_BY(mutex_);
std::function<void()> close_notifier_ ABSL_GUARDED_BY(mutex_);
bool closed_ ABSL_GUARDED_BY(mutex_) = false;
};
// Container of operations that can be performed over the BLE medium.
class BleMedium : public api::BleMedium {
public:
explicit BleMedium(api::BluetoothAdapter& adapter);
~BleMedium() override;
// Returns true once the Ble advertising has been initiated.
bool StartAdvertising(
const std::string& service_id, const ByteArray& advertisement_bytes,
const std::string& fast_advertisement_service_uuid) override
ABSL_LOCKS_EXCLUDED(mutex_);
bool StopAdvertising(const std::string& service_id) override
ABSL_LOCKS_EXCLUDED(mutex_);
// Returns true once the Ble scanning has been initiated.
bool StartScanning(const std::string& service_id,
const std::string& fast_advertisement_service_uuid,
DiscoveredPeripheralCallback callback) override
ABSL_LOCKS_EXCLUDED(mutex_);
// 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.
bool StopScanning(const std::string& service_id) override
ABSL_LOCKS_EXCLUDED(mutex_);
// Returns true once Ble socket connection requests to service_id can be
// accepted.
bool StartAcceptingConnections(const std::string& service_id,
AcceptedConnectionCallback callback)
override ABSL_LOCKS_EXCLUDED(mutex_);
bool StopAcceptingConnections(const std::string& service_id) override
ABSL_LOCKS_EXCLUDED(mutex_);
// Connects to existing remote Ble peripheral.
//
// On success, returns a new BleSocket.
// On error, returns nullptr.
std::unique_ptr<api::BleSocket> Connect(
api::BlePeripheral& remote_peripheral,
const std::string& service_id) override ABSL_LOCKS_EXCLUDED(mutex_);
BluetoothAdapter& GetAdapter() { return *adapter_; }
private:
static constexpr int kMaxConcurrentAcceptLoops = 5;
struct AdvertisingInfo {
bool Empty() const { return service_id.empty(); }
void Clear() { service_id.clear(); }
std::string service_id;
};
struct ScanningInfo {
bool Empty() const { return service_id.empty(); }
void Clear() { service_id.clear(); }
std::string service_id;
};
absl::Mutex mutex_;
BluetoothAdapter* adapter_; // Our device adapter; read-only.
// A thread pool dedicated to running all the accept loops from
// StartAdvertising().
MultiThreadExecutor accept_loops_runner_{kMaxConcurrentAcceptLoops};
std::atomic_bool acceptance_thread_running_ = false;
// A thread pool dedicated to wait to complete the accept_loops_runner_.
MultiThreadExecutor close_accept_loops_runner_{kMaxConcurrentAcceptLoops};
// A server socket is established when start advertising.
std::unique_ptr<BleServerSocket> server_socket_;
AdvertisingInfo advertising_info_ ABSL_GUARDED_BY(mutex_);
ScanningInfo scanning_info_ ABSL_GUARDED_BY(mutex_);
};
} // namespace g3
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_G3_BLE_H_
+121
View File
@@ -0,0 +1,121 @@
#include "platform/impl/g3/bluetooth_adapter.h"
#include <string>
#include "platform/base/medium_environment.h"
#include "platform/base/prng.h"
#include "platform/impl/g3/bluetooth_classic.h"
namespace location {
namespace nearby {
namespace g3 {
BlePeripheral::BlePeripheral(BluetoothAdapter* adapter) : adapter_(*adapter) {}
std::string BlePeripheral::GetName() const { return adapter_.GetName(); }
ByteArray BlePeripheral::GetAdvertisementBytes(
const std::string& service_id) const {
return advertisement_bytes_;
}
void BlePeripheral::SetAdvertisementBytes(
const std::string& service_id, const ByteArray& advertisement_bytes) {
advertisement_bytes_ = advertisement_bytes;
}
BluetoothDevice::BluetoothDevice(BluetoothAdapter* adapter)
: adapter_(*adapter) {}
std::string BluetoothDevice::GetName() const { return adapter_.GetName(); }
std::string BluetoothDevice::GetMacAddress() const {
return adapter_.GetMacAddress();
}
BluetoothAdapter::BluetoothAdapter() {
std::string mac_address;
mac_address.resize(6);
int64_t raw_mac_addr = Prng().NextInt64();
mac_address[0] = static_cast<char>(raw_mac_addr >> 40);
mac_address[1] = static_cast<char>(raw_mac_addr >> 32);
mac_address[2] = static_cast<char>(raw_mac_addr >> 24);
mac_address[3] = static_cast<char>(raw_mac_addr >> 16);
mac_address[4] = static_cast<char>(raw_mac_addr >> 8);
mac_address[5] = static_cast<char>(raw_mac_addr >> 0);
SetMacAddress(mac_address);
}
BluetoothAdapter::~BluetoothAdapter() { SetStatus(Status::kDisabled); }
void BluetoothAdapter::SetBluetoothClassicMedium(
api::BluetoothClassicMedium* medium) {
bluetooth_classic_medium_ = medium;
}
void BluetoothAdapter::SetBleMedium(api::BleMedium* medium) {
ble_medium_ = medium;
}
bool BluetoothAdapter::SetStatus(Status status) {
BluetoothAdapter::ScanMode mode;
bool enabled = status == Status::kEnabled;
std::string name;
{
absl::MutexLock lock(&mutex_);
enabled_ = enabled;
name = name_;
mode = mode_;
}
auto& env = MediumEnvironment::Instance();
env.OnBluetoothAdapterChangedState(*this, device_, name, enabled, mode);
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) {
bool enabled;
std::string name;
{
absl::MutexLock lock(&mutex_);
mode_ = mode;
name = name_;
enabled = enabled_;
}
auto& env = MediumEnvironment::Instance();
env.OnBluetoothAdapterChangedState(*this, device_, std::move(name), enabled,
mode);
return true;
}
std::string BluetoothAdapter::GetName() const {
absl::MutexLock lock(&mutex_);
return name_;
}
bool BluetoothAdapter::SetName(absl::string_view name) {
BluetoothAdapter::ScanMode mode;
bool enabled;
{
absl::MutexLock lock(&mutex_);
name_ = name;
enabled = enabled_;
mode = mode_;
}
auto& env = MediumEnvironment::Instance();
env.OnBluetoothAdapterChangedState(*this, device_, std::string(name), enabled,
mode);
return true;
}
} // namespace g3
} // namespace nearby
} // namespace location
+128
View File
@@ -0,0 +1,128 @@
#ifndef PLATFORM_IMPL_G3_BLUETOOTH_ADAPTER_H_
#define PLATFORM_IMPL_G3_BLUETOOTH_ADAPTER_H_
#include <string>
#include "platform/api/ble.h"
#include "platform/api/bluetooth_adapter.h"
#include "platform/api/bluetooth_classic.h"
#include "platform/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;
// Opaque wrapper over a Ble peripheral. Must contain enough data about a
// particular Ble device to connect to its GATT server.
class BlePeripheral : public api::BlePeripheral {
public:
~BlePeripheral() override = default;
std::string GetName() const override;
ByteArray GetAdvertisementBytes(const std::string& service_id) const override;
void SetAdvertisementBytes(const std::string& service_id,
const ByteArray& advertisement_bytes);
BluetoothAdapter& GetAdapter() { return adapter_; }
private:
// Only BluetoothAdapter may instantiate BlePeripheral.
friend class BluetoothAdapter;
explicit BlePeripheral(BluetoothAdapter* adapter);
BluetoothAdapter& adapter_;
ByteArray advertisement_bytes_;
};
// 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;
std::string GetMacAddress() const override;
BluetoothAdapter& GetAdapter() { return adapter_; }
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();
~BluetoothAdapter() override;
// 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_);
// Returns BT MAC address assigned to this adapter.
std::string GetMacAddress() const override { return mac_address_; }
BluetoothDevice& GetDevice() { return device_; }
void SetBluetoothClassicMedium(api::BluetoothClassicMedium* medium);
api::BluetoothClassicMedium* GetBluetoothClassicMedium() {
return bluetooth_classic_medium_;
}
BlePeripheral& GetPeripheral() { return peripheral_; }
void SetBleMedium(api::BleMedium* medium);
api::BleMedium* GetBleMedium() { return ble_medium_; }
void SetMacAddress(std::string& mac_address) { mac_address_ = mac_address; }
private:
mutable absl::Mutex mutex_;
BluetoothDevice device_{this};
BlePeripheral peripheral_{this};
api::BluetoothClassicMedium* bluetooth_classic_medium_ = nullptr;
api::BleMedium* ble_medium_ = nullptr;
std::string mac_address_;
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;
};
} // namespace g3
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_G3_BLUETOOTH_ADAPTER_H_
+251
View File
@@ -0,0 +1,251 @@
#include "platform/impl/g3/bluetooth_classic.h"
#include <memory>
#include <string>
#include "platform/api/bluetooth_classic.h"
#include "platform/base/logging.h"
#include "platform/base/medium_environment.h"
#include "platform/impl/g3/bluetooth_adapter.h"
#include "absl/synchronization/mutex.h"
namespace location {
namespace nearby {
namespace g3 {
BluetoothSocket::~BluetoothSocket() {
absl::MutexLock lock(&mutex_);
DoClose();
}
void BluetoothSocket::Connect(BluetoothSocket& other) {
absl::MutexLock lock(&mutex_);
remote_socket_ = &other;
input_ = other.output_;
}
bool BluetoothSocket::IsConnected() const {
absl::MutexLock lock(&mutex_);
return IsConnectedLocked();
}
bool BluetoothSocket::IsClosed() const {
absl::MutexLock lock(&mutex_);
return closed_;
}
bool BluetoothSocket::IsConnectedLocked() const { return input_ != nullptr; }
InputStream& BluetoothSocket::GetInputStream() {
auto* remote_socket = GetRemoteSocket();
CHECK(remote_socket != nullptr);
return remote_socket->GetLocalInputStream();
}
OutputStream& BluetoothSocket::GetOutputStream() {
return GetLocalOutputStream();
}
InputStream& BluetoothSocket::GetLocalInputStream() {
absl::MutexLock lock(&mutex_);
return output_->GetInputStream();
}
OutputStream& BluetoothSocket::GetLocalOutputStream() {
absl::MutexLock lock(&mutex_);
return output_->GetOutputStream();
}
Exception BluetoothSocket::Close() {
absl::MutexLock lock(&mutex_);
DoClose();
return {Exception::kSuccess};
}
void BluetoothSocket::DoClose() {
if (!closed_) {
remote_socket_ = nullptr;
output_->GetOutputStream().Close();
output_->GetInputStream().Close();
input_->GetOutputStream().Close();
input_->GetInputStream().Close();
closed_ = true;
}
}
BluetoothSocket* BluetoothSocket::GetRemoteSocket() {
absl::MutexLock lock(&mutex_);
return remote_socket_;
}
BluetoothDevice* BluetoothSocket::GetRemoteDevice() {
BluetoothAdapter* remote_adapter = nullptr;
{
absl::MutexLock lock(&mutex_);
if (remote_socket_ == nullptr || remote_socket_->adapter_ == nullptr) {
return nullptr;
}
remote_adapter = remote_socket_->adapter_;
}
return remote_adapter ? &remote_adapter->GetDevice() : nullptr;
}
std::unique_ptr<api::BluetoothSocket> BluetoothServerSocket::Accept() {
absl::MutexLock lock(&mutex_);
while (pending_sockets_.empty()) {
cond_.Wait(&mutex_);
if (closed_) break;
}
// whether or not we were running in the wait loop, return early if closed.
if (closed_) return {};
auto* remote_socket =
pending_sockets_.extract(pending_sockets_.begin()).value();
CHECK(remote_socket);
auto local_socket = std::make_unique<BluetoothSocket>(adapter_);
local_socket->Connect(*remote_socket);
remote_socket->Connect(*local_socket);
cond_.SignalAll();
return local_socket;
}
bool BluetoothServerSocket::Connect(BluetoothSocket& socket) {
absl::MutexLock lock(&mutex_);
if (closed_) return false;
if (socket.IsConnected()) {
NEARBY_LOG(ERROR,
"Failed to connect to BT server socket: already connected");
return true; // already connected.
}
// add client socket to the pending list
pending_sockets_.emplace(&socket);
cond_.SignalAll();
while (!socket.IsConnected()) {
cond_.Wait(&mutex_);
if (closed_) return false;
}
return true;
}
void BluetoothServerSocket::SetCloseNotifier(std::function<void()> notifier) {
absl::MutexLock lock(&mutex_);
close_notifier_ = std::move(notifier);
}
BluetoothServerSocket::~BluetoothServerSocket() {
absl::MutexLock lock(&mutex_);
DoClose();
}
Exception BluetoothServerSocket::Close() {
absl::MutexLock lock(&mutex_);
return DoClose();
}
Exception BluetoothServerSocket::DoClose() {
bool should_notify = !closed_;
closed_ = true;
if (should_notify) {
cond_.SignalAll();
if (close_notifier_) {
auto notifier = std::move(close_notifier_);
mutex_.Unlock();
// Notifier may contain calls to public API, and may cause deadlock, if
// mutex_ is held during the call.
notifier();
mutex_.Lock();
}
}
return {Exception::kSuccess};
}
BluetoothClassicMedium::BluetoothClassicMedium(api::BluetoothAdapter& adapter)
// TODO(apolyudov): implement and use downcast<> with static assertions.
: adapter_(static_cast<BluetoothAdapter*>(&adapter)) {
adapter_->SetBluetoothClassicMedium(this);
auto& env = MediumEnvironment::Instance();
env.RegisterBluetoothMedium(*this, GetAdapter());
}
BluetoothClassicMedium::~BluetoothClassicMedium() {
adapter_->SetBluetoothClassicMedium(nullptr);
auto& env = MediumEnvironment::Instance();
env.UnregisterBluetoothMedium(*this);
}
bool BluetoothClassicMedium::StartDiscovery(DiscoveryCallback callback) {
auto& env = MediumEnvironment::Instance();
env.UpdateBluetoothMedium(*this, std::move(callback));
return true;
}
bool BluetoothClassicMedium::StopDiscovery() {
auto& env = MediumEnvironment::Instance();
env.UpdateBluetoothMedium(*this, {});
return true;
}
std::unique_ptr<api::BluetoothSocket> BluetoothClassicMedium::ConnectToService(
api::BluetoothDevice& remote_device, const std::string& service_uuid) {
NEARBY_LOG(INFO,
"G3 ConnectToService [self]: medium=%p, adapter=%p, device=%p",
this, &GetAdapter(), &GetAdapter().GetDevice());
// First, find an instance of remote medium, that exposed this device.
auto& adapter = static_cast<BluetoothDevice&>(remote_device).GetAdapter();
auto* medium =
static_cast<BluetoothClassicMedium*>(adapter.GetBluetoothClassicMedium());
if (!medium) return {}; // Adapter is not bound to medium. Bail out.
BluetoothServerSocket* server_socket = nullptr;
NEARBY_LOG(
INFO,
"G3 ConnectToService [peer]: medium=%p, adapter=%p, device=%p, uuid=%s",
medium, &adapter, &remote_device, service_uuid.c_str());
// Then, find our server socket context in this medium.
{
absl::MutexLock medium_lock(&medium->mutex_);
auto item = medium->sockets_.find(service_uuid);
server_socket = item != sockets_.end() ? item->second : nullptr;
if (server_socket == nullptr) {
NEARBY_LOG(ERROR, "Failed to find BT Server socket: uuid=%s",
service_uuid.c_str());
return {};
}
}
auto socket = std::make_unique<BluetoothSocket>(&GetAdapter());
// Finally, Request to connect to this socket.
if (!server_socket->Connect(*socket)) {
NEARBY_LOG(ERROR, "Failed to connect to existing BT Server socket: uuid=%s",
service_uuid.c_str());
return {};
}
NEARBY_LOG(INFO, "G3 ConnectToService: connected: socket=%p", socket.get());
return socket;
}
std::unique_ptr<api::BluetoothServerSocket>
BluetoothClassicMedium::ListenForService(const std::string& service_name,
const std::string& service_uuid) {
auto socket = std::make_unique<BluetoothServerSocket>(GetAdapter());
socket->SetCloseNotifier([this, uuid = service_uuid]() {
absl::MutexLock lock(&mutex_);
sockets_.erase(uuid);
});
NEARBY_LOG(INFO, "Adding service: medium=%p, uuid=%s", this,
service_uuid.c_str());
absl::MutexLock lock(&mutex_);
sockets_.emplace(service_uuid, socket.get());
return socket;
}
api::BluetoothDevice* BluetoothClassicMedium::GetRemoteDevice(
const std::string& mac_address) {
auto& env = MediumEnvironment::Instance();
return env.FindBluetoothDevice(mac_address);
}
} // namespace g3
} // namespace nearby
} // namespace location
+224
View File
@@ -0,0 +1,224 @@
#ifndef PLATFORM_IMPL_G3_BLUETOOTH_CLASSIC_H_
#define PLATFORM_IMPL_G3_BLUETOOTH_CLASSIC_H_
#include <memory>
#include <string>
#include "platform/api/bluetooth_classic.h"
#include "platform/base/byte_array.h"
#include "platform/base/exception.h"
#include "platform/base/input_stream.h"
#include "platform/base/listeners.h"
#include "platform/base/output_stream.h"
#include "platform/impl/g3/bluetooth_adapter.h"
#include "platform/impl/g3/pipe.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 {
// https://developer.android.com/reference/android/bluetooth/BluetoothSocket.html.
class BluetoothSocket : public api::BluetoothSocket {
public:
BluetoothSocket() = default;
explicit BluetoothSocket(BluetoothAdapter* adapter) : adapter_(adapter) {}
~BluetoothSocket() override;
// Connects to another BluetoothSocket, to form a functional low-level
// channel. From this point on, and until Close is called, connection exists.
void Connect(BluetoothSocket& other);
// NOTE:
// It is an undefined behavior if GetInputStream() or GetOutputStream() is
// called for a not-connected BluetoothSocket, i.e. any object that is not
// returned by BluetoothClassicMedium::ConnectToService() for client side or
// BluetoothServerSocket::Accept() for server side of connection.
// Returns the InputStream of this connected BluetoothSocket.
InputStream& GetInputStream() override;
// Returns the OutputStream of this connected BluetoothSocket.
// This stream is for local side to write.
OutputStream& GetOutputStream() override;
// Returns address of a remote BluetoothSocket or nullptr.
BluetoothSocket* GetRemoteSocket() ABSL_LOCKS_EXCLUDED(mutex_);
// Returns true if connection exists to the (possibly closed) remote socket.
bool IsConnected() const ABSL_LOCKS_EXCLUDED(mutex_);
// Returns true if socket is closed.
bool IsClosed() const ABSL_LOCKS_EXCLUDED(mutex_);
// Closes both input and output streams, marks Socket as closed.
// After this call object should be treated as not connected.
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
Exception Close() override ABSL_LOCKS_EXCLUDED(mutex_);
// https://developer.android.com/reference/android/bluetooth/BluetoothSocket.html#getRemoteDevice()
// Returns valid BluetoothDevice pointer if there is a connection, and
// nullptr otherwise.
BluetoothDevice* GetRemoteDevice() override ABSL_LOCKS_EXCLUDED(mutex_);
private:
void DoClose() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Returns true if connection exists to the (possibly closed) remote socket.
bool IsConnectedLocked() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Returns InputStream of our side of a connection.
// This is what the remote side is supposed to read from.
// This is a helper for GetInputStream() method.
InputStream& GetLocalInputStream() ABSL_LOCKS_EXCLUDED(mutex_);
// Returns OutputStream of our side of a connection.
// This is what the local size is supposed to write to.
// This is a helper for GetOutputStream() method.
OutputStream& GetLocalOutputStream() ABSL_LOCKS_EXCLUDED(mutex_);
// Output pipe is initialized by constructor, it remains always valid, until
// it is closed. it represents output part of a local socket. Input part of a
// local socket comes from the peer socket, after connection.
std::shared_ptr<Pipe> output_{new Pipe};
std::shared_ptr<Pipe> input_;
mutable absl::Mutex mutex_;
BluetoothAdapter* adapter_ = nullptr; // Our Adapter. Read only.
BluetoothSocket* remote_socket_ ABSL_GUARDED_BY(mutex_) = nullptr;
bool closed_ ABSL_GUARDED_BY(mutex_) = false;
};
// https://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html.
class BluetoothServerSocket : public api::BluetoothServerSocket {
public:
explicit BluetoothServerSocket(BluetoothAdapter& adapter)
: adapter_(&adapter) {}
~BluetoothServerSocket() override;
// Blocks until either:
// - at least one incoming connection request is available, or
// - ServerSocket is closed.
// On success, returns connected socket, ready to exchange data.
// Returns nullptr on error.
// Once error is reported, it is permanent, and ServerSocket has to be closed.
//
// Called by the server side of a connection.
// Returns BluetoothSocket to the server side.
// If not null, returned socket is connected to its remote (client-side) peer.
std::unique_ptr<api::BluetoothSocket> Accept() override
ABSL_LOCKS_EXCLUDED(mutex_);
// Blocks until either:
// - connection is available, or
// - server socket is closed, or
// - error happens.
//
// Called by the client side of a connection.
// socket is an initialized BluetoothSocket, associated with a client
// BluetoothAdapter.
// Returns true, if socket is successfully connected.
bool Connect(BluetoothSocket& socket) ABSL_LOCKS_EXCLUDED(mutex_);
// Called by the server side of a connection before passing ownership of
// BluetoothServerSocker to user, to track validity of a pointer to this
// server socket,
void SetCloseNotifier(std::function<void()> notifier)
ABSL_LOCKS_EXCLUDED(mutex_);
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
// Calls close_notifier if it was previously set, and marks socket as closed.
Exception Close() override ABSL_LOCKS_EXCLUDED(mutex_);
private:
Exception DoClose() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
absl::Mutex mutex_;
absl::CondVar cond_;
BluetoothAdapter* adapter_ = nullptr; // Our Adapter. Read only.
absl::flat_hash_set<BluetoothSocket*> pending_sockets_
ABSL_GUARDED_BY(mutex_);
std::function<void()> close_notifier_ ABSL_GUARDED_BY(mutex_);
bool closed_ ABSL_GUARDED_BY(mutex_) = false;
};
// Container of operations that can be performed over the Bluetooth Classic
// medium.
class BluetoothClassicMedium : public api::BluetoothClassicMedium {
public:
explicit BluetoothClassicMedium(api::BluetoothAdapter& adapter);
~BluetoothClassicMedium() override;
// NOTE(DiscoveryCallback):
// BluetoothDevice is a proxy object created as a result of BT discovery.
// Its lifetime spans between calls to device_discovered_cb and
// device_lost_cb.
// It is safe to use BluetoothDevice in device_discovered_cb() callback
// and at any time afterwards, until device_lost_cb() is called.
// It is not safe to use BluetoothDevice after returning from
// device_lost_cb() callback.
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#startDiscovery()
//
// Returns true once the process of discovery has been initiated.
bool StartDiscovery(DiscoveryCallback callback) override
ABSL_LOCKS_EXCLUDED(mutex_);
// 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().
bool StopDiscovery() override ABSL_LOCKS_EXCLUDED(mutex_);
// Connects to existing remote BT service.
//
// 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.
// On error, returns nullptr.
std::unique_ptr<api::BluetoothSocket> ConnectToService(
api::BluetoothDevice& remote_device,
const std::string& service_uuid) override ABSL_LOCKS_EXCLUDED(mutex_);
BluetoothAdapter& GetAdapter() { return *adapter_; }
// Creates BT service, and begins listening for remote attempts to connect.
//
// 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 nullptr on error.
std::unique_ptr<api::BluetoothServerSocket> ListenForService(
const std::string& service_name, const std::string& service_uuid) override
ABSL_LOCKS_EXCLUDED(mutex_);
api::BluetoothDevice* GetRemoteDevice(
const std::string& mac_address) override;
private:
absl::Mutex mutex_;
BluetoothAdapter* adapter_; // Our device adapter; read-only.
absl::flat_hash_map<std::string, BluetoothServerSocket*> sockets_
ABSL_GUARDED_BY(mutex_);
};
} // namespace g3
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_G3_BLUETOOTH_CLASSIC_H_
+37
View File
@@ -0,0 +1,37 @@
#ifndef PLATFORM_IMPL_G3_CONDITION_VARIABLE_H_
#define PLATFORM_IMPL_G3_CONDITION_VARIABLE_H_
#include "platform/api/condition_variable.h"
#include "platform/base/exception.h"
#include "platform/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};
}
Exception Wait(absl::Duration timeout) override {
cond_var_.WaitWithTimeout(mutex_, timeout);
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_IMPL_G3_CONDITION_VARIABLE_H_
+59
View File
@@ -0,0 +1,59 @@
#ifndef PLATFORM_IMPL_G3_COUNT_DOWN_LATCH_H_
#define PLATFORM_IMPL_G3_COUNT_DOWN_LATCH_H_
#include "platform/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_IMPL_G3_COUNT_DOWN_LATCH_H_
+39
View File
@@ -0,0 +1,39 @@
#include "platform/api/crypto.h"
#include <cstdint>
#include <string>
#include "platform/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
+56
View File
@@ -0,0 +1,56 @@
#include "platform/impl/g3/log_message.h"
#include <algorithm>
#include "base/stringprintf.h"
namespace location {
namespace nearby {
namespace g3 {
api::LogMessage::Severity g_min_log_severity = api::LogMessage::Severity::kInfo;
inline absl::LogSeverity ConvertSeverity(api::LogMessage::Severity severity) {
switch (severity) {
case api::LogMessage::Severity::kInfo:
return absl::LogSeverity::kInfo;
case api::LogMessage::Severity::kWarning:
return absl::LogSeverity::kWarning;
case api::LogMessage::Severity::kError:
return absl::LogSeverity::kError;
case api::LogMessage::Severity::kFatal:
return absl::LogSeverity::kFatal;
}
}
LogMessage::LogMessage(const char* file, int line, Severity severity)
: log_streamer_(ConvertSeverity(severity), file, line) {}
LogMessage::~LogMessage() = default;
void LogMessage::Print(const char* format, ...) {
va_list ap;
va_start(ap, format);
std::string result;
StringAppendV(&result, format, ap);
log_streamer_.stream() << result;
va_end(ap);
}
std::ostream& LogMessage::Stream() { return log_streamer_.stream(); }
} // namespace g3
namespace api {
void LogMessage::SetMinLogSeverity(Severity severity) {
g3::g_min_log_severity = severity;
}
bool LogMessage::ShouldCreateLogMessage(Severity severity) {
return severity >= g3::g_min_log_severity;
}
} // namespace api
} // namespace nearby
} // namespace location
+30
View File
@@ -0,0 +1,30 @@
#ifndef PLATFORM_IMPL_G3_LOG_MESSAGE_H_
#define PLATFORM_IMPL_G3_LOG_MESSAGE_H_
#include "base/logging.h"
#include "platform/api/log_message.h"
namespace location {
namespace nearby {
namespace g3 {
// See documentation in
// https://source.corp.google.com/piper///depot/google3/platform/api/log_message.h
class LogMessage : public api::LogMessage {
public:
LogMessage(const char* file, int line, Severity severity);
~LogMessage() override;
void Print(const char* format, ...) override;
std::ostream& Stream() override;
private:
absl::LogStreamer log_streamer_;
};
} // namespace g3
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_G3_LOG_MESSAGE_H_
@@ -0,0 +1,59 @@
#ifndef PLATFORM_IMPL_G3_MULTI_THREAD_EXECUTOR_H_
#define PLATFORM_IMPL_G3_MULTI_THREAD_EXECUTOR_H_
#include <atomic>
#include "platform/api/submittable_executor.h"
#include "platform/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(); }
int GetTid(int index) const override {
const auto* thread = thread_pool_.thread(index);
return thread ? thread->tid() : 0;
}
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_IMPL_G3_MULTI_THREAD_EXECUTOR_H_

Some files were not shown because too many files have changed in this diff Show More