Skip to content

Commit ce2bc68

Browse files
authored
[build] Optimize managed <-> java type lookups (#3992)
Typemap data is used to correlate JNI type names to .NET Assembly- Qualified Type Names, and vice versa: java/lang/Object <=> Java.Lang.Object, Mono.Android Typemap data is used from `JNIEnv.GetJniName()` for managed-to-JNI lookups, and from `TypeManager.GetJavaToManagedType()` for JNI-to-managed lookups. When [typemap files were first introduced][0], they relied on: 1. A string-oriented mapping from Java type names to .NET Assembly Qualified names and vice versa; and 2. A binary search via **bsearch**(3) over this table to find the associated type, using the source type as the "key". (The introduction of `libxamarin-app.so` (decfbcc) merely moved the (formerly separate) typemap data into `libxamarin-app.so` for Release config builds -- Debug builds continued using separate typemap files -- but didn't otherwise change how these mappings work.) This approach works very well at the expense of data size -- shorter strings are 0-padded to a common width -- and slightly degraded performance because of the requirement to perform string comparisons. Furthermore, the managed-to-JNI lookup required that Reflection is used to obtain the Assembly Qualified type name (`Type.AssemblyQualifiedName`), while the JNI-to-managed lookup likewise requires some Reflection to obtain `Type` instances (via `Type.GetType()`). Rework the typemap data in an effort to reduce Reflection use: For the managed-to-JNI mapping, use the combination of `type.Module.ModuleVersionId` and `Type.MetadataToken` -- a GUID and an int -- instead of using `Type.AssemblyQualifiedName`. This allows us to perform the binary search over a set of 20 bytes (16 bytes for the UUID and 4 bytes for the token ID). JNI-to-managed lookups still need to rely on a binary search across strings, but instead of mapping the JNI name to an Assembly-Qualified Type Name and using `Type.GetType()`, we instead map the JNI name to the same GUID+token pair via a new internal call which uses `mono_class_get()` & `mono_type_get_object()` to return the `Type`. As a result of this fundamental change, `libxamarin-app.so` decreases in size, and app startup time is reduced. For a Release configuration build of `tests/Xamarin.Forms-Performance-Integration`, `libs/arm64-v8a/libxamarin-app.so` shrinks from 377KB to 104KB (!), and on a Pixel 3 XL app the `ActivityTaskManager: Displayed` time was reduced from 805ms to 789ms (`$(AndroidEnablePreloadAssemblies)`=True), a nearly 10% improvement. Build time is also minimally impacted; `<GenerateJavaStubs/>` task time is reduced from 389ms to 247ms for the Xamarin.Forms build. ~~ Fast Deployment ~~ When Xamarin.Android Fast Deployment is *not* used for Debug builds (which is the case for OSS builds of xamarin-android), the typemap generation and deployment is identical for both Release and Debug builds: `libxamarin-app.so` contains the new typemap information. In commercial Xamarin.Android builds which use Fast Deployment, the typemap data is instead stored in two sets of files: * `typemap.index`: stores the mapping from module GUIDs to assembly filenames. * `*.typemap`: One file per .NET *module*, contain both the JNI-to- managed and managed-to-JNI maps, the latter using indexes into the Java to managed maps. All of these files are loaded during Debug app startup and used to construct a dataset which is then searched during all the lookups. ~~ File Formats ~~ All data in all file formats is little-endian. The `typemap.index` file stores the mapping from GUIDs to module filenames such as `Mono.Android.dll`. The file format in pseudo-C++: struct TypemapIndexHeader { byte magic [4]; // "XATI" uint32_t format_version; uint32_t entry_count; uint32_t module_filename_width; TypemapIndexEntry entries [entry_count]; }; struct TypemapIndexEntry { UUID module_uuid; // 16 bytes byte file_name [TypemapIndexHeader::module_filename_width]; }; `TypemapIndexHeader::module_filename_width` is the maximum filename length of any entry within `TypemapIndexEntry::file_name` + 1 for a terminating `NUL`. There is no order required within `TypemapIndexHeader::entries`. `TypemapIndexEntry::file_name` is `NUL` padded, filling the entire array until the next `TypemapIndexEntry` entry. The `*.typemap` file stores the mappings from JNI type names to module GUID and type token pairs. The file format in pseudo-C++: struct TypemapFileHeader { byte magic [4]; // "XATM" uint32_t format_version; GUID module_uuid; uint32_t entry_count; uint32_t duplicate_count; uint32_t jni_name_width; uint32_t assembly_name_size; byte assembly_name [assembly_name_size]; TypemapFileJavaToManagedEntry java_to_managed [entry_count]; TypemapFileManagedToJavaEntry managed_to_java [entry_count]; TypemapFileManagedToJavaEntry duplicates [duplicate_count]; }; struct TypemapFileJavaToManagedEntry { byte jni_name [TypemapFileHeader::jni_name_width]; uint32_t managed_type_token; }; struct TypemapFileManagedToJavaEntry { uint32_t managed_type_token; uint32_t java_to_managed_index; }; `TypemapFileHeader::duplicate_count` may be 0. `TypemapFileJavaToManagedEntry::jni_name` is `NUL` padded. `TypemapFileJavaToManagedEntry::managed_type_token` is the value of `Type.MetadataToken`. `TypemapFileManagedToJavaEntry::java_to_managed_index` is the index within `TypemapFileHeader::java_to_managed` that contains the JNI name. [0]: xamarin/monodroid@e69b76e [1]: https://github.com/xamarin/java.interop/blob/3226a4b57ad84574a69a151a310b077cfe69ee19/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/TypeNameMapGenerator.cs#L16-L56
1 parent 97d250b commit ce2bc68

File tree

63 files changed

+1939
-860
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+1939
-860
lines changed

Documentation/guides/messages/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ ms.date: 01/24/2020
104104
+ [XA4305](xa4305.md): MultiDex is enabled, but '{nameof (MultiDexMainDexListFile)}' was not specified.
105105
+ [XA4306](xa4306.md): R8 does not support \`@(MultiDexMainDexList)\` files when android:minSdkVersion >= 21
106106
+ [XA4307](xa4307.md): Invalid ProGuard configuration file.
107+
+ [XA4308](xa4308.md): Failed to generate type maps
107108

108109
## XA5xxx: GCC and toolchain
109110

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
title: Xamarin.Android error XA4308
3+
description: XA4308 error code
4+
ms.date: 02/07/2020
5+
---
6+
# Xamarin.Android error XA4308
7+
8+
## Issue
9+
10+
The `GenerateJavaStubs` task was unable to generate type maps. Detailed diagnostic will be found before this
11+
error in the build log.
12+
13+
## Solution
14+
15+
Consider submitting a [bug][bug] if you are getting this warning under
16+
normal circumstances.
17+
18+
[bug]: https://github.com/xamarin/xamarin-android/wiki/Submitting-Bugs,-Feature-Requests,-and-Pull-Requests

build-tools/xaprepare/xaprepare/Steps/Step_DownloadMonoArchive.cs

+32-18
Original file line numberDiff line numberDiff line change
@@ -60,26 +60,39 @@ async Task<bool> DownloadMonoArchive (Context context)
6060
localPath = Path.Combine (context.Properties.GetRequiredValue (KnownProperties.AndroidToolchainCacheDirectory), archiveFileName);
6161
}
6262

63-
bool result = await DownloadAndUpackIfNeeded (
64-
context,
65-
"Mono",
66-
context.MonoArchiveCustomUrl,
67-
localPath,
68-
archiveFileName,
69-
Configurables.Paths.MonoSDKSOutputDir
70-
);
63+
bool result = false;
64+
for (uint i = 0; i < 3; i++) {
65+
result = await DownloadAndUpackIfNeeded (
66+
context,
67+
"Mono",
68+
context.MonoArchiveCustomUrl,
69+
localPath,
70+
archiveFileName,
71+
Configurables.Paths.MonoSDKSOutputDir
72+
);
73+
74+
if (result)
75+
break;
76+
}
7177

7278
if (!result)
7379
return false;
7480

75-
return await DownloadAndUpackIfNeeded (
76-
context,
77-
"Windows Mono",
78-
customUrl: null,
79-
localPath: Configurables.Paths.MonoArchiveWindowsLocalPath,
80-
archiveFileName: Configurables.Paths.MonoArchiveWindowsFileName,
81-
destinationDirectory: Configurables.Paths.BCLWindowsOutputDir
82-
);
81+
for (uint i = 0; i < 3; i++) {
82+
result = await DownloadAndUpackIfNeeded (
83+
context,
84+
"Windows Mono",
85+
customUrl: null,
86+
localPath: Configurables.Paths.MonoArchiveWindowsLocalPath,
87+
archiveFileName: Configurables.Paths.MonoArchiveWindowsFileName,
88+
destinationDirectory: Configurables.Paths.BCLWindowsOutputDir
89+
);
90+
91+
if (result)
92+
break;
93+
}
94+
95+
return result;
8396
}
8497

8598
async Task<bool> DownloadAndUpackIfNeeded (Context context, string name, string customUrl, string localPath, string archiveFileName, string destinationDirectory)
@@ -109,7 +122,7 @@ async Task<bool> DownloadAndUpackIfNeeded (Context context, string name, string
109122
await Download (context, url, localPath, $"{name} Archive", archiveFileName, downloadStatus);
110123

111124
if (!File.Exists (localPath)) {
112-
Log.InfoLine ($"Download of {name} archive from {url} failed, Mono will be rebuilt");
125+
Log.InfoLine ($"Download of {name} archive from {url} failed");
113126
return false;
114127
}
115128
}
@@ -118,7 +131,8 @@ async Task<bool> DownloadAndUpackIfNeeded (Context context, string name, string
118131
if (!await Utilities.Unpack (localPath, tempDir, cleanDestinatioBeforeUnpacking: true)) {
119132
Utilities.DeleteFileSilent (localPath);
120133
Utilities.DeleteDirectorySilent (destinationDirectory);
121-
Log.WarningLine ($"Failed to unpack {name} archive {localPath}, Mono will be rebuilt");
134+
Log.WarningLine ($"Failed to unpack {name} archive {localPath}");
135+
Utilities.DeleteFileSilent (localPath);
122136
return false;
123137
}
124138

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

+6-6
Original file line numberDiff line numberDiff line change
@@ -231,9 +231,9 @@ protected override IEnumerable<Type> GetTypesForSimpleReference (string jniSimpl
231231

232232
protected override string GetSimpleReference (Type type)
233233
{
234-
var j = JNIEnv.monodroid_typemap_managed_to_java (type.FullName + ", " + type.Assembly.GetName ().Name);
235-
if (j != IntPtr.Zero) {
236-
return Marshal.PtrToStringAnsi (j);
234+
string j = JNIEnv.TypemapManagedToJava (type);
235+
if (j != null) {
236+
return j;
237237
}
238238
if (JNIEnv.IsRunningOnDesktop) {
239239
return JavaNativeTypeManager.ToJniName (type);
@@ -243,9 +243,9 @@ protected override string GetSimpleReference (Type type)
243243

244244
protected override IEnumerable<string> GetSimpleReferences (Type type)
245245
{
246-
var j = JNIEnv.monodroid_typemap_managed_to_java (type.FullName + ", " + type.Assembly.GetName ().Name);
247-
if (j != IntPtr.Zero) {
248-
yield return Marshal.PtrToStringAnsi (j);
246+
string j = JNIEnv.TypemapManagedToJava (type);
247+
if (j != null) {
248+
yield return j;
249249
}
250250
if (JNIEnv.IsRunningOnDesktop) {
251251
yield return JavaNativeTypeManager.ToJniName (type);

src/Mono.Android/Android.Runtime/JNIEnv.cs

+49-4
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,14 @@ public static partial class JNIEnv {
5757
static UncaughtExceptionHandler defaultUncaughtExceptionHandler;
5858

5959
internal static bool IsRunningOnDesktop;
60+
internal static bool LogTypemapMissStackTrace;
6061

6162
static AndroidRuntime androidRuntime;
6263
static BoundExceptionType BoundExceptionType;
6364

65+
[ThreadStatic]
66+
static byte[] mvid_bytes;
67+
6468
internal static AndroidValueManager AndroidValueManager;
6569

6670
[DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)]
@@ -146,6 +150,8 @@ internal static unsafe void Initialize (JnienvInitializeArgs* args)
146150
partial_timing_sequence = monodroid_timing_start (null);
147151
}
148152

153+
LogTypemapMissStackTrace = (args->logCategories & (uint)LogCategories.Assembly) != 0;
154+
149155
gref_gc_threshold = args->grefGcThreshold;
150156

151157
java_vm = args->javaVm;
@@ -632,16 +638,55 @@ public static string GetClassNameFromInstance (IntPtr jobject)
632638
}
633639

634640
[DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)]
635-
internal static extern IntPtr monodroid_typemap_managed_to_java (string managed);
641+
static extern IntPtr monodroid_typemap_managed_to_java (byte[] mvid, int token);
642+
643+
internal static void LogTypemapTrace (StackTrace st)
644+
{
645+
string trace = st.ToString ()?.Trim ();
646+
if (String.IsNullOrEmpty (trace))
647+
return;
648+
649+
monodroid_log (LogLevel.Warn, LogCategories.Assembly, "typemap: called from");
650+
foreach (string line in trace.Split ('\n')) {
651+
monodroid_log (LogLevel.Warn, LogCategories.Assembly, line);
652+
}
653+
}
654+
655+
internal static string TypemapManagedToJava (Type type)
656+
{
657+
if (mvid_bytes == null)
658+
mvid_bytes = new byte[16];
659+
660+
Span<byte> mvid = new Span<byte>(mvid_bytes);
661+
byte[] mvid_slow = null;
662+
if (!type.Module.ModuleVersionId.TryWriteBytes (mvid)) {
663+
monodroid_log (LogLevel.Warn, LogCategories.Default, $"Failed to obtain module MVID using the fast method, falling back to the slow one");
664+
mvid_slow = type.Module.ModuleVersionId.ToByteArray ();
665+
}
666+
667+
IntPtr ret = monodroid_typemap_managed_to_java (mvid_slow == null ? mvid_bytes : mvid_slow, type.MetadataToken);
668+
669+
if (ret == IntPtr.Zero) {
670+
if (LogTypemapMissStackTrace) {
671+
monodroid_log (LogLevel.Warn, LogCategories.Default, $"typemap: failed to map managed type to Java type: {type.AssemblyQualifiedName} (Module ID: {type.Module.ModuleVersionId}; Type token: {type.MetadataToken})");
672+
LogTypemapTrace (new StackTrace (true));
673+
}
674+
675+
return null;
676+
}
677+
678+
return Marshal.PtrToStringAnsi (ret);
679+
}
636680

637681
public static string GetJniName (Type type)
638682
{
639683
if (type == null)
640684
throw new ArgumentNullException ("type");
641-
var java = monodroid_typemap_managed_to_java (type.FullName + ", " + type.Assembly.GetName ().Name);
642-
return java == IntPtr.Zero
685+
686+
string java = TypemapManagedToJava (type);
687+
return java == null
643688
? JavaNativeTypeManager.ToJniName (type)
644-
: Marshal.PtrToStringAnsi (java);
689+
: java;
645690
}
646691

647692
public static IntPtr ToJniHandle (IJavaObject value)

src/Mono.Android/Java.Interop/TypeManager.cs

+10-6
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.Reflection;
44
using System.Linq;
5+
using System.Runtime.CompilerServices;
56
using System.Runtime.InteropServices;
67
using Java.Interop.Tools.TypeNameMappings;
78

@@ -203,22 +204,25 @@ static Exception CreateJavaLocationException ()
203204
return new JavaLocationException (loc.ToString ());
204205
}
205206

206-
[DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)]
207-
internal static extern IntPtr monodroid_typemap_java_to_managed (string java);
207+
[MethodImplAttribute(MethodImplOptions.InternalCall)]
208+
static extern Type monodroid_typemap_java_to_managed (string java_type_name);
208209

209210
internal static Type GetJavaToManagedType (string class_name)
210211
{
211-
var t = monodroid_typemap_java_to_managed (class_name);
212-
if (t != IntPtr.Zero)
213-
return Type.GetType (Marshal.PtrToStringAnsi (t));
212+
Type type = monodroid_typemap_java_to_managed (class_name);
213+
if (type != null)
214+
return type;
214215

215216
if (!JNIEnv.IsRunningOnDesktop) {
217+
// Miss message is logged in the native runtime
218+
if (JNIEnv.LogTypemapMissStackTrace)
219+
JNIEnv.LogTypemapTrace (new System.Diagnostics.StackTrace (true));
216220
return null;
217221
}
218222

219223
__TypeRegistrations.RegisterPackages ();
220224

221-
var type = (Type) null;
225+
type = null;
222226
int ls = class_name.LastIndexOf ('/');
223227
var package = ls >= 0 ? class_name.Substring (0, ls) : "";
224228
List<Converter<string, Type>> mappers;

src/Mono.Android/Properties/AssemblyInfo.cs.in

+4
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,7 @@ using System.Runtime.CompilerServices;
2727
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Drawing.Size))]
2828
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Drawing.SizeF))]
2929
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Drawing.SystemColors))]
30+
[assembly: InternalsVisibleTo("Mono.Android-Tests, PublicKey=0024000004800000940000000602000000240000525341310004000011000000438ac2a5acfbf16cbd2b2b47a62762f273df9cb2795ceccdf77d10bf508e69e7a362ea7a45455bbf3ac955e1f2e2814f144e5d817efc4c6502cc012df310783348304e3ae38573c6d658c234025821fda87a0be8a0d504df564e2c93b2b878925f42503e9d54dfef9f9586d9e6f38a305769587b1de01f6c0410328b2c9733db")]
31+
[assembly: InternalsVisibleTo("Java.Interop-Tests, PublicKey=0024000004800000940000000602000000240000525341310004000011000000438ac2a5acfbf16cbd2b2b47a62762f273df9cb2795ceccdf77d10bf508e69e7a362ea7a45455bbf3ac955e1f2e2814f144e5d817efc4c6502cc012df310783348304e3ae38573c6d658c234025821fda87a0be8a0d504df564e2c93b2b878925f42503e9d54dfef9f9586d9e6f38a305769587b1de01f6c0410328b2c9733db")]
32+
[assembly: InternalsVisibleTo("Mono.Android-TestsMultiDex, PublicKey=0024000004800000940000000602000000240000525341310004000011000000438ac2a5acfbf16cbd2b2b47a62762f273df9cb2795ceccdf77d10bf508e69e7a362ea7a45455bbf3ac955e1f2e2814f144e5d817efc4c6502cc012df310783348304e3ae38573c6d658c234025821fda87a0be8a0d504df564e2c93b2b878925f42503e9d54dfef9f9586d9e6f38a305769587b1de01f6c0410328b2c9733db")]
33+
[assembly: InternalsVisibleTo("Mono.Android-TestsAppBundle, PublicKey=0024000004800000940000000602000000240000525341310004000011000000438ac2a5acfbf16cbd2b2b47a62762f273df9cb2795ceccdf77d10bf508e69e7a362ea7a45455bbf3ac955e1f2e2814f144e5d817efc4c6502cc012df310783348304e3ae38573c6d658c234025821fda87a0be8a0d504df564e2c93b2b878925f42503e9d54dfef9f9586d9e6f38a305769587b1de01f6c0410328b2c9733db")]

src/Mono.Android/Test/Java.Interop-Tests/Java.Interop-Tests.csproj

+3-2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
1818
<TargetFrameworkVersion>v10.0</TargetFrameworkVersion>
1919
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
20+
<SignAssembly>true</SignAssembly>
21+
<AssemblyOriginatorKeyFile>..\..\..\..\product.snk</AssemblyOriginatorKeyFile>
2022
</PropertyGroup>
2123
<Import Project="..\..\..\..\Configuration.props" />
2224
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
@@ -48,12 +50,11 @@
4850
<Reference Include="Mono.Android" />
4951
<Reference Include="Xamarin.Android.NUnitLite" />
5052
<Reference Include="Mono.Linq.Expressions">
51-
<HintPath>..\..\..\..\packages\mono.linq.expressions.2.0.0\lib\netstandard2.0\Mono.Linq.Expressions.dll</HintPath>
53+
<HintPath>..\..\..\..\packages\Mono.Linq.Expressions.2.0.0\lib\netstandard2.0\Mono.Linq.Expressions.dll</HintPath>
5254
</Reference>
5355
</ItemGroup>
5456
<ItemGroup>
5557
<Compile Include="Resources\Resource.designer.cs" />
56-
<Compile Include="Properties\AssemblyInfo.cs" />
5758
<Compile Include="Java.InteropTests\JavaInterop_Tests_Reference.cs" />
5859
</ItemGroup>
5960
<ItemGroup>

src/Mono.Android/Test/Java.Interop-Tests/Properties/AssemblyInfo.cs

-30
This file was deleted.

src/Mono.Android/Test/Java.Interop/JnienvTest.cs

+11-15
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Linq;
3+
using System.Runtime.CompilerServices;
34
using System.Runtime.InteropServices;
45
using System.Threading;
56

@@ -373,32 +374,27 @@ public void MoarThreadingTests ()
373374
Assert.IsNull (ignore_t2, string.Format ("No exception should be thrown [t2]! Got: {0}", ignore_t2));
374375
}
375376

376-
[DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)]
377-
static extern IntPtr monodroid_typemap_java_to_managed (string java);
378-
379377
[Test]
380378
public void JavaToManagedTypeMapping ()
381379
{
382-
var m = monodroid_typemap_java_to_managed ("android/content/res/Resources");
383-
Assert.AreNotEqual (IntPtr.Zero, m);
384-
m = monodroid_typemap_java_to_managed ("this/type/does/not/exist");
385-
Assert.AreEqual (IntPtr.Zero, m);
380+
Type m = Java.Interop.TypeManager.GetJavaToManagedType ("android/content/res/Resources");
381+
Assert.AreNotEqual (null, m);
382+
m = Java.Interop.TypeManager.GetJavaToManagedType ("this/type/does/not/exist");
383+
Assert.AreEqual (null, m);
386384
}
387385

388386
[DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)]
389-
static extern IntPtr monodroid_typemap_managed_to_java (string java);
390-
391-
string GetTypeName (Type type)
392-
{
393-
return type.FullName + ", " + type.Assembly.GetName ().Name;
394-
}
387+
static extern IntPtr monodroid_typemap_managed_to_java (byte[] mvid, int token);
395388

396389
[Test]
397390
public void ManagedToJavaTypeMapping ()
398391
{
399-
var m = monodroid_typemap_managed_to_java (GetTypeName (typeof (Activity)));
392+
Type type = typeof(Activity);
393+
var m = monodroid_typemap_managed_to_java (type.Module.ModuleVersionId.ToByteArray (), type.MetadataToken);
400394
Assert.AreNotEqual (IntPtr.Zero, m, "`Activity` subclasses Java.Lang.Object, it should be in the typemap!");
401-
m = monodroid_typemap_managed_to_java (GetTypeName (typeof (JnienvTest)));
395+
396+
type = typeof (JnienvTest);
397+
m = monodroid_typemap_managed_to_java (type.Module.ModuleVersionId.ToByteArray (), type.MetadataToken);
402398
Assert.AreEqual (IntPtr.Zero, m, "`JnienvTest` does *not* subclass Java.Lang.Object, it should *not* be in the typemap!");
403399
}
404400

src/Mono.Android/Test/Mono.Android-Test.Library/Mono.Android-Test.Library.csproj

-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@
4646
</ItemGroup>
4747
<ItemGroup>
4848
<Compile Include="Resources\Resource.designer.cs" />
49-
<Compile Include="Properties\AssemblyInfo.cs" />
5049
<Compile Include="CustomTextView.cs" />
5150
</ItemGroup>
5251
<ItemGroup>

0 commit comments

Comments
 (0)