|
3 | 3 | using System; |
4 | 4 | using System.Collections.Generic; |
5 | 5 | using System.IO; |
6 | | -using System.Reflection; |
| 6 | +using System.Reflection.Metadata; |
| 7 | +using System.Reflection.Metadata.Ecma335; |
| 8 | +using System.Reflection.PortableExecutable; |
7 | 9 | using System.Text; |
8 | 10 | using Microsoft.Build.Framework; |
9 | 11 | using Microsoft.Build.Utilities; |
@@ -328,9 +330,22 @@ void AddEnvironment () |
328 | 330 | } |
329 | 331 | } |
330 | 332 |
|
| 333 | + int android_runtime_jnienv_class_token = -1; |
| 334 | + int jnienv_initialize_method_token = -1; |
| 335 | + int jnienv_registerjninatives_method_token = -1; |
331 | 336 | foreach (var assembly in ResolvedAssemblies) { |
332 | 337 | updateNameWidth (assembly); |
333 | 338 | updateAssemblyCount (assembly); |
| 339 | + |
| 340 | + if (android_runtime_jnienv_class_token != -1) { |
| 341 | + continue; |
| 342 | + } |
| 343 | + |
| 344 | + if (!assembly.ItemSpec.EndsWith ("Mono.Android.dll", StringComparison.OrdinalIgnoreCase)) { |
| 345 | + continue; |
| 346 | + } |
| 347 | + |
| 348 | + GetRequiredTokens (assembly.ItemSpec, out android_runtime_jnienv_class_token, out jnienv_initialize_method_token, out jnienv_registerjninatives_method_token); |
334 | 349 | } |
335 | 350 |
|
336 | 351 | if (!UseAssemblyStore) { |
@@ -409,6 +424,9 @@ void AddEnvironment () |
409 | 424 | MonoComponents = monoComponents, |
410 | 425 | NativeLibraries = uniqueNativeLibraries, |
411 | 426 | HaveAssemblyStore = UseAssemblyStore, |
| 427 | + AndroidRuntimeJNIEnvToken = android_runtime_jnienv_class_token, |
| 428 | + JNIEnvInitializeToken = jnienv_initialize_method_token, |
| 429 | + JNIEnvRegisterJniNativesToken = jnienv_registerjninatives_method_token, |
412 | 430 | }; |
413 | 431 | appConfigAsmGen.Init (); |
414 | 432 |
|
@@ -446,5 +464,71 @@ string ValidAssemblerString (string s) |
446 | 464 | return s.Replace ("\"", "\\\""); |
447 | 465 | } |
448 | 466 | } |
| 467 | + |
| 468 | + void GetRequiredTokens (string assemblyFilePath, out int android_runtime_jnienv_class_token, out int jnienv_initialize_method_token, out int jnienv_registerjninatives_method_token) |
| 469 | + { |
| 470 | + using (var pe = new PEReader (File.OpenRead (assemblyFilePath))) { |
| 471 | + GetRequiredTokens (pe.GetMetadataReader (), out android_runtime_jnienv_class_token, out jnienv_initialize_method_token, out jnienv_registerjninatives_method_token); |
| 472 | + } |
| 473 | + |
| 474 | + if (android_runtime_jnienv_class_token == -1 || jnienv_initialize_method_token == -1 || jnienv_registerjninatives_method_token == -1) { |
| 475 | + throw new InvalidOperationException ($"Unable to find the required Android.Runtime.JNIEnv method tokens"); |
| 476 | + } |
| 477 | + } |
| 478 | + |
| 479 | + void GetRequiredTokens (MetadataReader reader, out int android_runtime_jnienv_class_token, out int jnienv_initialize_method_token, out int jnienv_registerjninatives_method_token) |
| 480 | + { |
| 481 | + android_runtime_jnienv_class_token = -1; |
| 482 | + jnienv_initialize_method_token = -1; |
| 483 | + jnienv_registerjninatives_method_token = -1; |
| 484 | + |
| 485 | + TypeDefinition? typeDefinition = null; |
| 486 | + |
| 487 | + foreach (TypeDefinitionHandle typeHandle in reader.TypeDefinitions) { |
| 488 | + TypeDefinition td = reader.GetTypeDefinition (typeHandle); |
| 489 | + if (!TypeMatches (td)) { |
| 490 | + continue; |
| 491 | + } |
| 492 | + |
| 493 | + typeDefinition = td; |
| 494 | + android_runtime_jnienv_class_token = MetadataTokens.GetToken (reader, typeHandle); |
| 495 | + break; |
| 496 | + } |
| 497 | + |
| 498 | + if (typeDefinition == null) { |
| 499 | + return; |
| 500 | + } |
| 501 | + |
| 502 | + foreach (MethodDefinitionHandle methodHandle in typeDefinition.Value.GetMethods ()) { |
| 503 | + MethodDefinition md = reader.GetMethodDefinition (methodHandle); |
| 504 | + string name = reader.GetString (md.Name); |
| 505 | + |
| 506 | + if (jnienv_initialize_method_token == -1 && String.Compare (name, "Initialize", StringComparison.Ordinal) == 0) { |
| 507 | + jnienv_initialize_method_token = MetadataTokens.GetToken (reader, methodHandle); |
| 508 | + } else if (jnienv_registerjninatives_method_token == -1 && String.Compare (name, "RegisterJniNatives", StringComparison.Ordinal) == 0) { |
| 509 | + jnienv_registerjninatives_method_token = MetadataTokens.GetToken (reader, methodHandle); |
| 510 | + } |
| 511 | + |
| 512 | + if (jnienv_initialize_method_token != -1 && jnienv_registerjninatives_method_token != -1) { |
| 513 | + break; |
| 514 | + } |
| 515 | + } |
| 516 | + |
| 517 | + |
| 518 | + bool TypeMatches (TypeDefinition td) |
| 519 | + { |
| 520 | + string ns = reader.GetString (td.Namespace); |
| 521 | + if (String.Compare (ns, "Android.Runtime", StringComparison.Ordinal) != 0) { |
| 522 | + return false; |
| 523 | + } |
| 524 | + |
| 525 | + string name = reader.GetString (td.Name); |
| 526 | + if (String.Compare (name, "JNIEnv", StringComparison.Ordinal) != 0) { |
| 527 | + return false; |
| 528 | + } |
| 529 | + |
| 530 | + return true; |
| 531 | + } |
| 532 | + } |
449 | 533 | } |
450 | 534 | } |
0 commit comments