Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;

namespace Microsoft.Android.Sdk.TrimmableTypeMap;

/// <summary>
/// Helpers for parsing JNI method signatures.
/// </summary>
static class JniSignatureHelper
{
/// <summary>
/// Parses the JNI parameter type descriptors from a JNI method signature
/// and returns them as <see cref="JniParameterInfo"/> records.
/// </summary>
public static List<JniParameterInfo> ParseParameterTypes (string jniSignature)
{
var result = new List<JniParameterInfo> ();
int i = 1; // skip opening '('
while (i < jniSignature.Length && jniSignature [i] != ')') {
int start = i;
SkipSingleType (jniSignature, ref i);
result.Add (new JniParameterInfo { JniType = jniSignature.Substring (start, i - start) });
}
return result;
}

/// <summary>
/// Extracts the return type descriptor from a JNI method signature.
/// </summary>
public static string ParseReturnTypeString (string jniSignature)
{
int i = jniSignature.IndexOf (')') + 1;
return jniSignature.Substring (i);
}

static void SkipSingleType (string sig, ref int i)
{
switch (sig [i]) {
case 'V': case 'Z': case 'B': case 'C': case 'S':
case 'I': case 'J': case 'F': case 'D':
i++;
break;
case 'L':
int end = sig.IndexOf (';', i);
if (end < 0) {
throw new ArgumentException ($"Malformed JNI signature: missing ';' after 'L' at index {i} in '{sig}'");
}
i = end + 1;
break;
case '[':
i++;
SkipSingleType (sig, ref i);
break;
default:
throw new ArgumentException ($"Unknown JNI type character '{sig [i]}' in '{sig}' at index {i}");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,15 @@ sealed record RegisterInfo
public bool DoNotGenerateAcw { get; init; }
}

/// <summary>
/// Parsed [Export] attribute data for a method.
/// </summary>
sealed record ExportInfo
{
public IReadOnlyList<string>? ThrownNames { get; init; }
public string? SuperArgumentsString { get; init; }
}

class TypeAttributeInfo (string attributeName)
{
public string AttributeName { get; } = attributeName;
Expand Down
109 changes: 109 additions & 0 deletions src/Microsoft.Android.Sdk.TrimmableTypeMap/Scanner/JavaPeerInfo.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;

namespace Microsoft.Android.Sdk.TrimmableTypeMap;
Expand All @@ -15,6 +16,13 @@ sealed record JavaPeerInfo
/// </summary>
public required string JavaName { get; init; }

/// <summary>
/// Compat JNI type name, e.g., "myapp.namespace/MyType" for user types (uses raw namespace, not CRC64).
/// For MCW binding types (with [Register]), this equals <see cref="JavaName"/>.
/// Used by acw-map.txt to support legacy custom view name resolution in layout XMLs.
/// </summary>
public required string CompatJniName { get; init; }

/// <summary>
/// Full managed type name, e.g., "Android.App.Activity".
/// </summary>
Expand Down Expand Up @@ -50,6 +58,14 @@ sealed record JavaPeerInfo
/// </summary>
public bool IsUnconditional { get; init; }

/// <summary>
/// Marshal methods: methods with [Register(name, sig, connector)], [Export], or
/// constructor registrations ([Register(".ctor", sig, "")] / [JniConstructorSignature]).
/// Constructors are identified by <see cref="MarshalMethodInfo.IsConstructor"/>.
/// Ordered — the index in this list is the method's ordinal for RegisterNatives.
/// </summary>
public IReadOnlyList<MarshalMethodInfo> MarshalMethods { get; init; } = Array.Empty<MarshalMethodInfo> ();

/// <summary>
/// Information about the activation constructor for this type.
/// May reference a base type's constructor if the type doesn't define its own.
Expand Down Expand Up @@ -79,6 +95,99 @@ sealed record JavaPeerInfo
public bool IsGenericDefinition { get; init; }
}

/// <summary>
/// Describes a marshal method (a method with [Register] or [Export]) on a Java peer type.
/// Contains all data needed to generate a UCO wrapper, a JCW native declaration,
/// and a RegisterNatives call.
/// </summary>
sealed record MarshalMethodInfo
{
/// <summary>
/// JNI method name, e.g., "onCreate".
/// This is the Java method name (without n_ prefix).
/// </summary>
public required string JniName { get; init; }

/// <summary>
/// JNI method signature, e.g., "(Landroid/os/Bundle;)V".
/// Contains both parameter types and return type.
/// </summary>
public required string JniSignature { get; init; }

/// <summary>
/// The connector string from [Register], e.g., "GetOnCreate_Landroid_os_Bundle_Handler".
/// Null for [Export] methods.
/// </summary>
public string? Connector { get; init; }

/// <summary>
/// Name of the managed method this maps to, e.g., "OnCreate".
/// </summary>
public required string ManagedMethodName { get; init; }

/// <summary>
/// Full name of the type that declares the managed method (may be a base type).
/// Empty when the declaring type is the same as the peer type.
/// </summary>
public string DeclaringTypeName { get; init; } = "";

/// <summary>
/// Assembly name of the type that declares the managed method.
/// Needed for cross-assembly UCO wrapper generation.
/// Empty when the declaring type is the same as the peer type.
/// </summary>
public string DeclaringAssemblyName { get; init; } = "";

/// <summary>
/// The native callback method name, e.g., "n_onCreate".
/// This is the actual method the UCO wrapper delegates to.
/// </summary>
public required string NativeCallbackName { get; init; }

/// <summary>
/// JNI parameter types for UCO generation.
/// </summary>
public IReadOnlyList<JniParameterInfo> Parameters { get; init; } = Array.Empty<JniParameterInfo> ();

/// <summary>
/// JNI return type descriptor, e.g., "V", "Landroid/os/Bundle;".
/// </summary>
public required string JniReturnType { get; init; }

/// <summary>
/// True if this is a constructor registration.
/// </summary>
public bool IsConstructor { get; init; }

/// <summary>
/// For [Export] methods: Java exception types that the method declares it can throw.
/// Null for [Register] methods.
/// </summary>
public IReadOnlyList<string>? ThrownNames { get; init; }

/// <summary>
/// For [Export] methods: super constructor arguments string.
/// Null for [Register] methods.
/// </summary>
public string? SuperArgumentsString { get; init; }
}

/// <summary>
/// Describes a JNI parameter for UCO method generation.
/// </summary>
sealed record JniParameterInfo
{
/// <summary>
/// JNI type descriptor, e.g., "Landroid/os/Bundle;", "I", "Z".
/// </summary>
public required string JniType { get; init; }

/// <summary>
/// Managed parameter type name, e.g., "Android.OS.Bundle", "System.Int32".
/// </summary>
public string ManagedType { get; init; } = "";
}

/// <summary>
/// Describes how to call the activation constructor for a Java peer type.
/// </summary>
Expand Down
Loading