From 91297172eb3528c129e20a3d34e03692e1c8ab01 Mon Sep 17 00:00:00 2001 From: Dmitrii Merkurev Date: Thu, 9 Feb 2023 02:08:14 +0000 Subject: [PATCH] fastboot: Introduce network-connected devices storage Bug: 267507577 Bug: 267505625 Test: tested file lock api works on linux/windows Test: tested storage api works on linux/windows Change-Id: I33dda819370900310ae7fc63cbf6b00ba22ad4e8 Signed-off-by: Dmitrii Merkurev --- fastboot/Android.bp | 4 +- fastboot/filesystem.cpp | 105 ++++++++++++++++++++++++++++++++++++++++ fastboot/filesystem.h | 43 ++++++++++++++++ fastboot/storage.cpp | 67 +++++++++++++++++++++++++ fastboot/storage.h | 35 ++++++++++++++ 5 files changed, 253 insertions(+), 1 deletion(-) create mode 100644 fastboot/filesystem.cpp create mode 100644 fastboot/filesystem.h create mode 100644 fastboot/storage.cpp create mode 100644 fastboot/storage.h diff --git a/fastboot/Android.bp b/fastboot/Android.bp index 9512e7ed1..113e845bf 100644 --- a/fastboot/Android.bp +++ b/fastboot/Android.bp @@ -283,15 +283,17 @@ cc_library_host_static { srcs: [ "bootimg_utils.cpp", + "fastboot_driver.cpp", "fastboot.cpp", + "filesystem.cpp", "fs.cpp", "socket.cpp", + "storage.cpp", "super_flash_helper.cpp", "tcp.cpp", "udp.cpp", "util.cpp", "vendor_boot_img_utils.cpp", - "fastboot_driver.cpp", ], // Only version the final binaries diff --git a/fastboot/filesystem.cpp b/fastboot/filesystem.cpp new file mode 100644 index 000000000..a58ba004d --- /dev/null +++ b/fastboot/filesystem.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef _WIN32 +#include +#include +#include +#else +#include +#endif + +#include +#include +#include +#include +#include + +#include + +#include "filesystem.h" + +namespace { + +int LockFile(int fd) { +#ifdef _WIN32 + HANDLE handle = reinterpret_cast(_get_osfhandle(fd)); + OVERLAPPED overlapped = {}; + const BOOL locked = LockFileEx(handle, LOCKFILE_EXCLUSIVE_LOCK, 0, + MAXDWORD, MAXDWORD, &overlapped); + return locked ? 0 : -1; +#else + return flock(fd, LOCK_EX); +#endif +} + +} + +// inspired by adb implementation: +// cs.android.com/android/platform/superproject/+/master:packages/modules/adb/adb_utils.cpp;l=275 +std::string GetHomeDirPath() { +#ifdef _WIN32 + WCHAR path[MAX_PATH]; + const HRESULT hr = SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, 0, path); + if (FAILED(hr)) { + return {}; + } + std::string home_str; + if (!android::base::WideToUTF8(path, &home_str)) { + return {}; + } + return home_str; +#else + if (const char* const home = getenv("HOME")) { + return home; + } + + struct passwd pwent; + struct passwd* result; + int pwent_max = sysconf(_SC_GETPW_R_SIZE_MAX); + if (pwent_max == -1) { + pwent_max = 16384; + } + std::vector buf(pwent_max); + int rc = getpwuid_r(getuid(), &pwent, buf.data(), buf.size(), &result); + if (rc == 0 && result) { + return result->pw_dir; + } +#endif + + return {}; +} + +bool FileExists(const std::string& path) { + return access(path.c_str(), F_OK) == 0; +} + +bool EnsureDirectoryExists(const std::string& directory_path) { + const int result = +#ifdef _WIN32 + _mkdir(directory_path.c_str()); +#else + mkdir(directory_path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); +#endif + + return result == 0 || errno == EEXIST; +} + +FileLock::FileLock(const std::string& path) : fd_(open(path.c_str(), O_CREAT | O_WRONLY, 0644)) { + if (LockFile(fd_.get()) != 0) { + LOG(FATAL) << "Failed to acquire a lock on " << path; + } +} \ No newline at end of file diff --git a/fastboot/filesystem.h b/fastboot/filesystem.h new file mode 100644 index 000000000..32614964b --- /dev/null +++ b/fastboot/filesystem.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include + +using android::base::unique_fd; + +// TODO(b/175635923): remove after enabling libc++fs for windows +const char kPathSeparator = +#ifdef _WIN32 + '\\'; +#else + '/'; +#endif + +std::string GetHomeDirPath(); +bool EnsureDirectoryExists(const std::string& directory_path); + +class FileLock { + public: + FileLock() = delete; + FileLock(const std::string& path); + + private: + unique_fd fd_; +}; \ No newline at end of file diff --git a/fastboot/storage.cpp b/fastboot/storage.cpp new file mode 100644 index 000000000..db13dd63c --- /dev/null +++ b/fastboot/storage.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include + +#include "storage.h" +#include "util.h" + +ConnectedDevicesStorage::ConnectedDevicesStorage() { + const std::string home_path = GetHomeDirPath(); + if (home_path.empty()) { + return; + } + + const std::string home_fastboot_path = home_path + kPathSeparator + ".fastboot"; + + if (!EnsureDirectoryExists(home_fastboot_path)) { + LOG(FATAL) << "Cannot create directory: " << home_fastboot_path; + } + + // We're using a separate file for locking because the Windows LockFileEx does not + // permit opening a file stream for the locked file, even within the same process. So, + // we have to use fd or handle API to manipulate the storage files, which makes it + // nearly impossible to fully rewrite a file content without having to recreate it. + // Unfortunately, this is not an option during holding a lock. + devices_path_ = home_fastboot_path + kPathSeparator + "devices"; + devices_lock_path_ = home_fastboot_path + kPathSeparator + "devices.lock"; +} + +void ConnectedDevicesStorage::WriteDevices(const std::set& devices) { + std::ofstream devices_stream(devices_path_); + std::copy(devices.begin(), devices.end(), + std::ostream_iterator(devices_stream, "\n")); +} + +std::set ConnectedDevicesStorage::ReadDevices() { + std::ifstream devices_stream(devices_path_); + std::istream_iterator start(devices_stream), end; + std::set devices(start, end); + return devices; +} + +void ConnectedDevicesStorage::Clear() { + if (!android::base::RemoveFileIfExists(devices_path_)) { + LOG(FATAL) << "Failed to clear connected device list: " << devices_path_; + } +} + +FileLock ConnectedDevicesStorage::Lock() const { + return FileLock(devices_lock_path_); +} \ No newline at end of file diff --git a/fastboot/storage.h b/fastboot/storage.h new file mode 100644 index 000000000..1cce95092 --- /dev/null +++ b/fastboot/storage.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include "filesystem.h" + +class ConnectedDevicesStorage { + public: + ConnectedDevicesStorage(); + void WriteDevices(const std::set& devices); + std::set ReadDevices(); + void Clear(); + + FileLock Lock() const; + private: + std::string devices_path_; + std::string devices_lock_path_; +}; \ No newline at end of file