1 // Copyright 2022 The Android Open Source Project 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #pragma once 16 17 #include <optional> 18 #ifdef _WIN32 19 #include <windows.h> 20 #elif defined(__APPLE__) || defined(__linux__) || defined(__QNX__) 21 #include <unistd.h> 22 #endif 23 24 namespace android { 25 namespace base { 26 namespace internal { 27 #ifdef _WIN32 28 struct PlatformTraitWin32 { 29 using DescriptorType = HANDLE; closeDescriptorandroid::base::internal::PlatformTraitWin3230 void closeDescriptor(DescriptorType handle) { CloseHandle(handle); } 31 }; 32 #elif defined(__APPLE__) || defined(__linux__) || defined(__QNX__) 33 struct PlatformTraitUnixLike { 34 using DescriptorType = int; 35 void closeDescriptor(DescriptorType handle) { close(handle); } 36 }; 37 #endif 38 } // namespace internal 39 40 41 template <class PlatformTrait> 42 using DescriptorTypeBase = typename PlatformTrait::DescriptorType; 43 44 // An RAII wrapper for fd on *nix or HANDLE on Windows. The interfaces are similar to std::unique. 45 template <class PlatformTrait> 46 class ManagedDescriptorBase { 47 public: 48 using DescriptorType = typename PlatformTrait::DescriptorType; 49 // The platformTrait argument is only used for testing to inject. platformTrait must live longer 50 // than the created ManagedDescriptorBase object. ManagedDescriptorBase(DescriptorType rawDescriptor,PlatformTrait & platformTrait=sPlatformTrait)51 ManagedDescriptorBase(DescriptorType rawDescriptor, 52 PlatformTrait& platformTrait = sPlatformTrait) 53 : mRawDescriptor(rawDescriptor), mPlatformTrait(platformTrait) {} ManagedDescriptorBase(PlatformTrait & platformTrait=sPlatformTrait)54 ManagedDescriptorBase(PlatformTrait& platformTrait = sPlatformTrait) 55 : mRawDescriptor(std::nullopt), mPlatformTrait(platformTrait) {} ~ManagedDescriptorBase()56 ~ManagedDescriptorBase() { 57 if (!mRawDescriptor.has_value()) { 58 return; 59 } 60 mPlatformTrait.closeDescriptor(*mRawDescriptor); 61 } 62 63 ManagedDescriptorBase(const ManagedDescriptorBase&) = delete; 64 ManagedDescriptorBase& operator=(const ManagedDescriptorBase&) = delete; ManagedDescriptorBase(ManagedDescriptorBase && that)65 ManagedDescriptorBase(ManagedDescriptorBase&& that) 66 : mRawDescriptor(std::nullopt), mPlatformTrait(that.mPlatformTrait) { 67 *this = std::move(that); 68 } operator =(ManagedDescriptorBase && that)69 ManagedDescriptorBase& operator=(ManagedDescriptorBase&& that) { 70 // Assume this->mPlatformTrait and that.mPlatformTrait are the same. 71 if (this == &that) { 72 return *this; 73 } 74 75 ManagedDescriptorBase other(mPlatformTrait); 76 other.mRawDescriptor = std::move(mRawDescriptor); 77 78 mRawDescriptor = std::move(that.mRawDescriptor); 79 that.mRawDescriptor = std::nullopt; 80 return *this; 81 } 82 release()83 std::optional<DescriptorType> release() { 84 std::optional<DescriptorType> res = mRawDescriptor; 85 mRawDescriptor = std::nullopt; 86 return res; 87 } 88 get()89 std::optional<DescriptorType> get() { return mRawDescriptor; } 90 91 private: 92 std::optional<DescriptorType> mRawDescriptor; 93 PlatformTrait& mPlatformTrait; 94 95 // The PlatformTraits singleton used as the default value of the platformTrait parameter in the 96 // constructor. 97 inline static PlatformTrait sPlatformTrait = {}; 98 }; 99 100 #ifdef _WIN32 101 using DescriptorType = DescriptorTypeBase<internal::PlatformTraitWin32>; 102 using ManagedDescriptor = ManagedDescriptorBase<internal::PlatformTraitWin32>; 103 #elif defined(__APPLE__) || defined(__linux__) || defined(__QNX__) 104 using DescriptorType = DescriptorTypeBase<internal::PlatformTraitUnixLike>; 105 using ManagedDescriptor = ManagedDescriptorBase<internal::PlatformTraitUnixLike>; 106 #endif 107 108 } // namespace base 109 } // namespace android 110