Skip to content

Commit 9cfa5f3

Browse files
authored
[Xamarin..Android.Tools.Aidl] inout+inout array Parameters (#5726)
Fixes: #4717 Fixes: #5079 Context: https://cs.android.com/android/platform/superproject/+/af1f0005723416a36e025fded7eccb2fd8c777de:system/tools/aidl/generate_java_binder.cpp;l=358 Context: https://cs.android.com/android/platform/superproject/+/af1f0005723416a36e025fded7eccb2fd8c777de:system/tools/aidl/generate_java_binder.cpp;l=486 Context: https://cs.android.com/android/platform/superproject/+/af1f0005723416a36e025fded7eccb2fd8c777de:system/tools/aidl/generate_java_binder.cpp;l=646 `Xamarin.Android.Tools.Aidl.CSharpCodeGenerator` did not properly support `inout` or `out` parameter marshaling of array types. For `inout` arrays: // AIDL interface Test { void inoutArray (inout byte [] args); } the emitted `OnTransact()` method needs to write the "output" value to the `reply` parameter, *not* the `data` parameter: // generated C# public interface ITest : Android.OS.IInterface { void InoutArray (byte[] args) } abstract partial class ITestStub : Binder, ITest { protected override bool OnTransact (int code, Parcel data, Parcel reply, int flags) { switch (code) { case TransactionInoutArray: { data.EnforceInterface (descriptor); byte [] arg0 = default (byte []); arg0 = data.CreateStringArray (); this.InoutArray (arg0); reply.WriteNoException (); data.WriteByteArray (arg0); // SHOULD USE `reply`, not `data`! return true; } } } } Similar-yet-more-so, with `out` array parameters: // AIDL interface Test { void outArray (out byte [] args); } the `OnTransact()` method *also* needs to support `args` being `null`: // generated C# public interface ITest : global::Android.OS.IInterface { void OutArray (byte[] args) } abstract partial class ITestStub : Binder, ITest { protected override bool OnTransact (int code, Parcel data, Parcel reply, int flags) { switch (code) { case TransactionOutArray: { data.EnforceInterface (descriptor); byte [] arg0 = default (byte []); int arg0_length = data.ReadInt(); // NEEDED if (arg0_length < 0) { // NEEDED arg0 = null; // NEEDED } // NEEDED else { // NEEDED arg0 = new byte [arg0_length]; // NEEDED } // NEEDED this.OutArray (arg0); reply.WriteNoException (); reply.WriteByteArray (arg0); // PREVIOUSLY used data, not reply! return true; } } } } *Plus* the `Proxy` implementation needs to support `null`: partial class ITestStub { public class Proxy : Java.Lang.Object, ITest { public void OutArray (byte[] args) { var __data = Parcel.Obtain (); var __reply = Parcel.Obtain (); try { __data.WriteInterfaceToken (descriptor); if (args == null) { // NEEDED __data.WriteInt (-1); // NEEDED } else { // NEEDED __data.WriteInt(args.Length); // NEEDED } // NEEDED remote.Transact (ITestStub.TransactionOutArray, __data, __reply, 0); … } } } This is comparable to the Java code the Android Studio produces.
1 parent cc3d123 commit 9cfa5f3

File tree

7 files changed

+295
-758
lines changed

7 files changed

+295
-758
lines changed

src/Xamarin.Android.Tools.Aidl/CSharpCodeGenerator.cs

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,20 @@ protected override bool OnTransact (int code, global::Android.OS.Parcel data, gl
277277
w.WriteLine ("\t\t\t\t{0} {1} = default ({0});", ToOutputTypeName (name_cache.ToCSharp (a.Type)), "arg" + i);
278278
if (a.Modifier == null || a.Modifier.Contains ("in"))
279279
w.WriteLine ("\t\t\t\t{0}", GetCreateStatements (a.Type, "data", "arg" + i));
280+
else if (a.Modifier != null && a.Modifier.Contains ("out")) {
281+
if (a.Type.ArrayDimension > 0) {
282+
w.WriteLine (@" int {0}_length = data.ReadInt();
283+
if ({0}_length < 0) {{
284+
{0} = null;
285+
}}
286+
else {{
287+
{0} = new {1}[{0}_length];
288+
}}", "arg" + i, ToOutputTypeName (name_cache.ToCSharp (a.Type)).Replace ("[]", ""));
289+
}
290+
else {
291+
w.WriteLine ("\t\t\t\t{0} = new {1}();", "arg" + i, ToOutputTypeName (name_cache.ToCSharp (a.Type)));
292+
}
293+
}
280294
}
281295
string args = String.Join (", ", (from i in Enumerable.Range (0, method.Arguments.Length) select "arg" + i).ToArray ());
282296
if (isVoidReturn)
@@ -289,8 +303,8 @@ protected override bool OnTransact (int code, global::Android.OS.Parcel data, gl
289303
w.WriteLine ("\t\t\t\t{0}", GetWriteStatements (method.ReturnType, "reply", "result", "global::Android.OS.ParcelableWriteFlags.ReturnValue"));
290304
for (int i = 0; method.Arguments != null && i < method.Arguments.Length; i++) {
291305
var a = method.Arguments [i];
292-
if (a.Modifier == null || a.Modifier.Contains ("out"))
293-
w.WriteLine ("\t\t\t\t{0}", GetWriteStatements (a.Type, "data", "arg" + i, "global::Android.OS.ParcelableWriteFlags.None"));
306+
if (a.Modifier != null && a.Modifier.Contains ("out"))
307+
w.WriteLine ("\t\t\t\t{0}", GetWriteStatements (a.Type, "reply", "arg" + i, "global::Android.OS.ParcelableWriteFlags.ReturnValue"));
294308
}
295309
w.WriteLine ("\t\t\t\treturn true;");
296310
w.WriteLine ("\t\t\t\t}");
@@ -331,13 +345,16 @@ public string GetInterfaceDescriptor ()
331345
if (!isOneWay)
332346
w.WriteLine ("\t\t\t\tglobal::Android.OS.Parcel __reply = global::Android.OS.Parcel.Obtain ();");
333347
if (hasReturn)
334-
w.WriteLine ("{0} __result = default ({0});", ToOutputTypeName (name_cache.ToCSharp (method.ReturnType)));
348+
w.WriteLine ("\t\t\t\t{0} __result = default ({0});", ToOutputTypeName (name_cache.ToCSharp (method.ReturnType)));
335349
w.WriteLine (@"
336350
try {
337351
__data.WriteInterfaceToken (descriptor);");
338-
foreach (var arg in method.Arguments)
352+
foreach (var arg in method.Arguments) {
339353
if (arg.Modifier == null || arg.Modifier.Contains ("in"))
340354
w.WriteLine ("\t\t\t\t\t" + GetWriteStatements (arg.Type, "__data", SafeCSharpName (arg.Name), "global::Android.OS.ParcelableWriteFlags.None"));
355+
else if (arg.Modifier != null && arg.Modifier.Contains ("out") && arg.Type.ArrayDimension > 0)
356+
w.WriteLine ("\t\t\t\t\t" + GetWriteOutStatements (arg.Type, "__data", SafeCSharpName (arg.Name)));
357+
}
341358
w.WriteLine ("\t\t\t\t\tremote.Transact ({1}Stub.Transaction{0}, __data, {2}, 0);",
342359
method.Name,
343360
type.Name,
@@ -613,7 +630,15 @@ string GetWriteStatements (TypeName type, string parcel, string arg, string parc
613630
return String.Format ("{1}.WriteStrongBinder (((({0} != null)) ? ({0}.AsBinder ()) : (null)));", arg, parcel);
614631
}
615632
}
616-
633+
634+
string GetWriteOutStatements (TypeName type, string parcel, string arg)
635+
{
636+
if (type.ArrayDimension > 0) {
637+
return "if (" + arg + " == null) { " + parcel + ".WriteInt(-1); } else { " + parcel + ".WriteInt(" + arg + ".Length); }";
638+
} else
639+
return "";
640+
}
641+
617642
// FIXME: should this be used?
618643
string GetCreatorName (TypeName type)
619644
{

tests/Xamarin.Android.Tools.Aidl-Tests/TestData/FaceService.txt

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,6 @@ namespace Com.Android.Internal.Util.Custom.Faceunlock
113113
long arg0 = default (long);
114114
arg0 = data.ReadLong ();
115115
this.Authenticate (arg0);
116-
data.WriteLong (arg0);
117116
return true;
118117
}
119118

@@ -132,7 +131,6 @@ namespace Com.Android.Internal.Util.Custom.Faceunlock
132131
int [] arg2 = default (int []);
133132
arg2 = data.CreateIntArray ();
134133
this.Enroll (arg0, arg1, arg2);
135-
data.WriteInt (arg1);
136134
return true;
137135
}
138136

@@ -151,7 +149,6 @@ namespace Com.Android.Internal.Util.Custom.Faceunlock
151149
var result = this.GenerateChallenge (arg0);
152150
reply.WriteNoException ();
153151
reply.WriteLong (result);
154-
data.WriteInt (arg0);
155152
return true;
156153
}
157154

@@ -172,8 +169,6 @@ namespace Com.Android.Internal.Util.Custom.Faceunlock
172169
var result = this.GetFeature (arg0, arg1);
173170
reply.WriteNoException ();
174171
reply.WriteInt (result ? 1 : 0);
175-
data.WriteInt (arg0);
176-
data.WriteInt (arg1);
177172
return true;
178173
}
179174

@@ -190,7 +185,6 @@ namespace Com.Android.Internal.Util.Custom.Faceunlock
190185
int arg0 = default (int);
191186
arg0 = data.ReadInt ();
192187
this.Remove (arg0);
193-
data.WriteInt (arg0);
194188
return true;
195189
}
196190

@@ -229,9 +223,6 @@ namespace Com.Android.Internal.Util.Custom.Faceunlock
229223
int arg3 = default (int);
230224
arg3 = data.ReadInt ();
231225
this.SetFeature (arg0, arg1, arg2, arg3);
232-
data.WriteInt (arg0);
233-
data.WriteInt (arg1 ? 1 : 0);
234-
data.WriteInt (arg3);
235226
return true;
236227
}
237228

@@ -321,7 +312,7 @@ namespace Com.Android.Internal.Util.Custom.Faceunlock
321312
global::Android.OS.Parcel __data = global::Android.OS.Parcel.Obtain ();
322313

323314
global::Android.OS.Parcel __reply = global::Android.OS.Parcel.Obtain ();
324-
int __result = default (int);
315+
int __result = default (int);
325316

326317
try {
327318
__data.WriteInterfaceToken (descriptor);
@@ -343,7 +334,7 @@ int __result = default (int);
343334
global::Android.OS.Parcel __data = global::Android.OS.Parcel.Obtain ();
344335

345336
global::Android.OS.Parcel __reply = global::Android.OS.Parcel.Obtain ();
346-
long __result = default (long);
337+
long __result = default (long);
347338

348339
try {
349340
__data.WriteInterfaceToken (descriptor);
@@ -366,7 +357,7 @@ long __result = default (long);
366357
global::Android.OS.Parcel __data = global::Android.OS.Parcel.Obtain ();
367358

368359
global::Android.OS.Parcel __reply = global::Android.OS.Parcel.Obtain ();
369-
int __result = default (int);
360+
int __result = default (int);
370361

371362
try {
372363
__data.WriteInterfaceToken (descriptor);
@@ -388,7 +379,7 @@ int __result = default (int);
388379
global::Android.OS.Parcel __data = global::Android.OS.Parcel.Obtain ();
389380

390381
global::Android.OS.Parcel __reply = global::Android.OS.Parcel.Obtain ();
391-
bool __result = default (bool);
382+
bool __result = default (bool);
392383

393384
try {
394385
__data.WriteInterfaceToken (descriptor);
@@ -412,7 +403,7 @@ bool __result = default (bool);
412403
global::Android.OS.Parcel __data = global::Android.OS.Parcel.Obtain ();
413404

414405
global::Android.OS.Parcel __reply = global::Android.OS.Parcel.Obtain ();
415-
int __result = default (int);
406+
int __result = default (int);
416407

417408
try {
418409
__data.WriteInterfaceToken (descriptor);
@@ -472,7 +463,7 @@ int __result = default (int);
472463
global::Android.OS.Parcel __data = global::Android.OS.Parcel.Obtain ();
473464

474465
global::Android.OS.Parcel __reply = global::Android.OS.Parcel.Obtain ();
475-
int __result = default (int);
466+
int __result = default (int);
476467

477468
try {
478469
__data.WriteInterfaceToken (descriptor);

0 commit comments

Comments
 (0)