summaryrefslogtreecommitdiffstats
path: root/tools/aidl
diff options
context:
space:
mode:
Diffstat (limited to 'tools/aidl')
-rwxr-xr-xtools/aidl/AST.cpp60
-rwxr-xr-xtools/aidl/AST.h24
-rw-r--r--tools/aidl/Android.mk4
-rwxr-xr-xtools/aidl/Type.cpp337
-rwxr-xr-xtools/aidl/Type.h122
-rw-r--r--tools/aidl/aidl.cpp175
-rw-r--r--tools/aidl/aidl_language.h21
-rw-r--r--tools/aidl/aidl_language_l.l2
-rw-r--r--tools/aidl/aidl_language_y.y66
-rw-r--r--tools/aidl/generate_java.cpp579
-rw-r--r--tools/aidl/generate_java.h19
-rw-r--r--tools/aidl/generate_java_binder.cpp559
-rw-r--r--tools/aidl/generate_java_rpc.cpp996
13 files changed, 2239 insertions, 725 deletions
diff --git a/tools/aidl/AST.cpp b/tools/aidl/AST.cpp
index 752ef7c..bfa6765 100755
--- a/tools/aidl/AST.cpp
+++ b/tools/aidl/AST.cpp
@@ -111,6 +111,21 @@ LiteralExpression::Write(FILE* to)
fprintf(to, "%s", this->value.c_str());
}
+StringLiteralExpression::StringLiteralExpression(const string& v)
+ :value(v)
+{
+}
+
+StringLiteralExpression::~StringLiteralExpression()
+{
+}
+
+void
+StringLiteralExpression::Write(FILE* to)
+{
+ fprintf(to, "\"%s\"", this->value.c_str());
+}
+
Variable::Variable()
:type(NULL),
name(),
@@ -277,6 +292,17 @@ MethodCall::MethodCall(const string& n)
{
}
+MethodCall::MethodCall(const string& n, int argc = 0, ...)
+ :obj(NULL),
+ clazz(NULL),
+ name(n)
+{
+ va_list args;
+ va_start(args, argc);
+ init(argc, args);
+ va_end(args);
+}
+
MethodCall::MethodCall(Expression* o, const string& n)
:obj(o),
clazz(NULL),
@@ -367,11 +393,29 @@ NewExpression::NewExpression(Type* t)
{
}
+NewExpression::NewExpression(Type* t, int argc = 0, ...)
+ :type(t)
+{
+ va_list args;
+ va_start(args, argc);
+ init(argc, args);
+ va_end(args);
+}
+
NewExpression::~NewExpression()
{
}
void
+NewExpression::init(int n, va_list args)
+{
+ for (int i=0; i<n; i++) {
+ Expression* expression = (Expression*)va_arg(args, void*);
+ this->arguments.push_back(expression);
+ }
+}
+
+void
NewExpression::Write(FILE* to)
{
fprintf(to, "new %s(", this->type->InstantiableName().c_str());
@@ -636,6 +680,20 @@ SwitchStatement::Write(FILE* to)
fprintf(to, "}\n");
}
+Break::Break()
+{
+}
+
+Break::~Break()
+{
+}
+
+void
+Break::Write(FILE* to)
+{
+ fprintf(to, "break;\n");
+}
+
Method::Method()
:ClassElement(),
modifiers(0),
@@ -678,7 +736,7 @@ Method::Write(FILE* to)
fprintf(to, "%s\n", this->comment.c_str());
}
- WriteModifiers(to, this->modifiers, SCOPE_MASK | STATIC | FINAL | OVERRIDE);
+ WriteModifiers(to, this->modifiers, SCOPE_MASK | STATIC | ABSTRACT | FINAL | OVERRIDE);
if (this->returnType != NULL) {
string dim;
diff --git a/tools/aidl/AST.h b/tools/aidl/AST.h
index 3156356..ead5e7a 100755
--- a/tools/aidl/AST.h
+++ b/tools/aidl/AST.h
@@ -54,6 +54,16 @@ struct LiteralExpression : public Expression
virtual void Write(FILE* to);
};
+// TODO: also escape the contents. not needed for now
+struct StringLiteralExpression : public Expression
+{
+ string value;
+
+ StringLiteralExpression(const string& value);
+ virtual ~StringLiteralExpression();
+ virtual void Write(FILE* to);
+};
+
struct Variable : public Expression
{
Type* type;
@@ -104,7 +114,7 @@ struct Statement
virtual void Write(FILE* to) = 0;
};
-struct StatementBlock
+struct StatementBlock : public Statement
{
vector<Statement*> statements;
@@ -146,6 +156,7 @@ struct MethodCall : public Expression
vector<string> exceptions;
MethodCall(const string& name);
+ MethodCall(const string& name, int argc, ...);
MethodCall(Expression* obj, const string& name);
MethodCall(Type* clazz, const string& name);
MethodCall(Expression* obj, const string& name, int argc, ...);
@@ -174,8 +185,12 @@ struct NewExpression : public Expression
vector<Expression*> arguments;
NewExpression(Type* type);
+ NewExpression(Type* type, int argc, ...);
virtual ~NewExpression();
virtual void Write(FILE* to);
+
+private:
+ void init(int n, va_list args);
};
struct NewArrayExpression : public Expression
@@ -292,6 +307,13 @@ struct SwitchStatement : public Statement
virtual void Write(FILE* to);
};
+struct Break : public Statement
+{
+ Break();
+ virtual ~Break();
+ virtual void Write(FILE* to);
+};
+
struct Method : public ClassElement
{
string comment;
diff --git a/tools/aidl/Android.mk b/tools/aidl/Android.mk
index 2ad0728..77d46ab 100644
--- a/tools/aidl/Android.mk
+++ b/tools/aidl/Android.mk
@@ -17,7 +17,9 @@ LOCAL_SRC_FILES := \
search_path.cpp \
AST.cpp \
Type.cpp \
- generate_java.cpp
+ generate_java.cpp \
+ generate_java_binder.cpp \
+ generate_java_rpc.cpp
LOCAL_CFLAGS := -g
LOCAL_MODULE := aidl
diff --git a/tools/aidl/Type.cpp b/tools/aidl/Type.cpp
index 6b69864..700d6ef 100755
--- a/tools/aidl/Type.cpp
+++ b/tools/aidl/Type.cpp
@@ -11,6 +11,7 @@ Type* LONG_TYPE;
Type* FLOAT_TYPE;
Type* DOUBLE_TYPE;
Type* STRING_TYPE;
+Type* OBJECT_TYPE;
Type* CHAR_SEQUENCE_TYPE;
Type* TEXT_UTILS_TYPE;
Type* REMOTE_EXCEPTION_TYPE;
@@ -21,9 +22,13 @@ Type* BINDER_NATIVE_TYPE;
Type* BINDER_PROXY_TYPE;
Type* PARCEL_TYPE;
Type* PARCELABLE_INTERFACE_TYPE;
+Type* CONTEXT_TYPE;
Type* MAP_TYPE;
Type* LIST_TYPE;
Type* CLASSLOADER_TYPE;
+Type* RPC_DATA_TYPE;
+Type* RPC_ERROR_TYPE;
+Type* EVENT_FAKE_TYPE;
Expression* NULL_VALUE;
Expression* THIS_VALUE;
@@ -34,38 +39,48 @@ Expression* FALSE_VALUE;
void
register_base_types()
{
- VOID_TYPE = new BasicType("void", "XXX", "XXX", "XXX", "XXX", "XXX");
+ VOID_TYPE = new BasicType("void",
+ "XXX", "XXX", "XXX", "XXX", "XXX",
+ "XXX", "XXX", "XXX", "XXX", "XXX");
NAMES.Add(VOID_TYPE);
BOOLEAN_TYPE = new BooleanType();
NAMES.Add(BOOLEAN_TYPE);
- BYTE_TYPE = new BasicType("byte", "writeByte", "readByte",
- "writeByteArray", "createByteArray", "readByteArray");
+ BYTE_TYPE = new BasicType("byte",
+ "writeByte", "readByte", "writeByteArray", "createByteArray", "readByteArray",
+ "putByte", "getByte", "putByteArray", "createByteArray", "getByteArray");
NAMES.Add(BYTE_TYPE);
CHAR_TYPE = new CharType();
NAMES.Add(CHAR_TYPE);
- INT_TYPE = new BasicType("int", "writeInt", "readInt",
- "writeIntArray", "createIntArray", "readIntArray");
+ INT_TYPE = new BasicType("int",
+ "writeInt", "readInt", "writeIntArray", "createIntArray", "readIntArray",
+ "putInteger", "getInteger", "putIntegerArray", "createIntegerArray", "getIntegerArray");
NAMES.Add(INT_TYPE);
- LONG_TYPE = new BasicType("long", "writeLong", "readLong",
- "writeLongArray", "createLongArray", "readLongArray");
+ LONG_TYPE = new BasicType("long",
+ "writeLong", "readLong", "writeLongArray", "createLongArray", "readLongArray",
+ "putLong", "getLong", "putLongArray", "createLongArray", "getLongArray");
NAMES.Add(LONG_TYPE);
- FLOAT_TYPE = new BasicType("float", "writeFloat", "readFloat",
- "writeFloatArray", "createFloatArray", "readFloatArray");
+ FLOAT_TYPE = new BasicType("float",
+ "writeFloat", "readFloat", "writeFloatArray", "createFloatArray", "readFloatArray",
+ "putFloat", "getFloat", "putFloatArray", "createFloatArray", "getFloatArray");
NAMES.Add(FLOAT_TYPE);
- DOUBLE_TYPE = new BasicType("double", "writeDouble", "readDouble",
- "writeDoubleArray", "createDoubleArray", "readDoubleArray");
+ DOUBLE_TYPE = new BasicType("double",
+ "writeDouble", "readDouble", "writeDoubleArray", "createDoubleArray", "readDoubleArray",
+ "putDouble", "getDouble", "putDoubleArray", "createDoubleArray", "getDoubleArray");
NAMES.Add(DOUBLE_TYPE);
STRING_TYPE = new StringType();
NAMES.Add(STRING_TYPE);
+ OBJECT_TYPE = new Type("java.lang", "Object", Type::BUILT_IN, false, false, false);
+ NAMES.Add(OBJECT_TYPE);
+
CHAR_SEQUENCE_TYPE = new CharSequenceType();
NAMES.Add(CHAR_SEQUENCE_TYPE);
@@ -75,8 +90,7 @@ register_base_types()
LIST_TYPE = new ListType();
NAMES.Add(LIST_TYPE);
- TEXT_UTILS_TYPE = new Type("android.text", "TextUtils",
- Type::BUILT_IN, false, false);
+ TEXT_UTILS_TYPE = new Type("android.text", "TextUtils", Type::BUILT_IN, false, false, false);
NAMES.Add(TEXT_UTILS_TYPE);
REMOTE_EXCEPTION_TYPE = new RemoteExceptionType();
@@ -103,6 +117,19 @@ register_base_types()
PARCELABLE_INTERFACE_TYPE = new ParcelableInterfaceType();
NAMES.Add(PARCELABLE_INTERFACE_TYPE);
+ CONTEXT_TYPE = new Type("android.content", "Context", Type::BUILT_IN, false, false, false);
+ NAMES.Add(CONTEXT_TYPE);
+
+ RPC_DATA_TYPE = new RpcDataType();
+ NAMES.Add(RPC_DATA_TYPE);
+
+ RPC_ERROR_TYPE = new UserDataType("android.support.place.rpc", "RpcError",
+ true, __FILE__, __LINE__);
+ NAMES.Add(RPC_ERROR_TYPE);
+
+ EVENT_FAKE_TYPE = new Type("event", Type::BUILT_IN, false, false, false);
+ NAMES.Add(EVENT_FAKE_TYPE);
+
CLASSLOADER_TYPE = new ClassLoaderType();
NAMES.Add(CLASSLOADER_TYPE);
@@ -129,27 +156,30 @@ make_generic_type(const string& package, const string& name,
// ================================================================
-Type::Type(const string& name, int kind, bool canWriteToParcel, bool canBeOut)
+Type::Type(const string& name, int kind, bool canWriteToParcel, bool canWriteToRpcData,
+ bool canBeOut)
:m_package(),
m_name(name),
m_declFile(""),
m_declLine(-1),
m_kind(kind),
m_canWriteToParcel(canWriteToParcel),
+ m_canWriteToRpcData(canWriteToRpcData),
m_canBeOut(canBeOut)
{
m_qualifiedName = name;
}
Type::Type(const string& package, const string& name,
- int kind, bool canWriteToParcel, bool canBeOut,
- const string& declFile, int declLine)
+ int kind, bool canWriteToParcel, bool canWriteToRpcData,
+ bool canBeOut, const string& declFile, int declLine)
:m_package(package),
m_name(name),
m_declFile(declFile),
m_declLine(declLine),
m_kind(kind),
m_canWriteToParcel(canWriteToParcel),
+ m_canWriteToRpcData(canWriteToRpcData),
m_canBeOut(canBeOut)
{
if (package.length() > 0) {
@@ -182,6 +212,12 @@ Type::CreatorName() const
}
string
+Type::RpcCreatorName() const
+{
+ return "";
+}
+
+string
Type::InstantiableName() const
{
return QualifiedName();
@@ -244,6 +280,26 @@ Type::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
}
void
+Type::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags)
+{
+ fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
+ __FILE__, __LINE__, m_qualifiedName.c_str());
+ addTo->Add(new LiteralExpression("/* WriteToRpcData error "
+ + m_qualifiedName + " */"));
+}
+
+void
+Type::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
+ Variable** cl)
+{
+ fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
+ __FILE__, __LINE__, m_qualifiedName.c_str());
+ addTo->Add(new LiteralExpression("/* ReadFromRpcData error "
+ + m_qualifiedName + " */"));
+}
+
+void
Type::SetQualifiedName(const string& qualified)
{
m_qualifiedName = qualified;
@@ -264,29 +320,35 @@ Type::BuildWriteToParcelFlags(int flags)
// ================================================================
-BasicType::BasicType(const string& name, const string& marshallMethod,
- const string& unmarshallMethod,
- const string& writeArray, const string& createArray,
- const string& readArray)
- :Type(name, BUILT_IN, true, false),
- m_marshallMethod(marshallMethod),
- m_unmarshallMethod(unmarshallMethod),
- m_writeArrayMethod(writeArray),
- m_createArrayMethod(createArray),
- m_readArrayMethod(readArray)
+BasicType::BasicType(const string& name, const string& marshallParcel,
+ const string& unmarshallParcel, const string& writeArrayParcel,
+ const string& createArrayParcel, const string& readArrayParcel,
+ const string& marshallRpc, const string& unmarshallRpc,
+ const string& writeArrayRpc, const string& createArrayRpc, const string& readArrayRpc)
+ :Type(name, BUILT_IN, true, true, false),
+ m_marshallParcel(marshallParcel),
+ m_unmarshallParcel(unmarshallParcel),
+ m_writeArrayParcel(writeArrayParcel),
+ m_createArrayParcel(createArrayParcel),
+ m_readArrayParcel(readArrayParcel),
+ m_marshallRpc(marshallRpc),
+ m_unmarshallRpc(unmarshallRpc),
+ m_writeArrayRpc(writeArrayRpc),
+ m_createArrayRpc(createArrayRpc),
+ m_readArrayRpc(readArrayRpc)
{
}
void
BasicType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
{
- addTo->Add(new MethodCall(parcel, m_marshallMethod, 1, v));
+ addTo->Add(new MethodCall(parcel, m_marshallParcel, 1, v));
}
void
BasicType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
- addTo->Add(new Assignment(v, new MethodCall(parcel, m_unmarshallMethod)));
+ addTo->Add(new Assignment(v, new MethodCall(parcel, m_unmarshallParcel)));
}
bool
@@ -298,27 +360,40 @@ BasicType::CanBeArray() const
void
BasicType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
{
- addTo->Add(new MethodCall(parcel, m_writeArrayMethod, 1, v));
+ addTo->Add(new MethodCall(parcel, m_writeArrayParcel, 1, v));
}
void
BasicType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, Variable**)
{
- addTo->Add(new Assignment(v, new MethodCall(parcel, m_createArrayMethod)));
+ addTo->Add(new Assignment(v, new MethodCall(parcel, m_createArrayParcel)));
}
void
BasicType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
- addTo->Add(new MethodCall(parcel, m_readArrayMethod, 1, v));
+ addTo->Add(new MethodCall(parcel, m_readArrayParcel, 1, v));
+}
+
+void
+BasicType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags)
+{
+ addTo->Add(new MethodCall(data, m_marshallRpc, 2, k, v));
}
+void
+BasicType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
+ Variable** cl)
+{
+ addTo->Add(new Assignment(v, new MethodCall(data, m_unmarshallRpc, 1, k)));
+}
// ================================================================
BooleanType::BooleanType()
- :Type("boolean", BUILT_IN, true, false)
+ :Type("boolean", BUILT_IN, true, true, false)
{
}
@@ -362,11 +437,24 @@ BooleanType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* p
addTo->Add(new MethodCall(parcel, "readBooleanArray", 1, v));
}
+void
+BooleanType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags)
+{
+ addTo->Add(new MethodCall(data, "putBoolean", 2, k, v));
+}
+
+void
+BooleanType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
+ Variable** cl)
+{
+ addTo->Add(new Assignment(v, new MethodCall(data, "getBoolean", 1, k)));
+}
// ================================================================
CharType::CharType()
- :Type("char", BUILT_IN, true, false)
+ :Type("char", BUILT_IN, true, true, false)
{
}
@@ -408,10 +496,24 @@ CharType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parc
addTo->Add(new MethodCall(parcel, "readCharArray", 1, v));
}
+void
+CharType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags)
+{
+ addTo->Add(new MethodCall(data, "putChar", 2, k, v));
+}
+
+void
+CharType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
+ Variable** cl)
+{
+ addTo->Add(new Assignment(v, new MethodCall(data, "getChar", 1, k)));
+}
+
// ================================================================
StringType::StringType()
- :Type("java.lang", "String", BUILT_IN, true, false)
+ :Type("java.lang", "String", BUILT_IN, true, true, false)
{
}
@@ -458,10 +560,24 @@ StringType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* pa
addTo->Add(new MethodCall(parcel, "readStringArray", 1, v));
}
+void
+StringType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags)
+{
+ addTo->Add(new MethodCall(data, "putString", 2, k, v));
+}
+
+void
+StringType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, Variable**)
+{
+ addTo->Add(new Assignment(v, new MethodCall(data, "getString", 1, k)));
+}
+
// ================================================================
CharSequenceType::CharSequenceType()
- :Type("java.lang", "CharSequence", BUILT_IN, true, false)
+ :Type("java.lang", "CharSequence", BUILT_IN, true, true, false)
{
}
@@ -521,7 +637,7 @@ CharSequenceType::CreateFromParcel(StatementBlock* addTo, Variable* v,
// ================================================================
RemoteExceptionType::RemoteExceptionType()
- :Type("android.os", "RemoteException", BUILT_IN, false, false)
+ :Type("android.os", "RemoteException", BUILT_IN, false, false, false)
{
}
@@ -540,7 +656,7 @@ RemoteExceptionType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variab
// ================================================================
RuntimeExceptionType::RuntimeExceptionType()
- :Type("java.lang", "RuntimeException", BUILT_IN, false, false)
+ :Type("java.lang", "RuntimeException", BUILT_IN, false, false, false)
{
}
@@ -560,7 +676,7 @@ RuntimeExceptionType::CreateFromParcel(StatementBlock* addTo, Variable* v, Varia
// ================================================================
IBinderType::IBinderType()
- :Type("android.os", "IBinder", BUILT_IN, true, false)
+ :Type("android.os", "IBinder", BUILT_IN, true, false, false)
{
}
@@ -599,7 +715,7 @@ IBinderType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* p
// ================================================================
IInterfaceType::IInterfaceType()
- :Type("android.os", "IInterface", BUILT_IN, false, false)
+ :Type("android.os", "IInterface", BUILT_IN, false, false, false)
{
}
@@ -619,7 +735,7 @@ IInterfaceType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* p
// ================================================================
BinderType::BinderType()
- :Type("android.os", "Binder", BUILT_IN, false, false)
+ :Type("android.os", "Binder", BUILT_IN, false, false, false)
{
}
@@ -640,7 +756,7 @@ BinderType::CreateFromParcel(StatementBlock* addTo, Variable* v,
// ================================================================
BinderProxyType::BinderProxyType()
- :Type("android.os", "BinderProxy", BUILT_IN, false, false)
+ :Type("android.os", "BinderProxy", BUILT_IN, false, false, false)
{
}
@@ -661,7 +777,7 @@ BinderProxyType::CreateFromParcel(StatementBlock* addTo, Variable* v,
// ================================================================
ParcelType::ParcelType()
- :Type("android.os", "Parcel", BUILT_IN, false, false)
+ :Type("android.os", "Parcel", BUILT_IN, false, false, false)
{
}
@@ -680,7 +796,7 @@ ParcelType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parce
// ================================================================
ParcelableInterfaceType::ParcelableInterfaceType()
- :Type("android.os", "Parcelable", BUILT_IN, false, false)
+ :Type("android.os", "Parcelable", BUILT_IN, false, false, false)
{
}
@@ -699,7 +815,7 @@ ParcelableInterfaceType::CreateFromParcel(StatementBlock* addTo, Variable* v, Va
// ================================================================
MapType::MapType()
- :Type("java.util", "Map", BUILT_IN, true, true)
+ :Type("java.util", "Map", BUILT_IN, true, false, true)
{
}
@@ -729,8 +845,7 @@ MapType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
}
void
-MapType::ReadFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl)
+MapType::ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl)
{
EnsureClassLoader(addTo, cl);
addTo->Add(new MethodCall(parcel, "readMap", 2, v, *cl));
@@ -740,7 +855,7 @@ MapType::ReadFromParcel(StatementBlock* addTo, Variable* v,
// ================================================================
ListType::ListType()
- :Type("java.util", "List", BUILT_IN, true, true)
+ :Type("java.util", "List", BUILT_IN, true, true, true)
{
}
@@ -771,24 +886,45 @@ ListType::ReadFromParcel(StatementBlock* addTo, Variable* v,
addTo->Add(new MethodCall(parcel, "readList", 2, v, *cl));
}
+void
+ListType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags)
+{
+ addTo->Add(new MethodCall(data, "putList", 2, k, v));
+}
+
+void
+ListType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
+ Variable** cl)
+{
+ addTo->Add(new Assignment(v, new MethodCall(data, "getList", 1, k)));
+}
// ================================================================
-ParcelableType::ParcelableType(const string& package, const string& name,
- bool builtIn, const string& declFile, int declLine)
- :Type(package, name, builtIn ? BUILT_IN : PARCELABLE, true, true,
- declFile, declLine)
+UserDataType::UserDataType(const string& package, const string& name,
+ bool builtIn, bool canWriteToParcel, bool canWriteToRpcData,
+ const string& declFile, int declLine)
+ //:Type(package, name, builtIn ? BUILT_IN : USERDATA, canWriteToParcel, canWriteToRpcData,
+ :Type(package, name, builtIn ? BUILT_IN : USERDATA, true, true,
+ true, declFile, declLine)
{
}
string
-ParcelableType::CreatorName() const
+UserDataType::CreatorName() const
{
return QualifiedName() + ".CREATOR";
}
+string
+UserDataType::RpcCreatorName() const
+{
+ return QualifiedName() + ".RPC_CREATOR";
+}
+
void
-ParcelableType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+UserDataType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
{
// if (v != null) {
// parcel.writeInt(1);
@@ -811,7 +947,7 @@ ParcelableType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parc
}
void
-ParcelableType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
+UserDataType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
// if (0 != parcel.readInt()) {
// v = CLASS.CREATOR.createFromParcel(parcel)
@@ -832,7 +968,7 @@ ParcelableType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* p
}
void
-ParcelableType::ReadFromParcel(StatementBlock* addTo, Variable* v,
+UserDataType::ReadFromParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, Variable**)
{
// TODO: really, we don't need to have this extra check, but we
@@ -848,20 +984,20 @@ ParcelableType::ReadFromParcel(StatementBlock* addTo, Variable* v,
}
bool
-ParcelableType::CanBeArray() const
+UserDataType::CanBeArray() const
{
return true;
}
void
-ParcelableType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+UserDataType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
{
addTo->Add(new MethodCall(parcel, "writeTypedArray", 2, v,
BuildWriteToParcelFlags(flags)));
}
void
-ParcelableType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+UserDataType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, Variable**)
{
string creator = v->type->QualifiedName() + ".CREATOR";
@@ -870,20 +1006,36 @@ ParcelableType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
}
void
-ParcelableType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
+UserDataType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
string creator = v->type->QualifiedName() + ".CREATOR";
addTo->Add(new MethodCall(parcel, "readTypedArray", 2,
v, new LiteralExpression(creator)));
}
+void
+UserDataType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags)
+{
+ // data.putFlattenable(k, v);
+ addTo->Add(new MethodCall(data, "putFlattenable", 2, k, v));
+}
+
+void
+UserDataType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, Variable** cl)
+{
+ // data.getFlattenable(k, CLASS.RPC_CREATOR);
+ addTo->Add(new Assignment(v, new MethodCall(data, "getFlattenable", 2, k,
+ new FieldVariable(v->type, "RPC_CREATOR"))));
+}
// ================================================================
InterfaceType::InterfaceType(const string& package, const string& name,
bool builtIn, bool oneway,
const string& declFile, int declLine)
- :Type(package, name, builtIn ? BUILT_IN : INTERFACE, true, false,
+ :Type(package, name, builtIn ? BUILT_IN : INTERFACE, true, false, false,
declFile, declLine)
,m_oneway(oneway)
{
@@ -922,7 +1074,7 @@ InterfaceType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* pa
GenericType::GenericType(const string& package, const string& name,
const vector<Type*>& args)
- :Type(package, name, BUILT_IN, true, true)
+ :Type(package, name, BUILT_IN, true, true, true)
{
m_args = args;
@@ -942,6 +1094,12 @@ GenericType::GenericType(const string& package, const string& name,
SetQualifiedName(m_importName + gen);
}
+const vector<Type*>&
+GenericType::GenericArgumentTypes() const
+{
+ return m_args;
+}
+
string
GenericType::GenericArguments() const
{
@@ -1041,10 +1199,65 @@ GenericListType::ReadFromParcel(StatementBlock* addTo, Variable* v,
}
}
+void
+GenericListType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags)
+{
+ Type* generic = GenericArgumentTypes()[0];
+ if (generic == RPC_DATA_TYPE) {
+ addTo->Add(new MethodCall(data, "putRpcDataList", 2, k, v));
+ } else if (generic->RpcCreatorName() != "") {
+ addTo->Add(new MethodCall(data, "putFlattenableList", 2, k, v));
+ } else {
+ addTo->Add(new MethodCall(data, "putList", 2, k, v));
+ }
+}
+
+void
+GenericListType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, Variable** cl)
+{
+ Type* generic = GenericArgumentTypes()[0];
+ if (generic == RPC_DATA_TYPE) {
+ addTo->Add(new Assignment(v, new MethodCall(data, "getRpcDataList", 2, k)));
+ } else if (generic->RpcCreatorName() != "") {
+ addTo->Add(new Assignment(v, new MethodCall(data, "getFlattenableList", 2, k,
+ new LiteralExpression(generic->RpcCreatorName()))));
+ } else {
+ string classArg = GenericArgumentTypes()[0]->QualifiedName();
+ classArg += ".class";
+ addTo->Add(new Assignment(v, new MethodCall(data, "getList", 2, k,
+ new LiteralExpression(classArg))));
+ }
+}
+
+
+// ================================================================
+
+RpcDataType::RpcDataType()
+ :UserDataType("android.support.place.rpc", "RpcData", true, true, true)
+{
+}
+
+void
+RpcDataType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags)
+{
+ addTo->Add(new MethodCall(data, "putRpcData", 2, k, v));
+}
+
+void
+RpcDataType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
+ Variable** cl)
+{
+ addTo->Add(new Assignment(v, new MethodCall(data, "getRpcData", 1, k)));
+}
+
+
// ================================================================
ClassLoaderType::ClassLoaderType()
- :Type("java.lang", "ClassLoader", BUILT_IN, false, false)
+ :Type("java.lang", "ClassLoader", BUILT_IN, false, false, false)
{
}
diff --git a/tools/aidl/Type.h b/tools/aidl/Type.h
index 662e3a2..ae12720 100755
--- a/tools/aidl/Type.h
+++ b/tools/aidl/Type.h
@@ -13,7 +13,7 @@ public:
// kinds
enum {
BUILT_IN,
- PARCELABLE,
+ USERDATA,
INTERFACE,
GENERATED
};
@@ -24,9 +24,9 @@ public:
};
Type(const string& name, int kind, bool canWriteToParcel,
- bool canBeOut);
+ bool canWriteToRpcData, bool canBeOut);
Type(const string& package, const string& name,
- int kind, bool canWriteToParcel, bool canBeOut,
+ int kind, bool canWriteToParcel, bool canWriteToRpcData, bool canBeOut,
const string& declFile = "", int declLine = -1);
virtual ~Type();
@@ -36,11 +36,13 @@ public:
inline int Kind() const { return m_kind; }
inline string DeclFile() const { return m_declFile; }
inline int DeclLine() const { return m_declLine; }
- inline bool CanBeMarshalled() const { return m_canWriteToParcel; }
+ inline bool CanWriteToParcel() const { return m_canWriteToParcel; }
+ inline bool CanWriteToRpcData() const { return m_canWriteToRpcData; }
inline bool CanBeOutParameter() const { return m_canBeOut; }
virtual string ImportType() const;
virtual string CreatorName() const;
+ virtual string RpcCreatorName() const;
virtual string InstantiableName() const;
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
@@ -59,6 +61,11 @@ public:
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, Variable** cl);
+ virtual void WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags);
+ virtual void CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, Variable** cl);
+
protected:
void SetQualifiedName(const string& qualified);
Expression* BuildWriteToParcelFlags(int flags);
@@ -74,17 +81,24 @@ private:
int m_declLine;
int m_kind;
bool m_canWriteToParcel;
+ bool m_canWriteToRpcData;
bool m_canBeOut;
};
class BasicType : public Type
{
public:
- BasicType(const string& name, const string& marshallMethod,
- const string& unmarshallMethod,
- const string& writeArray,
- const string& createArray,
- const string& readArray);
+ BasicType(const string& name,
+ const string& marshallParcel,
+ const string& unmarshallParcel,
+ const string& writeArrayParcel,
+ const string& createArrayParcel,
+ const string& readArrayParcel,
+ const string& marshallRpc,
+ const string& unmarshallRpc,
+ const string& writeArrayRpc,
+ const string& createArrayRpc,
+ const string& readArrayRpc);
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
@@ -100,12 +114,22 @@ public:
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, Variable** cl);
+ virtual void WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags);
+ virtual void CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, Variable** cl);
+
private:
- string m_marshallMethod;
- string m_unmarshallMethod;
- string m_writeArrayMethod;
- string m_createArrayMethod;
- string m_readArrayMethod;
+ string m_marshallParcel;
+ string m_unmarshallParcel;
+ string m_writeArrayParcel;
+ string m_createArrayParcel;
+ string m_readArrayParcel;
+ string m_marshallRpc;
+ string m_unmarshallRpc;
+ string m_writeArrayRpc;
+ string m_createArrayRpc;
+ string m_readArrayRpc;
};
class BooleanType : public Type
@@ -126,6 +150,11 @@ public:
Variable* parcel, Variable** cl);
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, Variable** cl);
+
+ virtual void WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags);
+ virtual void CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, Variable** cl);
};
class CharType : public Type
@@ -146,6 +175,11 @@ public:
Variable* parcel, Variable** cl);
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, Variable** cl);
+
+ virtual void WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags);
+ virtual void CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, Variable** cl);
};
@@ -169,6 +203,11 @@ public:
Variable* parcel, Variable** cl);
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, Variable** cl);
+
+ virtual void WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags);
+ virtual void CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, Variable** cl);
};
class CharSequenceType : public Type
@@ -305,15 +344,22 @@ public:
Variable* parcel, Variable** cl);
virtual void ReadFromParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, Variable** cl);
+
+ virtual void WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags);
+ virtual void CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, Variable** cl);
};
-class ParcelableType : public Type
+class UserDataType : public Type
{
public:
- ParcelableType(const string& package, const string& name,
- bool builtIn, const string& declFile, int declLine);
+ UserDataType(const string& package, const string& name,
+ bool builtIn, bool canWriteToParcel, bool canWriteToRpcData,
+ const string& declFile = "", int declLine = -1);
virtual string CreatorName() const;
+ virtual string RpcCreatorName() const;
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
@@ -330,6 +376,11 @@ public:
Variable* parcel, Variable** cl);
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, Variable** cl);
+
+ virtual void WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags);
+ virtual void CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, Variable** cl);
};
class InterfaceType : public Type
@@ -357,6 +408,7 @@ public:
GenericType(const string& package, const string& name,
const vector<Type*>& args);
+ const vector<Type*>& GenericArgumentTypes() const;
string GenericArguments() const;
virtual string ImportType() const;
@@ -374,6 +426,22 @@ private:
vector<Type*> m_args;
};
+class RpcDataType : public UserDataType
+{
+public:
+ RpcDataType();
+
+ virtual void WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags);
+ virtual void CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, Variable** cl);
+};
+
+class ClassLoaderType : public Type
+{
+public:
+ ClassLoaderType();
+};
class GenericListType : public GenericType
{
@@ -391,16 +459,15 @@ public:
virtual void ReadFromParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, Variable** cl);
+ virtual void WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, int flags);
+ virtual void CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data, Variable** cl);
+
private:
string m_creator;
};
-class ClassLoaderType : public Type
-{
-public:
- ClassLoaderType();
-};
-
class Namespace
{
public:
@@ -438,11 +505,13 @@ extern Namespace NAMES;
extern Type* VOID_TYPE;
extern Type* BOOLEAN_TYPE;
+extern Type* BYTE_TYPE;
extern Type* CHAR_TYPE;
extern Type* INT_TYPE;
extern Type* LONG_TYPE;
extern Type* FLOAT_TYPE;
extern Type* DOUBLE_TYPE;
+extern Type* OBJECT_TYPE;
extern Type* STRING_TYPE;
extern Type* CHAR_SEQUENCE_TYPE;
extern Type* TEXT_UTILS_TYPE;
@@ -455,6 +524,13 @@ extern Type* BINDER_PROXY_TYPE;
extern Type* PARCEL_TYPE;
extern Type* PARCELABLE_INTERFACE_TYPE;
+extern Type* CONTEXT_TYPE;
+
+extern Type* RPC_DATA_TYPE;
+extern Type* RPC_ERROR_TYPE;
+extern Type* RPC_CONTEXT_TYPE;
+extern Type* EVENT_FAKE_TYPE;
+
extern Expression* NULL_VALUE;
extern Expression* THIS_VALUE;
extern Expression* SUPER_VALUE;
diff --git a/tools/aidl/aidl.cpp b/tools/aidl/aidl.cpp
index fb4067a..3d314db 100644
--- a/tools/aidl/aidl.cpp
+++ b/tools/aidl/aidl.cpp
@@ -29,7 +29,7 @@ static void
test_document(document_item_type* d)
{
while (d) {
- if (d->item_type == INTERFACE_TYPE) {
+ if (d->item_type == INTERFACE_TYPE_BINDER) {
interface_type* c = (interface_type*)d;
printf("interface %s %s {\n", c->package, c->name.data);
interface_item_type *q = (interface_item_type*)c->interface_items;
@@ -50,9 +50,14 @@ test_document(document_item_type* d)
}
printf("}\n");
}
- else if (d->item_type == PARCELABLE_TYPE) {
- parcelable_type* b = (parcelable_type*)d;
- printf("parcelable %s %s;\n", b->package, b->name.data);
+ else if (d->item_type == USER_DATA_TYPE) {
+ user_data_type* b = (user_data_type*)d;
+ if ((b->flattening_methods & PARCELABLE_DATA) != 0) {
+ printf("parcelable %s %s;\n", b->package, b->name.data);
+ }
+ if ((b->flattening_methods & RPC_DATA) != 0) {
+ printf("flattenable %s %s;\n", b->package, b->name.data);
+ }
}
else {
printf("UNKNOWN d=0x%08lx d->item_type=%d\n", (long)d, d->item_type);
@@ -238,11 +243,12 @@ check_filenames(const char* filename, document_item_type* items)
{
int err = 0;
while (items) {
- if (items->item_type == PARCELABLE_TYPE) {
- parcelable_type* p = (parcelable_type*)items;
+ if (items->item_type == USER_DATA_TYPE) {
+ user_data_type* p = (user_data_type*)items;
err |= check_filename(filename, p->package, &p->name);
}
- else if (items->item_type == INTERFACE_TYPE) {
+ else if (items->item_type == INTERFACE_TYPE_BINDER
+ || items->item_type == INTERFACE_TYPE_RPC) {
interface_type* c = (interface_type*)items;
err |= check_filename(filename, c->package, &c->name);
}
@@ -264,8 +270,8 @@ kind_to_string(int kind)
{
case Type::INTERFACE:
return "an interface";
- case Type::PARCELABLE:
- return "a parcelable";
+ case Type::USERDATA:
+ return "a user data";
default:
return "ERROR";
}
@@ -290,12 +296,14 @@ gather_types(const char* filename, document_item_type* items)
int err = 0;
while (items) {
Type* type;
- if (items->item_type == PARCELABLE_TYPE) {
- parcelable_type* p = (parcelable_type*)items;
- type = new ParcelableType(p->package ? p->package : "",
- p->name.data, false, filename, p->name.lineno);
+ if (items->item_type == USER_DATA_TYPE) {
+ user_data_type* p = (user_data_type*)items;
+ type = new UserDataType(p->package ? p->package : "", p->name.data,
+ false, ((p->flattening_methods & PARCELABLE_DATA) != 0),
+ ((p->flattening_methods & RPC_DATA) != 0), filename, p->name.lineno);
}
- else if (items->item_type == INTERFACE_TYPE) {
+ else if (items->item_type == INTERFACE_TYPE_BINDER
+ || items->item_type == INTERFACE_TYPE_RPC) {
interface_type* c = (interface_type*)items;
type = new InterfaceType(c->package ? c->package : "",
c->name.data, false, c->oneway,
@@ -310,7 +318,7 @@ gather_types(const char* filename, document_item_type* items)
if (old == NULL) {
NAMES.Add(type);
- if (items->item_type == INTERFACE_TYPE) {
+ if (items->item_type == INTERFACE_TYPE_BINDER) {
// for interfaces, also add the stub and proxy types, we don't
// bother checking these for duplicates, because the parser
// won't let us do it.
@@ -319,17 +327,30 @@ gather_types(const char* filename, document_item_type* items)
string name = c->name.data;
name += ".Stub";
Type* stub = new Type(c->package ? c->package : "",
- name, Type::GENERATED, false, false,
+ name, Type::GENERATED, false, false, false,
filename, c->name.lineno);
NAMES.Add(stub);
name = c->name.data;
name += ".Stub.Proxy";
Type* proxy = new Type(c->package ? c->package : "",
- name, Type::GENERATED, false, false,
+ name, Type::GENERATED, false, false, false,
filename, c->name.lineno);
NAMES.Add(proxy);
}
+ else if (items->item_type == INTERFACE_TYPE_RPC) {
+ // for interfaces, also add the service base type, we don't
+ // bother checking these for duplicates, because the parser
+ // won't let us do it.
+ interface_type* c = (interface_type*)items;
+
+ string name = c->name.data;
+ name += ".ServiceBase";
+ Type* base = new Type(c->package ? c->package : "",
+ name, Type::GENERATED, false, false, false,
+ filename, c->name.lineno);
+ NAMES.Add(base);
+ }
} else {
if (old->Kind() == Type::BUILT_IN) {
fprintf(stderr, "%s:%d attempt to redefine built in class %s\n",
@@ -381,7 +402,7 @@ matches_keyword(const char* str)
}
static int
-check_method(const char* filename, method_type* m)
+check_method(const char* filename, int kind, method_type* m)
{
int err = 0;
@@ -394,10 +415,20 @@ check_method(const char* filename, method_type* m)
return err;
}
- if (!returnType->CanBeMarshalled()) {
- fprintf(stderr, "%s:%d return type %s can't be marshalled.\n", filename,
- m->type.type.lineno, m->type.type.data);
- err = 1;
+ if (returnType == EVENT_FAKE_TYPE) {
+ if (kind != INTERFACE_TYPE_RPC) {
+ fprintf(stderr, "%s:%d event methods only supported for rpc interfaces\n",
+ filename, m->type.type.lineno);
+ err = 1;
+ }
+ } else {
+ if (!(kind == INTERFACE_TYPE_BINDER ? returnType->CanWriteToParcel()
+ : returnType->CanWriteToRpcData())) {
+ fprintf(stderr, "%s:%d return type %s can't be marshalled. kind=%d p=%d m=%d\n", filename,
+ m->type.type.lineno, m->type.type.data, kind,
+ returnType->CanWriteToParcel(), returnType->CanWriteToRpcData());
+ err = 1;
+ }
}
if (m->type.dimension > 0 && !returnType->CanBeArray()) {
@@ -429,14 +460,31 @@ check_method(const char* filename, method_type* m)
err = 1;
goto next;
}
+
+ if (t == EVENT_FAKE_TYPE) {
+ fprintf(stderr, "%s:%d parameter %s (%d) event can not be used as a parameter %s\n",
+ filename, m->type.type.lineno, arg->name.data, index,
+ arg->type.type.data);
+ err = 1;
+ goto next;
+ }
- if (!t->CanBeMarshalled()) {
+ if (!(kind == INTERFACE_TYPE_BINDER ? t->CanWriteToParcel() : t->CanWriteToRpcData())) {
fprintf(stderr, "%s:%d parameter %d: '%s %s' can't be marshalled.\n",
filename, m->type.type.lineno, index,
arg->type.type.data, arg->name.data);
err = 1;
}
+ if (returnType == EVENT_FAKE_TYPE
+ && convert_direction(arg->direction.data) != IN_PARAMETER) {
+ fprintf(stderr, "%s:%d parameter %d: '%s %s' All paremeters on events must be 'in'.\n",
+ filename, m->type.type.lineno, index,
+ arg->type.type.data, arg->name.data);
+ err = 1;
+ goto next;
+ }
+
if (arg->direction.data == NULL
&& (arg->type.dimension != 0 || t->CanBeOutParameter())) {
fprintf(stderr, "%s:%d parameter %d: '%s %s' can be an out"
@@ -479,7 +527,7 @@ check_method(const char* filename, method_type* m)
// check that the name doesn't match a keyword
if (matches_keyword(arg->name.data)) {
fprintf(stderr, "%s:%d parameter %d %s is named the same as a"
- " Java keyword\n",
+ " Java or aidl keyword\n",
filename, m->name.lineno, index, arg->name.data);
err = 1;
}
@@ -497,8 +545,9 @@ check_types(const char* filename, document_item_type* items)
{
int err = 0;
while (items) {
- // (nothing to check for PARCELABLE_TYPE)
- if (items->item_type == INTERFACE_TYPE) {
+ // (nothing to check for USER_DATA_TYPE)
+ if (items->item_type == INTERFACE_TYPE_BINDER
+ || items->item_type == INTERFACE_TYPE_RPC) {
map<string,method_type*> methodNames;
interface_type* c = (interface_type*)items;
@@ -507,7 +556,7 @@ check_types(const char* filename, document_item_type* items)
if (member->item_type == METHOD_TYPE) {
method_type* m = (method_type*)member;
- err |= check_method(filename, m);
+ err |= check_method(filename, items->item_type, m);
// prevent duplicate methods
if (methodNames.find(m->name.data) == methodNames.end()) {
@@ -544,26 +593,29 @@ exactly_one_interface(const char* filename, const document_item_type* items, con
const document_item_type* next = items->next;
if (items->next != NULL) {
int lineno = -1;
- if (next->item_type == INTERFACE_TYPE) {
+ if (next->item_type == INTERFACE_TYPE_BINDER) {
+ lineno = ((interface_type*)next)->interface_token.lineno;
+ }
+ else if (next->item_type == INTERFACE_TYPE_RPC) {
lineno = ((interface_type*)next)->interface_token.lineno;
}
- else if (next->item_type == PARCELABLE_TYPE) {
- lineno = ((parcelable_type*)next)->parcelable_token.lineno;
+ else if (next->item_type == USER_DATA_TYPE) {
+ lineno = ((user_data_type*)next)->keyword_token.lineno;
}
fprintf(stderr, "%s:%d aidl can only handle one interface per file\n",
filename, lineno);
return 1;
}
- if (items->item_type == PARCELABLE_TYPE) {
+ if (items->item_type == USER_DATA_TYPE) {
*onlyParcelable = true;
if (options.failOnParcelable) {
fprintf(stderr, "%s:%d aidl can only generate code for interfaces, not"
- " parcelables,\n", filename,
- ((parcelable_type*)items)->parcelable_token.lineno);
- fprintf(stderr, "%s:%d .aidl files that only declare parcelables "
- "don't need to go in the Makefile.\n", filename,
- ((parcelable_type*)items)->parcelable_token.lineno);
+ " parcelables or flattenables,\n", filename,
+ ((user_data_type*)items)->keyword_token.lineno);
+ fprintf(stderr, "%s:%d .aidl files that only declare parcelables or flattenables"
+ "may not go in the Makefile.\n", filename,
+ ((user_data_type*)items)->keyword_token.lineno);
return 1;
}
} else {
@@ -598,7 +650,7 @@ generate_dep_file(const Options& options, const document_item_type* items)
slash = "";
}
- if (items->item_type == INTERFACE_TYPE) {
+ if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
fprintf(to, "%s: \\\n", options.outputFileName.c_str());
} else {
// parcelable: there's no output file.
@@ -658,12 +710,12 @@ static string
generate_outputFileName(const Options& options, const document_item_type* items)
{
// items has already been checked to have only one interface.
- if (items->item_type == INTERFACE_TYPE) {
+ if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
interface_type* type = (interface_type*)items;
return generate_outputFileName2(options, type->name, type->package);
- } else if (items->item_type == PARCELABLE_TYPE) {
- parcelable_type* type = (parcelable_type*)items;
+ } else if (items->item_type == USER_DATA_TYPE) {
+ user_data_type* type = (user_data_type*)items;
return generate_outputFileName2(options, type->name, type->package);
}
@@ -734,24 +786,40 @@ parse_preprocessed_file(const string& filename)
document_item_type* doc;
if (0 == strcmp("parcelable", type)) {
- parcelable_type* parcl = (parcelable_type*)malloc(
- sizeof(parcelable_type));
- memset(parcl, 0, sizeof(parcelable_type));
- parcl->document_item.item_type = PARCELABLE_TYPE;
- parcl->parcelable_token.lineno = lineno;
- parcl->parcelable_token.data = strdup(type);
+ user_data_type* parcl = (user_data_type*)malloc(
+ sizeof(user_data_type));
+ memset(parcl, 0, sizeof(user_data_type));
+ parcl->document_item.item_type = USER_DATA_TYPE;
+ parcl->keyword_token.lineno = lineno;
+ parcl->keyword_token.data = strdup(type);
parcl->package = packagename ? strdup(packagename) : NULL;
parcl->name.lineno = lineno;
parcl->name.data = strdup(classname);
parcl->semicolon_token.lineno = lineno;
parcl->semicolon_token.data = strdup(";");
+ parcl->flattening_methods = PARCELABLE_DATA;
+ doc = (document_item_type*)parcl;
+ }
+ else if (0 == strcmp("flattenable", type)) {
+ user_data_type* parcl = (user_data_type*)malloc(
+ sizeof(user_data_type));
+ memset(parcl, 0, sizeof(user_data_type));
+ parcl->document_item.item_type = USER_DATA_TYPE;
+ parcl->keyword_token.lineno = lineno;
+ parcl->keyword_token.data = strdup(type);
+ parcl->package = packagename ? strdup(packagename) : NULL;
+ parcl->name.lineno = lineno;
+ parcl->name.data = strdup(classname);
+ parcl->semicolon_token.lineno = lineno;
+ parcl->semicolon_token.data = strdup(";");
+ parcl->flattening_methods = RPC_DATA;
doc = (document_item_type*)parcl;
}
else if (0 == strcmp("interface", type)) {
interface_type* iface = (interface_type*)malloc(
sizeof(interface_type));
memset(iface, 0, sizeof(interface_type));
- iface->document_item.item_type = INTERFACE_TYPE;
+ iface->document_item.item_type = INTERFACE_TYPE_BINDER;
iface->interface_token.lineno = lineno;
iface->interface_token.data = strdup(type);
iface->package = packagename ? strdup(packagename) : NULL;
@@ -923,9 +991,14 @@ preprocess_aidl(const Options& options)
}
document_item_type* doc = g_document;
string line;
- if (doc->item_type == PARCELABLE_TYPE) {
- line = "parcelable ";
- parcelable_type* parcelable = (parcelable_type*)doc;
+ if (doc->item_type == USER_DATA_TYPE) {
+ user_data_type* parcelable = (user_data_type*)doc;
+ if ((parcelable->flattening_methods & PARCELABLE_DATA) != 0) {
+ line = "parcelable ";
+ }
+ if ((parcelable->flattening_methods & RPC_DATA) != 0) {
+ line = "flattenable ";
+ }
if (parcelable->package) {
line += parcelable->package;
line += '.';
@@ -995,5 +1068,3 @@ main(int argc, const char **argv)
fprintf(stderr, "aidl: internal error\n");
return 1;
}
-
-
diff --git a/tools/aidl/aidl_language.h b/tools/aidl/aidl_language.h
index 9ca5deb..f203dbb 100644
--- a/tools/aidl/aidl_language.h
+++ b/tools/aidl/aidl_language.h
@@ -63,8 +63,9 @@ typedef struct method_type {
} method_type;
enum {
- PARCELABLE_TYPE = 12,
- INTERFACE_TYPE
+ USER_DATA_TYPE = 12,
+ INTERFACE_TYPE_BINDER,
+ INTERFACE_TYPE_RPC
};
typedef struct document_item_type {
@@ -72,13 +73,21 @@ typedef struct document_item_type {
struct document_item_type* next;
} document_item_type;
-typedef struct parcelable_type {
+
+// for user_data_type.flattening_methods
+enum {
+ PARCELABLE_DATA = 0x1,
+ RPC_DATA = 0x2
+};
+
+typedef struct user_data_type {
document_item_type document_item;
- buffer_type parcelable_token;
+ buffer_type keyword_token; // only the first one
char* package;
buffer_type name;
buffer_type semicolon_token;
-} parcelable_type;
+ int flattening_methods;
+} user_data_type;
typedef struct interface_type {
document_item_type document_item;
@@ -100,7 +109,7 @@ typedef union lexer_type {
method_type* method;
interface_item_type* interface_item;
interface_type* interface_obj;
- parcelable_type* parcelable;
+ user_data_type* user_data;
document_item_type* document_item;
} lexer_type;
diff --git a/tools/aidl/aidl_language_l.l b/tools/aidl/aidl_language_l.l
index 567b1cf..7c5290c 100644
--- a/tools/aidl/aidl_language_l.l
+++ b/tools/aidl/aidl_language_l.l
@@ -81,6 +81,8 @@ brackets \[{whitespace}?\]
/* keywords */
parcelable { SET_BUFFER(PARCELABLE); return PARCELABLE; }
interface { SET_BUFFER(INTERFACE); return INTERFACE; }
+flattenable { SET_BUFFER(FLATTENABLE); return FLATTENABLE; }
+rpc { SET_BUFFER(INTERFACE); return RPC; }
in { SET_BUFFER(IN); return IN; }
out { SET_BUFFER(OUT); return OUT; }
inout { SET_BUFFER(INOUT); return INOUT; }
diff --git a/tools/aidl/aidl_language_y.y b/tools/aidl/aidl_language_y.y
index 3d65f17..3c16e15 100644
--- a/tools/aidl/aidl_language_y.y
+++ b/tools/aidl/aidl_language_y.y
@@ -19,6 +19,8 @@ static int count_brackets(const char*);
%token ARRAY
%token PARCELABLE
%token INTERFACE
+%token FLATTENABLE
+%token RPC
%token IN
%token OUT
%token INOUT
@@ -72,36 +74,61 @@ document_items:
;
declaration:
- parcelable_decl { $$.document_item = (document_item_type*)$1.parcelable; }
+ parcelable_decl { $$.document_item = (document_item_type*)$1.user_data; }
| interface_decl { $$.document_item = (document_item_type*)$1.interface_item; }
;
parcelable_decl:
- PARCELABLE IDENTIFIER ';' {
- parcelable_type* b = (parcelable_type*)malloc(sizeof(parcelable_type));
- b->document_item.item_type = PARCELABLE_TYPE;
+ PARCELABLE IDENTIFIER ';' {
+ user_data_type* b = (user_data_type*)malloc(sizeof(user_data_type));
+ b->document_item.item_type = USER_DATA_TYPE;
b->document_item.next = NULL;
- b->parcelable_token = $1.buffer;
+ b->keyword_token = $1.buffer;
b->name = $2.buffer;
b->package = g_currentPackage ? strdup(g_currentPackage) : NULL;
b->semicolon_token = $3.buffer;
- $$.parcelable = b;
+ b->flattening_methods = PARCELABLE_DATA | RPC_DATA;
+ $$.user_data = b;
}
| PARCELABLE ';' {
fprintf(stderr, "%s:%d syntax error in parcelable declaration. Expected type name.\n",
g_currentFilename, $1.buffer.lineno);
- $$.parcelable = NULL;
+ $$.user_data = NULL;
}
| PARCELABLE error ';' {
fprintf(stderr, "%s:%d syntax error in parcelable declaration. Expected type name, saw \"%s\".\n",
g_currentFilename, $2.buffer.lineno, $2.buffer.data);
- $$.parcelable = NULL;
+ $$.user_data = NULL;
}
+ | FLATTENABLE IDENTIFIER ';' {
+ user_data_type* b = (user_data_type*)malloc(sizeof(user_data_type));
+ b->document_item.item_type = USER_DATA_TYPE;
+ b->document_item.next = NULL;
+ b->keyword_token = $1.buffer;
+ b->name = $2.buffer;
+ b->package = g_currentPackage ? strdup(g_currentPackage) : NULL;
+ b->semicolon_token = $3.buffer;
+ b->flattening_methods = PARCELABLE_DATA | RPC_DATA;
+ $$.user_data = b;
+ }
+ | FLATTENABLE ';' {
+ fprintf(stderr, "%s:%d syntax error in flattenable declaration. Expected type name.\n",
+ g_currentFilename, $1.buffer.lineno);
+ $$.user_data = NULL;
+ }
+ | FLATTENABLE error ';' {
+ fprintf(stderr, "%s:%d syntax error in flattenable declaration. Expected type name, saw \"%s\".\n",
+ g_currentFilename, $2.buffer.lineno, $2.buffer.data);
+ $$.user_data = NULL;
+ }
+
;
interface_header:
INTERFACE {
interface_type* c = (interface_type*)malloc(sizeof(interface_type));
+ c->document_item.item_type = INTERFACE_TYPE_BINDER;
+ c->document_item.next = NULL;
c->interface_token = $1.buffer;
c->oneway = false;
memset(&c->oneway_token, 0, sizeof(buffer_type));
@@ -110,19 +137,34 @@ interface_header:
}
| ONEWAY INTERFACE {
interface_type* c = (interface_type*)malloc(sizeof(interface_type));
+ c->document_item.item_type = INTERFACE_TYPE_BINDER;
+ c->document_item.next = NULL;
c->interface_token = $2.buffer;
c->oneway = true;
c->oneway_token = $1.buffer;
c->comments_token = &c->oneway_token;
$$.interface_obj = c;
}
+ | RPC {
+ interface_type* c = (interface_type*)malloc(sizeof(interface_type));
+ c->document_item.item_type = INTERFACE_TYPE_RPC;
+ c->document_item.next = NULL;
+ c->interface_token = $1.buffer;
+ c->oneway = false;
+ memset(&c->oneway_token, 0, sizeof(buffer_type));
+ c->comments_token = &c->interface_token;
+ $$.interface_obj = c;
+ }
+ ;
+
+interface_keywords:
+ INTERFACE
+ | RPC
;
interface_decl:
interface_header IDENTIFIER '{' interface_items '}' {
interface_type* c = $1.interface_obj;
- c->document_item.item_type = INTERFACE_TYPE;
- c->document_item.next = NULL;
c->name = $2.buffer;
c->package = g_currentPackage ? strdup(g_currentPackage) : NULL;
c->open_brace_token = $3.buffer;
@@ -130,12 +172,12 @@ interface_decl:
c->close_brace_token = $5.buffer;
$$.interface_obj = c;
}
- | INTERFACE error '{' interface_items '}' {
+ | interface_keywords error '{' interface_items '}' {
fprintf(stderr, "%s:%d: syntax error in interface declaration. Expected type name, saw \"%s\"\n",
g_currentFilename, $2.buffer.lineno, $2.buffer.data);
$$.document_item = NULL;
}
- | INTERFACE error '}' {
+ | interface_keywords error '}' {
fprintf(stderr, "%s:%d: syntax error in interface declaration. Expected type name, saw \"%s\"\n",
g_currentFilename, $2.buffer.lineno, $2.buffer.data);
$$.document_item = NULL;
diff --git a/tools/aidl/generate_java.cpp b/tools/aidl/generate_java.cpp
index 83e3bbc..9e57407 100644
--- a/tools/aidl/generate_java.cpp
+++ b/tools/aidl/generate_java.cpp
@@ -1,5 +1,4 @@
#include "generate_java.h"
-#include "AST.h"
#include "Type.h"
#include <string.h>
#include <stdio.h>
@@ -7,18 +6,6 @@
#include <string.h>
// =================================================
-class VariableFactory
-{
-public:
- VariableFactory(const string& base); // base must be short
- Variable* Get(Type* type);
- Variable* Get(int index);
-private:
- vector<Variable*> m_vars;
- string m_base;
- int m_index;
-};
-
VariableFactory::VariableFactory(const string& base)
:m_base(base),
m_index(0)
@@ -43,195 +30,7 @@ VariableFactory::Get(int index)
}
// =================================================
-class StubClass : public Class
-{
-public:
- StubClass(Type* type, Type* interfaceType);
- virtual ~StubClass();
-
- Variable* transact_code;
- Variable* transact_data;
- Variable* transact_reply;
- Variable* transact_flags;
- SwitchStatement* transact_switch;
-private:
- void make_as_interface(Type* interfaceType);
-};
-
-StubClass::StubClass(Type* type, Type* interfaceType)
- :Class()
-{
- this->comment = "/** Local-side IPC implementation stub class. */";
- this->modifiers = PUBLIC | ABSTRACT | STATIC;
- this->what = Class::CLASS;
- this->type = type;
- this->extends = BINDER_NATIVE_TYPE;
- this->interfaces.push_back(interfaceType);
-
- // descriptor
- Field* descriptor = new Field(STATIC | FINAL | PRIVATE,
- new Variable(STRING_TYPE, "DESCRIPTOR"));
- descriptor->value = "\"" + interfaceType->QualifiedName() + "\"";
- this->elements.push_back(descriptor);
-
- // ctor
- Method* ctor = new Method;
- ctor->modifiers = PUBLIC;
- ctor->comment = "/** Construct the stub at attach it to the "
- "interface. */";
- ctor->name = "Stub";
- ctor->statements = new StatementBlock;
- MethodCall* attach = new MethodCall(THIS_VALUE, "attachInterface",
- 2, THIS_VALUE, new LiteralExpression("DESCRIPTOR"));
- ctor->statements->Add(attach);
- this->elements.push_back(ctor);
-
- // asInterface
- make_as_interface(interfaceType);
-
- // asBinder
- Method* asBinder = new Method;
- asBinder->modifiers = PUBLIC;
- asBinder->returnType = IBINDER_TYPE;
- asBinder->name = "asBinder";
- asBinder->statements = new StatementBlock;
- asBinder->statements->Add(new ReturnStatement(THIS_VALUE));
- this->elements.push_back(asBinder);
-
- // onTransact
- this->transact_code = new Variable(INT_TYPE, "code");
- this->transact_data = new Variable(PARCEL_TYPE, "data");
- this->transact_reply = new Variable(PARCEL_TYPE, "reply");
- this->transact_flags = new Variable(INT_TYPE, "flags");
- Method* onTransact = new Method;
- onTransact->modifiers = PUBLIC | OVERRIDE;
- onTransact->returnType = BOOLEAN_TYPE;
- onTransact->name = "onTransact";
- onTransact->parameters.push_back(this->transact_code);
- onTransact->parameters.push_back(this->transact_data);
- onTransact->parameters.push_back(this->transact_reply);
- onTransact->parameters.push_back(this->transact_flags);
- onTransact->statements = new StatementBlock;
- onTransact->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
- this->elements.push_back(onTransact);
- this->transact_switch = new SwitchStatement(this->transact_code);
-
- onTransact->statements->Add(this->transact_switch);
- MethodCall* superCall = new MethodCall(SUPER_VALUE, "onTransact", 4,
- this->transact_code, this->transact_data,
- this->transact_reply, this->transact_flags);
- onTransact->statements->Add(new ReturnStatement(superCall));
-}
-
-StubClass::~StubClass()
-{
-}
-
-void
-StubClass::make_as_interface(Type *interfaceType)
-{
- Variable* obj = new Variable(IBINDER_TYPE, "obj");
-
- Method* m = new Method;
- m->comment = "/**\n * Cast an IBinder object into an ";
- m->comment += interfaceType->QualifiedName();
- m->comment += " interface,\n";
- m->comment += " * generating a proxy if needed.\n */";
- m->modifiers = PUBLIC | STATIC;
- m->returnType = interfaceType;
- m->name = "asInterface";
- m->parameters.push_back(obj);
- m->statements = new StatementBlock;
-
- IfStatement* ifstatement = new IfStatement();
- ifstatement->expression = new Comparison(obj, "==", NULL_VALUE);
- ifstatement->statements = new StatementBlock;
- ifstatement->statements->Add(new ReturnStatement(NULL_VALUE));
- m->statements->Add(ifstatement);
-
- // IInterface iin = obj.queryLocalInterface(DESCRIPTOR)
- MethodCall* queryLocalInterface = new MethodCall(obj, "queryLocalInterface");
- queryLocalInterface->arguments.push_back(new LiteralExpression("DESCRIPTOR"));
- IInterfaceType* iinType = new IInterfaceType();
- Variable *iin = new Variable(iinType, "iin");
- VariableDeclaration* iinVd = new VariableDeclaration(iin, queryLocalInterface, iinType);
- m->statements->Add(iinVd);
-
- // Ensure the instance type of the local object is as expected.
- // One scenario where this is needed is if another package (with a
- // different class loader) runs in the same process as the service.
-
- // if (iin != null && iin instanceof <interfaceType>) return (<interfaceType>) iin;
- Comparison* iinNotNull = new Comparison(iin, "!=", NULL_VALUE);
- Comparison* instOfCheck = new Comparison(iin, " instanceof ",
- new LiteralExpression(interfaceType->QualifiedName()));
- IfStatement* instOfStatement = new IfStatement();
- instOfStatement->expression = new Comparison(iinNotNull, "&&", instOfCheck);
- instOfStatement->statements = new StatementBlock;
- instOfStatement->statements->Add(new ReturnStatement(new Cast(interfaceType, iin)));
- m->statements->Add(instOfStatement);
-
- string proxyType = interfaceType->QualifiedName();
- proxyType += ".Stub.Proxy";
- NewExpression* ne = new NewExpression(NAMES.Find(proxyType));
- ne->arguments.push_back(obj);
- m->statements->Add(new ReturnStatement(ne));
-
- this->elements.push_back(m);
-}
-
-
-
-// =================================================
-class ProxyClass : public Class
-{
-public:
- ProxyClass(Type* type, InterfaceType* interfaceType);
- virtual ~ProxyClass();
-
- Variable* mRemote;
- bool mOneWay;
-};
-
-ProxyClass::ProxyClass(Type* type, InterfaceType* interfaceType)
- :Class()
-{
- this->modifiers = PRIVATE | STATIC;
- this->what = Class::CLASS;
- this->type = type;
- this->interfaces.push_back(interfaceType);
-
- mOneWay = interfaceType->OneWay();
-
- // IBinder mRemote
- mRemote = new Variable(IBINDER_TYPE, "mRemote");
- this->elements.push_back(new Field(PRIVATE, mRemote));
-
- // Proxy()
- Variable* remote = new Variable(IBINDER_TYPE, "remote");
- Method* ctor = new Method;
- ctor->name = "Proxy";
- ctor->statements = new StatementBlock;
- ctor->parameters.push_back(remote);
- ctor->statements->Add(new Assignment(mRemote, remote));
- this->elements.push_back(ctor);
-
- // IBinder asBinder()
- Method* asBinder = new Method;
- asBinder->modifiers = PUBLIC;
- asBinder->returnType = IBINDER_TYPE;
- asBinder->name = "asBinder";
- asBinder->statements = new StatementBlock;
- asBinder->statements->Add(new ReturnStatement(mRemote));
- this->elements.push_back(asBinder);
-}
-
-ProxyClass::~ProxyClass()
-{
-}
-
-// =================================================
-static string
+string
gather_comments(extra_text_type* extra)
{
string s;
@@ -249,7 +48,7 @@ gather_comments(extra_text_type* extra)
return s;
}
-static string
+string
append(const char* a, const char* b)
{
string s = a;
@@ -257,379 +56,25 @@ append(const char* a, const char* b)
return s;
}
-static void
-generate_new_array(Type* t, StatementBlock* addTo, Variable* v,
- Variable* parcel)
-{
- Variable* len = new Variable(INT_TYPE, v->name + "_length");
- addTo->Add(new VariableDeclaration(len, new MethodCall(parcel, "readInt")));
- IfStatement* lencheck = new IfStatement();
- lencheck->expression = new Comparison(len, "<", new LiteralExpression("0"));
- lencheck->statements->Add(new Assignment(v, NULL_VALUE));
- lencheck->elseif = new IfStatement();
- lencheck->elseif->statements->Add(new Assignment(v,
- new NewArrayExpression(t, len)));
- addTo->Add(lencheck);
-}
-
-static void
-generate_write_to_parcel(Type* t, StatementBlock* addTo, Variable* v,
- Variable* parcel, int flags)
-{
- if (v->dimension == 0) {
- t->WriteToParcel(addTo, v, parcel, flags);
- }
- if (v->dimension == 1) {
- t->WriteArrayToParcel(addTo, v, parcel, flags);
- }
-}
-
-static void
-generate_create_from_parcel(Type* t, StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl)
+// =================================================
+int
+generate_java(const string& filename, const string& originalSrc,
+ interface_type* iface)
{
- if (v->dimension == 0) {
- t->CreateFromParcel(addTo, v, parcel, cl);
- }
- if (v->dimension == 1) {
- t->CreateArrayFromParcel(addTo, v, parcel, cl);
- }
-}
+ Class* cl;
-static void
-generate_read_from_parcel(Type* t, StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl)
-{
- if (v->dimension == 0) {
- t->ReadFromParcel(addTo, v, parcel, cl);
- }
- if (v->dimension == 1) {
- t->ReadArrayFromParcel(addTo, v, parcel, cl);
+ if (iface->document_item.item_type == INTERFACE_TYPE_BINDER) {
+ cl = generate_binder_interface_class(iface);
}
-}
-
-
-static void
-generate_method(const method_type* method, Class* interface,
- StubClass* stubClass, ProxyClass* proxyClass, int index)
-{
- arg_type* arg;
- int i;
- bool hasOutParams = false;
-
- const bool oneway = proxyClass->mOneWay || method->oneway;
-
- // == the TRANSACT_ constant =============================================
- string transactCodeName = "TRANSACTION_";
- transactCodeName += method->name.data;
-
- char transactCodeValue[50];
- sprintf(transactCodeValue, "(android.os.IBinder.FIRST_CALL_TRANSACTION + %d)", index);
-
- Field* transactCode = new Field(STATIC | FINAL,
- new Variable(INT_TYPE, transactCodeName));
- transactCode->value = transactCodeValue;
- stubClass->elements.push_back(transactCode);
-
- // == the declaration in the interface ===================================
- Method* decl = new Method;
- decl->comment = gather_comments(method->comments_token->extra);
- decl->modifiers = PUBLIC;
- decl->returnType = NAMES.Search(method->type.type.data);
- decl->returnTypeDimension = method->type.dimension;
- decl->name = method->name.data;
-
- arg = method->args;
- while (arg != NULL) {
- decl->parameters.push_back(new Variable(
- NAMES.Search(arg->type.type.data), arg->name.data,
- arg->type.dimension));
- arg = arg->next;
+ else if (iface->document_item.item_type == INTERFACE_TYPE_RPC) {
+ cl = generate_rpc_interface_class(iface);
}
- decl->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
-
- interface->elements.push_back(decl);
-
- // == the stub method ====================================================
-
- Case* c = new Case(transactCodeName);
-
- MethodCall* realCall = new MethodCall(THIS_VALUE, method->name.data);
-
- // interface token validation is the very first thing we do
- c->statements->Add(new MethodCall(stubClass->transact_data,
- "enforceInterface", 1, new LiteralExpression("DESCRIPTOR")));
-
- // args
- Variable* cl = NULL;
- VariableFactory stubArgs("_arg");
- arg = method->args;
- while (arg != NULL) {
- Type* t = NAMES.Search(arg->type.type.data);
- Variable* v = stubArgs.Get(t);
- v->dimension = arg->type.dimension;
-
- c->statements->Add(new VariableDeclaration(v));
-
- if (convert_direction(arg->direction.data) & IN_PARAMETER) {
- generate_create_from_parcel(t, c->statements, v,
- stubClass->transact_data, &cl);
- } else {
- if (arg->type.dimension == 0) {
- c->statements->Add(new Assignment(
- v, new NewExpression(v->type)));
- }
- else if (arg->type.dimension == 1) {
- generate_new_array(v->type, c->statements, v,
- stubClass->transact_data);
- }
- else {
- fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__,
- __LINE__);
- }
- }
-
- realCall->arguments.push_back(v);
-
- arg = arg->next;
- }
-
- // the real call
- Variable* _result = NULL;
- if (0 == strcmp(method->type.type.data, "void")) {
- c->statements->Add(realCall);
-
- if (!oneway) {
- // report that there were no exceptions
- MethodCall* ex = new MethodCall(stubClass->transact_reply,
- "writeNoException", 0);
- c->statements->Add(ex);
- }
- } else {
- _result = new Variable(decl->returnType, "_result",
- decl->returnTypeDimension);
- c->statements->Add(new VariableDeclaration(_result, realCall));
-
- if (!oneway) {
- // report that there were no exceptions
- MethodCall* ex = new MethodCall(stubClass->transact_reply,
- "writeNoException", 0);
- c->statements->Add(ex);
- }
-
- // marshall the return value
- generate_write_to_parcel(decl->returnType, c->statements, _result,
- stubClass->transact_reply,
- Type::PARCELABLE_WRITE_RETURN_VALUE);
- }
-
- // out parameters
- i = 0;
- arg = method->args;
- while (arg != NULL) {
- Type* t = NAMES.Search(arg->type.type.data);
- Variable* v = stubArgs.Get(i++);
-
- if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
- generate_write_to_parcel(t, c->statements, v,
- stubClass->transact_reply,
- Type::PARCELABLE_WRITE_RETURN_VALUE);
- hasOutParams = true;
- }
-
- arg = arg->next;
- }
-
- // return true
- c->statements->Add(new ReturnStatement(TRUE_VALUE));
- stubClass->transact_switch->cases.push_back(c);
-
- // == the proxy method ===================================================
- Method* proxy = new Method;
- proxy->comment = gather_comments(method->comments_token->extra);
- proxy->modifiers = PUBLIC;
- proxy->returnType = NAMES.Search(method->type.type.data);
- proxy->returnTypeDimension = method->type.dimension;
- proxy->name = method->name.data;
- proxy->statements = new StatementBlock;
- arg = method->args;
- while (arg != NULL) {
- proxy->parameters.push_back(new Variable(
- NAMES.Search(arg->type.type.data), arg->name.data,
- arg->type.dimension));
- arg = arg->next;
- }
- proxy->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
- proxyClass->elements.push_back(proxy);
-
- // the parcels
- Variable* _data = new Variable(PARCEL_TYPE, "_data");
- proxy->statements->Add(new VariableDeclaration(_data,
- new MethodCall(PARCEL_TYPE, "obtain")));
- Variable* _reply = NULL;
- if (!oneway) {
- _reply = new Variable(PARCEL_TYPE, "_reply");
- proxy->statements->Add(new VariableDeclaration(_reply,
- new MethodCall(PARCEL_TYPE, "obtain")));
- }
-
- // the return value
- _result = NULL;
- if (0 != strcmp(method->type.type.data, "void")) {
- _result = new Variable(proxy->returnType, "_result",
- method->type.dimension);
- proxy->statements->Add(new VariableDeclaration(_result));
- }
-
- // try and finally
- TryStatement* tryStatement = new TryStatement();
- proxy->statements->Add(tryStatement);
- FinallyStatement* finallyStatement = new FinallyStatement();
- proxy->statements->Add(finallyStatement);
-
- // the interface identifier token: the DESCRIPTOR constant, marshalled as a string
- tryStatement->statements->Add(new MethodCall(_data, "writeInterfaceToken",
- 1, new LiteralExpression("DESCRIPTOR")));
-
- // the parameters
- arg = method->args;
- while (arg != NULL) {
- Type* t = NAMES.Search(arg->type.type.data);
- Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
- int dir = convert_direction(arg->direction.data);
- if (dir == OUT_PARAMETER && arg->type.dimension != 0) {
- IfStatement* checklen = new IfStatement();
- checklen->expression = new Comparison(v, "==", NULL_VALUE);
- checklen->statements->Add(new MethodCall(_data, "writeInt", 1,
- new LiteralExpression("-1")));
- checklen->elseif = new IfStatement();
- checklen->elseif->statements->Add(new MethodCall(_data, "writeInt",
- 1, new FieldVariable(v, "length")));
- tryStatement->statements->Add(checklen);
- }
- else if (dir & IN_PARAMETER) {
- generate_write_to_parcel(t, tryStatement->statements, v, _data, 0);
- }
- arg = arg->next;
- }
-
- // the transact call
- MethodCall* call = new MethodCall(proxyClass->mRemote, "transact", 4,
- new LiteralExpression("Stub." + transactCodeName),
- _data, _reply ? _reply : NULL_VALUE,
- new LiteralExpression(
- oneway ? "android.os.IBinder.FLAG_ONEWAY" : "0"));
- tryStatement->statements->Add(call);
-
- // throw back exceptions.
- if (_reply) {
- MethodCall* ex = new MethodCall(_reply, "readException", 0);
- tryStatement->statements->Add(ex);
- }
-
- // returning and cleanup
- if (_reply != NULL) {
- if (_result != NULL) {
- generate_create_from_parcel(proxy->returnType,
- tryStatement->statements, _result, _reply, &cl);
- }
-
- // the out/inout parameters
- arg = method->args;
- while (arg != NULL) {
- Type* t = NAMES.Search(arg->type.type.data);
- Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
- if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
- generate_read_from_parcel(t, tryStatement->statements,
- v, _reply, &cl);
- }
- arg = arg->next;
- }
-
- finallyStatement->statements->Add(new MethodCall(_reply, "recycle"));
- }
- finallyStatement->statements->Add(new MethodCall(_data, "recycle"));
-
- if (_result != NULL) {
- proxy->statements->Add(new ReturnStatement(_result));
- }
-}
-
-static void
-generate_interface_descriptors(StubClass* stub, ProxyClass* proxy)
-{
- // the interface descriptor transaction handler
- Case* c = new Case("INTERFACE_TRANSACTION");
- c->statements->Add(new MethodCall(stub->transact_reply, "writeString",
- 1, new LiteralExpression("DESCRIPTOR")));
- c->statements->Add(new ReturnStatement(TRUE_VALUE));
- stub->transact_switch->cases.push_back(c);
-
- // and the proxy-side method returning the descriptor directly
- Method* getDesc = new Method;
- getDesc->modifiers = PUBLIC;
- getDesc->returnType = STRING_TYPE;
- getDesc->returnTypeDimension = 0;
- getDesc->name = "getInterfaceDescriptor";
- getDesc->statements = new StatementBlock;
- getDesc->statements->Add(new ReturnStatement(new LiteralExpression("DESCRIPTOR")));
- proxy->elements.push_back(getDesc);
-}
-
-static Class*
-generate_interface_class(const interface_type* iface)
-{
- InterfaceType* interfaceType = static_cast<InterfaceType*>(
- NAMES.Find(iface->package, iface->name.data));
-
- // the interface class
- Class* interface = new Class;
- interface->comment = gather_comments(iface->comments_token->extra);
- interface->modifiers = PUBLIC;
- interface->what = Class::INTERFACE;
- interface->type = interfaceType;
- interface->interfaces.push_back(IINTERFACE_TYPE);
-
- // the stub inner class
- StubClass* stub = new StubClass(
- NAMES.Find(iface->package, append(iface->name.data, ".Stub").c_str()),
- interfaceType);
- interface->elements.push_back(stub);
-
- // the proxy inner class
- ProxyClass* proxy = new ProxyClass(
- NAMES.Find(iface->package,
- append(iface->name.data, ".Stub.Proxy").c_str()),
- interfaceType);
- stub->elements.push_back(proxy);
-
- // stub and proxy support for getInterfaceDescriptor()
- generate_interface_descriptors(stub, proxy);
-
- // all the declared methods of the interface
- int index = 0;
- interface_item_type* item = iface->interface_items;
- while (item != NULL) {
- if (item->item_type == METHOD_TYPE) {
- generate_method((method_type*)item, interface, stub, proxy, index);
- }
- item = item->next;
- index++;
- }
-
- return interface;
-}
-
-int
-generate_java(const string& filename, const string& originalSrc,
- interface_type* iface)
-{
Document* document = new Document;
document->comment = "";
if (iface->package) document->package = iface->package;
document->originalSrc = originalSrc;
- document->classes.push_back(generate_interface_class(iface));
+ document->classes.push_back(cl);
// printf("outputting... filename=%s\n", filename.c_str());
FILE* to;
diff --git a/tools/aidl/generate_java.h b/tools/aidl/generate_java.h
index 203fe23..4bfcfeb 100644
--- a/tools/aidl/generate_java.h
+++ b/tools/aidl/generate_java.h
@@ -2,6 +2,7 @@
#define GENERATE_JAVA_H
#include "aidl_language.h"
+#include "AST.h"
#include <string>
@@ -10,5 +11,23 @@ using namespace std;
int generate_java(const string& filename, const string& originalSrc,
interface_type* iface);
+Class* generate_binder_interface_class(const interface_type* iface);
+Class* generate_rpc_interface_class(const interface_type* iface);
+
+string gather_comments(extra_text_type* extra);
+string append(const char* a, const char* b);
+
+class VariableFactory
+{
+public:
+ VariableFactory(const string& base); // base must be short
+ Variable* Get(Type* type);
+ Variable* Get(int index);
+private:
+ vector<Variable*> m_vars;
+ string m_base;
+ int m_index;
+};
+
#endif // GENERATE_JAVA_H
diff --git a/tools/aidl/generate_java_binder.cpp b/tools/aidl/generate_java_binder.cpp
new file mode 100644
index 0000000..2e459a8
--- /dev/null
+++ b/tools/aidl/generate_java_binder.cpp
@@ -0,0 +1,559 @@
+#include "generate_java.h"
+#include "Type.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+// =================================================
+class StubClass : public Class
+{
+public:
+ StubClass(Type* type, Type* interfaceType);
+ virtual ~StubClass();
+
+ Variable* transact_code;
+ Variable* transact_data;
+ Variable* transact_reply;
+ Variable* transact_flags;
+ SwitchStatement* transact_switch;
+private:
+ void make_as_interface(Type* interfaceType);
+};
+
+StubClass::StubClass(Type* type, Type* interfaceType)
+ :Class()
+{
+ this->comment = "/** Local-side IPC implementation stub class. */";
+ this->modifiers = PUBLIC | ABSTRACT | STATIC;
+ this->what = Class::CLASS;
+ this->type = type;
+ this->extends = BINDER_NATIVE_TYPE;
+ this->interfaces.push_back(interfaceType);
+
+ // descriptor
+ Field* descriptor = new Field(STATIC | FINAL | PRIVATE,
+ new Variable(STRING_TYPE, "DESCRIPTOR"));
+ descriptor->value = "\"" + interfaceType->QualifiedName() + "\"";
+ this->elements.push_back(descriptor);
+
+ // ctor
+ Method* ctor = new Method;
+ ctor->modifiers = PUBLIC;
+ ctor->comment = "/** Construct the stub at attach it to the "
+ "interface. */";
+ ctor->name = "Stub";
+ ctor->statements = new StatementBlock;
+ MethodCall* attach = new MethodCall(THIS_VALUE, "attachInterface",
+ 2, THIS_VALUE, new LiteralExpression("DESCRIPTOR"));
+ ctor->statements->Add(attach);
+ this->elements.push_back(ctor);
+
+ // asInterface
+ make_as_interface(interfaceType);
+
+ // asBinder
+ Method* asBinder = new Method;
+ asBinder->modifiers = PUBLIC;
+ asBinder->returnType = IBINDER_TYPE;
+ asBinder->name = "asBinder";
+ asBinder->statements = new StatementBlock;
+ asBinder->statements->Add(new ReturnStatement(THIS_VALUE));
+ this->elements.push_back(asBinder);
+
+ // onTransact
+ this->transact_code = new Variable(INT_TYPE, "code");
+ this->transact_data = new Variable(PARCEL_TYPE, "data");
+ this->transact_reply = new Variable(PARCEL_TYPE, "reply");
+ this->transact_flags = new Variable(INT_TYPE, "flags");
+ Method* onTransact = new Method;
+ onTransact->modifiers = PUBLIC | OVERRIDE;
+ onTransact->returnType = BOOLEAN_TYPE;
+ onTransact->name = "onTransact";
+ onTransact->parameters.push_back(this->transact_code);
+ onTransact->parameters.push_back(this->transact_data);
+ onTransact->parameters.push_back(this->transact_reply);
+ onTransact->parameters.push_back(this->transact_flags);
+ onTransact->statements = new StatementBlock;
+ onTransact->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
+ this->elements.push_back(onTransact);
+ this->transact_switch = new SwitchStatement(this->transact_code);
+
+ onTransact->statements->Add(this->transact_switch);
+ MethodCall* superCall = new MethodCall(SUPER_VALUE, "onTransact", 4,
+ this->transact_code, this->transact_data,
+ this->transact_reply, this->transact_flags);
+ onTransact->statements->Add(new ReturnStatement(superCall));
+}
+
+StubClass::~StubClass()
+{
+}
+
+void
+StubClass::make_as_interface(Type *interfaceType)
+{
+ Variable* obj = new Variable(IBINDER_TYPE, "obj");
+
+ Method* m = new Method;
+ m->comment = "/**\n * Cast an IBinder object into an ";
+ m->comment += interfaceType->QualifiedName();
+ m->comment += " interface,\n";
+ m->comment += " * generating a proxy if needed.\n */";
+ m->modifiers = PUBLIC | STATIC;
+ m->returnType = interfaceType;
+ m->name = "asInterface";
+ m->parameters.push_back(obj);
+ m->statements = new StatementBlock;
+
+ IfStatement* ifstatement = new IfStatement();
+ ifstatement->expression = new Comparison(obj, "==", NULL_VALUE);
+ ifstatement->statements = new StatementBlock;
+ ifstatement->statements->Add(new ReturnStatement(NULL_VALUE));
+ m->statements->Add(ifstatement);
+
+ // IInterface iin = obj.queryLocalInterface(DESCRIPTOR)
+ MethodCall* queryLocalInterface = new MethodCall(obj, "queryLocalInterface");
+ queryLocalInterface->arguments.push_back(new LiteralExpression("DESCRIPTOR"));
+ IInterfaceType* iinType = new IInterfaceType();
+ Variable *iin = new Variable(iinType, "iin");
+ VariableDeclaration* iinVd = new VariableDeclaration(iin, queryLocalInterface, iinType);
+ m->statements->Add(iinVd);
+
+ // Ensure the instance type of the local object is as expected.
+ // One scenario where this is needed is if another package (with a
+ // different class loader) runs in the same process as the service.
+
+ // if (iin != null && iin instanceof <interfaceType>) return (<interfaceType>) iin;
+ Comparison* iinNotNull = new Comparison(iin, "!=", NULL_VALUE);
+ Comparison* instOfCheck = new Comparison(iin, " instanceof ",
+ new LiteralExpression(interfaceType->QualifiedName()));
+ IfStatement* instOfStatement = new IfStatement();
+ instOfStatement->expression = new Comparison(iinNotNull, "&&", instOfCheck);
+ instOfStatement->statements = new StatementBlock;
+ instOfStatement->statements->Add(new ReturnStatement(new Cast(interfaceType, iin)));
+ m->statements->Add(instOfStatement);
+
+ string proxyType = interfaceType->QualifiedName();
+ proxyType += ".Stub.Proxy";
+ NewExpression* ne = new NewExpression(NAMES.Find(proxyType));
+ ne->arguments.push_back(obj);
+ m->statements->Add(new ReturnStatement(ne));
+
+ this->elements.push_back(m);
+}
+
+
+
+// =================================================
+class ProxyClass : public Class
+{
+public:
+ ProxyClass(Type* type, InterfaceType* interfaceType);
+ virtual ~ProxyClass();
+
+ Variable* mRemote;
+ bool mOneWay;
+};
+
+ProxyClass::ProxyClass(Type* type, InterfaceType* interfaceType)
+ :Class()
+{
+ this->modifiers = PRIVATE | STATIC;
+ this->what = Class::CLASS;
+ this->type = type;
+ this->interfaces.push_back(interfaceType);
+
+ mOneWay = interfaceType->OneWay();
+
+ // IBinder mRemote
+ mRemote = new Variable(IBINDER_TYPE, "mRemote");
+ this->elements.push_back(new Field(PRIVATE, mRemote));
+
+ // Proxy()
+ Variable* remote = new Variable(IBINDER_TYPE, "remote");
+ Method* ctor = new Method;
+ ctor->name = "Proxy";
+ ctor->statements = new StatementBlock;
+ ctor->parameters.push_back(remote);
+ ctor->statements->Add(new Assignment(mRemote, remote));
+ this->elements.push_back(ctor);
+
+ // IBinder asBinder()
+ Method* asBinder = new Method;
+ asBinder->modifiers = PUBLIC;
+ asBinder->returnType = IBINDER_TYPE;
+ asBinder->name = "asBinder";
+ asBinder->statements = new StatementBlock;
+ asBinder->statements->Add(new ReturnStatement(mRemote));
+ this->elements.push_back(asBinder);
+}
+
+ProxyClass::~ProxyClass()
+{
+}
+
+// =================================================
+static void
+generate_new_array(Type* t, StatementBlock* addTo, Variable* v,
+ Variable* parcel)
+{
+ Variable* len = new Variable(INT_TYPE, v->name + "_length");
+ addTo->Add(new VariableDeclaration(len, new MethodCall(parcel, "readInt")));
+ IfStatement* lencheck = new IfStatement();
+ lencheck->expression = new Comparison(len, "<", new LiteralExpression("0"));
+ lencheck->statements->Add(new Assignment(v, NULL_VALUE));
+ lencheck->elseif = new IfStatement();
+ lencheck->elseif->statements->Add(new Assignment(v,
+ new NewArrayExpression(t, len)));
+ addTo->Add(lencheck);
+}
+
+static void
+generate_write_to_parcel(Type* t, StatementBlock* addTo, Variable* v,
+ Variable* parcel, int flags)
+{
+ if (v->dimension == 0) {
+ t->WriteToParcel(addTo, v, parcel, flags);
+ }
+ if (v->dimension == 1) {
+ t->WriteArrayToParcel(addTo, v, parcel, flags);
+ }
+}
+
+static void
+generate_create_from_parcel(Type* t, StatementBlock* addTo, Variable* v,
+ Variable* parcel, Variable** cl)
+{
+ if (v->dimension == 0) {
+ t->CreateFromParcel(addTo, v, parcel, cl);
+ }
+ if (v->dimension == 1) {
+ t->CreateArrayFromParcel(addTo, v, parcel, cl);
+ }
+}
+
+static void
+generate_read_from_parcel(Type* t, StatementBlock* addTo, Variable* v,
+ Variable* parcel, Variable** cl)
+{
+ if (v->dimension == 0) {
+ t->ReadFromParcel(addTo, v, parcel, cl);
+ }
+ if (v->dimension == 1) {
+ t->ReadArrayFromParcel(addTo, v, parcel, cl);
+ }
+}
+
+
+static void
+generate_method(const method_type* method, Class* interface,
+ StubClass* stubClass, ProxyClass* proxyClass, int index)
+{
+ arg_type* arg;
+ int i;
+ bool hasOutParams = false;
+
+ const bool oneway = proxyClass->mOneWay || method->oneway;
+
+ // == the TRANSACT_ constant =============================================
+ string transactCodeName = "TRANSACTION_";
+ transactCodeName += method->name.data;
+
+ char transactCodeValue[50];
+ sprintf(transactCodeValue, "(android.os.IBinder.FIRST_CALL_TRANSACTION + %d)", index);
+
+ Field* transactCode = new Field(STATIC | FINAL,
+ new Variable(INT_TYPE, transactCodeName));
+ transactCode->value = transactCodeValue;
+ stubClass->elements.push_back(transactCode);
+
+ // == the declaration in the interface ===================================
+ Method* decl = new Method;
+ decl->comment = gather_comments(method->comments_token->extra);
+ decl->modifiers = PUBLIC;
+ decl->returnType = NAMES.Search(method->type.type.data);
+ decl->returnTypeDimension = method->type.dimension;
+ decl->name = method->name.data;
+
+ arg = method->args;
+ while (arg != NULL) {
+ decl->parameters.push_back(new Variable(
+ NAMES.Search(arg->type.type.data), arg->name.data,
+ arg->type.dimension));
+ arg = arg->next;
+ }
+
+ decl->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
+
+ interface->elements.push_back(decl);
+
+ // == the stub method ====================================================
+
+ Case* c = new Case(transactCodeName);
+
+ MethodCall* realCall = new MethodCall(THIS_VALUE, method->name.data);
+
+ // interface token validation is the very first thing we do
+ c->statements->Add(new MethodCall(stubClass->transact_data,
+ "enforceInterface", 1, new LiteralExpression("DESCRIPTOR")));
+
+ // args
+ Variable* cl = NULL;
+ VariableFactory stubArgs("_arg");
+ arg = method->args;
+ while (arg != NULL) {
+ Type* t = NAMES.Search(arg->type.type.data);
+ Variable* v = stubArgs.Get(t);
+ v->dimension = arg->type.dimension;
+
+ c->statements->Add(new VariableDeclaration(v));
+
+ if (convert_direction(arg->direction.data) & IN_PARAMETER) {
+ generate_create_from_parcel(t, c->statements, v,
+ stubClass->transact_data, &cl);
+ } else {
+ if (arg->type.dimension == 0) {
+ c->statements->Add(new Assignment(v, new NewExpression(v->type)));
+ }
+ else if (arg->type.dimension == 1) {
+ generate_new_array(v->type, c->statements, v,
+ stubClass->transact_data);
+ }
+ else {
+ fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__,
+ __LINE__);
+ }
+ }
+
+ realCall->arguments.push_back(v);
+
+ arg = arg->next;
+ }
+
+ // the real call
+ Variable* _result = NULL;
+ if (0 == strcmp(method->type.type.data, "void")) {
+ c->statements->Add(realCall);
+
+ if (!oneway) {
+ // report that there were no exceptions
+ MethodCall* ex = new MethodCall(stubClass->transact_reply,
+ "writeNoException", 0);
+ c->statements->Add(ex);
+ }
+ } else {
+ _result = new Variable(decl->returnType, "_result",
+ decl->returnTypeDimension);
+ c->statements->Add(new VariableDeclaration(_result, realCall));
+
+ if (!oneway) {
+ // report that there were no exceptions
+ MethodCall* ex = new MethodCall(stubClass->transact_reply,
+ "writeNoException", 0);
+ c->statements->Add(ex);
+ }
+
+ // marshall the return value
+ generate_write_to_parcel(decl->returnType, c->statements, _result,
+ stubClass->transact_reply,
+ Type::PARCELABLE_WRITE_RETURN_VALUE);
+ }
+
+ // out parameters
+ i = 0;
+ arg = method->args;
+ while (arg != NULL) {
+ Type* t = NAMES.Search(arg->type.type.data);
+ Variable* v = stubArgs.Get(i++);
+
+ if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
+ generate_write_to_parcel(t, c->statements, v,
+ stubClass->transact_reply,
+ Type::PARCELABLE_WRITE_RETURN_VALUE);
+ hasOutParams = true;
+ }
+
+ arg = arg->next;
+ }
+
+ // return true
+ c->statements->Add(new ReturnStatement(TRUE_VALUE));
+ stubClass->transact_switch->cases.push_back(c);
+
+ // == the proxy method ===================================================
+ Method* proxy = new Method;
+ proxy->comment = gather_comments(method->comments_token->extra);
+ proxy->modifiers = PUBLIC;
+ proxy->returnType = NAMES.Search(method->type.type.data);
+ proxy->returnTypeDimension = method->type.dimension;
+ proxy->name = method->name.data;
+ proxy->statements = new StatementBlock;
+ arg = method->args;
+ while (arg != NULL) {
+ proxy->parameters.push_back(new Variable(
+ NAMES.Search(arg->type.type.data), arg->name.data,
+ arg->type.dimension));
+ arg = arg->next;
+ }
+ proxy->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
+ proxyClass->elements.push_back(proxy);
+
+ // the parcels
+ Variable* _data = new Variable(PARCEL_TYPE, "_data");
+ proxy->statements->Add(new VariableDeclaration(_data,
+ new MethodCall(PARCEL_TYPE, "obtain")));
+ Variable* _reply = NULL;
+ if (!oneway) {
+ _reply = new Variable(PARCEL_TYPE, "_reply");
+ proxy->statements->Add(new VariableDeclaration(_reply,
+ new MethodCall(PARCEL_TYPE, "obtain")));
+ }
+
+ // the return value
+ _result = NULL;
+ if (0 != strcmp(method->type.type.data, "void")) {
+ _result = new Variable(proxy->returnType, "_result",
+ method->type.dimension);
+ proxy->statements->Add(new VariableDeclaration(_result));
+ }
+
+ // try and finally
+ TryStatement* tryStatement = new TryStatement();
+ proxy->statements->Add(tryStatement);
+ FinallyStatement* finallyStatement = new FinallyStatement();
+ proxy->statements->Add(finallyStatement);
+
+ // the interface identifier token: the DESCRIPTOR constant, marshalled as a string
+ tryStatement->statements->Add(new MethodCall(_data, "writeInterfaceToken",
+ 1, new LiteralExpression("DESCRIPTOR")));
+
+ // the parameters
+ arg = method->args;
+ while (arg != NULL) {
+ Type* t = NAMES.Search(arg->type.type.data);
+ Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
+ int dir = convert_direction(arg->direction.data);
+ if (dir == OUT_PARAMETER && arg->type.dimension != 0) {
+ IfStatement* checklen = new IfStatement();
+ checklen->expression = new Comparison(v, "==", NULL_VALUE);
+ checklen->statements->Add(new MethodCall(_data, "writeInt", 1,
+ new LiteralExpression("-1")));
+ checklen->elseif = new IfStatement();
+ checklen->elseif->statements->Add(new MethodCall(_data, "writeInt",
+ 1, new FieldVariable(v, "length")));
+ tryStatement->statements->Add(checklen);
+ }
+ else if (dir & IN_PARAMETER) {
+ generate_write_to_parcel(t, tryStatement->statements, v, _data, 0);
+ }
+ arg = arg->next;
+ }
+
+ // the transact call
+ MethodCall* call = new MethodCall(proxyClass->mRemote, "transact", 4,
+ new LiteralExpression("Stub." + transactCodeName),
+ _data, _reply ? _reply : NULL_VALUE,
+ new LiteralExpression(
+ oneway ? "android.os.IBinder.FLAG_ONEWAY" : "0"));
+ tryStatement->statements->Add(call);
+
+ // throw back exceptions.
+ if (_reply) {
+ MethodCall* ex = new MethodCall(_reply, "readException", 0);
+ tryStatement->statements->Add(ex);
+ }
+
+ // returning and cleanup
+ if (_reply != NULL) {
+ if (_result != NULL) {
+ generate_create_from_parcel(proxy->returnType,
+ tryStatement->statements, _result, _reply, &cl);
+ }
+
+ // the out/inout parameters
+ arg = method->args;
+ while (arg != NULL) {
+ Type* t = NAMES.Search(arg->type.type.data);
+ Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
+ if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
+ generate_read_from_parcel(t, tryStatement->statements,
+ v, _reply, &cl);
+ }
+ arg = arg->next;
+ }
+
+ finallyStatement->statements->Add(new MethodCall(_reply, "recycle"));
+ }
+ finallyStatement->statements->Add(new MethodCall(_data, "recycle"));
+
+ if (_result != NULL) {
+ proxy->statements->Add(new ReturnStatement(_result));
+ }
+}
+
+static void
+generate_interface_descriptors(StubClass* stub, ProxyClass* proxy)
+{
+ // the interface descriptor transaction handler
+ Case* c = new Case("INTERFACE_TRANSACTION");
+ c->statements->Add(new MethodCall(stub->transact_reply, "writeString",
+ 1, new LiteralExpression("DESCRIPTOR")));
+ c->statements->Add(new ReturnStatement(TRUE_VALUE));
+ stub->transact_switch->cases.push_back(c);
+
+ // and the proxy-side method returning the descriptor directly
+ Method* getDesc = new Method;
+ getDesc->modifiers = PUBLIC;
+ getDesc->returnType = STRING_TYPE;
+ getDesc->returnTypeDimension = 0;
+ getDesc->name = "getInterfaceDescriptor";
+ getDesc->statements = new StatementBlock;
+ getDesc->statements->Add(new ReturnStatement(new LiteralExpression("DESCRIPTOR")));
+ proxy->elements.push_back(getDesc);
+}
+
+Class*
+generate_binder_interface_class(const interface_type* iface)
+{
+ InterfaceType* interfaceType = static_cast<InterfaceType*>(
+ NAMES.Find(iface->package, iface->name.data));
+
+ // the interface class
+ Class* interface = new Class;
+ interface->comment = gather_comments(iface->comments_token->extra);
+ interface->modifiers = PUBLIC;
+ interface->what = Class::INTERFACE;
+ interface->type = interfaceType;
+ interface->interfaces.push_back(IINTERFACE_TYPE);
+
+ // the stub inner class
+ StubClass* stub = new StubClass(
+ NAMES.Find(iface->package, append(iface->name.data, ".Stub").c_str()),
+ interfaceType);
+ interface->elements.push_back(stub);
+
+ // the proxy inner class
+ ProxyClass* proxy = new ProxyClass(
+ NAMES.Find(iface->package,
+ append(iface->name.data, ".Stub.Proxy").c_str()),
+ interfaceType);
+ stub->elements.push_back(proxy);
+
+ // stub and proxy support for getInterfaceDescriptor()
+ generate_interface_descriptors(stub, proxy);
+
+ // all the declared methods of the interface
+ int index = 0;
+ interface_item_type* item = iface->interface_items;
+ while (item != NULL) {
+ if (item->item_type == METHOD_TYPE) {
+ generate_method((method_type*)item, interface, stub, proxy, index);
+ }
+ item = item->next;
+ index++;
+ }
+
+ return interface;
+}
+
diff --git a/tools/aidl/generate_java_rpc.cpp b/tools/aidl/generate_java_rpc.cpp
new file mode 100644
index 0000000..2b50b76
--- /dev/null
+++ b/tools/aidl/generate_java_rpc.cpp
@@ -0,0 +1,996 @@
+#include "generate_java.h"
+#include "Type.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+Type* ANDROID_CONTEXT_TYPE = new Type("android.content",
+ "Context", Type::BUILT_IN, false, false, false);
+Type* PRESENTER_BASE_TYPE = new Type("android.support.place.connector",
+ "EventListener", Type::BUILT_IN, false, false, false);
+Type* PRESENTER_LISTENER_BASE_TYPE = new Type("android.support.place.connector",
+ "EventListener.Listener", Type::BUILT_IN, false, false, false);
+Type* RPC_BROKER_TYPE = new Type("android.support.place.connector", "Broker",
+ Type::BUILT_IN, false, false, false);
+Type* PLACE_INFO_TYPE = new Type("android.support.place.connector", "PlaceInfo",
+ Type::BUILT_IN, false, false, false);
+// TODO: Just use Endpoint, so this works for all endpoints.
+Type* RPC_CONNECTOR_TYPE = new Type("android.support.place.connector", "Connector",
+ Type::BUILT_IN, false, false, false);
+Type* RPC_ENDPOINT_INFO_TYPE = new UserDataType("android.support.place.rpc",
+ "EndpointInfo", true, __FILE__, __LINE__);
+Type* RPC_RESULT_HANDLER_TYPE = new UserDataType("android.support.place.rpc", "RpcResultHandler",
+ true, __FILE__, __LINE__);
+Type* RPC_ERROR_LISTENER_TYPE = new Type("android.support.place.rpc", "RpcErrorHandler",
+ Type::BUILT_IN, false, false, false);
+Type* RPC_CONTEXT_TYPE = new UserDataType("android.support.place.rpc", "RpcContext", true,
+ __FILE__, __LINE__);
+
+static void generate_create_from_data(Type* t, StatementBlock* addTo, const string& key,
+ Variable* v, Variable* data, Variable** cl);
+static void generate_new_array(Type* t, StatementBlock* addTo, Variable* v, Variable* from);
+static void generate_write_to_data(Type* t, StatementBlock* addTo, Expression* k, Variable* v,
+ Variable* data);
+
+static string
+format_int(int n)
+{
+ char str[20];
+ sprintf(str, "%d", n);
+ return string(str);
+}
+
+static string
+class_name_leaf(const string& str)
+{
+ string::size_type pos = str.rfind('.');
+ if (pos == string::npos) {
+ return str;
+ } else {
+ return string(str, pos+1);
+ }
+}
+
+static string
+results_class_name(const string& n)
+{
+ string str = n;
+ str[0] = toupper(str[0]);
+ str.insert(0, "On");
+ return str;
+}
+
+static string
+results_method_name(const string& n)
+{
+ string str = n;
+ str[0] = toupper(str[0]);
+ str.insert(0, "on");
+ return str;
+}
+
+static string
+push_method_name(const string& n)
+{
+ string str = n;
+ str[0] = toupper(str[0]);
+ str.insert(0, "push");
+ return str;
+}
+
+// =================================================
+class DispatcherClass : public Class
+{
+public:
+ DispatcherClass(const interface_type* iface, Expression* target);
+ virtual ~DispatcherClass();
+
+ void AddMethod(const method_type* method);
+ void DoneWithMethods();
+
+ Method* processMethod;
+ Variable* actionParam;
+ Variable* requestParam;
+ Variable* rpcContextParam;
+ Variable* errorParam;
+ Variable* requestData;
+ Variable* resultData;
+ IfStatement* dispatchIfStatement;
+ Expression* targetExpression;
+
+private:
+ void generate_process();
+};
+
+DispatcherClass::DispatcherClass(const interface_type* iface, Expression* target)
+ :Class(),
+ dispatchIfStatement(NULL),
+ targetExpression(target)
+{
+ generate_process();
+}
+
+DispatcherClass::~DispatcherClass()
+{
+}
+
+void
+DispatcherClass::generate_process()
+{
+ // byte[] process(String action, byte[] params, RpcContext context, RpcError status)
+ this->processMethod = new Method;
+ this->processMethod->modifiers = PUBLIC;
+ this->processMethod->returnType = BYTE_TYPE;
+ this->processMethod->returnTypeDimension = 1;
+ this->processMethod->name = "process";
+ this->processMethod->statements = new StatementBlock;
+
+ this->actionParam = new Variable(STRING_TYPE, "action");
+ this->processMethod->parameters.push_back(this->actionParam);
+
+ this->requestParam = new Variable(BYTE_TYPE, "requestParam", 1);
+ this->processMethod->parameters.push_back(this->requestParam);
+
+ this->rpcContextParam = new Variable(RPC_CONTEXT_TYPE, "context", 0);
+ this->processMethod->parameters.push_back(this->rpcContextParam);
+
+ this->errorParam = new Variable(RPC_ERROR_TYPE, "errorParam", 0);
+ this->processMethod->parameters.push_back(this->errorParam);
+
+ this->requestData = new Variable(RPC_DATA_TYPE, "request");
+ this->processMethod->statements->Add(new VariableDeclaration(requestData,
+ new NewExpression(RPC_DATA_TYPE, 1, this->requestParam)));
+
+ this->resultData = new Variable(RPC_DATA_TYPE, "resultData");
+ this->processMethod->statements->Add(new VariableDeclaration(this->resultData,
+ NULL_VALUE));
+}
+
+void
+DispatcherClass::AddMethod(const method_type* method)
+{
+ arg_type* arg;
+
+ // The if/switch statement
+ IfStatement* ifs = new IfStatement();
+ ifs->expression = new MethodCall(new StringLiteralExpression(method->name.data), "equals",
+ 1, this->actionParam);
+ StatementBlock* block = ifs->statements = new StatementBlock;
+ if (this->dispatchIfStatement == NULL) {
+ this->dispatchIfStatement = ifs;
+ this->processMethod->statements->Add(dispatchIfStatement);
+ } else {
+ this->dispatchIfStatement->elseif = ifs;
+ this->dispatchIfStatement = ifs;
+ }
+
+ // The call to decl (from above)
+ MethodCall* realCall = new MethodCall(this->targetExpression, method->name.data);
+
+ // args
+ Variable* classLoader = NULL;
+ VariableFactory stubArgs("_arg");
+ arg = method->args;
+ while (arg != NULL) {
+ Type* t = NAMES.Search(arg->type.type.data);
+ Variable* v = stubArgs.Get(t);
+ v->dimension = arg->type.dimension;
+
+ // Unmarshall the parameter
+ block->Add(new VariableDeclaration(v));
+ if (convert_direction(arg->direction.data) & IN_PARAMETER) {
+ generate_create_from_data(t, block, arg->name.data, v,
+ this->requestData, &classLoader);
+ } else {
+ if (arg->type.dimension == 0) {
+ block->Add(new Assignment(v, new NewExpression(v->type)));
+ }
+ else if (arg->type.dimension == 1) {
+ generate_new_array(v->type, block, v, this->requestData);
+ }
+ else {
+ fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__,
+ __LINE__);
+ }
+ }
+
+ // Add that parameter to the method call
+ realCall->arguments.push_back(v);
+
+ arg = arg->next;
+ }
+
+ // Add a final parameter: RpcContext. Contains data about
+ // incoming request (e.g., certificate)
+ realCall->arguments.push_back(new Variable(RPC_CONTEXT_TYPE, "context", 0));
+
+ Type* returnType = NAMES.Search(method->type.type.data);
+ if (returnType == EVENT_FAKE_TYPE) {
+ returnType = VOID_TYPE;
+ }
+
+ // the real call
+ bool first = true;
+ Variable* _result = NULL;
+ if (returnType == VOID_TYPE) {
+ block->Add(realCall);
+ } else {
+ _result = new Variable(returnType, "_result",
+ method->type.dimension);
+ block->Add(new VariableDeclaration(_result, realCall));
+
+ // need the result RpcData
+ if (first) {
+ block->Add(new Assignment(this->resultData,
+ new NewExpression(RPC_DATA_TYPE)));
+ first = false;
+ }
+
+ // marshall the return value
+ generate_write_to_data(returnType, block,
+ new StringLiteralExpression("_result"), _result, this->resultData);
+ }
+
+ // out parameters
+ int i = 0;
+ arg = method->args;
+ while (arg != NULL) {
+ Type* t = NAMES.Search(arg->type.type.data);
+ Variable* v = stubArgs.Get(i++);
+
+ if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
+ // need the result RpcData
+ if (first) {
+ block->Add(new Assignment(this->resultData, new NewExpression(RPC_DATA_TYPE)));
+ first = false;
+ }
+
+ generate_write_to_data(t, block, new StringLiteralExpression(arg->name.data),
+ v, this->resultData);
+ }
+
+ arg = arg->next;
+ }
+}
+
+void
+DispatcherClass::DoneWithMethods()
+{
+ if (this->dispatchIfStatement == NULL) {
+ return;
+ }
+
+ this->elements.push_back(this->processMethod);
+
+ IfStatement* fallthrough = new IfStatement();
+ fallthrough->statements = new StatementBlock;
+ fallthrough->statements->Add(new ReturnStatement(
+ new MethodCall(SUPER_VALUE, "process", 4,
+ this->actionParam, this->requestParam,
+ this->rpcContextParam,
+ this->errorParam)));
+ this->dispatchIfStatement->elseif = fallthrough;
+ IfStatement* s = new IfStatement;
+ s->statements = new StatementBlock;
+ this->processMethod->statements->Add(s);
+ s->expression = new Comparison(this->resultData, "!=", NULL_VALUE);
+ s->statements->Add(new ReturnStatement(new MethodCall(this->resultData, "serialize")));
+ s->elseif = new IfStatement;
+ s = s->elseif;
+ s->statements->Add(new ReturnStatement(NULL_VALUE));
+}
+
+// =================================================
+class RpcProxyClass : public Class
+{
+public:
+ RpcProxyClass(const interface_type* iface, InterfaceType* interfaceType);
+ virtual ~RpcProxyClass();
+
+ Variable* endpoint;
+ Variable* broker;
+
+private:
+ void generate_ctor();
+ void generate_get_endpoint_info();
+};
+
+RpcProxyClass::RpcProxyClass(const interface_type* iface, InterfaceType* interfaceType)
+ :Class()
+{
+ this->comment = gather_comments(iface->comments_token->extra);
+ this->modifiers = PUBLIC;
+ this->what = Class::CLASS;
+ this->type = interfaceType;
+
+ // broker
+ this->broker = new Variable(RPC_BROKER_TYPE, "_broker");
+ this->elements.push_back(new Field(PRIVATE, this->broker));
+ // endpoint
+ this->endpoint = new Variable(RPC_ENDPOINT_INFO_TYPE, "_endpoint");
+ this->elements.push_back(new Field(PRIVATE, this->endpoint));
+
+ // methods
+ generate_ctor();
+ generate_get_endpoint_info();
+}
+
+RpcProxyClass::~RpcProxyClass()
+{
+}
+
+void
+RpcProxyClass::generate_ctor()
+{
+ Variable* broker = new Variable(RPC_BROKER_TYPE, "broker");
+ Variable* endpoint = new Variable(RPC_ENDPOINT_INFO_TYPE, "endpoint");
+ Method* ctor = new Method;
+ ctor->modifiers = PUBLIC;
+ ctor->name = class_name_leaf(this->type->Name());
+ ctor->statements = new StatementBlock;
+ ctor->parameters.push_back(broker);
+ ctor->parameters.push_back(endpoint);
+ this->elements.push_back(ctor);
+
+ ctor->statements->Add(new Assignment(this->broker, broker));
+ ctor->statements->Add(new Assignment(this->endpoint, endpoint));
+}
+
+void
+RpcProxyClass::generate_get_endpoint_info()
+{
+ Method* get = new Method;
+ get->modifiers = PUBLIC;
+ get->returnType = RPC_ENDPOINT_INFO_TYPE;
+ get->name = "getEndpointInfo";
+ get->statements = new StatementBlock;
+ this->elements.push_back(get);
+
+ get->statements->Add(new ReturnStatement(this->endpoint));
+}
+
+// =================================================
+class EventListenerClass : public DispatcherClass
+{
+public:
+ EventListenerClass(const interface_type* iface, Type* listenerType);
+ virtual ~EventListenerClass();
+
+ Variable* _listener;
+
+private:
+ void generate_ctor();
+};
+
+Expression*
+generate_get_listener_expression(Type* cast)
+{
+ return new Cast(cast, new MethodCall(THIS_VALUE, "getView"));
+}
+
+EventListenerClass::EventListenerClass(const interface_type* iface, Type* listenerType)
+ :DispatcherClass(iface, new FieldVariable(THIS_VALUE, "_listener"))
+{
+ this->modifiers = PRIVATE;
+ this->what = Class::CLASS;
+ this->type = new Type(iface->package ? iface->package : "",
+ append(iface->name.data, ".Presenter"),
+ Type::GENERATED, false, false, false);
+ this->extends = PRESENTER_BASE_TYPE;
+
+ this->_listener = new Variable(listenerType, "_listener");
+ this->elements.push_back(new Field(PRIVATE, this->_listener));
+
+ // methods
+ generate_ctor();
+}
+
+EventListenerClass::~EventListenerClass()
+{
+}
+
+void
+EventListenerClass::generate_ctor()
+{
+ Variable* broker = new Variable(RPC_BROKER_TYPE, "broker");
+ Variable* listener = new Variable(this->_listener->type, "listener");
+ Method* ctor = new Method;
+ ctor->modifiers = PUBLIC;
+ ctor->name = class_name_leaf(this->type->Name());
+ ctor->statements = new StatementBlock;
+ ctor->parameters.push_back(broker);
+ ctor->parameters.push_back(listener);
+ this->elements.push_back(ctor);
+
+ ctor->statements->Add(new MethodCall("super", 2, broker, listener));
+ ctor->statements->Add(new Assignment(this->_listener, listener));
+}
+
+// =================================================
+class ListenerClass : public Class
+{
+public:
+ ListenerClass(const interface_type* iface);
+ virtual ~ListenerClass();
+
+ bool needed;
+
+private:
+ void generate_ctor();
+};
+
+ListenerClass::ListenerClass(const interface_type* iface)
+ :Class(),
+ needed(false)
+{
+ this->comment = "/** Extend this to listen to the events from this class. */";
+ this->modifiers = STATIC | PUBLIC ;
+ this->what = Class::CLASS;
+ this->type = new Type(iface->package ? iface->package : "",
+ append(iface->name.data, ".Listener"),
+ Type::GENERATED, false, false, false);
+ this->extends = PRESENTER_LISTENER_BASE_TYPE;
+}
+
+ListenerClass::~ListenerClass()
+{
+}
+
+// =================================================
+class EndpointBaseClass : public DispatcherClass
+{
+public:
+ EndpointBaseClass(const interface_type* iface);
+ virtual ~EndpointBaseClass();
+
+ bool needed;
+
+private:
+ void generate_ctor();
+};
+
+EndpointBaseClass::EndpointBaseClass(const interface_type* iface)
+ :DispatcherClass(iface, THIS_VALUE),
+ needed(false)
+{
+ this->comment = "/** Extend this to implement a link service. */";
+ this->modifiers = STATIC | PUBLIC | ABSTRACT;
+ this->what = Class::CLASS;
+ this->type = new Type(iface->package ? iface->package : "",
+ append(iface->name.data, ".EndpointBase"),
+ Type::GENERATED, false, false, false);
+ this->extends = RPC_CONNECTOR_TYPE;
+
+ // methods
+ generate_ctor();
+}
+
+EndpointBaseClass::~EndpointBaseClass()
+{
+}
+
+void
+EndpointBaseClass::generate_ctor()
+{
+ Variable* container = new Variable(ANDROID_CONTEXT_TYPE, "context");
+ Variable* broker = new Variable(RPC_BROKER_TYPE, "broker");
+ Variable* place = new Variable(PLACE_INFO_TYPE, "placeInfo");
+ Method* ctor = new Method;
+ ctor->modifiers = PUBLIC;
+ ctor->name = class_name_leaf(this->type->Name());
+ ctor->statements = new StatementBlock;
+ ctor->parameters.push_back(container);
+ ctor->parameters.push_back(broker);
+ ctor->parameters.push_back(place);
+ this->elements.push_back(ctor);
+
+ ctor->statements->Add(new MethodCall("super", 3, container, broker, place));
+}
+
+// =================================================
+class ResultDispatcherClass : public Class
+{
+public:
+ ResultDispatcherClass();
+ virtual ~ResultDispatcherClass();
+
+ void AddMethod(int index, const string& name, Method** method, Variable** param);
+
+ bool needed;
+ Variable* methodId;
+ Variable* callback;
+ Method* onResultMethod;
+ Variable* resultParam;
+ SwitchStatement* methodSwitch;
+
+private:
+ void generate_ctor();
+ void generate_onResult();
+};
+
+ResultDispatcherClass::ResultDispatcherClass()
+ :Class(),
+ needed(false)
+{
+ this->modifiers = PRIVATE | FINAL;
+ this->what = Class::CLASS;
+ this->type = new Type("_ResultDispatcher", Type::GENERATED, false, false, false);
+ this->interfaces.push_back(RPC_RESULT_HANDLER_TYPE);
+
+ // methodId
+ this->methodId = new Variable(INT_TYPE, "methodId");
+ this->elements.push_back(new Field(PRIVATE, this->methodId));
+ this->callback = new Variable(OBJECT_TYPE, "callback");
+ this->elements.push_back(new Field(PRIVATE, this->callback));
+
+ // methods
+ generate_ctor();
+ generate_onResult();
+}
+
+ResultDispatcherClass::~ResultDispatcherClass()
+{
+}
+
+void
+ResultDispatcherClass::generate_ctor()
+{
+ Variable* methodIdParam = new Variable(INT_TYPE, "methId");
+ Variable* callbackParam = new Variable(OBJECT_TYPE, "cbObj");
+ Method* ctor = new Method;
+ ctor->modifiers = PUBLIC;
+ ctor->name = class_name_leaf(this->type->Name());
+ ctor->statements = new StatementBlock;
+ ctor->parameters.push_back(methodIdParam);
+ ctor->parameters.push_back(callbackParam);
+ this->elements.push_back(ctor);
+
+ ctor->statements->Add(new Assignment(this->methodId, methodIdParam));
+ ctor->statements->Add(new Assignment(this->callback, callbackParam));
+}
+
+void
+ResultDispatcherClass::generate_onResult()
+{
+ this->onResultMethod = new Method;
+ this->onResultMethod->modifiers = PUBLIC;
+ this->onResultMethod->returnType = VOID_TYPE;
+ this->onResultMethod->returnTypeDimension = 0;
+ this->onResultMethod->name = "onResult";
+ this->onResultMethod->statements = new StatementBlock;
+ this->elements.push_back(this->onResultMethod);
+
+ this->resultParam = new Variable(BYTE_TYPE, "result", 1);
+ this->onResultMethod->parameters.push_back(this->resultParam);
+
+ this->methodSwitch = new SwitchStatement(this->methodId);
+ this->onResultMethod->statements->Add(this->methodSwitch);
+}
+
+void
+ResultDispatcherClass::AddMethod(int index, const string& name, Method** method, Variable** param)
+{
+ Method* m = new Method;
+ m->modifiers = PUBLIC;
+ m->returnType = VOID_TYPE;
+ m->returnTypeDimension = 0;
+ m->name = name;
+ m->statements = new StatementBlock;
+ *param = new Variable(BYTE_TYPE, "result", 1);
+ m->parameters.push_back(*param);
+ this->elements.push_back(m);
+ *method = m;
+
+ Case* c = new Case(format_int(index));
+ c->statements->Add(new MethodCall(new LiteralExpression("this"), name, 1, this->resultParam));
+ c->statements->Add(new Break());
+
+ this->methodSwitch->cases.push_back(c);
+}
+
+// =================================================
+static void
+generate_new_array(Type* t, StatementBlock* addTo, Variable* v, Variable* from)
+{
+ fprintf(stderr, "aidl: implement generate_new_array %s:%d\n", __FILE__, __LINE__);
+ exit(1);
+}
+
+static void
+generate_create_from_data(Type* t, StatementBlock* addTo, const string& key, Variable* v,
+ Variable* data, Variable** cl)
+{
+ Expression* k = new StringLiteralExpression(key);
+ if (v->dimension == 0) {
+ t->CreateFromRpcData(addTo, k, v, data, cl);
+ }
+ if (v->dimension == 1) {
+ //t->ReadArrayFromRpcData(addTo, v, data, cl);
+ fprintf(stderr, "aidl: implement generate_create_from_data for arrays%s:%d\n",
+ __FILE__, __LINE__);
+ }
+}
+
+static void
+generate_write_to_data(Type* t, StatementBlock* addTo, Expression* k, Variable* v, Variable* data)
+{
+ if (v->dimension == 0) {
+ t->WriteToRpcData(addTo, k, v, data, 0);
+ }
+ if (v->dimension == 1) {
+ //t->WriteArrayToParcel(addTo, v, data);
+ fprintf(stderr, "aidl: implement generate_write_to_data for arrays%s:%d\n",
+ __FILE__, __LINE__);
+ }
+}
+
+// =================================================
+static Type*
+generate_results_method(const method_type* method, RpcProxyClass* proxyClass)
+{
+ arg_type* arg;
+
+ string resultsMethodName = results_method_name(method->name.data);
+ Type* resultsInterfaceType = new Type(results_class_name(method->name.data),
+ Type::GENERATED, false, false, false);
+
+ if (!method->oneway) {
+ Class* resultsClass = new Class;
+ resultsClass->modifiers = STATIC | PUBLIC;
+ resultsClass->what = Class::INTERFACE;
+ resultsClass->type = resultsInterfaceType;
+
+ Method* resultMethod = new Method;
+ resultMethod->comment = gather_comments(method->comments_token->extra);
+ resultMethod->modifiers = PUBLIC;
+ resultMethod->returnType = VOID_TYPE;
+ resultMethod->returnTypeDimension = 0;
+ resultMethod->name = resultsMethodName;
+ if (0 != strcmp("void", method->type.type.data)) {
+ resultMethod->parameters.push_back(new Variable(NAMES.Search(method->type.type.data),
+ "_result", method->type.dimension));
+ }
+ arg = method->args;
+ while (arg != NULL) {
+ if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
+ resultMethod->parameters.push_back(new Variable(
+ NAMES.Search(arg->type.type.data), arg->name.data,
+ arg->type.dimension));
+ }
+ arg = arg->next;
+ }
+ resultsClass->elements.push_back(resultMethod);
+
+ if (resultMethod->parameters.size() > 0) {
+ proxyClass->elements.push_back(resultsClass);
+ return resultsInterfaceType;
+ }
+ }
+ //delete resultsInterfaceType;
+ return NULL;
+}
+
+static void
+generate_proxy_method(const method_type* method, RpcProxyClass* proxyClass,
+ ResultDispatcherClass* resultsDispatcherClass, Type* resultsInterfaceType, int index)
+{
+ arg_type* arg;
+ Method* proxyMethod = new Method;
+ proxyMethod->comment = gather_comments(method->comments_token->extra);
+ proxyMethod->modifiers = PUBLIC;
+ proxyMethod->returnType = VOID_TYPE;
+ proxyMethod->returnTypeDimension = 0;
+ proxyMethod->name = method->name.data;
+ proxyMethod->statements = new StatementBlock;
+ proxyClass->elements.push_back(proxyMethod);
+
+ // The local variables
+ Variable* _data = new Variable(RPC_DATA_TYPE, "_data");
+ proxyMethod->statements->Add(new VariableDeclaration(_data, new NewExpression(RPC_DATA_TYPE)));
+
+ // Add the arguments
+ arg = method->args;
+ while (arg != NULL) {
+ if (convert_direction(arg->direction.data) & IN_PARAMETER) {
+ // Function signature
+ Type* t = NAMES.Search(arg->type.type.data);
+ Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
+ proxyMethod->parameters.push_back(v);
+
+ // Input parameter marshalling
+ generate_write_to_data(t, proxyMethod->statements,
+ new StringLiteralExpression(arg->name.data), v, _data);
+ }
+ arg = arg->next;
+ }
+
+ // If there is a results interface for this class
+ Expression* resultParameter;
+ if (resultsInterfaceType != NULL) {
+ // Result interface parameter
+ Variable* resultListener = new Variable(resultsInterfaceType, "_result");
+ proxyMethod->parameters.push_back(resultListener);
+
+ // Add the results dispatcher callback
+ resultsDispatcherClass->needed = true;
+ resultParameter = new NewExpression(resultsDispatcherClass->type, 2,
+ new LiteralExpression(format_int(index)), resultListener);
+ } else {
+ resultParameter = NULL_VALUE;
+ }
+
+ // All proxy methods take an error parameter
+ Variable* errorListener = new Variable(RPC_ERROR_LISTENER_TYPE, "_errors");
+ proxyMethod->parameters.push_back(errorListener);
+
+ // Call the broker
+ proxyMethod->statements->Add(new MethodCall(new FieldVariable(THIS_VALUE, "_broker"),
+ "sendRpc", 5,
+ proxyClass->endpoint,
+ new StringLiteralExpression(method->name.data),
+ new MethodCall(_data, "serialize"),
+ resultParameter,
+ errorListener));
+}
+
+static void
+generate_result_dispatcher_method(const method_type* method,
+ ResultDispatcherClass* resultsDispatcherClass, Type* resultsInterfaceType, int index)
+{
+ arg_type* arg;
+ Method* dispatchMethod;
+ Variable* dispatchParam;
+ resultsDispatcherClass->AddMethod(index, method->name.data, &dispatchMethod, &dispatchParam);
+
+ Variable* classLoader = NULL;
+ Variable* resultData = new Variable(RPC_DATA_TYPE, "resultData");
+ dispatchMethod->statements->Add(new VariableDeclaration(resultData,
+ new NewExpression(RPC_DATA_TYPE, 1, dispatchParam)));
+
+ // The callback method itself
+ MethodCall* realCall = new MethodCall(
+ new Cast(resultsInterfaceType, new FieldVariable(THIS_VALUE, "callback")),
+ results_method_name(method->name.data));
+
+ // The return value
+ {
+ Type* t = NAMES.Search(method->type.type.data);
+ if (t != VOID_TYPE) {
+ Variable* rv = new Variable(t, "rv");
+ dispatchMethod->statements->Add(new VariableDeclaration(rv));
+ generate_create_from_data(t, dispatchMethod->statements, "_result", rv,
+ resultData, &classLoader);
+ realCall->arguments.push_back(rv);
+ }
+ }
+
+ VariableFactory stubArgs("arg");
+ arg = method->args;
+ while (arg != NULL) {
+ if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
+ // Unmarshall the results
+ Type* t = NAMES.Search(arg->type.type.data);
+ Variable* v = stubArgs.Get(t);
+ dispatchMethod->statements->Add(new VariableDeclaration(v));
+
+ generate_create_from_data(t, dispatchMethod->statements, arg->name.data, v,
+ resultData, &classLoader);
+
+ // Add the argument to the callback
+ realCall->arguments.push_back(v);
+ }
+ arg = arg->next;
+ }
+
+ // Call the callback method
+ dispatchMethod->statements->Add(realCall);
+}
+
+static void
+generate_regular_method(const method_type* method, RpcProxyClass* proxyClass,
+ EndpointBaseClass* serviceBaseClass, ResultDispatcherClass* resultsDispatcherClass,
+ int index)
+{
+ arg_type* arg;
+
+ // == the callback interface for results ================================
+ // the service base class
+ Type* resultsInterfaceType = generate_results_method(method, proxyClass);
+
+ // == the method in the proxy class =====================================
+ generate_proxy_method(method, proxyClass, resultsDispatcherClass, resultsInterfaceType, index);
+
+ // == the method in the result dispatcher class =========================
+ if (resultsInterfaceType != NULL) {
+ generate_result_dispatcher_method(method, resultsDispatcherClass, resultsInterfaceType,
+ index);
+ }
+
+ // == The abstract method that the service developers implement ==========
+ Method* decl = new Method;
+ decl->comment = gather_comments(method->comments_token->extra);
+ decl->modifiers = PUBLIC | ABSTRACT;
+ decl->returnType = NAMES.Search(method->type.type.data);
+ decl->returnTypeDimension = method->type.dimension;
+ decl->name = method->name.data;
+ arg = method->args;
+ while (arg != NULL) {
+ decl->parameters.push_back(new Variable(
+ NAMES.Search(arg->type.type.data), arg->name.data,
+ arg->type.dimension));
+ arg = arg->next;
+ }
+
+ // Add the default RpcContext param to all methods
+ decl->parameters.push_back(new Variable(RPC_CONTEXT_TYPE, "context", 0));
+
+ serviceBaseClass->elements.push_back(decl);
+
+
+ // == the dispatch method in the service base class ======================
+ serviceBaseClass->AddMethod(method);
+}
+
+static void
+generate_event_method(const method_type* method, RpcProxyClass* proxyClass,
+ EndpointBaseClass* serviceBaseClass, ListenerClass* listenerClass,
+ EventListenerClass* presenterClass, int index)
+{
+ arg_type* arg;
+ listenerClass->needed = true;
+
+ // == the push method in the service base class =========================
+ Method* push = new Method;
+ push->modifiers = PUBLIC;
+ push->name = push_method_name(method->name.data);
+ push->statements = new StatementBlock;
+ push->returnType = VOID_TYPE;
+ serviceBaseClass->elements.push_back(push);
+
+ // The local variables
+ Variable* _data = new Variable(RPC_DATA_TYPE, "_data");
+ push->statements->Add(new VariableDeclaration(_data, new NewExpression(RPC_DATA_TYPE)));
+
+ // Add the arguments
+ arg = method->args;
+ while (arg != NULL) {
+ // Function signature
+ Type* t = NAMES.Search(arg->type.type.data);
+ Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
+ push->parameters.push_back(v);
+
+ // Input parameter marshalling
+ generate_write_to_data(t, push->statements,
+ new StringLiteralExpression(arg->name.data), v, _data);
+
+ arg = arg->next;
+ }
+
+ // Send the notifications
+ push->statements->Add(new MethodCall("pushEvent", 2,
+ new StringLiteralExpression(method->name.data),
+ new MethodCall(_data, "serialize")));
+
+ // == the event callback dispatcher method ====================================
+ presenterClass->AddMethod(method);
+
+ // == the event method in the listener base class =====================
+ Method* event = new Method;
+ event->modifiers = PUBLIC;
+ event->name = method->name.data;
+ event->statements = new StatementBlock;
+ event->returnType = VOID_TYPE;
+ listenerClass->elements.push_back(event);
+ arg = method->args;
+ while (arg != NULL) {
+ event->parameters.push_back(new Variable(
+ NAMES.Search(arg->type.type.data), arg->name.data,
+ arg->type.dimension));
+ arg = arg->next;
+ }
+
+ // Add a final parameter: RpcContext. Contains data about
+ // incoming request (e.g., certificate)
+ event->parameters.push_back(new Variable(RPC_CONTEXT_TYPE, "context", 0));
+}
+
+static void
+generate_listener_methods(RpcProxyClass* proxyClass, Type* presenterType, Type* listenerType)
+{
+ // AndroidAtHomePresenter _presenter;
+ // void startListening(Listener listener) {
+ // stopListening();
+ // _presenter = new Presenter(_broker, listener);
+ // _presenter.startListening(_endpoint);
+ // }
+ // void stopListening() {
+ // if (_presenter != null) {
+ // _presenter.stopListening();
+ // }
+ // }
+
+ Variable* _presenter = new Variable(presenterType, "_presenter");
+ proxyClass->elements.push_back(new Field(PRIVATE, _presenter));
+
+ Variable* listener = new Variable(listenerType, "listener");
+
+ Method* startListeningMethod = new Method;
+ startListeningMethod->modifiers = PUBLIC;
+ startListeningMethod->returnType = VOID_TYPE;
+ startListeningMethod->name = "startListening";
+ startListeningMethod->statements = new StatementBlock;
+ startListeningMethod->parameters.push_back(listener);
+ proxyClass->elements.push_back(startListeningMethod);
+
+ startListeningMethod->statements->Add(new MethodCall(THIS_VALUE, "stopListening"));
+ startListeningMethod->statements->Add(new Assignment(_presenter,
+ new NewExpression(presenterType, 2, proxyClass->broker, listener)));
+ startListeningMethod->statements->Add(new MethodCall(_presenter,
+ "startListening", 1, proxyClass->endpoint));
+
+ Method* stopListeningMethod = new Method;
+ stopListeningMethod->modifiers = PUBLIC;
+ stopListeningMethod->returnType = VOID_TYPE;
+ stopListeningMethod->name = "stopListening";
+ stopListeningMethod->statements = new StatementBlock;
+ proxyClass->elements.push_back(stopListeningMethod);
+
+ IfStatement* ifst = new IfStatement;
+ ifst->expression = new Comparison(_presenter, "!=", NULL_VALUE);
+ stopListeningMethod->statements->Add(ifst);
+
+ ifst->statements->Add(new MethodCall(_presenter, "stopListening"));
+ ifst->statements->Add(new Assignment(_presenter, NULL_VALUE));
+}
+
+Class*
+generate_rpc_interface_class(const interface_type* iface)
+{
+ // the proxy class
+ InterfaceType* interfaceType = static_cast<InterfaceType*>(
+ NAMES.Find(iface->package, iface->name.data));
+ RpcProxyClass* proxy = new RpcProxyClass(iface, interfaceType);
+
+ // the listener class
+ ListenerClass* listener = new ListenerClass(iface);
+
+ // the presenter class
+ EventListenerClass* presenter = new EventListenerClass(iface, listener->type);
+
+ // the service base class
+ EndpointBaseClass* base = new EndpointBaseClass(iface);
+ proxy->elements.push_back(base);
+
+ // the result dispatcher
+ ResultDispatcherClass* results = new ResultDispatcherClass();
+
+ // all the declared methods of the proxy
+ int index = 0;
+ interface_item_type* item = iface->interface_items;
+ while (item != NULL) {
+ if (item->item_type == METHOD_TYPE) {
+ if (NAMES.Search(((method_type*)item)->type.type.data) == EVENT_FAKE_TYPE) {
+ generate_event_method((method_type*)item, proxy, base, listener, presenter, index);
+ } else {
+ generate_regular_method((method_type*)item, proxy, base, results, index);
+ }
+ }
+ item = item->next;
+ index++;
+ }
+ presenter->DoneWithMethods();
+ base->DoneWithMethods();
+
+ // only add this if there are methods with results / out parameters
+ if (results->needed) {
+ proxy->elements.push_back(results);
+ }
+ if (listener->needed) {
+ proxy->elements.push_back(listener);
+ proxy->elements.push_back(presenter);
+ generate_listener_methods(proxy, presenter->type, listener->type);
+ }
+
+ return proxy;
+}