Version query mechanism and default impl for NDK backend
am: 965c5b9f8b
Change-Id: I7991f14e708083be957723b3da5142a0414c07d5
diff --git a/aidl.cpp b/aidl.cpp
index 5c6fa5d..ebd8c7c 100644
--- a/aidl.cpp
+++ b/aidl.cpp
@@ -67,16 +67,29 @@
namespace aidl {
namespace {
-// The following are gotten as the offset from the allowable id's between
-// android.os.IBinder.FIRST_CALL_TRANSACTION=1 and
-// android.os.IBinder.LAST_CALL_TRANSACTION=16777215
-const int kMinUserSetMethodId = 0;
-const int kMaxUserSetMethodId = 0x00ffffff;
+// Copied from android.is.IBinder.[FIRST|LAST]_CALL_TRANSACTION
+const int kFirstCallTransaction = 1;
+const int kLastCallTransaction = 0x00ffffff;
+
+// Following IDs are all offsets from kFirstCallTransaction
// IDs for meta transactions. Most of the meta transactions are implemented in
// the framework side (Binder.java or Binder.cpp). But these are the ones that
// are auto-implemented by the AIDL compiler.
-const int kGetInterfaceVersionId = ('_' << 24) | ('V' << 16) | ('E' << 8) | 'R';
+const int kFirstMetaMethodId = kLastCallTransaction - kFirstCallTransaction;
+const int kGetInterfaceVersionId = kFirstMetaMethodId;
+// Additional meta transactions implemented by AIDL should use
+// kFirstMetaMethodId -1, -2, ...and so on.
+
+// Reserve 100 IDs for meta methods, which is more than enough. If we don't reserve,
+// in the future, a newly added meta transaction ID will have a chance to
+// collide with the user-defined methods that were added in the past. So,
+// let's prevent users from using IDs in this range from the beginning.
+const int kLastMetaMethodId = kFirstMetaMethodId - 99;
+
+// Range of IDs that is allowed for user-defined methods.
+const int kMinUserSetMethodId = 0;
+const int kMaxUserSetMethodId = kLastMetaMethodId - 1;
bool check_filename(const std::string& filename, const AidlDefinedType& defined_type) {
const char* p;
diff --git a/aidl_to_ndk.cpp b/aidl_to_ndk.cpp
index cfd23e1..582f798 100644
--- a/aidl_to_ndk.cpp
+++ b/aidl_to_ndk.cpp
@@ -312,33 +312,22 @@
aspect.read_func(c);
}
-std::string NdkArgListOf(const AidlTypenames& types, const AidlMethod& method) {
+std::string NdkArgList(
+ const AidlTypenames& types, const AidlMethod& method,
+ std::function<std::string(const std::string& type, const std::string& name, bool isOut)>
+ formatter) {
std::vector<std::string> method_arguments;
for (const auto& a : method.GetArguments()) {
StorageMode mode = a->IsOut() ? StorageMode::OUT_ARGUMENT : StorageMode::ARGUMENT;
std::string type = NdkNameOf(types, a->GetType(), mode);
std::string name = cpp::BuildVarName(*a);
- method_arguments.emplace_back(type + " " + name);
+ method_arguments.emplace_back(formatter(type, name, a->IsOut()));
}
if (method.GetType().GetName() != "void") {
- std::string return_type = NdkNameOf(types, method.GetType(), StorageMode::OUT_ARGUMENT);
- method_arguments.emplace_back(return_type + " _aidl_return");
- }
-
- return Join(method_arguments, ", ");
-}
-
-std::string NdkCallListFor(const AidlMethod& method) {
- std::vector<std::string> method_arguments;
- for (const auto& a : method.GetArguments()) {
- std::string reference_prefix = a->IsOut() ? "&" : "";
- std::string name = cpp::BuildVarName(*a);
- method_arguments.emplace_back(reference_prefix + name);
- }
-
- if (method.GetType().GetName() != "void") {
- method_arguments.emplace_back("&_aidl_return");
+ std::string type = NdkNameOf(types, method.GetType(), StorageMode::OUT_ARGUMENT);
+ std::string name = "_aidl_return";
+ method_arguments.emplace_back(formatter(type, name, true));
}
return Join(method_arguments, ", ");
@@ -348,7 +337,7 @@
const std::string& clazz) {
std::string class_prefix = clazz.empty() ? "" : (clazz + "::");
return "::ndk::ScopedAStatus " + class_prefix + method.GetName() + "(" +
- NdkArgListOf(types, method) + ")";
+ NdkArgList(types, method, FormatArgForDecl) + ")";
}
} // namespace ndk
diff --git a/aidl_to_ndk.h b/aidl_to_ndk.h
index 54de198..50fb880 100644
--- a/aidl_to_ndk.h
+++ b/aidl_to_ndk.h
@@ -51,11 +51,32 @@
void WriteToParcelFor(const CodeGeneratorContext& c);
void ReadFromParcelFor(const CodeGeneratorContext& c);
-// -> 'type name, type name, type name' for a method
-std::string NdkArgListOf(const AidlTypenames& types, const AidlMethod& method);
+// Returns argument list of a method where each arg is formatted by the fomatter
+std::string NdkArgList(
+ const AidlTypenames& types, const AidlMethod& method,
+ std::function<std::string(const std::string& type, const std::string& name, bool isOut)>
+ formatter);
-// -> 'name, name, name' for a method where out arguments are '&name'
-std::string NdkCallListFor(const AidlMethod& method);
+inline std::string FormatArgForDecl(const std::string& type, const std::string& name,
+ bool /*isOut*/) {
+ return type + " " + name;
+}
+
+inline std::string FormatArgNameUnused(const std::string& type, const std::string& name,
+ bool /*isOut*/) {
+ return type + " /*" + name + "*/";
+}
+
+inline std::string FormatArgForCall(const std::string& /*type*/, const std::string& name,
+ bool isOut) {
+ std::string reference_prefix = isOut ? "&" : "";
+ return reference_prefix + name;
+}
+
+inline std::string FormatArgNameOnly(const std::string& /*type*/, const std::string& name,
+ bool /*isOut*/) {
+ return name;
+}
// -> 'status (class::)name(type name, ...)' for a method
std::string NdkMethodDecl(const AidlTypenames& types, const AidlMethod& method,
diff --git a/build/aidl_interface.go b/build/aidl_interface.go
index 09c3013..b458737 100644
--- a/build/aidl_interface.go
+++ b/build/aidl_interface.go
@@ -15,6 +15,11 @@
package aidl
import (
+ "android/soong/android"
+ "android/soong/cc"
+ "android/soong/genrule"
+ "android/soong/java"
+ "android/soong/phony"
"fmt"
"io"
"path/filepath"
@@ -25,12 +30,6 @@
"github.com/google/blueprint"
"github.com/google/blueprint/pathtools"
"github.com/google/blueprint/proptools"
-
- "android/soong/android"
- "android/soong/cc"
- "android/soong/genrule"
- "android/soong/java"
- "android/soong/phony"
)
var (
@@ -39,6 +38,7 @@
langCpp = "cpp"
langJava = "java"
langNdk = "ndk"
+ futureVersion = "10000"
pctx = android.NewPackageContext("android/aidl")
@@ -55,13 +55,13 @@
aidlJavaRule = pctx.StaticRule("aidlJavaRule", blueprint.RuleParams{
Command: `rm -rf "${outDir}" && mkdir -p "${outDir}" && ` +
- `${aidlCmd} --lang=java --structured --ninja -d ${out}.d ` +
+ `${aidlCmd} --lang=java ${optionalFlags} --structured --ninja -d ${out}.d ` +
`-o ${outDir} ${imports} ${in}`,
Depfile: "${out}.d",
Deps: blueprint.DepsGCC,
CommandDeps: []string{"${aidlCmd}"},
Description: "AIDL Java ${in}",
- }, "imports", "outDir")
+ }, "imports", "outDir", "optionalFlags")
aidlDumpApiRule = pctx.StaticRule("aidlDumpApiRule", blueprint.RuleParams{
Command: `rm -rf "${out}" && mkdir -p "${out}" && ` +
@@ -120,6 +120,7 @@
Lang string // target language [java|cpp|ndk]
BaseName string
GenLog bool
+ Version string
}
type aidlGenRule struct {
@@ -166,6 +167,11 @@
imports := strings.Join(wrap("-I", importPaths, ""), " ")
+ var optionalFlags []string
+ if g.properties.Version != "" {
+ optionalFlags = append(optionalFlags, "--version "+g.properties.Version)
+ }
+
if g.properties.Lang == langJava {
ctx.ModuleBuild(pctx, android.ModuleBuildParams{
Rule: aidlJavaRule,
@@ -173,8 +179,9 @@
Implicits: checkApiTimestamps,
Outputs: g.genOutputs,
Args: map[string]string{
- "imports": imports,
- "outDir": outDir.String(),
+ "imports": imports,
+ "outDir": outDir.String(),
+ "optionalFlags": strings.Join(optionalFlags, " "),
},
})
} else {
@@ -203,10 +210,10 @@
headers = append(headers, g.genHeaderDir.Join(ctx, prefix, packagePath,
"Bn"+baseName+".h"))
- var optionalFlags []string
if g.properties.GenLog {
optionalFlags = append(optionalFlags, "--log")
}
+
ctx.ModuleBuild(pctx, android.ModuleBuildParams{
Rule: aidlCppRule,
Input: input,
@@ -555,14 +562,14 @@
func (i *aidlInterface) versionedName(version string) string {
name := i.ModuleBase.Name()
- if version != "" {
+ if version != futureVersion && version != "" {
name = name + "-V" + version
}
return name
}
func (i *aidlInterface) srcsForVersion(mctx android.LoadHookContext, version string) (srcs []string, base string) {
- if version == "" {
+ if version == futureVersion || version == "" {
return i.rawSrcs, i.properties.Local_include_dir
} else {
var apiDir string
@@ -600,21 +607,26 @@
var libs []string
+ currentVersion := ""
+ if len(i.properties.Versions) > 0 {
+ currentVersion = futureVersion
+ }
+
if i.shouldGenerateCppBackend() {
- libs = append(libs, addCppLibrary(mctx, i, "", langCpp))
+ libs = append(libs, addCppLibrary(mctx, i, currentVersion, langCpp))
for _, version := range i.properties.Versions {
addCppLibrary(mctx, i, version, langCpp)
}
}
if i.shouldGenerateNdkBackend() {
- libs = append(libs, addCppLibrary(mctx, i, "", langNdk))
+ libs = append(libs, addCppLibrary(mctx, i, currentVersion, langNdk))
for _, version := range i.properties.Versions {
addCppLibrary(mctx, i, version, langNdk)
}
}
- libs = append(libs, addJavaLibrary(mctx, i, ""))
+ libs = append(libs, addJavaLibrary(mctx, i, currentVersion))
for _, version := range i.properties.Versions {
addJavaLibrary(mctx, i, version)
}
@@ -660,6 +672,7 @@
Lang: lang,
BaseName: i.ModuleBase.Name(),
GenLog: genLog,
+ Version: version,
})
cppGeneratedSources = append(cppGeneratedSources, cppSourceGenName)
}
@@ -728,6 +741,7 @@
Imports: concat(i.properties.Imports, []string{i.ModuleBase.Name()}),
Lang: langJava,
BaseName: i.ModuleBase.Name(),
+ Version: version,
})
javaGeneratedSources = append(javaGeneratedSources, javaSourceGenName)
}
diff --git a/generate_cpp.cpp b/generate_cpp.cpp
index 34fc136..edec267 100644
--- a/generate_cpp.cpp
+++ b/generate_cpp.cpp
@@ -490,9 +490,10 @@
// give write the same value to cached_version_.
std::ostringstream code;
code << "int32_t " << proxy << "::" << kGetInterfaceVersion << "() {\n"
- << " if (cached_version_ != -1) {\n"
+ << " if (cached_version_ == -1) {\n"
<< " ::android::Parcel data;\n"
<< " ::android::Parcel reply;\n"
+ << " data.writeInterfaceToken(getInterfaceDescriptor());\n"
<< " ::android::status_t err = remote()->transact(" << GetTransactionIdFor(method)
<< ", data, &reply);\n"
<< " if (err == ::android::OK) {\n"
@@ -684,7 +685,8 @@
if (method.GetName() == kGetInterfaceVersion && options.Version() > 0) {
std::ostringstream code;
- code << "_aidl_reply->writeInt32(" << ClassName(interface, ClassNames::INTERFACE)
+ code << "_aidl_data.checkInterface(this);\n"
+ << "_aidl_reply->writeInt32(" << ClassName(interface, ClassNames::INTERFACE)
<< "::VERSION)";
b->AddLiteral(code.str());
return true;
diff --git a/generate_java_binder.cpp b/generate_java_binder.cpp
index 7fbb472..3714f3d 100644
--- a/generate_java_binder.cpp
+++ b/generate_java_binder.cpp
@@ -814,7 +814,9 @@
if (method.GetName() == kGetInterfaceVersion && options.Version() > 0) {
Case* c = new Case(transactCodeName);
std::ostringstream code;
- code << "reply.writeInt(" << kGetInterfaceVersion << "());\n"
+ code << "data.enforceInterface(descriptor);\n"
+ << "reply.writeNoException();\n"
+ << "reply.writeInt(" << kGetInterfaceVersion << "());\n"
<< "return true;\n";
c->statements->Add(new LiteralStatement(code.str()));
stubClass->transact_switch->cases.push_back(c);
@@ -839,6 +841,7 @@
<< " android.os.Parcel data = android.os.Parcel.obtain();\n"
<< " android.os.Parcel reply = android.os.Parcel.obtain();\n"
<< " try {\n"
+ << " data.writeInterfaceToken(DESCRIPTOR);\n"
<< " mRemote.transact(Stub." << transactCodeName << ", "
<< "data, reply, 0);\n"
<< " mCachedVersion = reply.readInt();\n"
diff --git a/generate_ndk.cpp b/generate_ndk.cpp
index ea42a5a..3c09f09 100644
--- a/generate_ndk.cpp
+++ b/generate_ndk.cpp
@@ -16,6 +16,7 @@
#include "generate_ndk.h"
+#include "aidl.h"
#include "aidl_language.h"
#include "aidl_to_cpp_common.h"
#include "aidl_to_ndk.h"
@@ -26,6 +27,10 @@
namespace aidl {
namespace ndk {
+static constexpr const char* kClazz = "clazz";
+static constexpr const char* kDescriptor = "descriptor";
+static constexpr const char* kVersion = "version";
+
using namespace internals;
using cpp::ClassNames;
@@ -257,6 +262,18 @@
out << "_aidl_out.getR(),\n";
out << (method.IsOneway() ? "FLAG_ONEWAY" : "0") << ");\n";
out.Dedent();
+
+ // If the method is not implmented in the server side but the client has
+ // provided the default implementation, call it instead of failing hard.
+ const std::string iface = ClassName(defined_type, ClassNames::INTERFACE);
+ out << "if (_aidl_ret_status == STATUS_UNKNOWN_TRANSACTION && ";
+ out << iface << "::getDefaultImpl()) {\n";
+ out.Indent();
+ out << "return " << iface << "::getDefaultImpl()->" << method.GetName() << "(";
+ out << NdkArgList(types, method, FormatArgNameOnly) << ");\n";
+ out.Dedent();
+ out << "}\n";
+
StatusCheckGoto(out);
if (!method.IsOneway()) {
@@ -286,6 +303,63 @@
out << "}\n";
}
+static void GenerateClientMetaMethodDefinition(CodeWriter& out, const AidlTypenames& types,
+ const AidlInterface& defined_type,
+ const AidlMethod& method, const Options& options) {
+ CHECK(!method.IsUserDefined());
+ if (method.GetName() == kGetInterfaceVersion && options.Version() > 0) {
+ // Client-side implementation for getInterfaceVersion. The version is cached
+ // in the proxy object.
+ const std::string clazz = ClassName(defined_type, ClassNames::CLIENT);
+
+ out << NdkMethodDecl(types, method, clazz) << " {\n";
+ out.Indent();
+ out << "::ndk::ScopedAStatus _aidl_status;\n";
+ out << "binder_status_t _aidl_ret_status = STATUS_OK;\n";
+ out << "if (cached_version_ == -1) {\n";
+ out.Indent();
+ out << "::ndk::ScopedAParcel _aidl_in;\n";
+ out << "::ndk::ScopedAParcel _aidl_out;\n";
+ out << "\n";
+
+ out << "_aidl_ret_status = AIBinder_prepareTransaction(asBinder().get(), _aidl_in.getR());\n";
+ StatusCheckGoto(out);
+
+ out << "_aidl_ret_status = AIBinder_transact(\n";
+ out.Indent();
+ out << "asBinder().get(),\n";
+ out << MethodId(method) << ",\n";
+ out << "_aidl_in.getR(),\n";
+ out << "_aidl_out.getR(),\n";
+ out << "0);\n";
+ out.Dedent();
+ StatusCheckGoto(out);
+
+ out << "_aidl_ret_status = AParcel_readStatusHeader(_aidl_out.get(), _aidl_status.getR());\n";
+ StatusCheckGoto(out);
+
+ out << "if (!AStatus_isOk(_aidl_status.get())) return _aidl_status;\n\n";
+
+ out << "_aidl_ret_status = AParcel_readInt32(_aidl_out.get(), _aidl_return);\n";
+ StatusCheckGoto(out);
+
+ out << "cached_version_ = *_aidl_return;\n";
+ out << "_aidl_status.set(AStatus_fromStatus(_aidl_ret_status));\n";
+ out << "return _aidl_status;\n";
+
+ out.Dedent();
+ out << "}\n";
+
+ // Shortcut. If cached, just return it without doing the transaction.
+ out << "*_aidl_return = cached_version_;\n";
+ out << "_aidl_error:\n";
+ out << "_aidl_status.set(AStatus_fromStatus(_aidl_ret_status));\n";
+ out << "return _aidl_status;\n";
+ out.Dedent();
+ out << "}\n";
+ }
+}
+
static void GenerateServerCaseDefinition(CodeWriter& out, const AidlTypenames& types,
const AidlInterface& /*defined_type*/,
const AidlMethod& method) {
@@ -314,7 +388,7 @@
}
out << "::ndk::ScopedAStatus _aidl_status = _aidl_impl->" << method.GetName() << "("
- << NdkCallListFor(method) << ");\n";
+ << NdkArgList(types, method, FormatArgForCall) << ");\n";
if (method.IsOneway()) {
// For a oneway transaction, the kernel will have already returned a result. This is for the
@@ -356,7 +430,7 @@
out << "struct " << data_clazz << " {\n";
out.Indent();
- out << "static AIBinder_Class* clazz;\n";
+ out << "static AIBinder_Class* " << kClazz << ";\n";
out << "std::shared_ptr<" << bn_clazz << "> instance;\n";
out.Dedent();
out << "};\n\n";
@@ -400,11 +474,12 @@
out.Dedent();
out << "};\n\n";
- out << "AIBinder_Class* " << data_clazz << "::clazz = AIBinder_Class_define(" << clazz
- << "::descriptor, " << on_create << ", " << on_destroy << ", " << on_transact << ");\n\n";
+ out << "AIBinder_Class* " << data_clazz << ":: " << kClazz << " = AIBinder_Class_define(" << clazz
+ << "::" << kDescriptor << ", " << on_create << ", " << on_destroy << ", " << on_transact
+ << ");\n\n";
}
void GenerateClientSource(CodeWriter& out, const AidlTypenames& types,
- const AidlInterface& defined_type, const Options& /*options*/) {
+ const AidlInterface& defined_type, const Options& options) {
const std::string clazz = ClassName(defined_type, ClassNames::CLIENT);
const std::string data_clazz = DataClassFor(defined_type);
@@ -412,8 +487,8 @@
out << "std::shared_ptr<" << clazz << "> " << clazz
<< "::associate(const ::ndk::SpAIBinder& binder) {\n";
out.Indent();
- out << "if (!AIBinder_associateClass(binder.get(), " << data_clazz
- << "::clazz)) { return nullptr; }\n";
+ out << "if (!AIBinder_associateClass(binder.get(), " << data_clazz << "::" << kClazz
+ << ")) { return nullptr; }\n";
out << "return (new " << clazz << "(binder))->ref<" << clazz << ">();\n";
out.Dedent();
out << "}\n\n";
@@ -422,12 +497,17 @@
out << clazz << "::~" << clazz << "() {}\n";
out << "\n";
for (const auto& method : defined_type.GetMethods()) {
- GenerateClientMethodDefinition(out, types, defined_type, *method);
+ if (method->IsUserDefined()) {
+ GenerateClientMethodDefinition(out, types, defined_type, *method);
+ } else {
+ GenerateClientMetaMethodDefinition(out, types, defined_type, *method, options);
+ }
}
}
-void GenerateServerSource(CodeWriter& out, const AidlTypenames& /*types*/,
- const AidlInterface& defined_type, const Options& /*options*/) {
+void GenerateServerSource(CodeWriter& out, const AidlTypenames& types,
+ const AidlInterface& defined_type, const Options& options) {
const std::string clazz = ClassName(defined_type, ClassNames::SERVER);
+ const std::string iface = ClassName(defined_type, ClassNames::INTERFACE);
const std::string data_clazz = DataClassFor(defined_type);
out << "// Source for " << clazz << "\n";
@@ -436,20 +516,35 @@
out << "::ndk::SpAIBinder " << clazz << "::createBinder() {\n";
out.Indent();
- out << "AIBinder* binder = AIBinder_new(" << data_clazz
- << "::clazz, static_cast<void*>(this));\n";
+ out << "AIBinder* binder = AIBinder_new(" << data_clazz << "::" << kClazz
+ << ", static_cast<void*>(this));\n";
out << "return ::ndk::SpAIBinder(binder);\n";
out.Dedent();
out << "}\n";
+
+ // Implement the meta methods
+ for (const auto& method : defined_type.GetMethods()) {
+ if (method->IsUserDefined()) {
+ continue;
+ }
+ if (method->GetName() == kGetInterfaceVersion && options.Version() > 0) {
+ out << NdkMethodDecl(types, *method, clazz) << " {\n";
+ out.Indent();
+ out << "*_aidl_return = " << iface << "::" << kVersion << ";\n";
+ out << "return ::ndk::ScopedAStatus(AStatus_newOk());\n";
+ out.Dedent();
+ out << "}\n";
+ }
+ }
}
-void GenerateInterfaceSource(CodeWriter& out, const AidlTypenames& /*types*/,
- const AidlInterface& defined_type, const Options& /*options*/) {
+void GenerateInterfaceSource(CodeWriter& out, const AidlTypenames& types,
+ const AidlInterface& defined_type, const Options& options) {
const std::string clazz = ClassName(defined_type, ClassNames::INTERFACE);
const std::string data_clazz = DataClassFor(defined_type);
out << "// Source for " << clazz << "\n";
- out << "const char* " << clazz << "::descriptor = \"" << defined_type.GetCanonicalName()
- << "\";\n";
+ out << "const char* " << clazz << "::" << kDescriptor << " = \""
+ << defined_type.GetCanonicalName() << "\";\n";
out << clazz << "::" << clazz << "() {}\n";
out << clazz << "::~" << clazz << "() {}\n";
out << "\n";
@@ -485,9 +580,70 @@
out << "return STATUS_OK;\n";
out.Dedent();
out << "}\n";
+
+ // defintion for static member setDefaultImpl
+ out << "bool " << clazz << "::setDefaultImpl(std::shared_ptr<" << clazz << "> impl) {\n";
+ out.Indent();
+ out << "if (!" << clazz << "::default_impl && impl) {\n";
+ out.Indent();
+ out << clazz << "::default_impl = impl;\n";
+ out << "return true;\n";
+ out.Dedent();
+ out << "}\n";
+ out << "return false;\n";
+ out.Dedent();
+ out << "}\n";
+
+ // definition for static member getDefaultImpl
+ out << "const std::shared_ptr<" << clazz << ">& " << clazz << "::getDefaultImpl() {\n";
+ out.Indent();
+ out << "return " << clazz << "::default_impl;\n";
+ out.Dedent();
+ out << "}\n";
+
+ // definition for the static field default_impl
+ out << "std::shared_ptr<" << clazz << "> " << clazz << "::default_impl = nullptr;\n";
+
+ // default implementation for the <Name>Default class members
+ const std::string defaultClazz = clazz + "Default";
+ for (const auto& method : defined_type.GetMethods()) {
+ if (method->IsUserDefined()) {
+ out << "::ndk::ScopedAStatus " << defaultClazz << "::" << method->GetName() << "("
+ << NdkArgList(types, *method, FormatArgNameUnused) << ") {\n";
+ out.Indent();
+ out << "::ndk::ScopedAStatus _aidl_status;\n";
+ out << "_aidl_status.set(AStatus_fromStatus(STATUS_UNKNOWN_TRANSACTION));\n";
+ out << "return _aidl_status;\n";
+ out.Dedent();
+ out << "}\n";
+ } else {
+ if (method->GetName() == kGetInterfaceVersion && options.Version() > 0) {
+ out << "::ndk::ScopedAStatus " << defaultClazz << "::" << method->GetName() << "("
+ << "int32_t* _aidl_return) {\n";
+ out.Indent();
+ out << "*_aidl_return = 0;\n";
+ out << "return ::ndk::ScopedAStatus(AStatus_newOk());\n";
+ out.Dedent();
+ out << "}\n";
+ }
+ }
+ }
+
+ out << "::ndk::SpAIBinder " << defaultClazz << "::asBinder() {\n";
+ out.Indent();
+ out << "return ::ndk::SpAIBinder();\n";
+ out.Dedent();
+ out << "}\n";
+
+ out << "bool " << defaultClazz << "::isRemote() {\n";
+ out.Indent();
+ out << "return false;\n";
+ out.Dedent();
+ out << "}\n";
}
+
void GenerateClientHeader(CodeWriter& out, const AidlTypenames& types,
- const AidlInterface& defined_type, const Options& /*options*/) {
+ const AidlInterface& defined_type, const Options& options) {
const std::string clazz = ClassName(defined_type, ClassNames::CLIENT);
out << "#pragma once\n\n";
@@ -511,13 +667,19 @@
out << "private:\n";
out.Indent();
out << clazz << "(const ::ndk::SpAIBinder& binder);\n";
+
+ if (options.Version() > 0) {
+ out << "int32_t cached_version_ = -1;\n";
+ }
+
out.Dedent();
out << "};\n";
LeaveNdkNamespace(out, defined_type);
}
-void GenerateServerHeader(CodeWriter& out, const AidlTypenames& /*types*/,
- const AidlInterface& defined_type, const Options& /*options*/) {
+void GenerateServerHeader(CodeWriter& out, const AidlTypenames& types,
+ const AidlInterface& defined_type, const Options& options) {
const std::string clazz = ClassName(defined_type, ClassNames::SERVER);
+ const std::string iface = ClassName(defined_type, ClassNames::INTERFACE);
out << "#pragma once\n\n";
out << "#include \"" << NdkHeaderFile(defined_type, ClassNames::INTERFACE, false /*use_os_sep*/)
@@ -526,12 +688,24 @@
out << "#include <android/binder_ibinder.h>\n";
out << "\n";
EnterNdkNamespace(out, defined_type);
- out << "class " << clazz << " : public ::ndk::BnCInterface<"
- << ClassName(defined_type, ClassNames::INTERFACE) << "> {\n";
+ out << "class " << clazz << " : public ::ndk::BnCInterface<" << iface << "> {\n";
out << "public:\n";
out.Indent();
out << clazz << "();\n";
out << "virtual ~" << clazz << "();\n";
+
+ // Declare the meta methods
+ for (const auto& method : defined_type.GetMethods()) {
+ if (method->IsUserDefined()) {
+ continue;
+ }
+ if (method->GetName() == kGetInterfaceVersion && options.Version() > 0) {
+ out << NdkMethodDecl(types, *method) << " final override;\n";
+ } else {
+ AIDL_FATAL(defined_type) << "Meta method '" << method->GetName() << "' is unimplemented.";
+ }
+ }
+
out.Dedent();
out << "protected:\n";
out.Indent();
@@ -544,7 +718,7 @@
LeaveNdkNamespace(out, defined_type);
}
void GenerateInterfaceHeader(CodeWriter& out, const AidlTypenames& types,
- const AidlInterface& defined_type, const Options& /*options*/) {
+ const AidlInterface& defined_type, const Options& options) {
const std::string clazz = ClassName(defined_type, ClassNames::INTERFACE);
out << "#pragma once\n\n";
@@ -558,12 +732,16 @@
out << "class " << clazz << " : public ::ndk::ICInterface {\n";
out << "public:\n";
out.Indent();
- out << "static AIBinder_Class* clazz;\n";
- out << "static const char* descriptor;\n";
+ out << "static AIBinder_Class* " << kClazz << ";\n";
+ out << "static const char* " << kDescriptor << ";\n";
out << clazz << "();\n";
out << "virtual ~" << clazz << "();\n";
out << "\n";
GenerateConstantDeclarations(out, defined_type);
+ if (options.Version() > 0) {
+ out << "static const int32_t " << kVersion << " = " << std::to_string(options.Version())
+ << ";\n";
+ }
out << "\n";
out << "static binder_status_t writeToParcel(AParcel* parcel, const std::shared_ptr<" << clazz
<< ">& instance);";
@@ -571,11 +749,37 @@
out << "static binder_status_t readFromParcel(const AParcel* parcel, std::shared_ptr<" << clazz
<< ">* instance);";
out << "\n";
+ out << "static bool setDefaultImpl(std::shared_ptr<" << clazz << "> impl);";
+ out << "\n";
+ out << "static const std::shared_ptr<" << clazz << ">& getDefaultImpl();";
+ out << "\n";
for (const auto& method : defined_type.GetMethods()) {
out << "virtual " << NdkMethodDecl(types, *method) << " = 0;\n";
}
out.Dedent();
+ out << "private:\n";
+ out.Indent();
+ out << "static std::shared_ptr<" << clazz << "> default_impl;\n";
+ out.Dedent();
out << "};\n";
+
+ const std::string defaultClazz = clazz + "Default";
+
+ out << "class " << defaultClazz << " : public " << clazz << " {\n";
+ out << "public:\n";
+ out.Indent();
+ for (const auto& method : defined_type.GetMethods()) {
+ if (method->IsUserDefined()) {
+ out << NdkMethodDecl(types, *method) << " override;\n";
+ } else if (method->GetName() == kGetInterfaceVersion && options.Version() > 0) {
+ out << NdkMethodDecl(types, *method) << " override;\n";
+ }
+ }
+ out << "::ndk::SpAIBinder asBinder() override;\n";
+ out << "bool isRemote() override;\n";
+ out.Dedent();
+ out << "};\n";
+
LeaveNdkNamespace(out, defined_type);
}
void GenerateParcelHeader(CodeWriter& out, const AidlTypenames& types,
@@ -620,8 +824,8 @@
GenerateSourceIncludes(out, types, defined_type);
out << "\n";
EnterNdkNamespace(out, defined_type);
- out << "const char* " << clazz << "::descriptor = \"" << defined_type.GetCanonicalName()
- << "\";\n";
+ out << "const char* " << clazz << "::" << kDescriptor << " = \""
+ << defined_type.GetCanonicalName() << "\";\n";
out << "\n";
out << "binder_status_t " << clazz << "::readFromParcel(const AParcel* parcel) {\n";
diff --git a/tests/test_data_example_interface.cpp b/tests/test_data_example_interface.cpp
index 8b324e4..b6cc349 100644
--- a/tests/test_data_example_interface.cpp
+++ b/tests/test_data_example_interface.cpp
@@ -2118,7 +2118,7 @@
)";
const char kExpectedJavaOutputWithVersion[] =
-R"(/*
+ R"(/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: android/test/IExampleInterface.aidl
*/
@@ -2272,6 +2272,8 @@
}
case TRANSACTION_getInterfaceVersion:
{
+ data.enforceInterface(descriptor);
+ reply.writeNoException();
reply.writeInt(getInterfaceVersion());
return true;
}
@@ -2509,6 +2511,7 @@
android.os.Parcel data = android.os.Parcel.obtain();
android.os.Parcel reply = android.os.Parcel.obtain();
try {
+ data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getInterfaceVersion, data, reply, 0);
mCachedVersion = reply.readInt();
} finally {
@@ -2609,7 +2612,7 @@
}
return true;
}
- static final int TRANSACTION_getInterfaceVersion = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1599489362);
+ static final int TRANSACTION_getInterfaceVersion = (android.os.IBinder.FIRST_CALL_TRANSACTION + 16777214);
public static boolean setDefaultImpl(android.test.IExampleInterface impl) {
if (Stub.Proxy.sDefaultImpl == null && impl != null) {
Stub.Proxy.sDefaultImpl = impl;
diff --git a/tests/test_data_ping_responder.cpp b/tests/test_data_ping_responder.cpp
index f6731cb..b2cc14f 100644
--- a/tests/test_data_ping_responder.cpp
+++ b/tests/test_data_ping_responder.cpp
@@ -686,10 +686,11 @@
}
int32_t BpPingResponder::getInterfaceVersion() {
- if (cached_version_ != -1) {
+ if (cached_version_ == -1) {
::android::Parcel data;
::android::Parcel reply;
- ::android::status_t err = remote()->transact(1599489362 /* getInterfaceVersion */, data, &reply);
+ data.writeInterfaceToken(getInterfaceDescriptor());
+ ::android::status_t err = remote()->transact(16777214 /* getInterfaceVersion */, data, &reply);
if (err == ::android::OK) {
cached_version_ = reply.readInt32();
}
@@ -814,8 +815,9 @@
}
}
break;
- case 1599489362 /* getInterfaceVersion */:
+ case 16777214 /* getInterfaceVersion */:
{
+ _aidl_data.checkInterface(this);
_aidl_reply->writeInt32(IPingResponder::VERSION);
}
break;
diff --git a/tests/test_data_string_constants.cpp b/tests/test_data_string_constants.cpp
index 79046f0..41155cc 100644
--- a/tests/test_data_string_constants.cpp
+++ b/tests/test_data_string_constants.cpp
@@ -224,7 +224,7 @@
)";
const char kExpectedJavaOutputWithVersion[] =
-R"(/*
+ R"(/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: android/os/IStringConstants.aidl
*/
@@ -290,6 +290,8 @@
}
case TRANSACTION_getInterfaceVersion:
{
+ data.enforceInterface(descriptor);
+ reply.writeNoException();
reply.writeInt(getInterfaceVersion());
return true;
}
@@ -321,6 +323,7 @@
android.os.Parcel data = android.os.Parcel.obtain();
android.os.Parcel reply = android.os.Parcel.obtain();
try {
+ data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getInterfaceVersion, data, reply, 0);
mCachedVersion = reply.readInt();
} finally {
@@ -332,7 +335,7 @@
}
public static android.os.IStringConstants sDefaultImpl;
}
- static final int TRANSACTION_getInterfaceVersion = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1599489362);
+ static final int TRANSACTION_getInterfaceVersion = (android.os.IBinder.FIRST_CALL_TRANSACTION + 16777214);
public static boolean setDefaultImpl(android.os.IStringConstants impl) {
if (Stub.Proxy.sDefaultImpl == null && impl != null) {
Stub.Proxy.sDefaultImpl = impl;
@@ -424,10 +427,11 @@
}
int32_t BpStringConstants::getInterfaceVersion() {
- if (cached_version_ != -1) {
+ if (cached_version_ == -1) {
::android::Parcel data;
::android::Parcel reply;
- ::android::status_t err = remote()->transact(1599489362 /* getInterfaceVersion */, data, &reply);
+ data.writeInterfaceToken(getInterfaceDescriptor());
+ ::android::status_t err = remote()->transact(16777214 /* getInterfaceVersion */, data, &reply);
if (err == ::android::OK) {
cached_version_ = reply.readInt32();
}
@@ -448,8 +452,9 @@
::android::status_t BnStringConstants::onTransact(uint32_t _aidl_code, const ::android::Parcel& _aidl_data, ::android::Parcel* _aidl_reply, uint32_t _aidl_flags) {
::android::status_t _aidl_ret_status = ::android::OK;
switch (_aidl_code) {
- case 1599489362 /* getInterfaceVersion */:
+ case 16777214 /* getInterfaceVersion */:
{
+ _aidl_data.checkInterface(this);
_aidl_reply->writeInt32(IStringConstants::VERSION);
}
break;