gen_log: prints parcelable/union/enum types
User defined types are printed using toString().
Bug: 161439795
Test: aidl_integration_test
Change-Id: I10fbac5f268d19791899129e339dd7c64638be99
diff --git a/Android.bp b/Android.bp
index dd88a5d..df214b8 100644
--- a/Android.bp
+++ b/Android.bp
@@ -394,6 +394,9 @@
local_include_dir: "tests",
srcs: [
"tests/android/aidl/loggable/ILoggableInterface.aidl",
+ "tests/android/aidl/loggable/Data.aidl",
+ "tests/android/aidl/loggable/Enum.aidl",
+ "tests/android/aidl/loggable/Union.aidl",
],
gen_trace: true,
backend: {
diff --git a/aidl_to_cpp_common.cpp b/aidl_to_cpp_common.cpp
index 58dafdb..5e0ef1f 100644
--- a/aidl_to_cpp_common.cpp
+++ b/aidl_to_cpp_common.cpp
@@ -32,13 +32,16 @@
namespace aidl {
namespace cpp {
-namespace {
-constexpr char kToStringHelper[] =
- R"(template <typename _T, ::std::enable_if_t<::std::is_same_v<::std::string, decltype(std::declval<_T>().toString())>, int> = 0>
-static inline ::std::string _call_toString(const _T& _t) { return _t.toString(); }
-static inline ::std::string _call_toString(...) { return "{no toString() implemented}"; }
-)";
+char kToStringHelper[] = R"(template <typename _T> class _has_toString {
+ template <typename _U> static std::true_type __has_toString(decltype(&_U::toString));
+ template <typename _U> static std::false_type __has_toString(...);
+ public: enum { value = decltype(__has_toString<_T>(nullptr))::value };
+};
+template <typename _T> inline static std::string _call_toString(const _T& t) {
+ if constexpr (_has_toString<_T>::value) return t.toString();
+ return "{no toString() implemented}";
}
+)";
string ClassName(const AidlDefinedType& defined_type, ClassNames type) {
string base_name = defined_type.GetName();
@@ -198,7 +201,9 @@
// function that writes an expression to convert a variable to a Json::Value
// object
- std::function<void(CodeWriter& w, const string& var_name, bool isNdk)> toJsonValueExpr;
+ std::function<void(CodeWriter& w, const AidlTypeSpecifier& type, const string& var_name,
+ bool isNdk)>
+ toJsonValueExpr;
};
const static std::unordered_map<std::string, TypeInfo> kTypeInfoMap = {
@@ -206,21 +211,21 @@
{"boolean",
{
"bool",
- [](CodeWriter& c, const string& var_name, bool) {
+ [](CodeWriter& c, const AidlTypeSpecifier&, const string& var_name, bool) {
c << "Json::Value(" << var_name << "? \"true\" : \"false\")";
},
}},
{"byte",
{
"int8_t",
- [](CodeWriter& c, const string& var_name, bool) {
+ [](CodeWriter& c, const AidlTypeSpecifier&, const string& var_name, bool) {
c << "Json::Value(" << var_name << ")";
},
}},
{"char",
{
"char16_t",
- [](CodeWriter& c, const string& var_name, bool isNdk) {
+ [](CodeWriter& c, const AidlTypeSpecifier&, const string& var_name, bool isNdk) {
if (isNdk) {
c << "Json::Value(" << var_name << ")";
} else {
@@ -231,54 +236,68 @@
{"int",
{
"int32_t",
- [](CodeWriter& c, const string& var_name, bool) {
+ [](CodeWriter& c, const AidlTypeSpecifier&, const string& var_name, bool) {
c << "Json::Value(" << var_name << ")";
},
}},
{"long",
{
"int64_t",
- [](CodeWriter& c, const string& var_name, bool) {
+ [](CodeWriter& c, const AidlTypeSpecifier&, const string& var_name, bool) {
c << "Json::Value(static_cast<Json::Int64>(" << var_name << "))";
},
}},
{"float",
{
"float",
- [](CodeWriter& c, const string& var_name, bool) {
+ [](CodeWriter& c, const AidlTypeSpecifier&, const string& var_name, bool) {
c << "Json::Value(" << var_name << ")";
},
}},
{"double",
{
"double",
- [](CodeWriter& c, const string& var_name, bool) {
+ [](CodeWriter& c, const AidlTypeSpecifier&, const string& var_name, bool) {
c << "Json::Value(" << var_name << ")";
},
}},
{"String",
{
"std::string",
- [](CodeWriter& c, const string& var_name, bool) {
+ [](CodeWriter& c, const AidlTypeSpecifier&, const string& var_name, bool) {
c << "Json::Value(" << var_name << ")";
},
}}
// missing List, Map, ParcelFileDescriptor, IBinder
};
+const static TypeInfo kTypeInfoForDefinedType{
+ "<<parcelable>>", // pseudo-name for parcelable types
+ [](CodeWriter& c, const AidlTypeSpecifier& type, const string& var_name, bool) {
+ c << ToString(type, var_name);
+ }};
+
TypeInfo GetTypeInfo(const AidlTypeSpecifier& aidl) {
AIDL_FATAL_IF(!aidl.IsResolved(), aidl) << aidl.ToString();
const string& aidl_name = aidl.GetName();
- TypeInfo info;
if (AidlTypenames::IsBuiltinTypename(aidl_name)) {
auto it = kTypeInfoMap.find(aidl_name);
if (it != kTypeInfoMap.end()) {
- info = it->second;
+ return it->second;
}
+ return {};
}
- // Missing interface and parcelable type
- return info;
+
+ const AidlDefinedType* defined_type = aidl.GetDefinedType();
+ AIDL_FATAL_IF(defined_type == NULL, aidl) << aidl.ToString();
+ if (defined_type->AsStructuredParcelable() || defined_type->AsEnumDeclaration() ||
+ defined_type->AsUnionDeclaration()) {
+ return kTypeInfoForDefinedType;
+ }
+
+ // skip interface types
+ return {};
}
inline bool CanWriteLog(const TypeInfo& t) {
@@ -298,13 +317,14 @@
const string var_object_expr = ((isPointer ? "*" : "")) + name;
if (type.IsArray()) {
+ const AidlTypeSpecifier& base_type = type.ArrayBase();
writer << log << " = Json::Value(Json::arrayValue);\n";
writer << "for (const auto& v: " << var_object_expr << ") " << log << ".append(";
- info.toJsonValueExpr(writer, "v", isNdk);
+ info.toJsonValueExpr(writer, base_type, "v", isNdk);
writer << ");";
} else {
writer << log << " = ";
- info.toJsonValueExpr(writer, var_object_expr, isNdk);
+ info.toJsonValueExpr(writer, type, var_object_expr, isNdk);
writer << ";";
}
writer << "\n";
diff --git a/aidl_to_cpp_common.h b/aidl_to_cpp_common.h
index d11b067..2b2db4a 100644
--- a/aidl_to_cpp_common.h
+++ b/aidl_to_cpp_common.h
@@ -29,6 +29,9 @@
namespace aidl {
namespace cpp {
+// provides _call_toString(expr) which call expr.toString() if possible
+extern char kToStringHelper[];
+
// These roughly correspond to the various class names in the C++ hierarchy:
enum class ClassNames {
BASE, // Foo (not a real class, but useful in some circumstances).
diff --git a/aidl_unittest.cpp b/aidl_unittest.cpp
index df29b8c..6c4b2f0 100644
--- a/aidl_unittest.cpp
+++ b/aidl_unittest.cpp
@@ -3065,9 +3065,15 @@
static const std::string DESCIPTOR = "a.Foo";
return DESCIPTOR;
}
- template <typename _T, ::std::enable_if_t<::std::is_same_v<::std::string, decltype(std::declval<_T>().toString())>, int> = 0>
- static inline ::std::string _call_toString(const _T& _t) { return _t.toString(); }
- static inline ::std::string _call_toString(...) { return "{no toString() implemented}"; }
+ template <typename _T> class _has_toString {
+ template <typename _U> static std::true_type __has_toString(decltype(&_U::toString));
+ template <typename _U> static std::false_type __has_toString(...);
+ public: enum { value = decltype(__has_toString<_T>(nullptr))::value };
+ };
+ template <typename _T> inline static std::string _call_toString(const _T& t) {
+ if constexpr (_has_toString<_T>::value) return t.toString();
+ return "{no toString() implemented}";
+ }
inline std::string toString() const {
std::ostringstream os;
os << "Foo{";
@@ -3211,9 +3217,15 @@
binder_status_t readFromParcel(const AParcel* _parcel);
binder_status_t writeToParcel(AParcel* _parcel) const;
static const ::ndk::parcelable_stability_t _aidl_stability = ::ndk::STABILITY_LOCAL;
- template <typename _T, ::std::enable_if_t<::std::is_same_v<::std::string, decltype(std::declval<_T>().toString())>, int> = 0>
- static inline ::std::string _call_toString(const _T& _t) { return _t.toString(); }
- static inline ::std::string _call_toString(...) { return "{no toString() implemented}"; }
+ template <typename _T> class _has_toString {
+ template <typename _U> static std::true_type __has_toString(decltype(&_U::toString));
+ template <typename _U> static std::false_type __has_toString(...);
+ public: enum { value = decltype(__has_toString<_T>(nullptr))::value };
+ };
+ template <typename _T> inline static std::string _call_toString(const _T& t) {
+ if constexpr (_has_toString<_T>::value) return t.toString();
+ return "{no toString() implemented}";
+ }
inline std::string toString() const {
std::ostringstream os;
os << "Foo{";
diff --git a/generate_cpp.cpp b/generate_cpp.cpp
index 770c3c7..7784a97 100644
--- a/generate_cpp.cpp
+++ b/generate_cpp.cpp
@@ -815,6 +815,8 @@
ConstructorDecl::IS_VIRTUAL | ConstructorDecl::IS_DEFAULT}};
vector<unique_ptr<Declaration>> publics;
+ vector<unique_ptr<Declaration>> privates;
+
publics.push_back(std::move(constructor));
publics.push_back(std::move(destructor));
@@ -832,10 +834,9 @@
includes.emplace_back("json/value.h");
publics.emplace_back(
new LiteralDecl{"static std::function<void(const Json::Value&)> logFunc;\n"});
+ privates.emplace_back(new LiteralDecl{kToStringHelper});
}
- vector<unique_ptr<Declaration>> privates;
-
if (options.Version() > 0) {
privates.emplace_back(new LiteralDecl("int32_t cached_version_ = -1;\n"));
}
@@ -876,6 +877,8 @@
vector<string> includes = {"binder/IInterface.h", HeaderFile(interface, ClassNames::RAW, false)};
vector<unique_ptr<Declaration>> publics;
+ vector<unique_ptr<Declaration>> privates;
+
publics.push_back(std::move(constructor));
publics.push_back(std::move(on_transact));
@@ -896,9 +899,13 @@
includes.emplace_back("json/value.h");
publics.emplace_back(
new LiteralDecl{"static std::function<void(const Json::Value&)> logFunc;\n"});
+ privates.emplace_back(new LiteralDecl{kToStringHelper});
}
- unique_ptr<ClassDecl> bn_class{
- new ClassDecl{bn_name, "::android::BnInterface<" + i_name + ">", {}, std::move(publics), {}}};
+ unique_ptr<ClassDecl> bn_class{new ClassDecl{bn_name,
+ "::android::BnInterface<" + i_name + ">",
+ {},
+ std::move(publics),
+ std::move(privates)}};
return unique_ptr<Document>{
new CppHeader{includes, NestInNamespaces(std::move(bn_class), interface.GetSplitPackage())}};
diff --git a/generate_ndk.cpp b/generate_ndk.cpp
index 717f60c..8ef2a67 100644
--- a/generate_ndk.cpp
+++ b/generate_ndk.cpp
@@ -365,6 +365,9 @@
out << "\n";
EnterNdkNamespace(out, defined_type);
+ if (options.GenLog()) {
+ out << cpp::kToStringHelper;
+ }
GenerateClassSource(out, types, defined_type, options);
GenerateClientSource(out, types, defined_type, options);
GenerateServerSource(out, types, defined_type, options);
diff --git a/tests/aidl_test_client_loggable_interface.cpp b/tests/aidl_test_client_loggable_interface.cpp
index ba99d4c..50202dd 100644
--- a/tests/aidl_test_client_loggable_interface.cpp
+++ b/tests/aidl_test_client_loggable_interface.cpp
@@ -29,7 +29,10 @@
using android::sp;
using android::String16;
using android::aidl::loggable::BpLoggableInterface;
+using android::aidl::loggable::Data;
+using android::aidl::loggable::Enum;
using android::aidl::loggable::ILoggableInterface;
+using android::aidl::loggable::Union;
using android::aidl::tests::BackendType;
using android::os::ParcelFileDescriptor;
using std::optional;
@@ -71,6 +74,11 @@
String16 stringValue("def");
vector<String16> stringArray{String16("ghi"), String16("jkl")};
vector<String16> listValue{String16("mno")};
+ Data dataValue;
+ dataValue.num = 42;
+ dataValue.str = "abc";
+ dataValue.nestedUnion = "def";
+ dataValue.nestedEnum = Enum::FOO;
sp<IBinder> binderValue;
optional<ParcelFileDescriptor> pfdValue;
vector<ParcelFileDescriptor> pfdArray;
@@ -79,7 +87,7 @@
status = loggable->LogThis(boolValue, &boolArray, byteValue, &byteArray, charValue, &charArray,
intValue, &intArray, longValue, &longArray, floatValue, &floatArray,
doubleValue, &doubleArray, stringValue, &stringArray, &listValue,
- binderValue, &pfdValue, &pfdArray, &_aidl_return);
+ dataValue, binderValue, &pfdValue, &pfdArray, &_aidl_return);
EXPECT_TRUE(status.isOk());
EXPECT_EQ(vector<String16>{String16("loggable")}, _aidl_return);
@@ -155,6 +163,10 @@
{
"name" : "stringArray",
"value" : [ true, true ]
+ },
+ {
+ "name" : "dataValue",
+ "value" : "Data{num: 42, str: abc, nestedUnion: Union{str: def}, nestedEnum: FOO}"
}
],
"interface_name" : "android.aidl.loggable.ILoggableInterface",
diff --git a/tests/aidl_test_service.cpp b/tests/aidl_test_service.cpp
index 0b1674e..26a9718 100644
--- a/tests/aidl_test_service.cpp
+++ b/tests/aidl_test_service.cpp
@@ -55,6 +55,7 @@
#include "android/aidl/tests/extension/MyExt2.h"
#include "android/aidl/loggable/BnLoggableInterface.h"
+#include "android/aidl/loggable/Data.h"
// Used implicitly.
#undef LOG_TAG
@@ -636,9 +637,9 @@
virtual Status LogThis(bool, vector<bool>*, int8_t, vector<uint8_t>*, char16_t, vector<char16_t>*,
int32_t, vector<int32_t>*, int64_t, vector<int64_t>*, float,
vector<float>*, double, vector<double>*, const String16&,
- vector<String16>*, vector<String16>*, const sp<IBinder>&,
- optional<ParcelFileDescriptor>*, vector<ParcelFileDescriptor>*,
- vector<String16>* _aidl_return) override {
+ vector<String16>*, vector<String16>*, const android::aidl::loggable::Data&,
+ const sp<IBinder>&, optional<ParcelFileDescriptor>*,
+ vector<ParcelFileDescriptor>*, vector<String16>* _aidl_return) override {
*_aidl_return = vector<String16>{String16("loggable")};
return Status::ok();
}
diff --git a/tests/android/aidl/loggable/Data.aidl b/tests/android/aidl/loggable/Data.aidl
new file mode 100644
index 0000000..cd7f4ae
--- /dev/null
+++ b/tests/android/aidl/loggable/Data.aidl
@@ -0,0 +1,11 @@
+package android.aidl.loggable;
+
+import android.aidl.loggable.Enum;
+import android.aidl.loggable.Union;
+
+parcelable Data {
+ int num;
+ @utf8InCpp String str;
+ Union nestedUnion;
+ Enum nestedEnum;
+}
\ No newline at end of file
diff --git a/tests/android/aidl/loggable/Enum.aidl b/tests/android/aidl/loggable/Enum.aidl
new file mode 100644
index 0000000..bb6a180
--- /dev/null
+++ b/tests/android/aidl/loggable/Enum.aidl
@@ -0,0 +1,3 @@
+package android.aidl.loggable;
+
+enum Enum { FOO = 42 }
\ No newline at end of file
diff --git a/tests/android/aidl/loggable/ILoggableInterface.aidl b/tests/android/aidl/loggable/ILoggableInterface.aidl
index 8944fb0..a19efc1 100644
--- a/tests/android/aidl/loggable/ILoggableInterface.aidl
+++ b/tests/android/aidl/loggable/ILoggableInterface.aidl
@@ -1,4 +1,5 @@
package android.aidl.loggable;
+import android.aidl.loggable.Data;
interface ILoggableInterface {
String[] LogThis(boolean boolValue, inout boolean[] boolArray,
@@ -10,6 +11,7 @@
double doubleValue, inout double[] doubleArray,
String stringValue, inout String[] stringArray,
inout List<String> listValue,
+ in Data dataValue,
@nullable IBinder binderValue,
inout @nullable ParcelFileDescriptor pfdValue, inout ParcelFileDescriptor[] pfdArray);
}
diff --git a/tests/android/aidl/loggable/Union.aidl b/tests/android/aidl/loggable/Union.aidl
new file mode 100644
index 0000000..4e116ae
--- /dev/null
+++ b/tests/android/aidl/loggable/Union.aidl
@@ -0,0 +1,6 @@
+package android.aidl.loggable;
+
+union Union {
+ int num = 43;
+ @utf8InCpp String str;
+}
\ No newline at end of file