improve [un]marshalling of non-binder objects
this change introduces a new class LightFlattenable<> which is
a protocol to flatten simple objects that don't require
binders or file descriptors; the benefit of this protocol is that
it doesn't require the objects to have a virtual table and give us
a consitant way of doing this.
we also introduce an implementation of this protocol for
POD structures, LightFlattenablePod<>.
Parcel has been update to handle this protocol automatically.
Sensor, Rect, Point and Region now use this new protocol.
Change-Id: Icb3ce7fa1d785249eb666f39c2129f2fc143ea4a
diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h
index 33b2f00..877b17c 100644
--- a/include/binder/Parcel.h
+++ b/include/binder/Parcel.h
@@ -22,10 +22,12 @@
#include <utils/RefBase.h>
#include <utils/String16.h>
#include <utils/Vector.h>
+#include <utils/Flattenable.h>
// ---------------------------------------------------------------------------
namespace android {
+template <typename T> class LightFlattenable;
class Flattenable;
class IBinder;
class IPCThreadState;
@@ -102,6 +104,10 @@
status_t writeWeakBinder(const wp<IBinder>& val);
status_t write(const Flattenable& val);
+ template<typename T>
+ status_t write(const LightFlattenable<T>& val);
+
+
// Place a native_handle into the parcel (the native_handle's file-
// descriptors are dup'ed, so it is safe to delete the native_handle
// when this function returns).
@@ -153,6 +159,9 @@
wp<IBinder> readWeakBinder() const;
status_t read(Flattenable& val) const;
+ template<typename T>
+ status_t read(LightFlattenable<T>& val) const;
+
// Like Parcel.java's readExceptionCode(). Reads the first int32
// off of a Parcel's header, returning 0 or the negative error
// code on exceptions, but also deals with skipping over rich
@@ -267,6 +276,40 @@
// ---------------------------------------------------------------------------
+template<typename T>
+status_t Parcel::write(const LightFlattenable<T>& val) {
+ size_t size(val.getSize());
+ if (!val.isFixedSize()) {
+ status_t err = writeInt32(size);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ }
+ void* buffer = writeInplace(size);
+ return buffer == NULL ? NO_MEMORY :
+ val.flatten(buffer);
+}
+
+template<typename T>
+status_t Parcel::read(LightFlattenable<T>& val) const {
+ size_t size;
+ if (val.isFixedSize()) {
+ size = val.getSize();
+ } else {
+ int32_t s;
+ status_t err = readInt32(&s);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ size = s;
+ }
+ void const* buffer = readInplace(size);
+ return buffer == NULL ? NO_MEMORY :
+ val.unflatten(buffer, size);
+}
+
+// ---------------------------------------------------------------------------
+
inline TextOutput& operator<<(TextOutput& to, const Parcel& parcel)
{
parcel.print(to);
diff --git a/include/gui/Sensor.h b/include/gui/Sensor.h
index e59757a..2af2307 100644
--- a/include/gui/Sensor.h
+++ b/include/gui/Sensor.h
@@ -41,7 +41,7 @@
// ----------------------------------------------------------------------------
-class Sensor : public ASensor, public Flattenable
+class Sensor : public ASensor, public LightFlattenable<Sensor>
{
public:
enum {
@@ -54,7 +54,7 @@
Sensor();
Sensor(struct sensor_t const* hwSensor);
- virtual ~Sensor();
+ ~Sensor();
const String8& getName() const;
const String8& getVendor() const;
@@ -68,13 +68,11 @@
nsecs_t getMinDelayNs() const;
int32_t getVersion() const;
- // Flattenable interface
- virtual size_t getFlattenedSize() const;
- virtual size_t getFdCount() const;
- virtual status_t flatten(void* buffer, size_t size,
- int fds[], size_t count) const;
- virtual status_t unflatten(void const* buffer, size_t size,
- int fds[], size_t count);
+ // LightFlattenable protocol
+ inline bool isFixedSize() const { return false; }
+ size_t getSize() const;
+ status_t flatten(void* buffer) const;
+ status_t unflatten(void const* buffer, size_t size);
private:
String8 mName;
diff --git a/include/ui/Point.h b/include/ui/Point.h
index 1653120..1d7f64d 100644
--- a/include/ui/Point.h
+++ b/include/ui/Point.h
@@ -17,11 +17,12 @@
#ifndef ANDROID_UI_POINT
#define ANDROID_UI_POINT
+#include <utils/Flattenable.h>
#include <utils/TypeHelpers.h>
namespace android {
-class Point
+class Point : public LightFlattenablePod<Point>
{
public:
int x;
diff --git a/include/ui/Rect.h b/include/ui/Rect.h
index c2c2675..47d37b6 100644
--- a/include/ui/Rect.h
+++ b/include/ui/Rect.h
@@ -17,6 +17,7 @@
#ifndef ANDROID_UI_RECT
#define ANDROID_UI_RECT
+#include <utils/Flattenable.h>
#include <utils/TypeHelpers.h>
#include <ui/Point.h>
@@ -24,7 +25,7 @@
namespace android {
-class Rect : public ARect
+class Rect : public ARect, public LightFlattenablePod<Rect>
{
public:
typedef ARect::value_type value_type;
diff --git a/include/ui/Region.h b/include/ui/Region.h
index f242f18..f0819af 100644
--- a/include/ui/Region.h
+++ b/include/ui/Region.h
@@ -23,6 +23,7 @@
#include <utils/Vector.h>
#include <ui/Rect.h>
+#include <utils/Flattenable.h>
namespace android {
// ---------------------------------------------------------------------------
@@ -30,13 +31,12 @@
class String8;
// ---------------------------------------------------------------------------
-class Region
+class Region : public LightFlattenable<Region>
{
public:
Region();
Region(const Region& rhs);
explicit Region(const Rect& rhs);
- explicit Region(const void* buffer);
~Region();
Region& operator = (const Region& rhs);
@@ -122,12 +122,10 @@
// be sorted in Y and X and must not make the region invalid.
void addRectUnchecked(int l, int t, int r, int b);
- // flatten/unflatten a region to/from a raw buffer
- ssize_t write(void* buffer, size_t size) const;
- static ssize_t writeEmpty(void* buffer, size_t size);
-
- ssize_t read(const void* buffer);
- static bool isEmpty(void* buffer);
+ inline bool isFixedSize() const { return false; }
+ size_t getSize() const;
+ status_t flatten(void* buffer) const;
+ status_t unflatten(void const* buffer, size_t size);
void dump(String8& out, const char* what, uint32_t flags=0) const;
void dump(const char* what, uint32_t flags=0) const;
diff --git a/include/utils/Flattenable.h b/include/utils/Flattenable.h
index 852be3b..e40d289 100644
--- a/include/utils/Flattenable.h
+++ b/include/utils/Flattenable.h
@@ -24,6 +24,11 @@
namespace android {
+/*
+ * The Flattenable interface allows an object to serialize itself out
+ * to a byte-buffer and an array of file descriptors.
+ */
+
class Flattenable
{
public:
@@ -56,6 +61,73 @@
};
+/*
+ * LightFlattenable is a protocol allowing object to serialize themselves out
+ * to a byte-buffer.
+ *
+ * LightFlattenable objects must implement this protocol.
+ *
+ * LightFlattenable doesn't require the object to be virtual.
+ */
+template <typename T>
+class LightFlattenable {
+public:
+ // returns whether this object always flatten into the same size.
+ // for efficiency, this should always be inline.
+ inline bool isFixedSize() const;
+
+ // returns size in bytes of the flattened object. must be a constant.
+ inline size_t getSize() const;
+
+ // flattens the object into buffer.
+ inline status_t flatten(void* buffer) const;
+
+ // unflattens the object from buffer of given size.
+ inline status_t unflatten(void const* buffer, size_t size);
+};
+
+template <typename T>
+inline bool LightFlattenable<T>::isFixedSize() const {
+ return static_cast<T const*>(this)->T::isFixedSize();
+}
+template <typename T>
+inline size_t LightFlattenable<T>::getSize() const {
+ return static_cast<T const*>(this)->T::getSize();
+}
+template <typename T>
+inline status_t LightFlattenable<T>::flatten(void* buffer) const {
+ return static_cast<T const*>(this)->T::flatten(buffer);
+}
+template <typename T>
+inline status_t LightFlattenable<T>::unflatten(void const* buffer, size_t size) {
+ return static_cast<T*>(this)->T::unflatten(buffer, size);
+}
+
+/*
+ * LightFlattenablePod is an implementation of the LightFlattenable protocol
+ * for POD (plain-old-data) objects.
+ */
+template <typename T>
+class LightFlattenablePod : public LightFlattenable<T> {
+public:
+ inline bool isFixedSize() const {
+ return true;
+ }
+
+ inline size_t getSize() const {
+ return sizeof(T);
+ }
+ inline status_t flatten(void* buffer) const {
+ *reinterpret_cast<T*>(buffer) = *static_cast<T const*>(this);
+ return NO_ERROR;
+ }
+ inline status_t unflatten(void const* buffer, size_t) {
+ *static_cast<T*>(this) = *reinterpret_cast<T const*>(buffer);
+ return NO_ERROR;
+ }
+};
+
+
}; // namespace android