Add support for List<String>
Bug: 24470786
Test: expanded unit tests pass, integration test passes
Change-Id: Ie85e43c04e214315f42a9f1ae83e6b4c67c2f081
diff --git a/generate_cpp_unittest.cpp b/generate_cpp_unittest.cpp
index f5518f5..af2fe23 100644
--- a/generate_cpp_unittest.cpp
+++ b/generate_cpp_unittest.cpp
@@ -43,6 +43,7 @@
int[] Send(in int[] goes_in, inout double[] goes_in_and_out, out boolean[] goes_out);
oneway void Piff(int times);
IFooType TakesABinder(IFooType f);
+ List<String> StringListMethod(in java.util.List<String> input, out List<String> output);
})";
const char kExpectedComplexTypeClientHeaderOutput[] =
@@ -65,6 +66,7 @@
android::status_t Send(const std::vector<int32_t>& goes_in, std::vector<double>* goes_in_and_out, std::vector<bool>* goes_out, std::vector<int32_t>* _aidl_return) override;
android::status_t Piff(int32_t times) override;
android::status_t TakesABinder(const android::sp<::foo::IFooType>& f, android::sp<::foo::IFooType>* _aidl_return) override;
+android::status_t StringListMethod(const std::vector<android::String16>& input, std::vector<android::String16>* output, std::vector<android::String16>* _aidl_return) override;
}; // class BpComplexTypeInterface
} // namespace os
@@ -170,6 +172,37 @@
return status;
}
+android::status_t BpComplexTypeInterface::StringListMethod(const std::vector<android::String16>& input, std::vector<android::String16>* output, std::vector<android::String16>* _aidl_return) {
+android::Parcel data;
+android::Parcel reply;
+android::status_t status;
+status = data.writeInterfaceToken(getInterfaceDescriptor());
+if (((status) != (android::OK))) {
+return status;
+}
+status = data.writeString16Vector(input);
+if (((status) != (android::OK))) {
+return status;
+}
+status = remote()->transact(IComplexTypeInterface::STRINGLISTMETHOD, data, &reply);
+if (((status) != (android::OK))) {
+return status;
+}
+if (reply.readExceptionCode()) {
+status = android::FAILED_TRANSACTION;
+return status;
+}
+status = reply.readString16Vector(_aidl_return);
+if (((status) != (android::OK))) {
+return status;
+}
+status = reply.readString16Vector(output);
+if (((status) != (android::OK))) {
+return status;
+}
+return status;
+}
+
} // namespace os
} // namespace android
@@ -295,6 +328,37 @@
}
}
break;
+case Call::STRINGLISTMETHOD:
+{
+std::vector<android::String16> in_input;
+std::vector<android::String16> out_output;
+std::vector<android::String16> _aidl_return;
+if ((!data.checkInterface(this))) {
+status = android::BAD_TYPE;
+break;
+}
+status = data.readString16Vector(&in_input);
+if (((status) != (android::OK))) {
+break;
+}
+status = StringListMethod(in_input, &out_output, &_aidl_return);
+if (((status) != (android::OK))) {
+break;
+}
+status = reply->writeNoException();
+if (((status) != (android::OK))) {
+break;
+}
+status = reply->writeString16Vector(_aidl_return);
+if (((status) != (android::OK))) {
+break;
+}
+status = reply->writeString16Vector(out_output);
+if (((status) != (android::OK))) {
+break;
+}
+}
+break;
default:
{
status = android::BBinder::onTransact(code, data, reply, flags);
@@ -317,6 +381,7 @@
#include <binder/IInterface.h>
#include <cstdint>
#include <foo/IFooType.h>
+#include <utils/String16.h>
#include <utils/StrongPointer.h>
#include <vector>
@@ -330,10 +395,12 @@
virtual android::status_t Send(const std::vector<int32_t>& goes_in, std::vector<double>* goes_in_and_out, std::vector<bool>* goes_out, std::vector<int32_t>* _aidl_return) = 0;
virtual android::status_t Piff(int32_t times) = 0;
virtual android::status_t TakesABinder(const android::sp<::foo::IFooType>& f, android::sp<::foo::IFooType>* _aidl_return) = 0;
+virtual android::status_t StringListMethod(const std::vector<android::String16>& input, std::vector<android::String16>* output, std::vector<android::String16>* _aidl_return) = 0;
enum Call {
SEND = android::IBinder::FIRST_CALL_TRANSACTION + 0,
PIFF = android::IBinder::FIRST_CALL_TRANSACTION + 1,
TAKESABINDER = android::IBinder::FIRST_CALL_TRANSACTION + 2,
+ STRINGLISTMETHOD = android::IBinder::FIRST_CALL_TRANSACTION + 3,
};
}; // class IComplexTypeInterface
diff --git a/tests/aidl_test_client.cpp b/tests/aidl_test_client.cpp
index b5f800c..23ca80d 100644
--- a/tests/aidl_test_client.cpp
+++ b/tests/aidl_test_client.cpp
@@ -153,6 +153,16 @@
return true;
}
+bool ConfirmReverseLists(const sp<ITestService>& s) {
+ cout << "Confirming passing and returning List<T> works." << endl;
+
+ if (!ReverseArray(s, &ITestService::ReverseStringList,
+ {String16{"f"}, String16{"a"}, String16{"b"}})) {
+ return false;
+ }
+
+ return true;
+}
} // namespace
int main(int /* argc */, char * /* argv */ []) {
@@ -164,5 +174,7 @@
if (!ConfirmReverseArrays(service)) return 1;
+ if (!ConfirmReverseLists(service)) return 1;
+
return 0;
}
diff --git a/tests/aidl_test_service.cpp b/tests/aidl_test_service.cpp
index 0e8a260..ca21b5d 100644
--- a/tests/aidl_test_service.cpp
+++ b/tests/aidl_test_service.cpp
@@ -252,6 +252,12 @@
return err;
}
+ status_t ReverseStringList(const vector<String16>& input,
+ vector<String16>* repeated,
+ vector<String16>* _aidl_return) override {
+ return ReverseArray(input, repeated, _aidl_return);
+ }
+
private:
map<String16, sp<INamedCallback>> service_map_;
};
diff --git a/tests/android/aidl/tests/ITestService.aidl b/tests/android/aidl/tests/ITestService.aidl
index bb992ac..5793139 100644
--- a/tests/android/aidl/tests/ITestService.aidl
+++ b/tests/android/aidl/tests/ITestService.aidl
@@ -39,6 +39,11 @@
double[] ReverseDouble (in double[] input, out double[] repeated);
String[] ReverseString (in String[] input, out String[] repeated);
+ // Test that clients can send and receive Binders.
INamedCallback GetOtherTestService(String name);
boolean VerifyName(INamedCallback service, String name);
+
+ // Test that List<T> types work correctly.
+ List<String> ReverseStringList(in List<String> input,
+ out List<String> repeated);
}
diff --git a/tests/java_app/src/android/aidl/tests/TestServiceClient.java b/tests/java_app/src/android/aidl/tests/TestServiceClient.java
index 2aad221..6388aed 100644
--- a/tests/java_app/src/android/aidl/tests/TestServiceClient.java
+++ b/tests/java_app/src/android/aidl/tests/TestServiceClient.java
@@ -28,6 +28,9 @@
import java.io.PrintWriter;
import java.io.FileOutputStream;
import java.util.Arrays;
+import java.util.List;
+import java.util.Collections;
+import java.util.ArrayList;
// Generated
import android.aidl.tests.ITestService;
@@ -366,6 +369,29 @@
mLog.log("...Exchange of binders works");
}
+ private void checkListReversal(ITestService service)
+ throws TestFailException {
+ mLog.log("Checking that service can reverse and return lists...");
+ try {
+ {
+ List<String> input = Arrays.asList("Walk", "into", "Córdoba");
+ List<String> echoed = new ArrayList<String>();
+ List<String> reversed = service.ReverseStringList(input, echoed);
+ if (!input.equals(echoed)) {
+ mLog.logAndThrow("Failed to echo input List<String> back.");
+ }
+ Collections.reverse(input);
+ if (!input.equals(reversed)) {
+ mLog.logAndThrow("Reversed list is not correct.");
+ }
+ }
+ } catch (RemoteException ex) {
+ mLog.log(ex.toString());
+ mLog.logAndThrow("Service failed to reverse an List<String>.");
+ }
+ mLog.log("...service can reverse and return lists.");
+ }
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
diff --git a/type_cpp.cpp b/type_cpp.cpp
index 0cf4767..06bcf2a 100644
--- a/type_cpp.cpp
+++ b/type_cpp.cpp
@@ -110,6 +110,28 @@
}
};
+class StringListType : public Type {
+ public:
+ StringListType()
+ : Type(ValidatableType::KIND_BUILT_IN, "java.util", "List<String>",
+ "utils/String16.h", "std::vector<android::String16>",
+ "readString16Vector", "writeString16Vector") {}
+ virtual ~StringListType() = default;
+ bool CanBeOutParameter() const override { return true; }
+
+ void GetHeaders(bool is_array, set<string>* headers) const {
+ if (is_array) {
+ LOG(FATAL) << "Type checking did not catch that List<String> "
+ "was marked as array";
+ }
+ Type::GetHeaders(is_array, headers);
+ headers->insert("vector");
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(StringListType);
+}; // class StringListType
+
} // namespace
Type::Type(int kind,
@@ -133,7 +155,6 @@
parcel_write_array_method_(write_array_method) {}
bool Type::CanBeArray() const { return ! parcel_read_array_method_.empty(); }
-bool Type::CanBeOutParameter() const { return false; }
bool Type::CanWriteToParcel() const { return true; }
void Type::GetHeaders(bool is_array, set<string>* headers) const {
if (!header_.empty()) {
@@ -199,10 +220,11 @@
kNoHeader, "char16_t", "readChar", "writeChar",
"readCharVector", "writeCharVector"));
- Add(new Type(ValidatableType::KIND_BUILT_IN, kNoPackage, "String",
- "utils/String16.h", "android::String16",
- "readString16", "writeString16", "readString16Vector",
- "writeString16Vector"));
+ string_type_ = new Type(ValidatableType::KIND_BUILT_IN, kNoPackage, "String",
+ "utils/String16.h", "android::String16",
+ "readString16", "writeString16",
+ "readString16Vector", "writeString16Vector");
+ Add(string_type_);
void_type_ = new class VoidType();
Add(void_type_);
@@ -221,9 +243,28 @@
return true;
}
-bool TypeNamespace::AddListType(const std::string& /* type_name */) {
- // TODO Support list types b/24470786
- LOG(ERROR) << "Passing lists is unimplemented in C++ generation.";
+bool TypeNamespace::AddListType(const std::string& type_name) {
+ const Type* contained_type = Find(type_name);
+ if (!contained_type) {
+ LOG(ERROR) << "Cannot create List<" << type_name << "> because contained "
+ "type cannot be found or is invalid.";
+ return false;
+ }
+ if (contained_type->IsCppPrimitive()) {
+ LOG(ERROR) << "Cannot create List<" << type_name << "> because contained "
+ "type is a primitive in Java and Java List cannot hold "
+ "primitives.";
+ return false;
+ }
+
+ if (contained_type == StringType()) {
+ Add(new StringListType());
+ return true;
+ }
+ // TODO Support lists of parcelables b/23600712
+ // TODO Support lists of binders b/24470875
+
+ LOG(ERROR) << "aidl-cpp does not yet support List<" << type_name << ">";
return false;
}
diff --git a/type_cpp.h b/type_cpp.h
index 98eb211..4226f9f 100644
--- a/type_cpp.h
+++ b/type_cpp.h
@@ -47,7 +47,7 @@
// overrides of ValidatableType
bool CanBeArray() const override;
- bool CanBeOutParameter() const override;
+ bool CanBeOutParameter() const override { return false; }
bool CanWriteToParcel() const override;
std::string CppType(bool is_array) const;
@@ -84,7 +84,6 @@
DISALLOW_COPY_AND_ASSIGN(PrimitiveType);
}; // class PrimitiveType
-
class TypeNamespace : public ::android::aidl::LanguageTypeNamespace<Type> {
public:
TypeNamespace() = default;
@@ -105,9 +104,11 @@
const std::string& filename) const override;
const Type* VoidType() const { return void_type_; }
+ const Type* StringType() const { return string_type_; }
private:
Type* void_type_ = nullptr;
+ Type* string_type_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(TypeNamespace);
}; // class TypeNamespace
diff --git a/type_cpp_unittest.cpp b/type_cpp_unittest.cpp
index d4232a0..ae5ffc8 100644
--- a/type_cpp_unittest.cpp
+++ b/type_cpp_unittest.cpp
@@ -43,6 +43,12 @@
EXPECT_NE(types_.Find("String"), nullptr);
}
+TEST_F(CppTypeNamespaceTest, SupportsListString) {
+ EXPECT_EQ(types_.Find("List<String>"), nullptr);
+ EXPECT_TRUE(types_.AddListType("String"));
+ EXPECT_NE(types_.Find("List<String>"), nullptr);
+}
+
} // namespace cpp
} // namespace android
} // namespace aidl