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
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 @@
                      "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<Type>();
-    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 @@
   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<Type>();
     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.