Skip to content

Commit 86ca249

Browse files
committed
[Xamarin.Android.Build.Tasks] MAM Member Remapping?
Context: dotnet/java-interop#867 Context: dotnet/java-interop#936 Does It Build? Does It Work? (Is It Sane?) For local "test" purposes, add a new `tools/remap-mam-json-to-xml` utility which parses the MAM JSON file into XML. $ dotnet run --project tools/remap-mam-json-to-xml -- \ $HOME/.nuget/packages/microsoft.intune.mam.remapper.tasks/0.1.4635.1/content/MonoAndroid10/remapping-config.json <replacements> <replace-type from="android/app/Activity" to="com/microsoft/intune/mam/client/app/MAMActivity" /> … <replace-method source-type="com/microsoft/intune/mam/client/support/v7/app/MAMAppCompatActivity" source-method-name="onStateNotSaved" target-type="com/microsoft/intune/mam/client/support/v7/app/MAMAppCompatActivity" target-method-name="onMAMStateNotSaved" target-method-instance-to-static="false" /> </replacements> dotnet bin/Debug/net6.0/remap-mam-json-to-xml.dll $HOME/.nuget/packages/microsoft.intune.mam.remapper.tasks/0.1.4635.1/content/MonoAndroid10/remapping-config.json
1 parent 05b7dbb commit 86ca249

File tree

7 files changed

+272
-3
lines changed

7 files changed

+272
-3
lines changed

.gitmodules

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
branch = main
1313
[submodule "external/Java.Interop"]
1414
path = external/Java.Interop
15-
url = https://github.com/xamarin/java.interop.git
16-
branch = main
15+
url = https://github.com/jonpryor/java.interop.git
16+
branch = jonp-member-remapping
1717
[submodule "external/lz4"]
1818
path = external/lz4
1919
url = https://github.com/lz4/lz4.git

src/Mono.Android/Android.Runtime/AndroidRuntime.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Linq;
55
using System.Runtime.CompilerServices;
66
using System.Runtime.InteropServices;
7+
using System.Runtime.Versioning;
78
using System.Text;
89
using System.Threading;
910
using System.Reflection;
@@ -282,6 +283,20 @@ protected override IEnumerable<string> GetSimpleReferences (Type type)
282283
}
283284
}
284285

286+
#if NET
287+
[RequiresPreviewFeatures]
288+
protected override IReadOnlyList<string>? GetStaticMethodFallbackTypesCore (string jniSimpleReference)
289+
{
290+
return new[]{$"{jniSimpleReference}$-CC"};
291+
}
292+
293+
[RequiresPreviewFeatures]
294+
protected override string? GetReplacementTypeCore (string jniSimpleReference) => null;
295+
296+
[RequiresPreviewFeatures]
297+
protected override JniRuntime.ReplacementMethodInfo? GetReplacementMethodInfoCore (string jniSimpleReference, string jniMethodName, string jniMethodSignature) => null;
298+
#endif // NET
299+
285300
delegate Delegate GetCallbackHandler ();
286301

287302
static MethodInfo? dynamic_callback_gen;

src/Mono.Android/Mono.Android.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
<Nullable>enable</Nullable>
2323
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
2424
<EnableSingleFileAnalyzer>true</EnableSingleFileAnalyzer>
25+
<EnablePreviewFeatures>True</EnablePreviewFeatures>
2526
</PropertyGroup>
2627

2728
<PropertyGroup Condition=" '$(TargetFramework)' == 'monoandroid10' ">
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
#nullable enable
2+
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Diagnostics;
6+
using System.Diagnostics.CodeAnalysis;
7+
using System.IO;
8+
using System.Linq;
9+
using System.Xml.Linq;
10+
11+
using Newtonsoft.Json;
12+
using Newtonsoft.Json.Linq;
13+
14+
namespace Xamarin.Android.Tasks
15+
{
16+
public class MamJsonParser
17+
{
18+
Action<TraceLevel, string> Logger;
19+
20+
Dictionary<string, string> ReplacmentTypes = new ();
21+
Dictionary<(string SourceType, string SourceName, string? SourceSignature), (string? TargetType, string? TargetName, string? TargetSignature, int? ParamCount, bool IsStatic)>
22+
ReplacementMethods = new ();
23+
24+
public MamJsonParser (Action<TraceLevel, string> logger)
25+
{
26+
Logger = logger;
27+
}
28+
29+
public void Load (string jsonPath)
30+
{
31+
var json = ReadJson (jsonPath);
32+
33+
var classRewrites = json["ClassRewrites"];
34+
if (classRewrites != null) {
35+
ReadClassRewrites (classRewrites);
36+
}
37+
38+
var globalMethodCalls = json["GlobalMethodCalls"];
39+
if (globalMethodCalls != null) {
40+
ReadGlobalMethodCalls (globalMethodCalls);
41+
}
42+
}
43+
44+
public XElement ToXml ()
45+
{
46+
return new XElement ("replacements",
47+
GetReplacementTypes (),
48+
GetReplacementMethods ());
49+
}
50+
51+
static JObject ReadJson (string path)
52+
{
53+
using (var f = File.OpenText (path))
54+
using (var r = new JsonTextReader (f))
55+
return (JObject) JToken.ReadFrom (r);
56+
}
57+
58+
void ReadClassRewrites (JToken classRewrites)
59+
{
60+
foreach (var classRewrite in classRewrites) {
61+
if (!TryReadClassFromTo (classRewrite, out var from, out var to)) {
62+
Logger (TraceLevel.Verbose, $"No from or to! {classRewrite}");
63+
continue;
64+
}
65+
ReplacmentTypes [from] = to;
66+
var methods = classRewrite ["Methods"];
67+
if (methods == null) {
68+
continue;
69+
}
70+
foreach (var method in methods) {
71+
var makeStatic = (bool?) method["MakeStatic"] ?? false;
72+
var oldName = (string?) method["OriginalName"];
73+
var newName = (string?) method["NewName"];
74+
var oldSig = ReadSignature (method["OriginalParams"]);
75+
if (oldName == null || newName == null) {
76+
continue;
77+
}
78+
ReplacementMethods [(to, oldName, oldSig)] = (to, newName, null, null, makeStatic);
79+
}
80+
}
81+
}
82+
83+
bool TryReadClassFromTo (JToken token, [NotNullWhen(true)] out string? from, [NotNullWhen(true)] out string? to)
84+
{
85+
from = (string?) token["Class"]?["From"];
86+
to = (string?) token["Class"]?["To"];
87+
if (from == null || to == null) {
88+
return false;
89+
}
90+
from = JavaToJniType (from);
91+
to = JavaToJniType (to);
92+
return true;
93+
}
94+
95+
string? ReadSignature (JToken? token)
96+
{
97+
if (token == null)
98+
return null;
99+
var types = new List<string> ();
100+
foreach (var type in token) {
101+
if (type == null) {
102+
continue;
103+
}
104+
var javaType = ((string?) type) switch {
105+
"boolean" => "Z",
106+
"byte" => "B",
107+
"char" => "C",
108+
"double" => "D",
109+
"float" => "F",
110+
"int" => "I",
111+
"long" => "J",
112+
"short" => "S",
113+
"void" => "V",
114+
var o => JavaToJniTypeSignature (o),
115+
};
116+
if (javaType == null) {
117+
continue;
118+
}
119+
types.Add (javaType);
120+
}
121+
if (types.Count == 0)
122+
return null;
123+
return "(" + string.Join ("", types) + ")";
124+
}
125+
126+
string JavaToJniType (string javaType)
127+
{
128+
return javaType.Replace (".", "/");
129+
}
130+
131+
string? JavaToJniTypeSignature (string? javaType)
132+
{
133+
if (javaType == null) {
134+
return null;
135+
}
136+
int arrayCount = 0;
137+
while (javaType.EndsWith ("[]")) {
138+
arrayCount++;
139+
javaType = javaType.Substring(0, javaType.Length - "[]".Length);
140+
}
141+
return new string('[', arrayCount) + "L" + JavaToJniType (javaType) + ";";
142+
}
143+
144+
void ReadGlobalMethodCalls (JToken globalMethodCalls)
145+
{
146+
foreach (var globalMethodCall in globalMethodCalls) {
147+
if (!TryReadClassFromTo (globalMethodCall, out var from, out var to)) {
148+
Logger (TraceLevel.Info, $"No from or to! {globalMethodCall}");
149+
continue;
150+
}
151+
var methods = globalMethodCall ["Methods"];
152+
if (methods == null) {
153+
continue;
154+
}
155+
foreach (var method in methods) {
156+
var makeStatic = (bool?) method["MakeStatic"] ?? false;
157+
var oldName = (string?) method["OriginalName"];
158+
var oldSig = ReadSignature (method["OriginalParams"]);
159+
if (oldSig != null) {
160+
throw new Exception ("huh?");
161+
}
162+
if (oldName == null || oldName.Length < 1) {
163+
continue;
164+
}
165+
var newName = oldName;
166+
ReplacementMethods [(from, oldName, null)] = (to, newName, null, null, makeStatic);
167+
}
168+
}
169+
}
170+
171+
IEnumerable<XElement> GetReplacementTypes ()
172+
{
173+
foreach (var k in ReplacmentTypes.Keys.OrderBy (k => k)) {
174+
yield return new XElement ("replace-type",
175+
new XAttribute ("from", k),
176+
new XAttribute ("to", ReplacmentTypes [k]));
177+
}
178+
}
179+
180+
IEnumerable<XElement> GetReplacementMethods ()
181+
{
182+
var entries = ReplacementMethods.Keys.OrderBy (e => e.SourceType)
183+
.ThenBy (e => e.SourceName)
184+
.ThenBy (e => e.SourceSignature);
185+
foreach (var k in entries) {
186+
var v = ReplacementMethods [k];
187+
yield return new XElement ("replace-method",
188+
new XAttribute ("source-type", k.SourceType),
189+
new XAttribute ("source-method-name", k.SourceName),
190+
CreateAttribute ("source-method-signature", k.SourceSignature),
191+
CreateAttribute ("target-type", v.TargetType),
192+
CreateAttribute ("target-method-name", v.TargetName),
193+
CreateAttribute ("target-method-signature", v.TargetSignature),
194+
CreateAttribute ("target-method-parameter-count", v.ParamCount.HasValue ? v.ParamCount.Value.ToString () : null),
195+
CreateAttribute ("target-method-instance-to-static", v.IsStatic ? "true" : "false"));
196+
}
197+
}
198+
199+
XAttribute? CreateAttribute (string name, string? value)
200+
{
201+
if (value == null) {
202+
return null;
203+
}
204+
return new XAttribute (name, value);
205+
}
206+
}
207+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System.Diagnostics;
2+
using Xamarin.Android.Tasks;
3+
// See https://aka.ms/new-console-template for more information
4+
Console.WriteLine("Hello, World!");
5+
6+
var mam = new MamJsonParser (Log);
7+
foreach (var path in args) {
8+
mam.Load (path);
9+
}
10+
Console.WriteLine (mam.ToXml ());
11+
12+
void Log (TraceLevel level, string message)
13+
{
14+
switch (level) {
15+
case TraceLevel.Error:
16+
Console.Error.WriteLine ($"remap-mam-json-to-xml: {message}");
17+
break;
18+
default:
19+
Console.WriteLine (message);
20+
break;
21+
}
22+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net6.0</TargetFramework>
6+
<RootNamespace>Xamarin.Android.Tools.RemapMapjsonToXml</RootNamespace>
7+
<ImplicitUsings>enable</ImplicitUsings>
8+
<Nullable>enable</Nullable>
9+
<OutputPath>..\..\bin\Test$(Configuration)</OutputPath>
10+
</PropertyGroup>
11+
12+
<ItemGroup>
13+
<ProjectReference Include="..\..\src\Xamarin.Android.Build.Tasks\Xamarin.Android.Build.Tasks.csproj" />
14+
</ItemGroup>
15+
16+
<ItemGroup>
17+
<PackageReference
18+
Include="Microsoft.Intune.MAM.Remapper.Tasks"
19+
Version="0.1.4635.1"
20+
IncludeAssets="none"
21+
ReferenceOutputAssembly="False"
22+
/>
23+
</ItemGroup>
24+
</Project>

0 commit comments

Comments
 (0)