protected JniMember(IntPtr handle, JniClass declaringClass, bool isStatic, string signature) { if (handle == IntPtr.Zero) { throw new JniException("TODO"); } VerifyInputJniObject(declaringClass); mHandle = handle; mDeclaringClass = declaringClass; mIsStatic = isStatic; // TODO - refactor this mess string returnType = signature.Trim(); int pos = returnType.LastIndexOf(')'); if (pos > -1) returnType = returnType.Substring(pos + 1); pos = returnType.LastIndexOf('['); mArrayRank = -1; string type = returnType; if (pos > -1) { mArrayRank = pos + 1; type = type.Substring(pos + 1); } if (type.Length == 1) { if (type == "V") { mJniType = JniType.Void; } else { mJniType = CsJni.JniArray.ParseArrayPrimitiveType(type); if (mJniType == JniType.Null) { throw new JniException("TODO"); } } } else { if (!(type.StartsWith("L", StringComparison.Ordinal) && type.EndsWith(";", StringComparison.Ordinal))) { throw new JniException("TODO"); } switch (type) { case "Ljava/lang/String;": mJniType = JniType.String; break; case "Ljava/lang/Class;": mJniType = JniType.Class; break; case "Ljava/lang/Throwable;": mJniType = JniType.Throwable; break; default: mJniType = JniType.NonPrimitive; break; } } }
internal static JniObject NDimensionalArrayFromHandle(JniEnvironment environment, IntPtr handle, int arrayRank, JniType elementType) { if (arrayRank == 1) { return OneDimensionalArrayFromHandle(environment, handle, elementType); } else if (arrayRank > 1) { return new JniObjectArray(environment, handle, JniObjectLifecycle.Local, arrayRank, elementType); } else { throw new JniException("TODO"); } }
static string GetJniTypeName(TypeReference typeRef, ExportParameterKind exportKind) { return(JniType.GetJniTypeName(typeRef, exportKind)); }
internal static ExportAttribute ToExportAttribute(CustomAttribute attr, IMemberDefinition declaringMember) { var name = attr.ConstructorArguments.Count > 0 ? (string)attr.ConstructorArguments [0].Value : declaringMember.Name; if (attr.Properties.Count == 0) { return(new ExportAttribute(name)); } var typeArgs = (CustomAttributeArgument [])attr.Properties.FirstOrDefault(p => p.Name == "Throws").Argument.Value; var thrown = typeArgs != null && typeArgs.Any() ? (from caa in typeArgs select JniType.Parse(GetJniTypeName((TypeReference)caa.Value)).Type).ToArray() : null; var superArgs = (string)attr.Properties.FirstOrDefault(p => p.Name == "SuperArgumentsString").Argument.Value; return(new ExportAttribute(name) { ThrownNames = thrown, SuperArgumentsString = superArgs }); }
JavaCallableWrapperGenerator(TypeDefinition type, string outerType, Action <string, object[]> log) { this.type = type; this.log = log; if (!type.IsClass) { Diagnostic.Error(4200, LookupSource(type), "Can only generate Java wrappers for 'class' types, not type '{0}'.", type.FullName); } string jniName = JniType.ToJniName(type); if (jniName == null) { Diagnostic.Error(4201, LookupSource(type), "Unable to determine Java name for type {0}", type.FullName); } if (!string.IsNullOrEmpty(outerType)) { string p; jniName = jniName.Substring(outerType.Length + 1); ExtractJavaNames(outerType, out p, out outerType); } ExtractJavaNames(jniName, out package, out name); if (string.IsNullOrEmpty(package) && (type.IsSubclassOf("Android.App.Activity") || type.IsSubclassOf("Android.App.Application") || type.IsSubclassOf("Android.App.Service") || type.IsSubclassOf("Android.Content.BroadcastReceiver") || type.IsSubclassOf("Android.Content.ContentProvider"))) { Diagnostic.Error(4203, LookupSource(type), "The Name property must be a fully qualified 'package.TypeName' value, and no package was found for '{0}'.", jniName); } foreach (MethodDefinition minfo in type.Methods.Where(m => !m.IsConstructor)) { var baseMethods = GetBaseMethods(minfo); var baseRegiteredMethod = baseMethods.FirstOrDefault(m => GetRegisterAttributes(m).Any()); if (baseRegiteredMethod != null) { AddMethod(baseRegiteredMethod, minfo); } else if (GetExportFieldAttributes(minfo).Any()) { AddMethod(null, minfo); HasExport = true; } else if (GetExportAttributes(minfo).Any()) { AddMethod(null, minfo); HasExport = true; } } foreach (MethodDefinition imethod in type.Interfaces.Cast <TypeReference> () .Select(r => { var d = r.Resolve(); if (d == null) { Diagnostic.Error(4204, LookupSource(type), "Unable to resolve interface type '{0}'. Are you missing an assembly reference?", r.FullName); } return(d); }) .Where(d => GetRegisterAttributes(d).Any()) .SelectMany(d => d.Methods.Cast <MethodDefinition>())) { AddMethod(imethod, imethod); } var ctorTypes = new List <TypeDefinition> () { type, }; foreach (var bt in type.GetBaseTypes()) { ctorTypes.Add(bt); RegisterAttribute rattr = GetRegisterAttributes(bt).FirstOrDefault(); if (rattr != null && rattr.DoNotGenerateAcw) { break; } } ctorTypes.Reverse(); var curCtors = new List <MethodDefinition> (); foreach (MethodDefinition minfo in type.Methods.Where(m => m.IsConstructor)) { if (GetExportAttributes(minfo).Any()) { if (minfo.IsStatic) { // Diagnostic.Warning (log, "ExportAttribute does not work on static constructor"); } else { AddConstructor(minfo, ctorTypes [0], outerType, null, curCtors, false, true); HasExport = true; } } } AddConstructors(ctorTypes [0], outerType, null, curCtors, true); for (int i = 1; i < ctorTypes.Count; ++i) { var baseCtors = curCtors; curCtors = new List <MethodDefinition> (); AddConstructors(ctorTypes [i], outerType, baseCtors, curCtors, false); } }
public override void RegisterNativeMembers(JniType nativeClass, Type type, string?methods) { if (FastRegisterNativeMembers(nativeClass, type, methods)) { return; } if (string.IsNullOrEmpty(methods)) { if (jniAddNativeMethodRegistrationAttributePresent) { base.RegisterNativeMembers(nativeClass, type, methods); } return; } string[] members = methods !.Split('\n'); if (members.Length < 2) { if (jniAddNativeMethodRegistrationAttributePresent) { base.RegisterNativeMembers(nativeClass, type, methods); } return; } JniNativeMethodRegistration[] natives = new JniNativeMethodRegistration [members.Length - 1]; for (int i = 0; i < members.Length; ++i) { string method = members [i]; if (string.IsNullOrEmpty(method)) { continue; } string[] toks = members [i].Split(new[] { ':' }, 4); Delegate callback; if (toks [2] == "__export__") { var mname = toks [0].Substring(2); MethodInfo?minfo = null; foreach (var mi in type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)) { if (mi.Name == mname && JavaNativeTypeManager.GetJniSignature(mi) == toks [1]) { minfo = mi; break; } } if (minfo == null) { throw new InvalidOperationException(String.Format("Specified managed method '{0}' was not found. Signature: {1}", mname, toks [1])); } callback = CreateDynamicCallback(minfo); } else { Type callbackDeclaringType = type; if (toks.Length == 4) { callbackDeclaringType = Type.GetType(toks [3], throwOnError: true) !; } while (callbackDeclaringType.ContainsGenericParameters) { callbackDeclaringType = callbackDeclaringType.BaseType !; } GetCallbackHandler connector = (GetCallbackHandler)Delegate.CreateDelegate(typeof(GetCallbackHandler), callbackDeclaringType, toks [2]); callback = connector(); } natives [i] = new JniNativeMethodRegistration(toks [0], toks [1], callback); } JniEnvironment.Types.RegisterNatives(nativeClass.PeerReference, natives, natives.Length); }
public unsafe void MethodInvocationTiming() { FooMethods pinvoke_methods; foo_get_methods(out pinvoke_methods); var p_instance_void = (DV)Marshal.GetDelegateForFunctionPointer(pinvoke_methods.instance_void, typeof(DV)); var p_instance_int = (DI)Marshal.GetDelegateForFunctionPointer(pinvoke_methods.instance_int, typeof(DI)); var p_instance_ptr = (DP)Marshal.GetDelegateForFunctionPointer(pinvoke_methods.instance_ptr, typeof(DP)); var p_void_1a = (DV1A)Marshal.GetDelegateForFunctionPointer(pinvoke_methods.void_1_args, typeof(DV1A)); var p_void_2a = (DV2A)Marshal.GetDelegateForFunctionPointer(pinvoke_methods.void_2_args, typeof(DV2A)); var p_void_3a = (DV3A)Marshal.GetDelegateForFunctionPointer(pinvoke_methods.void_3_args, typeof(DV3A)); var p_void_1ai = (DV1AI)Marshal.GetDelegateForFunctionPointer(pinvoke_methods.void_1_iargs, typeof(DV1AI)); var p_void_2ai = (DV2AI)Marshal.GetDelegateForFunctionPointer(pinvoke_methods.void_2_iargs, typeof(DV2AI)); var p_void_3ai = (DV3AI)Marshal.GetDelegateForFunctionPointer(pinvoke_methods.void_3_iargs, typeof(DV3AI)); var Object_class = new JniType("java/lang/Object"); var Object_init = Object_class.GetConstructor("()V"); var transfer = JniObjectReferenceOptions.CopyAndDispose; var jobj1 = CreateJavaObject(Object_class.NewObject(Object_init, null), transfer); var jobj2 = CreateJavaObject(Object_class.NewObject(Object_init, null), transfer); var jobj3 = CreateJavaObject(Object_class.NewObject(Object_init, null), transfer); var obj1 = new SomeClass(); var obj2 = new SomeClass(); var obj3 = new SomeClass(); var j = new JavaTiming(); var m = new ManagedTiming(); var comparisons = new[] { new { Name = "static void", Jni = A(() => JavaTiming.StaticVoidMethod()), Managed = A(() => ManagedTiming.StaticVoidMethod()), Pinvoke = A(() => foo_void_timing()), }, new { Name = "static int", Jni = A(() => JavaTiming.StaticIntMethod()), Managed = A(() => ManagedTiming.StaticIntMethod()), Pinvoke = A(() => foo_int_timing()), }, new { Name = "static object", Jni = A(() => JavaTiming.StaticObjectMethod()), Managed = A(() => ManagedTiming.StaticObjectMethod()), Pinvoke = A(() => foo_ptr_timing()), }, new { Name = "virtual void", Jni = A(() => j.VirtualVoidMethod()), Managed = A(() => m.VirtualVoidMethod()), Pinvoke = A(() => p_instance_void()), }, new { Name = "virtual int", Jni = A(() => j.VirtualIntMethod()), Managed = A(() => m.VirtualIntMethod()), Pinvoke = A(() => p_instance_int()), }, new { Name = "virtual object", Jni = A(() => j.VirtualObjectMethod()), Managed = A(() => m.VirtualObjectMethod()), Pinvoke = A(() => p_instance_ptr()), }, new { Name = "final void", Jni = A(() => j.FinalVoidMethod()), Managed = A(() => m.FinalVoidMethod()), Pinvoke = A(null), }, new { Name = "final int", Jni = A(() => j.FinalIntMethod()), Managed = A(() => m.FinalIntMethod()), Pinvoke = A(null), }, new { Name = "final object", Jni = A(() => j.FinalObjectMethod()), Managed = A(() => m.FinalObjectMethod()), Pinvoke = A(null), }, new { Name = "static void o1", Jni = A(() => JavaTiming.StaticVoidMethod1Args(jobj1)), Managed = A(() => ManagedTiming.StaticVoidMethod1Args(obj1)), Pinvoke = A(() => { // We include timing of the GCHandle manipulation since // a JNI invocation has to do similar work, and pinning // is usually always needed for P/Invokes. GCHandle h1 = GCHandle.Alloc(obj1, GCHandleType.Pinned); IntPtr addr1 = h1.AddrOfPinnedObject(); p_void_1a(addr1); h1.Free(); }), }, new { Name = "static void o2", Jni = A(() => JavaTiming.StaticVoidMethod2Args(jobj1, jobj2)), Managed = A(() => ManagedTiming.StaticVoidMethod2Args(obj1, obj2)), Pinvoke = A(() => { GCHandle h1 = GCHandle.Alloc(obj1, GCHandleType.Pinned), h2 = GCHandle.Alloc(obj2, GCHandleType.Pinned); IntPtr addr1 = h1.AddrOfPinnedObject(), addr2 = h2.AddrOfPinnedObject(); p_void_2a(addr1, addr2); h1.Free(); h2.Free(); }), }, new { Name = "static void o3", Jni = A(() => JavaTiming.StaticVoidMethod3Args(jobj1, jobj2, jobj3)), Managed = A(() => ManagedTiming.StaticVoidMethod3Args(obj1, obj2, obj3)), Pinvoke = A(() => { GCHandle h1 = GCHandle.Alloc(obj1, GCHandleType.Pinned), h2 = GCHandle.Alloc(obj2, GCHandleType.Pinned), h3 = GCHandle.Alloc(obj3, GCHandleType.Pinned); IntPtr addr1 = h1.AddrOfPinnedObject(), addr2 = h2.AddrOfPinnedObject(), addr3 = h3.AddrOfPinnedObject(); p_void_3a(addr1, addr2, addr3); h1.Free(); h2.Free(); h3.Free(); }), }, new { Name = "static void i1", Jni = A(() => JavaTiming.StaticVoidMethod1IArgs(42)), Managed = A(() => ManagedTiming.StaticVoidMethod1IArgs(42)), Pinvoke = A(() => p_void_1ai(42)), }, new { Name = "static void i2", Jni = A(() => JavaTiming.StaticVoidMethod2IArgs(42, 42)), Managed = A(() => ManagedTiming.StaticVoidMethod2IArgs(42, 42)), Pinvoke = A(() => p_void_2ai(42, 42)), }, new { Name = "static void i3", Jni = A(() => JavaTiming.StaticVoidMethod3IArgs(42, 42, 42)), Managed = A(() => ManagedTiming.StaticVoidMethod3IArgs(42, 42, 42)), Pinvoke = A(() => p_void_3ai(42, 42, 42)), }, }; #if __ANDROID__ const int count = 1000; #else // __ANDROID__ const int count = 100000; #endif // __ANDROID__ var total = Stopwatch.StartNew(); foo_init(JniEnvironment.EnvironmentPointer); var jniTimes = new long [comparisons.Length]; foo_get_native_jni_timings(JniEnvironment.EnvironmentPointer, count, JavaTiming.TypeRef.PeerReference.Handle, j.PeerReference.Handle, jniTimes); int jniTimeIndex = 0; foreach (var c in comparisons) { var jw = System.Diagnostics.Stopwatch.StartNew(); for (int i = 0; i < count; ++i) { c.Jni(); } jw.Stop(); var mw = System.Diagnostics.Stopwatch.StartNew(); for (int i = 0; i < count; ++i) { c.Managed(); } mw.Stop(); System.Diagnostics.Stopwatch pw = null; if (c.Pinvoke != null) { pw = System.Diagnostics.Stopwatch.StartNew(); for (int i = 0; i < count; ++i) { c.Pinvoke(); } pw.Stop(); } string message = string.Format("Method Invoke: {0}: JNI is {1}x managed", c.Name, System.Math.Round(jw.Elapsed.TotalMilliseconds / mw.Elapsed.TotalMilliseconds)); Console.WriteLine(message); var ct = TimeSpan.FromMilliseconds(jniTimes [jniTimeIndex++]); Console.WriteLine("\t C/JNI: {0} ms | average: {1} ms", FormatFraction(ct.TotalMilliseconds, 12, 5), FormatFraction(ct.TotalMilliseconds / count, 12, 5)); Console.WriteLine("\t JNI: {0} ms; {1,3}x C/JNI | average: {2} ms", FormatFraction(jw.Elapsed.TotalMilliseconds, 12, 5), ToString(jw.Elapsed, ct), FormatFraction(jw.Elapsed.TotalMilliseconds / count, 12, 5)); Console.WriteLine("\tManaged: {0} ms | average: {1} ms", FormatFraction(mw.Elapsed.TotalMilliseconds, 12, 5), FormatFraction(mw.Elapsed.TotalMilliseconds / count, 12, 5)); if (pw != null) { Console.WriteLine("\tPinvoke: {0} ms; {1,3}x managed | average: {2} ms", FormatFraction(pw.Elapsed.TotalMilliseconds, 12, 5), ToString(pw.Elapsed, mw.Elapsed), FormatFraction(pw.Elapsed.TotalMilliseconds / count, 12, 5)); } } total.Stop(); Console.WriteLine("## {0} Timing: {1}", nameof(MethodInvocationTiming), total.Elapsed); }
protected void VerifyReturnType(JniType type) { if (this.ReturnJniType != type) { throw new JniException("TODO"); } }
public void ObjectArrayEnumerationTiming() { var total = Stopwatch.StartNew(); JniMethodInfo Class_getMethods; using (var t = new JniType("java/lang/Class")) { Class_getMethods = t.GetInstanceMethod("getMethods", "()[Ljava/lang/reflect/Method;"); } JniMethodInfo Method_getName; JniMethodInfo Method_getParameterTypes; JniMethodInfo Method_getReturnType; using (var t = new JniType("java/lang/reflect/Method")) { Method_getName = t.GetInstanceMethod("getName", "()Ljava/lang/String;"); Method_getParameterTypes = t.GetInstanceMethod("getParameterTypes", "()[Ljava/lang/Class;"); Method_getReturnType = t.GetInstanceMethod("getReturnType", "()Ljava/lang/Class;"); } Console.WriteLine("# {0}: Method Lookups Timing: {1}", nameof(ObjectArrayEnumerationTiming), total.Elapsed); var methodHandles = new List <JavaObject> (); using (var Arrays_class = new JniType("java/util/Arrays")) { var lrefMethods = JniEnvironment.InstanceMethods.CallObjectMethod(Arrays_class.PeerReference, Class_getMethods); Console.WriteLine("# {0}: java.util.Arrays.class.getMethods() Timing: {1}", nameof(ObjectArrayEnumerationTiming), total.Elapsed); var methodsTiming = Stopwatch.StartNew(); using (var methods = new JavaObjectArray <JavaObject> (ref lrefMethods, JniObjectReferenceOptions.Copy)) { foreach (var method in methods) { methodHandles.Add(method); } } methodsTiming.Stop(); Console.WriteLine("# methodHandles(JavaObjectArray<JavaObject>) creation timing: {0} Count={1}", methodsTiming.Elapsed, methodHandles.Count); methodsTiming = Stopwatch.StartNew(); var methodHandlesGO = new List <JavaObject> (); var vm = JniEnvironment.Runtime; int len = JniEnvironment.Arrays.GetArrayLength(lrefMethods); for (int i = 0; i < len; ++i) { var v = JniEnvironment.Arrays.GetObjectArrayElement(lrefMethods, i); methodHandlesGO.Add(vm.ValueManager.GetValue <JavaObject> (ref v, JniObjectReferenceOptions.CopyAndDoNotRegister)); JniObjectReference.Dispose(ref v); } methodsTiming.Stop(); Console.WriteLine("# methodHandles(JavaVM.GetObject) creation timing: {0} Count={1}", methodsTiming.Elapsed, methodHandles.Count); foreach (var h in methodHandlesGO) { h.DisposeUnlessReferenced(); } methodsTiming = Stopwatch.StartNew(); var methodHandlesAr = new List <JavaObject> (); len = JniEnvironment.Arrays.GetArrayLength(lrefMethods); for (int i = 0; i < len; ++i) { var v = JniEnvironment.Arrays.GetObjectArrayElement(lrefMethods, i); methodHandlesAr.Add(new JavaObject(ref v, JniObjectReferenceOptions.CopyAndDoNotRegister)); JniObjectReference.Dispose(ref v); } methodsTiming.Stop(); Console.WriteLine("# methodHandles(JavaObject[]) creation timing: {0} Count={1}", methodsTiming.Elapsed, methodHandles.Count); foreach (var h in methodHandlesAr) { h.Dispose(); } methodsTiming = Stopwatch.StartNew(); var methodHandlesGR = new List <JniObjectReference> (); len = JniEnvironment.Arrays.GetArrayLength(lrefMethods); for (int i = 0; i < len; ++i) { var v = JniEnvironment.Arrays.GetObjectArrayElement(lrefMethods, i); methodHandlesGR.Add(v.NewGlobalRef()); JniObjectReference.Dispose(ref v); } methodsTiming.Stop(); Console.WriteLine("# methodHandles(JniGlobalReference) creation timing: {0} Count={1}", methodsTiming.Elapsed, methodHandles.Count); for (int i = 0; i < methodHandlesGR.Count; ++i) { var h = methodHandlesGR [i]; JniObjectReference.Dispose(ref h); methodHandlesGR [i] = h; } JniObjectReference.Dispose(ref lrefMethods); } // HACK HACK HACK // This is to workaround an error wherein constructing `pt` (below) // throws an exception because `h` is NULL, when it really can't be. // I believe that this is due to the finalizer, which likewise makes // NO SENSE AT ALL, since `p` should be keeping the handle valid! // GC.Collect (); // GC.WaitForPendingFinalizers (); foreach (var method in methodHandles) { var lookupTiming = Stopwatch.StartNew(); var n_name = JniEnvironment.InstanceMethods.CallObjectMethod(method.PeerReference, Method_getName); var name = JniEnvironment.Strings.ToString(ref n_name, JniObjectReferenceOptions.CopyAndDispose); var n_rt = JniEnvironment.InstanceMethods.CallObjectMethod(method.PeerReference, Method_getReturnType); using (var rt = new JniType(ref n_rt, JniObjectReferenceOptions.CopyAndDispose)) { } var parameterTiming = Stopwatch.StartNew(); var enumTime = new TimeSpan(); var lrefPs = JniEnvironment.InstanceMethods.CallObjectMethod(method.PeerReference, Method_getParameterTypes); int len = JniEnvironment.Arrays.GetArrayLength(lrefPs); var enumSw = Stopwatch.StartNew(); for (int i = 0; i < len; ++i) { var p = JniEnvironment.Arrays.GetObjectArrayElement(lrefPs, i); using (var pt = new JniType(ref p, JniObjectReferenceOptions.Copy)) { } JniObjectReference.Dispose(ref p); } JniObjectReference.Dispose(ref lrefPs); enumSw.Stop(); enumTime = enumSw.Elapsed; parameterTiming.Stop(); Console.WriteLine("## method '{0}' timing: Total={1}; Parameters={2} Parameters.Dispose={3}", name, lookupTiming.Elapsed, enumTime, parameterTiming.Elapsed); } var mhDisposeTiming = Stopwatch.StartNew(); foreach (var method in methodHandles) { method.Dispose(); } mhDisposeTiming.Stop(); Console.WriteLine("# methodHandles -> Dispose() Timing: {0}", mhDisposeTiming.Elapsed); total.Stop(); Console.WriteLine("## {0} Timing: {1}", nameof(ObjectArrayEnumerationTiming), total.Elapsed); }
void Run(DirectoryAssemblyResolver res) { PackageNamingPolicy pnp; JniType.PackageNamingPolicy = Enum.TryParse(PackageNamingPolicy, out pnp) ? pnp : PackageNamingPolicyEnum.LowercaseHash; var temp = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); Directory.CreateDirectory(temp); var selectedWhitelistAssemblies = new List <string> (); // Put every assembly we'll need in the resolver foreach (var assembly in ResolvedAssemblies) { res.Load(Path.GetFullPath(assembly.ItemSpec)); if (MonoAndroidHelper.FrameworkAttributeLookupTargets.Any(a => Path.GetFileName(assembly.ItemSpec) == a)) { selectedWhitelistAssemblies.Add(Path.GetFullPath(assembly.ItemSpec)); } } // However we only want to look for JLO types in user code var assemblies = ResolvedUserAssemblies.Select(p => p.ItemSpec).ToList(); var fxAdditions = MonoAndroidHelper.GetFrameworkAssembliesToTreatAsUserAssemblies(ResolvedAssemblies) .Where(a => assemblies.All(x => Path.GetFileName(x) != Path.GetFileName(a))); assemblies = assemblies.Concat(fxAdditions).ToList(); // Step 1 - Find all the JLO types var all_java_types = JavaTypeScanner.GetJavaTypes(assemblies, res, Log.LogWarning); WriteTypeMappings(all_java_types); var java_types = all_java_types.Where(t => !JavaTypeScanner.ShouldSkipJavaCallableWrapperGeneration(t)); // Step 2 - Generate Java stub code var keep_going = Generator.CreateJavaSources( Log, java_types, temp, ApplicationJavaClass, UseSharedRuntime, int.Parse(AndroidSdkPlatform) <= 10, ResolvedAssemblies.Any(assembly => Path.GetFileName(assembly.ItemSpec) == "Mono.Android.Export.dll")); var temp_map_file = Path.Combine(temp, "acw-map.temp"); // We need to save a map of .NET type -> ACW type for resource file fixups var managed = new Dictionary <string, TypeDefinition> (); var java = new Dictionary <string, TypeDefinition> (); var acw_map = new StreamWriter(temp_map_file); foreach (var type in java_types) { string managedKey = type.FullName.Replace('/', '.'); string javaKey = JniType.ToJniName(type).Replace('/', '.'); acw_map.WriteLine("{0};{1}", type.GetPartialAssemblyQualifiedName(), javaKey); acw_map.WriteLine("{0};{1}", type.GetAssemblyQualifiedName(), javaKey); TypeDefinition conflict; if (managed.TryGetValue(managedKey, out conflict)) { Log.LogWarning( "Duplicate managed type found! Mappings between managed types and Java types must be unique. " + "First Type: '{0}'; Second Type: '{1}'.", conflict.GetAssemblyQualifiedName(), type.GetAssemblyQualifiedName()); Log.LogWarning( "References to the type '{0}' will refer to '{1}'.", managedKey, conflict.GetAssemblyQualifiedName()); continue; } if (java.TryGetValue(javaKey, out conflict)) { Log.LogError( "Duplicate Java type found! Mappings between managed types and Java types must be unique. " + "First Type: '{0}'; Second Type: '{1}'", conflict.GetAssemblyQualifiedName(), type.GetAssemblyQualifiedName()); keep_going = false; continue; } managed.Add(managedKey, type); java.Add(javaKey, type); acw_map.WriteLine("{0};{1}", managedKey, javaKey); acw_map.WriteLine("{0};{1}", JniType.ToCompatJniName(type).Replace('/', '.'), javaKey); } acw_map.Close(); //The previous steps found an error, so we must abort and not generate any further output //We must do so subsequent unchanged builds fail too. if (!keep_going) { File.Delete(temp_map_file); return; } MonoAndroidHelper.CopyIfChanged(temp_map_file, AcwMapFile); try { File.Delete(temp_map_file); } catch (Exception) { } // Only overwrite files if the contents actually changed foreach (var file in Directory.GetFiles(temp, "*", SearchOption.AllDirectories)) { var dest = Path.GetFullPath(Path.Combine(OutputDirectory, "src", file.Substring(temp.Length + 1))); MonoAndroidHelper.CopyIfChanged(file, dest); } // Step 3 - Merge [Activity] and friends into AndroidManifest.xml var manifest = new ManifestDocument(ManifestTemplate, this.Log); manifest.PackageName = PackageName; manifest.ApplicationName = ApplicationName ?? PackageName; manifest.Placeholders = ManifestPlaceholders; manifest.Assemblies.AddRange(assemblies); manifest.Resolver = res; manifest.SdkDir = AndroidSdkDir; manifest.SdkVersion = AndroidSdkPlatform; manifest.Debug = Debug; manifest.NeedsInternet = NeedsInternet; var additionalProviders = manifest.Merge(all_java_types, selectedWhitelistAssemblies, ApplicationJavaClass, EmbedAssemblies, BundledWearApplicationName, MergedManifestDocuments); var temp_manifest = Path.Combine(temp, "AndroidManifest.xml"); var real_manifest = Path.GetFullPath(MergedAndroidManifestOutput); manifest.Save(temp_manifest); // Only write the new manifest if it actually changed MonoAndroidHelper.CopyIfChanged(temp_manifest, real_manifest); // Create additional runtime provider java sources. string providerTemplateFile = UseSharedRuntime ? "MonoRuntimeProvider.Shared.java" : "MonoRuntimeProvider.Bundled.java"; string providerTemplate = new StreamReader(typeof(JavaCallableWrapperGenerator).Assembly.GetManifestResourceStream(providerTemplateFile)).ReadToEnd(); foreach (var provider in additionalProviders) { var temp_provider = Path.Combine(temp, provider + ".java"); File.WriteAllText(temp_provider, providerTemplate.Replace("MonoRuntimeProvider", provider)); var real_provider_dir = Path.GetFullPath(Path.Combine(OutputDirectory, "src", "mono")); Directory.CreateDirectory(real_provider_dir); var real_provider = Path.Combine(real_provider_dir, provider + ".java"); MonoAndroidHelper.CopyIfChanged(temp_provider, real_provider); } // Create additional application java sources. Action <string, string, string, Func <string, string> > save = (resource, filename, destDir, applyTemplate) => { string temp_file = Path.Combine(temp, filename); string template = applyTemplate(new StreamReader(typeof(GenerateJavaStubs).Assembly.GetManifestResourceStream(resource)).ReadToEnd()); File.WriteAllText(temp_file, template); Directory.CreateDirectory(destDir); var real_file = Path.Combine(destDir, filename); MonoAndroidHelper.CopyIfChanged(temp_file, real_file); }; StringWriter regCallsWriter = new StringWriter(); regCallsWriter.WriteLine("\t\t// Application and Instrumentation ACWs must be registered first."); foreach (var type in java_types) { if (JniType.IsApplication(type) || JniType.IsInstrumentation(type)) { string javaKey = JniType.ToJniName(type).Replace('/', '.'); regCallsWriter.WriteLine("\t\tmono.android.Runtime.register (\"{0}\", {1}.class, {1}.__md_methods);", type.GetAssemblyQualifiedName(), javaKey); } } regCallsWriter.Close(); var real_app_dir = Path.GetFullPath(Path.Combine(OutputDirectory, "src", "mono", "android", "app")); string applicationTemplateFile = "ApplicationRegistration.java"; save(applicationTemplateFile, applicationTemplateFile, real_app_dir, template => template.Replace("// REGISTER_APPLICATION_AND_INSTRUMENTATION_CLASSES_HERE", regCallsWriter.ToString())); // Create NotifyTimeZoneChanges java sources. string notifyTimeZoneChangesFile = "NotifyTimeZoneChanges.java"; save(notifyTimeZoneChangesFile, notifyTimeZoneChangesFile, real_app_dir, template => template); // Delete our temp directory try { Directory.Delete(temp, true); } catch (Exception) { } }
static bool CannotRegisterInStaticConstructor(TypeDefinition type) { return(JniType.IsApplication(type) || JniType.IsInstrumentation(type)); }
static string GetJniSignature(MethodDefinition ctor) { return(JniType.GetJniSignature(ctor)); }
public void InvalidSignatureThrowsJniException() { using (var Integer_class = new JniType("java/lang/Integer")) { Assert.Throws <JavaException> (() => Integer_class.GetConstructor("(C)V")).Dispose(); } }
private static JniObject OneDimensionalArrayFromHandle(JniEnvironment environment, IntPtr handle, JniType elementType) { switch (elementType) { case JniType.NonPrimitive: goto case JniType.Throwable; case JniType.String: goto case JniType.Throwable; case JniType.Class: goto case JniType.Throwable; case JniType.Throwable: return new JniObjectArray(environment, handle, JniObjectLifecycle.Local, 1, elementType); } JniConcreteObjectType primitiveArrayType = JniConcreteObjectType.None; switch (elementType) { case JniType.Boolean: primitiveArrayType = JniConcreteObjectType.BooleanArray; break; case JniType.Byte: primitiveArrayType = JniConcreteObjectType.ByteArray; break; case JniType.Char: primitiveArrayType = JniConcreteObjectType.CharArray; break; case JniType.Double: primitiveArrayType = JniConcreteObjectType.DoubleArray; break; case JniType.Float: primitiveArrayType = JniConcreteObjectType.FloatArray; break; case JniType.Int: primitiveArrayType = JniConcreteObjectType.IntArray; break; case JniType.Long: primitiveArrayType = JniConcreteObjectType.LongArray; break; case JniType.Short: primitiveArrayType = JniConcreteObjectType.ShortArray; break; default: throw new JniException("TODO"); } return JniObject.CreateObjectOfType(environment, handle, primitiveArrayType); }
public unsafe void ObjectCreationTiming() { const int C = 100; var total = Stopwatch.StartNew(); Stopwatch allocTime, newObjectTime, newTime, getObjectTime; using (var Object_class = new JniType("java/lang/Object")) { var Object_init = Object_class.GetConstructor("()V"); allocTime = Stopwatch.StartNew(); for (int i = 0; i < C; ++i) { var h = Object_class.AllocObject(); JniObjectReference.Dispose(ref h); } allocTime.Stop(); newObjectTime = Stopwatch.StartNew(); for (int i = 0; i < C; ++i) { var h = Object_class.NewObject(Object_init, null); JniObjectReference.Dispose(ref h); } newObjectTime.Stop(); newTime = Stopwatch.StartNew(); var olist = new List <JavaObject> (C); for (int i = 0; i < C; ++i) { olist.Add(new JavaObject()); } newTime.Stop(); foreach (var o in olist) { o.Dispose(); } var strings = new JavaObjectArray <string> (100); for (int i = 0; i < 100; ++i) { strings [i] = i.ToString(); } using (strings) { var vm = JniEnvironment.Runtime; var rlist = new List <JavaObject> (C); getObjectTime = Stopwatch.StartNew(); for (int i = 0; i < C; ++i) { var h = JniEnvironment.Arrays.GetObjectArrayElement(strings.PeerReference, i); var o = vm.ValueManager.GetValue <JavaObject> (ref h, JniObjectReferenceOptions.CopyAndDispose); rlist.Add(o); } getObjectTime.Stop(); foreach (var o in rlist) { o.DisposeUnlessReferenced(); } } } total.Stop(); Console.WriteLine("## {0} Timing: Total={1} AllocObject={2} NewObject={3} `new JavaObject()`={4} JavaVM.GetObject()={5}", nameof(ObjectCreationTiming), total.Elapsed, allocTime.Elapsed, newObjectTime.Elapsed, newTime.Elapsed, getObjectTime.Elapsed); }
internal JniObjectArray(JniEnvironment environment, IntPtr handle, JniObjectLifecycle lifecycle, int arrayRank, JniType elementType) : base(environment, handle, lifecycle) { mArrayRank = arrayRank; mElementType = elementType; }
public IList <string> Merge(List <TypeDefinition> subclasses, List <string> selectedWhitelistAssemblies, string applicationClass, bool embed, string bundledWearApplicationName, IEnumerable <string> mergedManifestDocuments) { string applicationName = ApplicationName; var manifest = doc.Root; if (manifest == null || manifest.Name != "manifest") { throw new Exception("Root element must be 'manifest'"); } var manifest_package = (string)manifest.Attribute("package"); if (!string.IsNullOrWhiteSpace(manifest_package)) { PackageName = manifest_package; } manifest.SetAttributeValue(XNamespace.Xmlns + "android", "http://schemas.android.com/apk/res/android"); if (manifest.Attribute(androidNs + "versionCode") == null) { manifest.SetAttributeValue(androidNs + "versionCode", "1"); } if (manifest.Attribute(androidNs + "versionName") == null) { manifest.SetAttributeValue(androidNs + "versionName", "1.0"); } app = CreateApplicationElement(manifest, applicationClass, subclasses, selectedWhitelistAssemblies); if (app.Attribute(androidNs + "label") == null && applicationName != null) { app.SetAttributeValue(androidNs + "label", applicationName); } var existingTypes = new HashSet <string> ( app.Descendants().Select(a => (string)a.Attribute(attName)).Where(v => v != null)); if (!string.IsNullOrEmpty(bundledWearApplicationName)) { if (!app.Elements("meta-data").Any(e => e.Attributes(androidNs + "name").Any(a => a.Value == bundledWearApplicationName))) { app.Add(new XElement("meta-data", new XAttribute(androidNs + "name", "com.google.android.wearable.beta.app"), new XAttribute(androidNs + "resource", "@xml/wearable_app_desc"))); } } // If no <uses-sdk> is specified, add it with both minSdkVersion and // targetSdkVersion set to TargetFrameworkVersion if (!manifest.Elements("uses-sdk").Any()) { manifest.AddFirst( new XElement("uses-sdk", new XAttribute(androidNs + "minSdkVersion", SdkVersionName), new XAttribute(androidNs + "targetSdkVersion", SdkVersionName))); } // If no minSdkVersion is specified, set it to TargetFrameworkVersion var uses = manifest.Element("uses-sdk"); if (uses.Attribute(androidNs + "minSdkVersion") == null) { int minSdkVersion; if (!int.TryParse(SdkVersionName, out minSdkVersion)) { minSdkVersion = 11; } minSdkVersion = Math.Min(minSdkVersion, 11); uses.SetAttributeValue(androidNs + "minSdkVersion", minSdkVersion.ToString()); } string targetSdkVersion; var tsv = uses.Attribute(androidNs + "targetSdkVersion"); if (tsv != null) { targetSdkVersion = tsv.Value; } else { targetSdkVersion = SdkVersionName; uses.AddBeforeSelf(new XComment("suppress UsesMinSdkAttributes")); } int targetSdkVersionValue; if (!int.TryParse(MonoAndroidHelper.GetPlatformApiLevel(targetSdkVersion), out targetSdkVersionValue)) { throw new InvalidOperationException(string.Format("The targetSdkVersion ({0}) is not a valid API level", targetSdkVersion)); } foreach (var t in subclasses) { if (t.IsAbstract) { continue; } if (PackageName == null) { PackageName = t.Namespace; } var name = JniType.ToJniName(t).Replace('/', '.'); var compatName = JniType.ToCompatJniName(t).Replace('/', '.'); if (((string)app.Attribute(attName)) == compatName) { app.SetAttributeValue(attName, name); } Func <TypeDefinition, string, int, XElement> generator = GetGenerator(t); if (generator == null) { continue; } try { // activity not present: create a launcher for it IFF it has attribute if (!existingTypes.Contains(name) && !existingTypes.Contains(compatName)) { XElement fromCode = generator(t, name, targetSdkVersionValue); if (fromCode == null) { continue; } if (!t.Methods.Where(m => m.IsConstructor).Cast <MethodDefinition> ().Any(c => !c.HasParameters && c.IsPublic)) { throw new InvalidOperationException(string.Format("The type '{0}' needs to have a public default constructor.", t.FullName)); } app.Add(fromCode); } foreach (var d in app.Descendants().Where(a => ((string)a.Attribute(attName)) == compatName)) { d.SetAttributeValue(attName, name); } } catch (InvalidActivityNameException ex) { log.LogErrorFromException(ex); } } var icon = app.Attribute(androidNs + "icon"); if (icon == null) { var activity = app.Element("activity"); if (activity != null) { var activityIcon = activity.Attribute(androidNs + "icon"); if (activityIcon != null) { app.Add(new XAttribute(androidNs + "icon", activityIcon.Value)); } } } PackageName = AndroidAppManifest.CanonicalizePackageName(PackageName); if (!PackageName.Contains('.')) { throw new InvalidOperationException("/manifest/@package attribute MUST contain a period ('.')."); } manifest.SetAttributeValue("package", PackageName); var providerNames = AddMonoRuntimeProviders(app); if (Debug) { app.Add(new XComment("suppress ExportedReceiver")); app.Add(new XElement("receiver", new XAttribute(androidNs + "name", "mono.android.Seppuku"), new XElement("intent-filter", new XElement("action", new XAttribute(androidNs + "name", "mono.android.intent.action.SEPPUKU")), new XElement("category", new XAttribute(androidNs + "name", "mono.android.intent.category.SEPPUKU." + PackageName))))); if (app.Attribute(androidNs + "debuggable") == null) { app.Add(new XAttribute(androidNs + "debuggable", "true")); } } if (Debug || NeedsInternet) { AddInternetPermissionForDebugger(); } if (!embed) { AddFastDeployPermissions(); } AddAddOns(app, SdkDir, SdkVersionName, Addons); // If the manifest has android:installLocation, but we are targeting // API 7 or lower, remove it for the user and show a warning if (manifest.Attribute(androidNs + "installLocation") != null) { if (targetSdkVersionValue < 8) { manifest.Attribute(androidNs + "installLocation").Remove(); Console.Error.WriteLine("monodroid: warning 1 : installLocation cannot be specified for Android versions less than 2.2. Attribute installLocation ignored."); } } AddInstrumentations(manifest, subclasses, targetSdkVersionValue); AddPermissions(app, selectedWhitelistAssemblies); AddPermissionGroups(app, selectedWhitelistAssemblies); AddPermissionTrees(app, selectedWhitelistAssemblies); AddUsesPermissions(app, selectedWhitelistAssemblies); AddUsesFeatures(app, selectedWhitelistAssemblies); AddSupportsGLTextures(app, selectedWhitelistAssemblies); ReorderActivityAliases(app); ReorderElements(app); if (mergedManifestDocuments != null) { foreach (var mergedManifest in mergedManifestDocuments) { try { MergeLibraryManifest(mergedManifest); } catch (Exception ex) { log.LogWarningFromException(ex); } } } return(providerNames); }