diff --git a/internal/platform/implementation/linux/BUILD b/internal/platform/implementation/linux/BUILD index 85a6c98c..81d7c97f 100644 --- a/internal/platform/implementation/linux/BUILD +++ b/internal/platform/implementation/linux/BUILD @@ -1,17 +1,88 @@ cc_library( - name = "linux_platform_impl", + name = "types", srcs = [ - "device_info.cc" + "device_info.cc", ], hdrs = [ - "device_info.h" + "atomics.h", + "bluetooth_adapter.h", + "generated/bluez_adapter_client_glue.h", + "device_info.h", + "multi_thread_executor.h", + "scheduled_executor.h", + "platform.h", ], + visibility = ["//visibility:private"], deps = [ - "@sdbus_cpp//:sdbus_cpp", - "@sdbus_cpp//:libsystemd", + "//internal/base:file_path", + "//internal/platform:base", "//internal/platform:logging", "//internal/platform/implementation:types", - "@com_google_absl//absl/strings" + "@com_google_absl//absl/strings", + "@sdbus_cpp//:sdbus_cpp", + "@sdbus_cpp//:libsystemd", + ], +) + +cc_library( + name = "linux", + srcs = [ + "bluetooth_adapter.cc", + "platform.cc", + "scheduled_executor.cc", + ], + hdrs = [ + "device_info.h", + "bluetooth_adapter.h", + ], + visibility = ["//visibility:public"], + deps = [ + ":types", + "//connections/implementation/flags:connections_flags", + "//internal/base:file_path", + "//internal/base:files", + "//internal/flags:nearby_flags", + "//internal/platform:base", + "//internal/platform:cancellation_flag", + "//internal/platform:logging", + "//internal/platform:mac_address", + "//internal/platform:types", + "//internal/platform:uuid", + "//internal/platform/flags:platform_flags", + "//internal/platform/implementation:comm", + "//internal/platform/implementation:platform", + "//internal/platform/implementation:types", + "//internal/platform/implementation:wifi_utils", + "//internal/platform/implementation/shared:posix_condition_variable", + "//internal/platform/implementation/shared:posix_mutex", + "//internal/platform/implementation/shared:count_down_latch", + "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/base:nullability", + "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/functional:any_invocable", + "@com_google_absl//absl/memory", + "@com_google_absl//absl/status", + "@com_google_absl//absl/status:statusor", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/synchronization", + "@com_google_absl//absl/time", + "@com_google_absl//absl/types:optional", + "@com_google_absl//absl/types:span", + "@nlohmann_json//:json", + + "@sdbus_cpp//:sdbus_cpp", + "@sdbus_cpp//:libsystemd", + ], +) + +# The existing target that other BUILD files select on; keep for compatibility. +cc_library( + name = "linux_platform_impl", + srcs = [], + hdrs = [], + deps = [ + ":linux", + ":types", ], visibility = ["//visibility:public"], ) diff --git a/internal/platform/implementation/linux/atomic_boolean.h b/internal/platform/implementation/linux/atomic_boolean.h deleted file mode 100644 index 259624dc..00000000 --- a/internal/platform/implementation/linux/atomic_boolean.h +++ /dev/null @@ -1,33 +0,0 @@ -// -// Created by root on 10/2/25. -// - -#ifndef LINUX_ATOMIC_BOOLEAN_H -#define LINUX_ATOMIC_BOOLEAN_H - -#include -#include "internal/platform/implementation/atomic_boolean.h" - -namespace nearby { - namespace linux { - -// A boolean value that may be updated atomically. -class AtomicBoolean : public api::AtomicBoolean { - public: - explicit AtomicBoolean(bool value = false) : atomic_boolean_(value) {} - ~AtomicBoolean() override = default; - - // Atomically read and return current value. - bool Get() const override { return atomic_boolean_; }; - - // Atomically exchange original value with a new one. Return previous value. - bool Set(bool value) override { return atomic_boolean_.exchange(value); }; - - private: - std::atomic_bool atomic_boolean_ = false; -}; - - } // namespace api -} // namespace nearby - -#endif //LINUX_ATOMIC_BOOLEAN_H \ No newline at end of file diff --git a/internal/platform/implementation/linux/bluetooth_adapter.cc b/internal/platform/implementation/linux/bluetooth_adapter.cc index 4641c804..2fbdc58a 100644 --- a/internal/platform/implementation/linux/bluetooth_adapter.cc +++ b/internal/platform/implementation/linux/bluetooth_adapter.cc @@ -18,8 +18,6 @@ #include "absl/strings/string_view.h" #include "internal/platform/implementation/linux/bluetooth_adapter.h" -#include "third_party/absl/absl/strings/str_format.h" - namespace nearby { namespace linux { bool BluetoothAdapter::SetStatus(Status status) diff --git a/internal/platform/implementation/linux/bluetooth_adapter.h b/internal/platform/implementation/linux/bluetooth_adapter.h index 1a756e5c..c6e74e10 100644 --- a/internal/platform/implementation/linux/bluetooth_adapter.h +++ b/internal/platform/implementation/linux/bluetooth_adapter.h @@ -52,10 +52,10 @@ class BluetoothAdapter : public api::BluetoothAdapter, public sdbus::ProxyInterf // Synchronously sets the status of the BluetoothAdapter to 'status', and // returns true if the operation was a success. - bool SetStatus(Status status) = 0; + bool SetStatus(Status status) override; // Returns true if the BluetoothAdapter's current status is // Status::Value::kEnabled. - bool IsEnabled() const = 0; + [[nodiscard]] bool IsEnabled() const override; // Scan modes of a BluetoothAdapter, as described at // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#getScanMode(). @@ -69,28 +69,28 @@ class BluetoothAdapter : public api::BluetoothAdapter, public sdbus::ProxyInterf // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#getScanMode() // // Returns ScanMode::kUnknown on error. - ScanMode GetScanMode() const = 0; + [[nodiscard]] ScanMode GetScanMode() const override; // Synchronously sets the scan mode of the adapter, and returns true if the // operation was a success. - bool SetScanMode(ScanMode scan_mode) = 0; + bool SetScanMode(ScanMode scan_mode) override; // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#getName() // Returns an empty string on error - std::string GetName() const = 0; + [[nodiscard]] std::string GetName() const override; // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#setName(java.lang.String) - bool SetName(absl::string_view name) = 0; - bool SetName(absl::string_view name, bool persist) = 0; + bool SetName(absl::string_view name) override; + bool SetName(absl::string_view name, bool persist) override; // Returns BT MAC address assigned to this adapter. ABSL_DEPRECATED("Use GetAddress() instead.") - std::string GetMacAddress() const = 0; + [[nodiscard]] std::string GetMacAddress() const override; // Implementation for migration only. Once subclasses implement this, the // above GetMacAddress() can be removed. - MacAddress GetAddress() const { + [[nodiscard]] MacAddress GetAddress() const override { std::string mac_address = GetMacAddress(); if (mac_address.empty()) { - return MacAddress(); + return {}; } MacAddress address; MacAddress::FromString(mac_address, address); diff --git a/internal/platform/implementation/linux/platform.cc b/internal/platform/implementation/linux/platform.cc new file mode 100644 index 00000000..ccc1fb3a --- /dev/null +++ b/internal/platform/implementation/linux/platform.cc @@ -0,0 +1,149 @@ +// filepath: /workspace/internal/platform/implementation/linux/platform.cc +// Minimal Linux implementation of ImplementationPlatform. + +#include "internal/platform/implementation/platform.h" + +#include +#include + +#include "bluetooth_adapter.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "absl/strings/str_cat.h" +#include "internal/platform/implementation/atomic_boolean.h" +#include "internal/platform/implementation/atomic_reference.h" +#include "internal/platform/implementation/count_down_latch.h" +#include "internal/platform/implementation/http_loader.h" +#include "internal/platform/implementation/shared/count_down_latch.h" +#include "internal/platform/implementation/linux/atomics.h" +#include "internal/platform/implementation/linux/multi_thread_executor.h" +#include "internal/platform/implementation/linux/scheduled_executor.h" +#include "internal/platform/implementation/linux/device_info.h" +#include "internal/platform/implementation/shared/posix_mutex.h" +#include "internal/platform/implementation/shared/posix_condition_variable.h" + + +#include +namespace nearby { +namespace api { + +std::string ImplementationPlatform::GetCustomSavePath(const std::string& parent_folder, + const std::string& file_name) { + return absl::StrCat(parent_folder, "/", file_name); +} + +std::string ImplementationPlatform::GetDownloadPath(const std::string& parent_folder, + const std::string& file_name) { + return absl::StrCat("/tmp/", file_name); +} + +std::string ImplementationPlatform::GetDownloadPath(const std::string& file_name) { + return absl::StrCat("/tmp/", file_name); +} + +std::string ImplementationPlatform::GetAppDataPath(const std::string& file_name) { + return absl::StrCat("/tmp/", file_name); +} + +OSName ImplementationPlatform::GetCurrentOS() { return OSName::kLinux; } + +std::unique_ptr ImplementationPlatform::CreateAtomicBoolean(bool initial_value) { + return std::make_unique(initial_value); +} + +std::unique_ptr ImplementationPlatform::CreateAtomicUint32(std::uint32_t value) { + return std::make_unique(value); +} + +std::unique_ptr ImplementationPlatform::CreateCountDownLatch(std::int32_t count) { + return std::make_unique(count); +} + +#pragma push_macro("CreateMutex") +#undef CreateMutex +std::unique_ptr ImplementationPlatform::CreateMutex(Mutex::Mode mode) { + // Use the shared POSIX mutex implementation. The posix::Mutex is recursive by + // design (uses PTHREAD_MUTEX_RECURSIVE), so return it for both regular and + // recursive modes to use a consistent POSIX implementation across Linux. + return std::make_unique(); +} +#pragma pop_macro("CreateMutex") + +std::unique_ptr ImplementationPlatform::CreateConditionVariable(Mutex* mutex) { + if (mutex == nullptr) return nullptr; + // Expect a posix::Mutex instance here; if it's not, return nullptr. + auto* derived = dynamic_cast(mutex); + if (!derived) return nullptr; + return std::make_unique(derived); +} + +std::unique_ptr ImplementationPlatform::CreateInputFile(PayloadId, std::int64_t) { + return nullptr; +} + +std::unique_ptr ImplementationPlatform::CreateInputFile(const std::string&, size_t) { + return nullptr; +} + +std::unique_ptr ImplementationPlatform::CreateOutputFile(PayloadId) { + return nullptr; +} + +std::unique_ptr ImplementationPlatform::CreateOutputFile(const std::string&) { + return nullptr; +} + +std::unique_ptr ImplementationPlatform::CreateLogMessage(const char* file, int line, LogMessage::Severity severity) { + return nullptr; +} + +std::unique_ptr ImplementationPlatform::CreateSingleThreadExecutor() { + return std::make_unique(1); +} + +std::unique_ptr ImplementationPlatform::CreateMultiThreadExecutor(std::int32_t max_concurrency) { + return std::make_unique(static_cast(max_concurrency)); +} + +std::unique_ptr ImplementationPlatform::CreateScheduledExecutor() { + return std::unique_ptr(new linux::ScheduledExecutor()); +} + +std::unique_ptr ImplementationPlatform::CreateAwdlMedium() { return nullptr; } +std::unique_ptr ImplementationPlatform::CreateBluetoothAdapter() +{ + static auto connection = sdbus::createConnection(); + return std::make_unique(*connection, "/org/bluez/hci0"); +} +std::unique_ptr ImplementationPlatform::CreateBluetoothClassicMedium(BluetoothAdapter&) { return nullptr; } +std::unique_ptr ImplementationPlatform::CreateBleMedium(BluetoothAdapter&) { return nullptr; } +std::unique_ptr ImplementationPlatform::CreateBleV2Medium(api::BluetoothAdapter&) { return nullptr; } +std::unique_ptr ImplementationPlatform::CreateCredentialStorage() { return nullptr; } +std::unique_ptr ImplementationPlatform::CreateServerSyncMedium() { return nullptr; } +std::unique_ptr ImplementationPlatform::CreateWifiMedium() { return nullptr; } +std::unique_ptr ImplementationPlatform::CreateWifiLanMedium() { return nullptr; } +std::unique_ptr ImplementationPlatform::CreateWifiHotspotMedium() { return nullptr; } +std::unique_ptr ImplementationPlatform::CreateWifiDirectMedium() { return nullptr; } + +std::unique_ptr ImplementationPlatform::CreateTimer() { return nullptr; } + +std::unique_ptr ImplementationPlatform::CreateDeviceInfo() { + return std::make_unique(); +} + +#ifndef NO_WEBRTC +std::unique_ptr ImplementationPlatform::CreateWebRtcMedium() { return nullptr; } +#endif + +absl::StatusOr ImplementationPlatform::SendRequest(const WebRequest& request) { + return absl::UnimplementedError("HTTP loader not implemented on this minimal linux platform"); +} + +#ifndef NEARBY_CHROMIUM +std::unique_ptr ImplementationPlatform::CreatePreferencesManager(absl::string_view path) { + return nullptr; +} +#endif + +} // namespace api +} // namespace nearby diff --git a/internal/platform/implementation/linux/platform.h b/internal/platform/implementation/linux/platform.h index 86bd0e33..35868ea7 100644 --- a/internal/platform/implementation/linux/platform.h +++ b/internal/platform/implementation/linux/platform.h @@ -6,6 +6,9 @@ namespace nearby { namespace linux { + class Platform: public api::ImplementationPlatform + { + }; } diff --git a/internal/platform/implementation/linux/scheduled_executor.cc b/internal/platform/implementation/linux/scheduled_executor.cc new file mode 100644 index 00000000..e69de29b diff --git a/internal/platform/implementation/linux/scheduled_executor.h b/internal/platform/implementation/linux/scheduled_executor.h new file mode 100644 index 00000000..6012d0da --- /dev/null +++ b/internal/platform/implementation/linux/scheduled_executor.h @@ -0,0 +1,97 @@ +// +// Created by root on 10/8/25. +// + +#ifndef WORKSPACE_SCHEDULED_EXECUTOR_H +#define WORKSPACE_SCHEDULED_EXECUTOR_H + +#include "internal/platform/implementation/scheduled_executor.h" +#include "internal/platform/runnable.h" +#include "internal/platform/implementation/cancelable.h" +#include "internal/platform/implementation/linux/multi_thread_executor.h" +#include +#include +#include +#include "absl/time/time.h" + +namespace nearby +{ + namespace linux + { + // Minimal ScheduledExecutor implementation for linux. + class ScheduledExecutor : public api::ScheduledExecutor + { + public: + ~ScheduledExecutor() override = default; + ScheduledExecutor() : shutdown_(false), executor_(1) {} + + // Schedule a runnable to run after `duration`. Returns a Cancelable which + // can be used to cancel the scheduled task before it runs. + std::shared_ptr Schedule(Runnable&& runnable, + absl::Duration duration) override + { + class ScheduledCancelable : public api::Cancelable { + public: + enum Status { kNotRun, kExecuted, kCanceled }; + ScheduledCancelable() : status_(kNotRun) {} + bool Cancel() override { + Status expected = kNotRun; + return status_.compare_exchange_strong(expected, kCanceled); + } + [[nodiscard]] bool IsCanceled() const { return status_.load() == kCanceled; } + [[nodiscard]] bool MarkExecuted() { + Status expected = kNotRun; + return status_.compare_exchange_strong(expected, kExecuted); + } + + private: + std::atomic status_; + }; + + auto cancelable = std::make_shared(); + if (shutdown_.load()) return cancelable; + + // Move runnable into the thread task. + Runnable task = [this, cancelable, runnable = std::move(runnable)]() mutable { + if (shutdown_.load()) return; + if (cancelable->IsCanceled()) return; + if (!cancelable->MarkExecuted()) return; + // Use executor_ to run the actual runnable. + executor_.Execute(std::move(runnable)); + }; + + // Spawn a detached thread that sleeps for the duration then runs the task + // through executor_. Using a detached thread is simple and sufficient for + // a minimal implementation. + std::thread([d = duration, t = std::move(task), cancelable, this]() mutable { + if (absl::ToInt64Nanoseconds(d) > 0) { + std::this_thread::sleep_for(std::chrono::nanoseconds( + absl::ToInt64Nanoseconds(d))); + } + if (shutdown_.load()) return; + if (cancelable->IsCanceled()) return; + if (t) t(); + }).detach(); + + return cancelable; + }; + + void Execute(Runnable&& runnable) override { + if (shutdown_.load()) return; + executor_.Execute(std::move(runnable)); + } + + void Shutdown() override { + if (!shutdown_.exchange(true)) { + executor_.Shutdown(); + } + } + + private: + std::atomic shutdown_; + // Reuse the multi-thread executor implementation for running tasks. + linux::MultiThreadExecutor executor_; + }; + } +} +#endif //WORKSPACE_SCHEDULED_EXECUTOR_H diff --git a/internal/platform/implementation/shared/BUILD b/internal/platform/implementation/shared/BUILD index ce871842..6a391b4a 100644 --- a/internal/platform/implementation/shared/BUILD +++ b/internal/platform/implementation/shared/BUILD @@ -50,6 +50,7 @@ cc_library( hdrs = [ "posix_condition_variable.h", ], + visibility = ["//internal/platform/implementation:__subpackages__"], deps = [ ":posix_mutex", "//internal/platform/implementation:types", diff --git a/internal/platform/implementation/shared/posix_condition_variable.cc b/internal/platform/implementation/shared/posix_condition_variable.cc index d239fee5..13089f5e 100644 --- a/internal/platform/implementation/shared/posix_condition_variable.cc +++ b/internal/platform/implementation/shared/posix_condition_variable.cc @@ -13,6 +13,8 @@ // limitations under the License. #include "internal/platform/implementation/shared/posix_condition_variable.h" +#include "absl/time/time.h" +#include namespace nearby { namespace posix { @@ -38,5 +40,20 @@ Exception ConditionVariable::Wait() { return {Exception::kSuccess}; } +Exception ConditionVariable::Wait(absl::Duration timeout) { + // Calculate absolute deadline as timespec for pthread_cond_timedwait. + absl::Time deadline = absl::Now() + timeout; + int64_t nanos = absl::ToUnixNanos(deadline); + timespec ts{}; // zero-initialize to satisfy static analyzers + ts.tv_sec = static_cast(nanos / 1000000000LL); + ts.tv_nsec = static_cast(nanos % 1000000000LL); + + int rc = pthread_cond_timedwait(&cond_, &(mutex_->mutex_), &ts); + if (rc == 0) return {Exception::kSuccess}; + if (rc == ETIMEDOUT) return {Exception::kTimeout}; + if (rc == EINTR) return {Exception::kInterrupted}; + return {Exception::kFailed}; +} + } // namespace posix } // namespace nearby diff --git a/internal/platform/implementation/shared/posix_condition_variable.h b/internal/platform/implementation/shared/posix_condition_variable.h index 2bb66f24..63c11693 100644 --- a/internal/platform/implementation/shared/posix_condition_variable.h +++ b/internal/platform/implementation/shared/posix_condition_variable.h @@ -30,6 +30,7 @@ class ConditionVariable : public api::ConditionVariable { void Notify() override; Exception Wait() override; + Exception Wait(absl::Duration timeout) override; private: Mutex* mutex_;