Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Xamarin..Android.Tools.Aidl] Handle out and inout Parameters in CodeGenerator properly #5726

Merged
merged 3 commits into from
Mar 26, 2021

Conversation

mfranke-moba
Copy link
Contributor

Fixes #5079 and #4717

The CodeGenerator responible for producing C# Code for AIDL files so far had the problem that function parameters of some array type (like int[]) marked with out or inout were not handled properly.
For such parameters the legth of the array has to be written to the data parcelable in the Proxy function. See https://cs.android.com/android/platform/superproject/+/master:system/tools/aidl/generate_java_binder.cpp (lines 646 - 656).
Now just like in the linked sources something like:

if {arrarParam == null} {
    _data.writeInt(-1);
}
else {
    _data.writeInt(arrayParam.lenght)
}

will be produced.

The counterpart which is the corresponding Stub function will contain:

int _argX_length = data.readInt();
if ((_argX_length<0)) {
    _argX = null;
}
else {
    _argX = new byte[_argX_length];
}

See https://cs.android.com/android/platform/superproject/+/master:system/tools/aidl/generate_java_binder.cpp (line 486 and lines 358 - 372)
This is comparable to the java code the Android Studio produces.

Now also return values will be written to _result instead of _data which was wrong before.

The improvements of this commit show for interprocess communication between different Apps/Services. Now also Communication betwen Xamarin and Java Apps/Services works for array parameters marked with out/inout.

I really hope this bugfix will find its way into the nex release of Visual Studio.

@jonpryor
Copy link
Member

@mfranke-moba: how "interested" are you in a "larger project"? :-D

If you're interested, src/Xamarin.Android.Tools.Aidl needs unit tests. I know of "a" pattern for writing unit tests for Irony grammars; see e.g. dotnet/java-interop@7574f16 and https://github.com/xamarin/java.interop/blob/94c0c70970cd30b9a86ec1607a5394f8c9a1bb8e/tests/Java.Interop.Tools.JavaSource-Tests/SourceJavadocToXmldocGrammar.InlineTagsBnfTermsTests.cs.

The question is whether or now you are interested in writing such a unit test framework. We'll get around to it…some day…

But in the meantime, src/Xamarin.Android.Tools.Aidl desperately could use some unit tests, so that we can "feel better" about future fixes and improvements to this assembly.

@jonpryor
Copy link
Member

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@mfranke-moba
Copy link
Contributor Author

I already noticed there are almost no unit tests for src/Xamarin.Android.Tools.Aidl. This may one point where I could contribute something.
Besides the issue with out/inout arrays I also noticed that Parcelables do not work. Some unit test illustrating this problem might be a good starting point helping to fix this as well.


string GetWriteOutStatements (TypeName type, string parcel, string arg)
{
if (type.ArrayDimension > 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

…ditto here: is int[][] possible?

A quick gander at the AIDL documentation suggests it isn't possible. However, it does suggest that List:

must be one of the supported data types in this list or one of the other AIDL-generated interfaces or parcelables you've declared

which implies that a List<List<List<String>>> may be viable…and I have no idea what we'd do with that. (Wouldn't impact type.ArrayDimension, though!)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The way I understand the AIDL dokumentation is that multidimensional arrays like int[][] are not supported. At the moment the CSharpCodeGenerator or maybe the AidlParser just ignores higher dimensions and int[][] is treated like int[]. However throwing some NotSupportedException might not be wrong.

For List I think - but not 100% sure - you can put any supported object in. And one object can be a List which can contain other Lists and so on. I don't know why (maybe a bug) but the Android Studio does not support parametrization like List<List<List<String>>>>, just List<String>. So you can use List and put Lists in but List<List>> does not work!?

The CSharpCodeGenerator might not cover all cases for Lists correct and should definetely be unit tested also in this perspect.

@jonpryor
Copy link
Member

Just to keep things "in the loop", PR #5756 adds unit tests for this assembly. Once PR #5756 is merged, we'll update this PR (#5726) to merge with to-be-current main, and update the unit test expected outputs accordingly.

jonpryor pushed a commit that referenced this pull request Mar 25, 2021
Context: #5726

We have someone willing to contribute fixes for
`Xamarin.Android.Tools.Aidl.dll` (yay!).  However, we no longer have
any expertise with AIDL available on the team, and there are no unit
tests for this area.  This makes us very reluctant to make changes
which could potentially break the currently working aspects of AIDL.

Add a new `tests/Xamarin.Android.Tools.Aidl-Tests` unit test project
and seed it with a few examples from our repo and a few large examples
from other OSS repos.

Note: this does *not* mean that the behavior tested by these tests is
necessarily *correct*.  It simply reflects what the code does *today*,
in order that we can see any changes made by future PR's.

~~ Note ~~

The format for test data files is delimited by 4 pound signs as:

	<input>

	####

	<output>

Test results can be generated by:

  - Placing the input in a test file
  - Enabling the `GENERATE_OUTPUT` define at the top of
    `AidlCompilerTestBase.cs`
  - Running the test
  - The test file in `bin/TestData` will now contain the test output
    which can be copied back to the original test data file.
This is to get unit tests for Xamarin.Android.Tools.Aidl.dll.
TODO: no verification/validation has been done to check that these
changes are *correct*.

These are the changes necessary in order for the unit tests to *pass*
given the changes in 4ec8c09.
@jonpryor
Copy link
Member

With the merging of PR #5756, I've merged main into the mfranke-moba/out_parameter_handling branch and updated the expected test output from 81d37a1 so that the unit tests pass.

I have not in any way validated the the "changes required for unit tests to pass" are in any way correct

@jonpryor
Copy link
Member

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

string GetWriteOutStatements (TypeName type, string parcel, string arg)
{
if (type.ArrayDimension > 0) {
return "if (" + arg + " == null) { " + parcel + ".WriteInt(-1); } else { " + parcel + ".WriteInt(" + arg + ".Length); }";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that .WriteInt(-1) doesn't show up anywhere in our current expected test output, we're going to need a new unit test which ensures this code path is hit.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mfranke-moba : please add a unit test which causes this line to be triggered.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is already covered by Test11. The WriteInt(-1) will be written for out array parameters like out byte[]. In this case no byte array is written with WriteXyzArray like for in byte[] or inout byte[] as no data has to be transmitted, just the size.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I had missed that. :-(

@@ -289,8 +303,8 @@ protected override bool OnTransact (int code, global::Android.OS.Parcel data, gl
w.WriteLine ("\t\t\t\t{0}", GetWriteStatements (method.ReturnType, "reply", "result", "global::Android.OS.ParcelableWriteFlags.ReturnValue"));
for (int i = 0; method.Arguments != null && i < method.Arguments.Length; i++) {
var a = method.Arguments [i];
if (a.Modifier == null || a.Modifier.Contains ("out"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this change/removal is why data.WriteLong (arg0); is removed in the unit test diff.

I think this is correct?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change was necessary because before for primitive input parameters like in void Authenticate (long operationId) the input parameter after function execution was written back to the reply Parcel which is only reqired for out and inout parameters.

@jonpryor jonpryor merged commit 9cfa5f3 into dotnet:main Mar 26, 2021
@mfranke-moba mfranke-moba deleted the out_parameter_handling branch March 30, 2021 05:55
@github-actions github-actions bot locked and limited conversation to collaborators Jan 25, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Bug] When using inout parameter in AIDL, the code generator is not working properly
2 participants