From 74b7bf1043d1905e6f999f7c47920319029453c0 Mon Sep 17 00:00:00 2001 From: Christopher Wiley Date: Fri, 19 Aug 2016 11:06:32 -0700 Subject: Write expected length of out arrays to parcel This makes generated C++ consistent with the Java. Unfortunately, C++ server authors still need to understand that if they resize inout/out arrays, this will cause runtime exceptions for Java clients, which cannot resize their array types. Addressing this is a much more invasive patch. Bug: 30836680 Change-Id: I996bfea8383d6207377e7bc545d3d39c21bbe033 Test: integration and unit tests continue to pass --- generate_cpp.cpp | 56 +++++++++++++++++++++++++++++++++-------------- generate_cpp_unittest.cpp | 8 +++++++ 2 files changed, 47 insertions(+), 17 deletions(-) diff --git a/generate_cpp.cpp b/generate_cpp.cpp index a8b2157..41e9fb4 100644 --- a/generate_cpp.cpp +++ b/generate_cpp.cpp @@ -279,20 +279,31 @@ unique_ptr DefineClientTransaction(const TypeNamespace& types, "getInterfaceDescriptor()"))); b->AddStatement(GotoErrorOnBadStatus()); - // Serialization looks roughly like: - // _aidl_ret_status = _aidl_data.WriteInt32(in_param_name); - // if (_aidl_ret_status != ::android::OK) { goto error; } - for (const AidlArgument* a : method.GetInArguments()) { + for (const auto& a: method.GetArguments()) { const Type* type = a->GetType().GetLanguageType(); - const string& method = type->WriteToParcelMethod(); - string var_name = ((a->IsOut()) ? "*" : "") + a->GetName(); var_name = type->WriteCast(var_name); - b->AddStatement(new Assignment( - kAndroidStatusVarName, - new MethodCall(StringPrintf("%s.%s", kDataVarName, method.c_str()), - ArgList(var_name)))); - b->AddStatement(GotoErrorOnBadStatus()); + + if (a->IsIn()) { + // Serialization looks roughly like: + // _aidl_ret_status = _aidl_data.WriteInt32(in_param_name); + // if (_aidl_ret_status != ::android::OK) { goto error; } + const string& method = type->WriteToParcelMethod(); + b->AddStatement(new Assignment( + kAndroidStatusVarName, + new MethodCall(StringPrintf("%s.%s", kDataVarName, method.c_str()), + ArgList(var_name)))); + b->AddStatement(GotoErrorOnBadStatus()); + } else if (a->IsOut() && a->GetType().IsArray()) { + // Special case, the length of the out array is written into the parcel. + // _aidl_ret_status = _aidl_data.writeVectorSize(&out_param_name); + // if (_aidl_ret_status != ::android::OK) { goto error; } + b->AddStatement(new Assignment( + kAndroidStatusVarName, + new MethodCall(StringPrintf("%s.writeVectorSize", kDataVarName), + ArgList(var_name)))); + b->AddStatement(GotoErrorOnBadStatus()); + } } // Invoke the transaction on the remote binder and confirm status. @@ -433,18 +444,29 @@ bool HandleServerTransaction(const TypeNamespace& types, interface_check->OnTrue()->AddLiteral("break"); // Deserialize each "in" parameter to the transaction. - for (const AidlArgument* a : method.GetInArguments()) { + for (const auto& a: method.GetArguments()) { // Deserialization looks roughly like: // _aidl_ret_status = _aidl_data.ReadInt32(&in_param_name); // if (_aidl_ret_status != ::android::OK) { break; } const Type* type = a->GetType().GetLanguageType(); const string& readMethod = type->ReadFromParcelMethod(); - b->AddStatement(new Assignment{ - kAndroidStatusVarName, - new MethodCall{string(kDataVarName) + "." + readMethod, - "&" + BuildVarName(*a)}}); - b->AddStatement(BreakOnStatusNotOk()); + if (a->IsIn()) { + b->AddStatement(new Assignment{ + kAndroidStatusVarName, + new MethodCall{string(kDataVarName) + "." + readMethod, + "&" + BuildVarName(*a)}}); + b->AddStatement(BreakOnStatusNotOk()); + } else if (a->IsOut() && a->GetType().IsArray()) { + // Special case, the length of the out array is written into the parcel. + // _aidl_ret_status = _aidl_data.resizeOutVector(&out_param_name); + // if (_aidl_ret_status != ::android::OK) { break; } + b->AddStatement(new Assignment{ + kAndroidStatusVarName, + new MethodCall{string(kDataVarName) + ".resizeOutVector", + "&" + BuildVarName(*a)}}); + b->AddStatement(BreakOnStatusNotOk()); + } } // Call the actual method. This is implemented by the subclass. diff --git a/generate_cpp_unittest.cpp b/generate_cpp_unittest.cpp index 6cdf835..50bfd9c 100644 --- a/generate_cpp_unittest.cpp +++ b/generate_cpp_unittest.cpp @@ -117,6 +117,10 @@ _aidl_ret_status = _aidl_data.writeDoubleVector(*goes_in_and_out); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } +_aidl_ret_status = _aidl_data.writeVectorSize(*goes_out); +if (((_aidl_ret_status) != (::android::OK))) { +goto _aidl_error; +} _aidl_ret_status = remote()->transact(IComplexTypeInterface::SEND, _aidl_data, &_aidl_reply); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; @@ -426,6 +430,10 @@ _aidl_ret_status = _aidl_data.readDoubleVector(&in_goes_in_and_out); if (((_aidl_ret_status) != (::android::OK))) { break; } +_aidl_ret_status = _aidl_data.resizeOutVector(&out_goes_out); +if (((_aidl_ret_status) != (::android::OK))) { +break; +} ::android::binder::Status _aidl_status(Send(in_goes_in, &in_goes_in_and_out, &out_goes_out, &_aidl_return)); _aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply); if (((_aidl_ret_status) != (::android::OK))) { -- cgit v1.2.3