Checkpoint adding @home RPC support to aidl

This commit is contained in:
Joe Onorato
2011-08-30 17:24:17 -07:00
committed by Mike Lockwood
parent a8f767a239
commit fdfe2ff8c6
13 changed files with 1487 additions and 586 deletions

View File

@@ -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,10 +393,28 @@ 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)
{
@@ -678,7 +722,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;

View File

@@ -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;
@@ -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

View File

@@ -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

View File

@@ -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,17 @@ 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_SERVICE_BASE_TYPE;
Type* RPC_DATA_TYPE;
Type* RPC_BROKER_TYPE;
Type* RPC_ENDPOINT_INFO_TYPE;
Type* RPC_RESULT_HANDLER_TYPE;
Type* RPC_ERROR_TYPE;
Type* RPC_ERROR_LISTENER_TYPE;
Expression* NULL_VALUE;
Expression* THIS_VALUE;
@@ -66,6 +75,10 @@ register_base_types()
STRING_TYPE = new StringType();
NAMES.Add(STRING_TYPE);
OBJECT_TYPE = new Type("java.lang", "Object",
Type::BUILT_IN, false, false);
NAMES.Add(OBJECT_TYPE);
CHAR_SEQUENCE_TYPE = new CharSequenceType();
NAMES.Add(CHAR_SEQUENCE_TYPE);
@@ -103,6 +116,38 @@ 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);
NAMES.Add(CONTEXT_TYPE);
RPC_SERVICE_BASE_TYPE = new Type("com.android.athome.service", "AndroidAtHomeService",
Type::BUILT_IN, false, false);
NAMES.Add(RPC_SERVICE_BASE_TYPE);
RPC_DATA_TYPE = new Type("com.android.athome.rpc", "RpcData",
Type::BUILT_IN, false, false);
NAMES.Add(RPC_DATA_TYPE);
RPC_BROKER_TYPE = new Type("com.android.athome.utils", "AndroidAtHomeBroker",
Type::BUILT_IN, false, false);
NAMES.Add(RPC_BROKER_TYPE);
RPC_ENDPOINT_INFO_TYPE = new ParcelableType("com.android.athome.rpc", "EndpointInfo",
true, __FILE__, __LINE__);
NAMES.Add(RPC_ENDPOINT_INFO_TYPE);
RPC_RESULT_HANDLER_TYPE = new ParcelableType("com.android.athome.rpc", "RpcResultHandler",
true, __FILE__, __LINE__);
NAMES.Add(RPC_RESULT_HANDLER_TYPE);
RPC_ERROR_TYPE = new ParcelableType("com.android.athome.rpc", "RpcError",
true, __FILE__, __LINE__);
NAMES.Add(RPC_ERROR_TYPE);
RPC_ERROR_LISTENER_TYPE = new Type("com.android.athome.rpc", "RpcErrorHandler",
Type::BUILT_IN, false, false);
NAMES.Add(RPC_ERROR_LISTENER_TYPE);
CLASSLOADER_TYPE = new ClassLoaderType();
NAMES.Add(CLASSLOADER_TYPE);
@@ -243,6 +288,36 @@ Type::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
+ m_qualifiedName + " */"));
}
void
Type::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
Variable* data, int flags)
{
fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%sn",
__FILE__, __LINE__, m_qualifiedName.c_str());
addTo->Add(new LiteralExpression("/* WriteToRpcData error "
+ m_qualifiedName + " */"));
}
void
Type::ReadFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
Variable** cl)
{
fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%sn",
__FILE__, __LINE__, m_qualifiedName.c_str());
addTo->Add(new LiteralExpression("/* ReadFromRpcData error "
+ m_qualifiedName + " */"));
}
void
Type::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
Variable** cl)
{
fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%sn",
__FILE__, __LINE__, m_qualifiedName.c_str());
addTo->Add(new LiteralExpression("/* ReadFromRpcData error "
+ m_qualifiedName + " */"));
}
void
Type::SetQualifiedName(const string& qualified)
{
@@ -458,6 +533,20 @@ 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()

View File

@@ -59,6 +59,14 @@ 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);
virtual void ReadFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
Variable* data, Variable** cl);
protected:
void SetQualifiedName(const string& qualified);
Expression* BuildWriteToParcelFlags(int flags);
@@ -169,6 +177,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
@@ -438,11 +451,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 +470,16 @@ extern Type* BINDER_PROXY_TYPE;
extern Type* PARCEL_TYPE;
extern Type* PARCELABLE_INTERFACE_TYPE;
extern Type* CONTEXT_TYPE;
extern Type* RPC_SERVICE_BASE_TYPE;
extern Type* RPC_DATA_TYPE;
extern Type* RPC_BROKER_TYPE;
extern Type* RPC_ENDPOINT_INFO_TYPE;
extern Type* RPC_RESULT_HANDLER_TYPE;
extern Type* RPC_ERROR_TYPE;
extern Type* RPC_ERROR_LISTENER_TYPE;
extern Expression* NULL_VALUE;
extern Expression* THIS_VALUE;
extern Expression* SUPER_VALUE;

View File

@@ -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;
@@ -242,7 +242,8 @@ check_filenames(const char* filename, document_item_type* items)
parcelable_type* p = (parcelable_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);
}
@@ -295,7 +296,8 @@ gather_types(const char* filename, document_item_type* items)
type = new ParcelableType(p->package ? p->package : "",
p->name.data, false, 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 +312,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.
@@ -330,6 +332,19 @@ gather_types(const char* filename, document_item_type* items)
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,
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",
@@ -498,7 +513,7 @@ 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) {
if (items->item_type == INTERFACE_TYPE_BINDER) {
map<string,method_type*> methodNames;
interface_type* c = (interface_type*)items;
@@ -544,7 +559,10 @@ 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) {
@@ -598,7 +616,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,7 +676,7 @@ 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);
@@ -751,7 +769,7 @@ parse_preprocessed_file(const string& filename)
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;
@@ -995,5 +1013,3 @@ main(int argc, const char **argv)
fprintf(stderr, "aidl: internal error\n");
return 1;
}

View File

@@ -64,7 +64,8 @@ typedef struct method_type {
enum {
PARCELABLE_TYPE = 12,
INTERFACE_TYPE
INTERFACE_TYPE_BINDER,
INTERFACE_TYPE_RPC
};
typedef struct document_item_type {

View File

@@ -81,6 +81,7 @@ brackets \[{whitespace}?\]
/* keywords */
parcelable { SET_BUFFER(PARCELABLE); return PARCELABLE; }
interface { SET_BUFFER(INTERFACE); return INTERFACE; }
rpc { SET_BUFFER(INTERFACE); return RPC; }
in { SET_BUFFER(IN); return IN; }
out { SET_BUFFER(OUT); return OUT; }
inout { SET_BUFFER(INOUT); return INOUT; }

View File

@@ -19,6 +19,7 @@ static int count_brackets(const char*);
%token ARRAY
%token PARCELABLE
%token INTERFACE
%token RPC
%token IN
%token OUT
%token INOUT
@@ -102,6 +103,8 @@ parcelable_decl:
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 +113,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 +148,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;

View File

@@ -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)
{
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);
}
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)
{
Class* cl;
if (iface->document_item.item_type == INTERFACE_TYPE_BINDER) {
cl = generate_binder_interface_class(iface);
}
else if (iface->document_item.item_type == INTERFACE_TYPE_RPC) {
cl = generate_rpc_interface_class(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;

View File

@@ -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

View File

@@ -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;
}

View File

@@ -0,0 +1,667 @@
#include "generate_java.h"
#include "Type.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Type* SERVICE_CONTAINER_TYPE = new Type("com.android.athome.service",
"AndroidAtHomeServiceContainer", Type::BUILT_IN, false, false);
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);
}
}
// =================================================
class RpcProxyClass : public Class
{
public:
RpcProxyClass(const interface_type* iface, InterfaceType* interfaceType);
virtual ~RpcProxyClass();
Variable* endpoint;
Variable* context;
private:
void generate_ctor();
};
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;
// context
this->context = new Variable(CONTEXT_TYPE, "_context");
this->elements.push_back(new Field(PRIVATE, this->context));
// endpoint
this->endpoint = new Variable(RPC_ENDPOINT_INFO_TYPE, "_endpoint");
this->elements.push_back(new Field(PRIVATE, this->endpoint));
// methods
generate_ctor();
}
RpcProxyClass::~RpcProxyClass()
{
}
void
RpcProxyClass::generate_ctor()
{
Variable* context = new Variable(CONTEXT_TYPE, "context");
Variable* endpoint = new Variable(RPC_ENDPOINT_INFO_TYPE, "endpoint");
Method* ctor = new Method;
ctor->modifiers = PUBLIC;
ctor->name = this->type->Name();
ctor->statements = new StatementBlock;
ctor->parameters.push_back(context);
ctor->parameters.push_back(endpoint);
this->elements.push_back(ctor);
ctor->statements->Add(new Assignment(this->context, context));
ctor->statements->Add(new Assignment(this->endpoint, endpoint));
}
// =================================================
class ServiceBaseClass : public Class
{
public:
ServiceBaseClass(const interface_type* iface);
virtual ~ServiceBaseClass();
void AddMethod(const string& methodName, StatementBlock** statements);
void DoneWithMethods();
bool needed;
Method* processMethod;
Variable* actionParam;
Variable* errorParam;
Variable* requestData;
Variable* resultData;
IfStatement* dispatchIfStatement;
private:
void generate_ctor();
void generate_process();
};
ServiceBaseClass::ServiceBaseClass(const interface_type* iface)
:Class(),
needed(false),
dispatchIfStatement(NULL)
{
this->comment = "/** Extend this to implement a link service. */";
this->modifiers = STATIC | PUBLIC | ABSTRACT;
this->what = Class::CLASS;
this->type = NAMES.Find(iface->package, append(iface->name.data, ".ServiceBase").c_str());
this->extends = RPC_SERVICE_BASE_TYPE;
// methods
generate_ctor();
generate_process();
}
ServiceBaseClass::~ServiceBaseClass()
{
}
void
ServiceBaseClass::generate_ctor()
{
Variable* container = new Variable(SERVICE_CONTAINER_TYPE, "container");
Variable* name = new Variable(STRING_TYPE, "name");
Variable* type = new Variable(STRING_TYPE, "type");
Variable* version = new Variable(INT_TYPE, "version");
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(name);
ctor->parameters.push_back(type);
ctor->parameters.push_back(version);
this->elements.push_back(ctor);
ctor->statements->Add(new MethodCall("super", 4, container, name, type, version));
}
void
ServiceBaseClass::generate_process()
{
// byte[] process(String action, byte[] params, 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->elements.push_back(this->processMethod);
this->actionParam = new Variable(STRING_TYPE, "action");
this->processMethod->parameters.push_back(this->actionParam);
Variable* requestParam = new Variable(BYTE_TYPE, "requestParam", 1);
this->processMethod->parameters.push_back(requestParam);
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, requestParam)));
this->resultData = new Variable(RPC_DATA_TYPE, "response");
this->processMethod->statements->Add(new VariableDeclaration(this->resultData,
NULL_VALUE));
}
void
ServiceBaseClass::AddMethod(const string& methodName, StatementBlock** statements)
{
IfStatement* ifs = new IfStatement();
ifs->expression = new MethodCall(new StringLiteralExpression(methodName), "equals", 1,
this->actionParam);
ifs->statements = *statements = new StatementBlock;
if (this->dispatchIfStatement == NULL) {
this->dispatchIfStatement = ifs;
this->processMethod->statements->Add(dispatchIfStatement);
} else {
this->dispatchIfStatement->elseif = ifs;
this->dispatchIfStatement = ifs;
}
}
void
ServiceBaseClass::DoneWithMethods()
{
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 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);
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 = 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));
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 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 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);
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(RPC_BROKER_TYPE, "sendRequest", 6,
new FieldVariable(THIS_VALUE, "_context"),
new StringLiteralExpression(method->name.data),
proxyClass->endpoint,
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);
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_service_base_methods(const method_type* method, ServiceBaseClass* serviceBaseClass)
{
arg_type* arg;
StatementBlock* block;
serviceBaseClass->AddMethod(method->name.data, &block);
// 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;
}
serviceBaseClass->elements.push_back(decl);
// The call to decl (from above)
MethodCall* realCall = new MethodCall(THIS_VALUE, 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,
serviceBaseClass->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, serviceBaseClass->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;
}
// the real call
Variable* _result = NULL;
if (0 == strcmp(method->type.type.data, "void")) {
block->Add(realCall);
} else {
_result = new Variable(decl->returnType, "_result",
decl->returnTypeDimension);
block->Add(new VariableDeclaration(_result, realCall));
// marshall the return value
generate_write_to_data(decl->returnType, block,
new StringLiteralExpression("_result"), _result, serviceBaseClass->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) {
generate_write_to_data(t, block, new StringLiteralExpression(arg->name.data),
v, serviceBaseClass->resultData);
}
arg = arg->next;
}
}
static void
generate_method(const method_type* method, RpcProxyClass* proxyClass,
ServiceBaseClass* serviceBaseClass, ResultDispatcherClass* resultsDispatcherClass,
int index)
{
// == 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 dispatch method in the service base class ======================
generate_service_base_methods(method, serviceBaseClass);
}
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 service base class
ServiceBaseClass* base = new ServiceBaseClass(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) {
generate_method((method_type*)item, proxy, base, results, index);
}
item = item->next;
index++;
}
base->DoneWithMethods();
// only add this if there are methods with results / out parameters
if (results->needed) {
proxy->elements.push_back(results);
}
return proxy;
}