Exemple #1
0
        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;
                }
            }
        }
Exemple #2
0
 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");
     }
 }
Exemple #3
0
 static string GetJniTypeName(TypeReference typeRef, ExportParameterKind exportKind)
 {
     return(JniType.GetJniTypeName(typeRef, exportKind));
 }
Exemple #4
0
        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
            });
        }
Exemple #5
0
        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);
        }
Exemple #8
0
 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) { }
        }
Exemple #11
0
 static bool CannotRegisterInStaticConstructor(TypeDefinition type)
 {
     return(JniType.IsApplication(type) || JniType.IsInstrumentation(type));
 }
Exemple #12
0
 static string GetJniSignature(MethodDefinition ctor)
 {
     return(JniType.GetJniSignature(ctor));
 }
Exemple #13
0
 public void InvalidSignatureThrowsJniException()
 {
     using (var Integer_class = new JniType("java/lang/Integer")) {
         Assert.Throws <JavaException> (() => Integer_class.GetConstructor("(C)V")).Dispose();
     }
 }
Exemple #14
0
 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);
        }
Exemple #16
0
 internal JniObjectArray(JniEnvironment environment, IntPtr handle, JniObjectLifecycle lifecycle, int arrayRank, JniType elementType)
     : base(environment, handle, lifecycle)
 {
     mArrayRank = arrayRank;
     mElementType = elementType;
 }
Exemple #17
0
        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);
        }