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 29namespace android { 30 31 32class FlattenableUtils { 33public: 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 89template <typename T> 90class Flattenable { 91public: 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 115template<typename T> 116inline size_t Flattenable<T>::getFlattenedSize() const { 117 return static_cast<T const*>(this)->T::getFlattenedSize(); 118} 119template<typename T> 120inline size_t Flattenable<T>::getFdCount() const { 121 return static_cast<T const*>(this)->T::getFdCount(); 122} 123template<typename T> 124inline 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} 128template<typename T> 129inline 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 */ 140template <typename T> 141class LightFlattenable { 142public: 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 157template <typename T> 158inline bool LightFlattenable<T>::isFixedSize() const { 159 return static_cast<T const*>(this)->T::isFixedSize(); 160} 161template <typename T> 162inline size_t LightFlattenable<T>::getFlattenedSize() const { 163 return static_cast<T const*>(this)->T::getFlattenedSize(); 164} 165template <typename T> 166inline status_t LightFlattenable<T>::flatten(void* buffer, size_t size) const { 167 return static_cast<T const*>(this)->T::flatten(buffer, size); 168} 169template <typename T> 170inline 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 */ 180template <typename T> 181class LightFlattenablePod : public LightFlattenable<T> { 182public: 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