1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef ANDROID_UTILS_FLATTENABLE_H 18 #define ANDROID_UTILS_FLATTENABLE_H 19 20 21 #include <stdint.h> 22 #include <string.h> 23 #include <sys/types.h> 24 #include <utils/Errors.h> 25 #include <utils/Debug.h> 26 27 #include <type_traits> 28 29 namespace android { 30 31 32 class FlattenableUtils { 33 public: 34 template<size_t N> 35 static size_t align(size_t size) { 36 static_assert(!(N & (N - 1)), "Can only align to a power of 2."); 37 return (size + (N-1)) & ~(N-1); 38 } 39 40 template<size_t N> 41 static size_t align(void const*& buffer) { 42 static_assert(!(N & (N - 1)), "Can only align to a power of 2."); 43 uintptr_t b = uintptr_t(buffer); 44 buffer = reinterpret_cast<void*>((uintptr_t(buffer) + (N-1)) & ~(N-1)); 45 return size_t(uintptr_t(buffer) - b); 46 } 47 48 template<size_t N> 49 static size_t align(void*& buffer) { 50 return align<N>( const_cast<void const*&>(buffer) ); 51 } 52 53 static void advance(void*& buffer, size_t& size, size_t offset) { 54 buffer = reinterpret_cast<void*>( uintptr_t(buffer) + offset ); 55 size -= offset; 56 } 57 58 static void advance(void const*& buffer, size_t& size, size_t offset) { 59 buffer = reinterpret_cast<void const*>( uintptr_t(buffer) + offset ); 60 size -= offset; 61 } 62 63 // write a POD structure 64 template<typename T> 65 static void write(void*& buffer, size_t& size, const T& value) { 66 static_assert(std::is_trivially_copyable<T>::value, 67 "Cannot flatten a non-trivially-copyable type"); 68 memcpy(buffer, &value, sizeof(T)); 69 advance(buffer, size, sizeof(T)); 70 } 71 72 // read a POD structure 73 template<typename T> 74 static void read(void const*& buffer, size_t& size, T& value) { 75 static_assert(std::is_trivially_copyable<T>::value, 76 "Cannot unflatten a non-trivially-copyable type"); 77 memcpy(&value, buffer, sizeof(T)); 78 advance(buffer, size, sizeof(T)); 79 } 80 }; 81 82 83 /* 84 * The Flattenable protocol allows an object to serialize itself out 85 * to a byte-buffer and an array of file descriptors. 86 * Flattenable objects must implement this protocol. 87 */ 88 89 template <typename T> 90 class Flattenable { 91 public: 92 // size in bytes of the flattened object 93 inline size_t getFlattenedSize() const; 94 95 // number of file descriptors to flatten 96 inline size_t getFdCount() const; 97 98 // flattens the object into buffer. 99 // size should be at least of getFlattenedSize() 100 // file descriptors are written in the fds[] array but ownership is 101 // not transfered (ie: they must be dupped by the caller of 102 // flatten() if needed). 103 inline status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const; 104 105 // unflattens the object from buffer. 106 // size should be equal to the value of getFlattenedSize() when the 107 // object was flattened. 108 // unflattened file descriptors are found in the fds[] array and 109 // don't need to be dupped(). ie: the caller of unflatten doesn't 110 // keep ownership. If a fd is not retained by unflatten() it must be 111 // explicitly closed. 112 inline status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count); 113 }; 114 115 template<typename T> 116 inline size_t Flattenable<T>::getFlattenedSize() const { 117 return static_cast<T const*>(this)->T::getFlattenedSize(); 118 } 119 template<typename T> 120 inline size_t Flattenable<T>::getFdCount() const { 121 return static_cast<T const*>(this)->T::getFdCount(); 122 } 123 template<typename T> 124 inline status_t Flattenable<T>::flatten( 125 void*& buffer, size_t& size, int*& fds, size_t& count) const { 126 return static_cast<T const*>(this)->T::flatten(buffer, size, fds, count); 127 } 128 template<typename T> 129 inline status_t Flattenable<T>::unflatten( 130 void const*& buffer, size_t& size, int const*& fds, size_t& count) { 131 return static_cast<T*>(this)->T::unflatten(buffer, size, fds, count); 132 } 133 134 /* 135 * LightFlattenable is a protocol allowing object to serialize themselves out 136 * to a byte-buffer. Because it doesn't handle file-descriptors, 137 * LightFlattenable is usually more size efficient than Flattenable. 138 * LightFlattenable objects must implement this protocol. 139 */ 140 template <typename T> 141 class LightFlattenable { 142 public: 143 // returns whether this object always flatten into the same size. 144 // for efficiency, this should always be inline. 145 inline bool isFixedSize() const; 146 147 // returns size in bytes of the flattened object. must be a constant. 148 inline size_t getFlattenedSize() const; 149 150 // flattens the object into buffer. 151 inline status_t flatten(void* buffer, size_t size) const; 152 153 // unflattens the object from buffer of given size. 154 inline status_t unflatten(void const* buffer, size_t size); 155 }; 156 157 template <typename T> 158 inline bool LightFlattenable<T>::isFixedSize() const { 159 return static_cast<T const*>(this)->T::isFixedSize(); 160 } 161 template <typename T> 162 inline size_t LightFlattenable<T>::getFlattenedSize() const { 163 return static_cast<T const*>(this)->T::getFlattenedSize(); 164 } 165 template <typename T> 166 inline status_t LightFlattenable<T>::flatten(void* buffer, size_t size) const { 167 return static_cast<T const*>(this)->T::flatten(buffer, size); 168 } 169 template <typename T> 170 inline status_t LightFlattenable<T>::unflatten(void const* buffer, size_t size) { 171 return static_cast<T*>(this)->T::unflatten(buffer, size); 172 } 173 174 /* 175 * LightFlattenablePod is an implementation of the LightFlattenable protocol 176 * for POD (plain-old-data) objects. 177 * Simply derive from LightFlattenablePod<Foo> to make Foo flattenable; no 178 * need to implement any methods; obviously Foo must be a POD structure. 179 */ 180 template <typename T> 181 class LightFlattenablePod : public LightFlattenable<T> { 182 public: 183 inline bool isFixedSize() const { 184 return true; 185 } 186 187 inline size_t getFlattenedSize() const { 188 return sizeof(T); 189 } 190 inline status_t flatten(void* buffer, size_t size) const { 191 if (size < sizeof(T)) return NO_MEMORY; 192 memcpy(buffer, static_cast<T const*>(this), sizeof(T)); 193 return NO_ERROR; 194 } 195 inline status_t unflatten(void const* buffer, size_t) { 196 memcpy(static_cast<T*>(this), buffer, sizeof(T)); 197 return NO_ERROR; 198 } 199 }; 200 201 202 }; // namespace android 203 204 205 #endif /* ANDROID_UTILS_FLATTENABLE_H */ 206