Checkpoint adding @home RPC support to aidl
This commit is contained in:
committed by
Mike Lockwood
parent
a8f767a239
commit
fdfe2ff8c6
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
559
tools/aidl/generate_java_binder.cpp
Normal file
559
tools/aidl/generate_java_binder.cpp
Normal 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;
|
||||
}
|
||||
|
||||
667
tools/aidl/generate_java_rpc.cpp
Normal file
667
tools/aidl/generate_java_rpc.cpp
Normal 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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user