diff --git a/build-tools/scripts/cmake-common.props b/build-tools/scripts/cmake-common.props
index fa1934051f3..ec00eae9b54 100644
--- a/build-tools/scripts/cmake-common.props
+++ b/build-tools/scripts/cmake-common.props
@@ -2,6 +2,6 @@
<_CmakeCommonFlags>-GNinja -DCMAKE_MAKE_PROGRAM=$(NinjaPath)
- <_CmakeAndroidFlags>$(_CmakeCommonFlags) -DANDROID_TOOLCHAIN=clang -DANDROID_NATIVE_API_LEVEL=$(AndroidNdkApiLevel) -DANDROID_PLATFORM=android-$(AndroidNdkApiLevel) -DCMAKE_TOOLCHAIN_FILE=$(AndroidNdkDirectory)\build\cmake\android.toolchain.cmake -DANDROID_NDK=$(AndroidNdkDirectory)
+ <_CmakeAndroidFlags>$(_CmakeCommonFlags) -DANDROID_STL="system" -DANDROID_CPP_FEATURES="" -DANDROID_TOOLCHAIN=clang -DANDROID_NATIVE_API_LEVEL=$(AndroidNdkApiLevel) -DANDROID_PLATFORM=android-$(AndroidNdkApiLevel) -DCMAKE_TOOLCHAIN_FILE=$(AndroidNdkDirectory)\build\cmake\android.toolchain.cmake -DANDROID_NDK=$(AndroidNdkDirectory)
diff --git a/src/Mono.Android/Android.Runtime/JNIEnv.cs b/src/Mono.Android/Android.Runtime/JNIEnv.cs
index 1ca1a11a996..66152a7fd3f 100644
--- a/src/Mono.Android/Android.Runtime/JNIEnv.cs
+++ b/src/Mono.Android/Android.Runtime/JNIEnv.cs
@@ -152,15 +152,16 @@ internal static unsafe void Initialize (JnienvInitializeArgs* args)
{
Logger.Categories = (LogCategories) args->logCategories;
- var __start = new DateTime ();
+ Stopwatch stopper = null;
+ long elapsed, totalElapsed = 0;
if (Logger.LogTiming) {
- __start = DateTime.UtcNow;
- Logger.Log (LogLevel.Info,
- "monodroid-timing",
- "JNIEnv.Initialize start: " + (__start - new DateTime (1970, 1, 1)).TotalMilliseconds);
- Logger.Log (LogLevel.Info,
- "monodroid-timing",
- "JNIEnv.Initialize: Logger JIT/etc. time: " + (DateTime.UtcNow - new DateTime (1970, 1, 1)).TotalMilliseconds + " [elapsed: " + (DateTime.UtcNow - __start).TotalMilliseconds + " ms]");
+ stopper = new Stopwatch ();
+ stopper.Start ();
+ Logger.Log (LogLevel.Info, "monodroid-timing", "JNIEnv.Initialize start");
+ elapsed = stopper.ElapsedMilliseconds;
+ totalElapsed += elapsed;
+ Logger.Log (LogLevel.Info, "monodroid-timing", $"JNIEnv.Initialize: Logger JIT/etc. time: elapsed {elapsed} ms]");
+ stopper.Restart ();
}
gref_gc_threshold = args->grefGcThreshold;
@@ -195,16 +196,14 @@ internal static unsafe void Initialize (JnienvInitializeArgs* args)
#endif // JAVA_INTEROP
if (Logger.LogTiming) {
- var __end = DateTime.UtcNow;
- Logger.Log (LogLevel.Info,
- "monodroid-timing",
- "JNIEnv.Initialize: time: " + (__end - new DateTime (1970, 1, 1)).TotalMilliseconds + " [elapsed: " + (__end - __start).TotalMilliseconds + " ms]");
- __start = DateTime.UtcNow;
+ elapsed = stopper.ElapsedMilliseconds;
+ totalElapsed += elapsed;
+ Logger.Log (LogLevel.Info, "monodroid-timing", $"JNIEnv.Initialize: managed runtime init time: elapsed {elapsed} ms]");
+ stopper.Restart ();
var _ = Java.Interop.TypeManager.jniToManaged;
- __end = DateTime.UtcNow;
- Logger.Log (LogLevel.Info,
- "monodroid-timing",
- "JNIEnv.Initialize: TypeManager init time: " + (__end - new DateTime (1970, 1, 1)).TotalMilliseconds + " [elapsed: " + (__end - __start).TotalMilliseconds + " ms]");
+ elapsed = stopper.ElapsedMilliseconds;
+ totalElapsed += elapsed;
+ Logger.Log (LogLevel.Info, "monodroid-timing", $"JNIEnv.Initialize: TypeManager init time: elapsed {elapsed} ms]");
}
AllocObjectSupported = androidSdkVersion > 10;
@@ -238,10 +237,10 @@ internal static unsafe void Initialize (JnienvInitializeArgs* args)
Java.Lang.Thread.DefaultUncaughtExceptionHandler = defaultUncaughtExceptionHandler;
}
- if (Logger.LogTiming)
- Logger.Log (LogLevel.Info,
- "monodroid-timing",
- "JNIEnv.Initialize end: " + (DateTime.UtcNow - new DateTime (1970, 1, 1)).TotalMilliseconds);
+ if (Logger.LogTiming) {
+ totalElapsed += stopper.ElapsedMilliseconds;
+ Logger.Log (LogLevel.Info, "monodroid-timing", $"JNIEnv.Initialize end: elapsed {totalElapsed} ms");
+ }
}
internal static void Exit ()
diff --git a/src/Mono.Android/java/mono/android/Runtime.java b/src/Mono.Android/java/mono/android/Runtime.java
index 16fcd441cf1..921551a9738 100644
--- a/src/Mono.Android/java/mono/android/Runtime.java
+++ b/src/Mono.Android/java/mono/android/Runtime.java
@@ -1,12 +1,17 @@
package mono.android;
public class Runtime {
+ static java.lang.Class java_lang_Class = java.lang.Class.class;;
+ static java.lang.Class java_lang_System = java.lang.System.class;
+ static java.lang.Class java_util_TimeZone = java.util.TimeZone.class;
+ static java.lang.Class mono_android_IGCUserPeer = mono.android.IGCUserPeer.class;
+ static java.lang.Class mono_android_GCUserPeer = mono.android.GCUserPeer.class;
private Runtime ()
{
}
- public static native void init (String lang, String[] runtimeApks, String runtimeDataDir, String[] appDirs, ClassLoader loader, String[] externalStorageDirs, String[] assemblies, String packageName);
+ public static native void init (String lang, String[] runtimeApks, String runtimeDataDir, String[] appDirs, ClassLoader loader, String[] externalStorageDirs, String[] assemblies, String packageName, int apiLevel, String[] environmentVariables);
public static native void register (String managedType, java.lang.Class nativeClass, String methods);
public static native void notifyTimeZoneChanged ();
public static native int createNewContext (String[] runtimeApks, String[] assemblies, ClassLoader loader);
diff --git a/src/Xamarin.Android.Build.Tasks/Resources/MonoPackageManager.java b/src/Xamarin.Android.Build.Tasks/Resources/MonoPackageManager.java
index 8a1381044ee..317cfdbc2b5 100644
--- a/src/Xamarin.Android.Build.Tasks/Resources/MonoPackageManager.java
+++ b/src/Xamarin.Android.Build.Tasks/Resources/MonoPackageManager.java
@@ -63,7 +63,9 @@ public static void LoadApplication (Context context, ApplicationInfo runtimePack
externalLegacyDir
},
MonoPackageManager_Resources.Assemblies,
- context.getPackageName ());
+ context.getPackageName (),
+ android.os.Build.VERSION.SDK_INT,
+ mono.android.app.XamarinAndroidEnvironmentVariables.Variables);
mono.android.app.ApplicationRegistration.registerApplications ();
diff --git a/src/Xamarin.Android.Build.Tasks/Resources/XamarinAndroidEnvironmentVariables.java b/src/Xamarin.Android.Build.Tasks/Resources/XamarinAndroidEnvironmentVariables.java
new file mode 100644
index 00000000000..00d41fcdd6d
--- /dev/null
+++ b/src/Xamarin.Android.Build.Tasks/Resources/XamarinAndroidEnvironmentVariables.java
@@ -0,0 +1,9 @@
+package mono.android.app;
+
+public class XamarinAndroidEnvironmentVariables
+{
+ // Variables are specified the in "name", "value" pairs
+ public static final String[] Variables = new String[] {
+//@ENVVARS@
+ };
+}
diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/BuildApk.cs b/src/Xamarin.Android.Build.Tasks/Tasks/BuildApk.cs
index 3162f098c9a..27d45b83b14 100644
--- a/src/Xamarin.Android.Build.Tasks/Tasks/BuildApk.cs
+++ b/src/Xamarin.Android.Build.Tasks/Tasks/BuildApk.cs
@@ -45,8 +45,6 @@ public class BuildApk : Task
public ITaskItem[] BundleNativeLibraries { get; set; }
- public ITaskItem[] Environments { get; set; }
-
public ITaskItem[] TypeMappings { get; set; }
[Required]
@@ -74,28 +72,17 @@ public class BuildApk : Task
public bool PreferNativeLibrariesWithDebugSymbols { get; set; }
- public string AndroidAotMode { get; set; }
-
public string AndroidSequencePointsMode { get; set; }
- public bool EnableLLVM { get; set; }
-
- public bool EnableSGenConcurrent { get; set; }
-
public string AndroidEmbedProfilers { get; set; }
- public string HttpClientHandlerType { get; set; }
public string TlsProvider { get; set; }
public string UncompressedFileExtensions { get; set; }
-
static readonly string MSBuildXamarinAndroidDirectory = Path.GetDirectoryName (typeof (BuildApk).Assembly.Location);
[Output]
public ITaskItem[] OutputFiles { get; set; }
- [Output]
- public string BuildId { get; set; }
-
bool _Debug {
get {
return string.Equals (Debug, "true", StringComparison.OrdinalIgnoreCase);
@@ -103,8 +90,6 @@ bool _Debug {
}
SequencePointsMode sequencePointsMode = SequencePointsMode.None;
-
- Guid buildId = Guid.NewGuid ();
public ITaskItem[] LibraryProjectJars { get; set; }
string [] uncompressedFileExtensions;
@@ -125,7 +110,6 @@ void ExecuteWithAbi (string supportedAbis, string apkInputPath, string apkOutput
if (EmbedAssemblies && !BundleAssemblies)
AddAssemblies (apk);
- AddEnvironment (apk);
AddRuntimeLibraries (apk, supportedAbis);
apk.Flush();
AddNativeLibraries (files, supportedAbis);
@@ -206,11 +190,9 @@ public override bool Execute ()
Log.LogDebugMessage (" Debug: {0}", Debug ?? "no");
Log.LogDebugMessage (" PreferNativeLibrariesWithDebugSymbols: {0}", PreferNativeLibrariesWithDebugSymbols);
Log.LogDebugMessage (" EmbedAssemblies: {0}", EmbedAssemblies);
- Log.LogDebugMessage (" AndroidAotMode: {0}", AndroidAotMode);
Log.LogDebugMessage (" AndroidSequencePointsMode: {0}", AndroidSequencePointsMode);
Log.LogDebugMessage (" CreatePackagePerAbi: {0}", CreatePackagePerAbi);
Log.LogDebugMessage (" UncompressedFileExtensions: {0}", UncompressedFileExtensions);
- Log.LogDebugTaskItems (" Environments:", Environments);
Log.LogDebugTaskItems (" ResolvedUserAssemblies:", ResolvedUserAssemblies);
Log.LogDebugTaskItems (" ResolvedFrameworkAssemblies:", ResolvedFrameworkAssemblies);
Log.LogDebugTaskItems (" NativeLibraries:", NativeLibraries);
@@ -220,8 +202,6 @@ public override bool Execute ()
Log.LogDebugTaskItems (" JavaLibraries:", JavaLibraries);
Log.LogDebugTaskItems (" LibraryProjectJars:", LibraryProjectJars);
Log.LogDebugTaskItems (" AdditionalNativeLibraryReferences:", AdditionalNativeLibraryReferences);
- Log.LogDebugTaskItems (" HttpClientHandlerType:", HttpClientHandlerType);
- Log.LogDebugMessage (" TlsProvider: {0}", TlsProvider);
Aot.TryGetSequencePointsMode (AndroidSequencePointsMode, out sequencePointsMode);
@@ -246,10 +226,6 @@ public override bool Execute ()
}
}
- BuildId = buildId.ToString ();
-
- Log.LogDebugMessage (" [Output] BuildId: {0}", BuildId);
-
OutputFiles = outputFiles.Select (a => new TaskItem (a)).ToArray ();
Log.LogDebugTaskItems (" [Output] OutputFiles :", OutputFiles);
@@ -349,83 +325,6 @@ static string GetTargetDirectory (string path)
return "assemblies";
}
- void AddEnvironment (ZipArchiveEx apk)
- {
- var environment = new StringWriter () {
- NewLine = "\n",
- };
-
- if (EnableLLVM) {
- environment.WriteLine ("mono.llvm=true");
- }
-
- AotMode aotMode;
- if (AndroidAotMode != null && Aot.GetAndroidAotMode(AndroidAotMode, out aotMode)) {
- environment.WriteLine ("mono.aot={0}", aotMode.ToString().ToLowerInvariant());
- }
-
- const string defaultLogLevel = "MONO_LOG_LEVEL=info";
- const string defaultMonoDebug = "MONO_DEBUG=gen-compact-seq-points";
- const string defaultHttpMessageHandler = "XA_HTTP_CLIENT_HANDLER_TYPE=System.Net.Http.HttpClientHandler, System.Net.Http";
- const string defaultTlsProvider = "XA_TLS_PROVIDER=btls";
- string xamarinBuildId = string.Format ("XAMARIN_BUILD_ID={0}", buildId);
-
- bool haveLogLevel = false;
- bool haveMonoDebug = false;
- bool havebuildId = false;
- bool haveHttpMessageHandler = false;
- bool haveTlsProvider = false;
- bool haveMonoGCParams = false;
-
- foreach (ITaskItem env in Environments ?? new TaskItem[0]) {
- environment.WriteLine ("## Source File: {0}", env.ItemSpec);
- foreach (string line in File.ReadLines (env.ItemSpec)) {
- var lineToWrite = line;
- if (lineToWrite.StartsWith ("MONO_LOG_LEVEL=", StringComparison.Ordinal))
- haveLogLevel = true;
- if (lineToWrite.StartsWith ("MONO_GC_PARAMS=", StringComparison.Ordinal))
- haveMonoGCParams = true;
- if (lineToWrite.StartsWith ("XAMARIN_BUILD_ID=", StringComparison.Ordinal))
- havebuildId = true;
- if (lineToWrite.StartsWith ("MONO_DEBUG=", StringComparison.Ordinal)) {
- haveMonoDebug = true;
- if (sequencePointsMode != SequencePointsMode.None && !lineToWrite.Contains ("gen-compact-seq-points"))
- lineToWrite = line + ",gen-compact-seq-points";
- }
- if (lineToWrite.StartsWith ("XA_HTTP_CLIENT_HANDLER_TYPE=", StringComparison.Ordinal))
- haveHttpMessageHandler = true;
- if (lineToWrite.StartsWith ("XA_TLS_PROVIDER=", StringComparison.Ordinal))
- haveTlsProvider = true;
- environment.WriteLine (lineToWrite);
- }
- }
-
- if (_Debug && !haveLogLevel) {
- environment.WriteLine (defaultLogLevel);
- }
-
- if (sequencePointsMode != SequencePointsMode.None && !haveMonoDebug) {
- environment.WriteLine (defaultMonoDebug);
- }
-
- if (!havebuildId)
- environment.WriteLine (xamarinBuildId);
-
- if (!haveHttpMessageHandler)
- environment.WriteLine (HttpClientHandlerType == null ? defaultHttpMessageHandler : $"XA_HTTP_CLIENT_HANDLER_TYPE={HttpClientHandlerType.Trim ()}");
- if (!haveTlsProvider)
- environment.WriteLine (TlsProvider == null ? defaultTlsProvider : $"XA_TLS_PROVIDER={TlsProvider.Trim ()}");
- if (!haveMonoGCParams) {
- if (EnableSGenConcurrent)
- environment.WriteLine ("MONO_GC_PARAMS=major=marksweep-conc");
- else
- environment.WriteLine ("MONO_GC_PARAMS=major=marksweep");
- }
-
- apk.Archive.AddEntry ("environment", environment.ToString (),
- new UTF8Encoding (encoderShouldEmitUTF8Identifier:false));
- }
-
class LibInfo
{
public string Path;
diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs
index 99f9ffab016..370c146457f 100644
--- a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs
+++ b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs
@@ -13,6 +13,10 @@ namespace Xamarin.Android.Tasks
{
public class GeneratePackageManagerJava : Task
{
+ const string EnvironmentFileName = "XamarinAndroidEnvironmentVariables.java";
+
+ Guid buildId = Guid.NewGuid ();
+
[Required]
public ITaskItem[] ResolvedAssemblies { get; set; }
@@ -22,6 +26,9 @@ public class GeneratePackageManagerJava : Task
[Required]
public string OutputDirectory { get; set; }
+ [Required]
+ public string EnvironmentOutputDirectory { get; set; }
+
[Required]
public string UseSharedRuntime { get; set; }
@@ -34,6 +41,24 @@ public class GeneratePackageManagerJava : Task
[Required]
public string Manifest { get; set; }
+ public string Debug { get; set; }
+ public ITaskItem[] Environments { get; set; }
+ public string AndroidAotMode { get; set; }
+ public bool EnableLLVM { get; set; }
+ public string HttpClientHandlerType { get; set; }
+ public string TlsProvider { get; set; }
+ public string AndroidSequencePointsMode { get; set; }
+ public bool EnableSGenConcurrent { get; set; }
+
+ [Output]
+ public string BuildId { get; set; }
+
+ bool _Debug {
+ get {
+ return string.Equals (Debug, "true", StringComparison.OrdinalIgnoreCase);
+ }
+ }
+
public override bool Execute ()
{
Log.LogDebugMessage ("GeneratePackageManagerJava Task");
@@ -45,6 +70,9 @@ public override bool Execute ()
Log.LogDebugTaskItems (" ResolvedAssemblies:", ResolvedAssemblies);
Log.LogDebugTaskItems (" ResolvedUserAssemblies:", ResolvedUserAssemblies);
+ BuildId = buildId.ToString ();
+ Log.LogDebugMessage (" [Output] BuildId: {0}", BuildId);
+
var shared_runtime = string.Compare (UseSharedRuntime, "true", true) == 0;
var doc = AndroidAppManifest.Load (Manifest, MonoAndroidHelper.SupportedVersions);
int minApiVersion = doc.MinSdkVersion == null ? 4 : (int) doc.MinSdkVersion;
@@ -103,10 +131,131 @@ public override bool Execute ()
MonoAndroidHelper.CopyIfChanged (temp, dest);
try { File.Delete (temp); } catch (Exception) { }
-
- try { File.Delete (temp); } catch (Exception) { }
+
+ AddEnvironment ();
return !Log.HasLoggedErrors;
}
+
+ static readonly string[] defaultLogLevel = {"MONO_LOG_LEVEL", "info"};
+ static readonly string[] defaultMonoDebug = {"MONO_DEBUG", "gen-compact-seq-points"};
+ static readonly string[] defaultHttpMessageHandler = {"XA_HTTP_CLIENT_HANDLER_TYPE", "System.Net.Http.HttpClientHandler, System.Net.Http"};
+ static readonly string[] defaultTlsProvider = {"XA_TLS_PROVIDER", "btls"};
+
+ void AddEnvironment ()
+ {
+ var environment = new StringWriter () {
+ NewLine = "\n",
+ };
+
+ if (EnableLLVM) {
+ WriteEnvironment ("mono.llvm", "true");
+ }
+
+ AotMode aotMode;
+ if (AndroidAotMode != null && Aot.GetAndroidAotMode (AndroidAotMode, out aotMode)) {
+ WriteEnvironment ("mono.aot", aotMode.ToString ().ToLowerInvariant());
+ }
+
+ bool haveLogLevel = false;
+ bool haveMonoDebug = false;
+ bool havebuildId = false;
+ bool haveHttpMessageHandler = false;
+ bool haveTlsProvider = false;
+ bool haveMonoGCParams = false;
+
+ SequencePointsMode sequencePointsMode;
+ if (!Aot.TryGetSequencePointsMode (AndroidSequencePointsMode, out sequencePointsMode))
+ sequencePointsMode = SequencePointsMode.None;
+
+ foreach (ITaskItem env in Environments ?? new TaskItem[0]) {
+ environment.WriteLine ("\t\t// Source File: {0}", env.ItemSpec);
+ foreach (string line in File.ReadLines (env.ItemSpec)) {
+ var lineToWrite = line;
+ if (lineToWrite.StartsWith ("MONO_LOG_LEVEL=", StringComparison.Ordinal))
+ haveLogLevel = true;
+ if (lineToWrite.StartsWith ("MONO_GC_PARAMS=", StringComparison.Ordinal))
+ haveMonoGCParams = true;
+ if (lineToWrite.StartsWith ("XAMARIN_BUILD_ID=", StringComparison.Ordinal))
+ havebuildId = true;
+ if (lineToWrite.StartsWith ("MONO_DEBUG=", StringComparison.Ordinal)) {
+ haveMonoDebug = true;
+ if (sequencePointsMode != SequencePointsMode.None && !lineToWrite.Contains ("gen-compact-seq-points"))
+ lineToWrite = line + ",gen-compact-seq-points";
+ }
+ if (lineToWrite.StartsWith ("XA_HTTP_CLIENT_HANDLER_TYPE=", StringComparison.Ordinal))
+ haveHttpMessageHandler = true;
+ if (lineToWrite.StartsWith ("XA_TLS_PROVIDER=", StringComparison.Ordinal))
+ haveTlsProvider = true;
+ WriteEnvironmentLine (lineToWrite);
+ }
+ }
+
+ if (_Debug && !haveLogLevel) {
+ WriteEnvironment (defaultLogLevel[0], defaultLogLevel[1]);
+ }
+
+ if (sequencePointsMode != SequencePointsMode.None && !haveMonoDebug) {
+ WriteEnvironment (defaultMonoDebug[0], defaultMonoDebug[1]);
+ }
+
+ if (!havebuildId)
+ WriteEnvironment ("XAMARIN_BUILD_ID", buildId.ToString ());
+
+ if (!haveHttpMessageHandler) {
+ if (HttpClientHandlerType == null)
+ WriteEnvironment (defaultHttpMessageHandler[0], defaultHttpMessageHandler[1]);
+ else
+ WriteEnvironment ("XA_HTTP_CLIENT_HANDLER_TYPE", HttpClientHandlerType.Trim ());
+ }
+
+ if (!haveTlsProvider) {
+ if (TlsProvider == null)
+ WriteEnvironment (defaultTlsProvider[0], defaultTlsProvider[1]);
+ else
+ WriteEnvironment ("XA_TLS_PROVIDER", TlsProvider.Trim ());
+ }
+
+ if (!haveMonoGCParams) {
+ if (EnableSGenConcurrent)
+ WriteEnvironment ("MONO_GC_PARAMS", "major=marksweep-conc");
+ else
+ WriteEnvironment ("MONO_GC_PARAMS", "major=marksweep");
+ }
+
+ string environmentTemplate;
+ using (var sr = new StreamReader (typeof (BuildApk).Assembly.GetManifestResourceStream (EnvironmentFileName))) {
+ environmentTemplate = sr.ReadToEnd ();
+ }
+
+ using (var ms = new MemoryStream ()) {
+ using (var sw = new StreamWriter (ms)) {
+ sw.Write (environmentTemplate.Replace ("//@ENVVARS@", environment.ToString ()));
+ sw.Flush ();
+
+ string dest = Path.GetFullPath (Path.Combine (EnvironmentOutputDirectory, EnvironmentFileName));
+ MonoAndroidHelper.CopyIfStreamChanged (ms, dest);
+ }
+ }
+
+ void WriteEnvironment (string name, string value)
+ {
+ environment.WriteLine ($"\t\t\"{ValidJavaString (name)}\", \"{ValidJavaString (value)}\",");
+ }
+
+ void WriteEnvironmentLine (string line)
+ {
+ if (String.IsNullOrEmpty (line))
+ return;
+
+ string[] nv = line.Split (new char[]{'='}, 2);
+ WriteEnvironment (nv[0].Trim (), nv.Length < 2 ? String.Empty : nv[1].Trim ());
+ }
+
+ string ValidJavaString (string s)
+ {
+ return s.Replace ("\"", "\\\"");
+ }
+ }
}
}
diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs
index 759d1a9accb..4ea64b85fb8 100644
--- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs
+++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs
@@ -1773,19 +1773,21 @@ public void BuildApplicationWithMonoEnvironment ([Values ("", "Normal", "Offline
Assert.IsTrue (libb.Build (lib), "Library build should have succeeded.");
Assert.IsTrue (appb.Build (app), "App should have succeeded.");
Assert.IsTrue (StringAssertEx.ContainsText (appb.LastBuildOutput, $"Save assembly: {linkSkip}"), $"{linkSkip} should be saved, and not linked!");
- var apk = Path.Combine (Root, appb.ProjectDirectory,
- app.IntermediateOutputPath, "android", "bin", "UnnamedProject.UnnamedProject.apk");
- using (var zipFile = ZipHelper.OpenZip (apk)) {
- var data = ZipHelper.ReadFileFromZip (zipFile, "environment");
- Assert.IsNotNull (data, "environment should exist in the apk.");
- var env = Encoding.ASCII.GetString (data);
- var lines = env.Split (new char [] { '\n' });
+ string javaEnv = Path.Combine (Root, appb.ProjectDirectory,
+ app.IntermediateOutputPath, "android", "src", "mono", "android", "app", "XamarinAndroidEnvironmentVariables.java");
+ Assert.IsTrue (File.Exists (javaEnv), $"Java environment source does not exist at {javaEnv}");
- Assert.IsTrue (lines.Any (x => x.Contains ("MONO_DEBUG") &&
+ string[] lines = File.ReadAllLines (javaEnv);
+ Assert.IsTrue (lines.Any (x => x.Contains ("MONO_DEBUG") &&
x.Contains ("soft-breakpoints") &&
string.IsNullOrEmpty (sequencePointsMode) ? true : x.Contains ("gen-compact-seq-points")),
"The values from Mono.env should have been merged into environment");
- }
+
+ string dexFile = Path.Combine (Root, appb.ProjectDirectory, app.IntermediateOutputPath, "android", "bin", "classes.dex");
+ Assert.IsTrue (File.Exists (dexFile), $"dex file does not exist at {dexFile}");
+ Assert.IsTrue (DexUtils.ContainsClass ("Lmono/android/app/XamarinAndroidEnvironmentVariables;", dexFile, appb.AndroidSdkDirectory),
+ $"dex file {dexFile} does not contain the XamarinAndroidEnvironmentVariables class");
+
var assemblyDir = Path.Combine (Root, appb.ProjectDirectory, app.IntermediateOutputPath, "android", "assets");
var rp = new ReaderParameters { ReadSymbols = false };
foreach (var assemblyFile in Directory.EnumerateFiles (assemblyDir, "*.dll")) {
@@ -1811,21 +1813,22 @@ public void CheckMonoDebugIsAddedToEnvironment ([Values ("", "Normal", "Offline"
using (var b = CreateApkBuilder (Path.Combine ("temp", TestName))) {
b.Verbosity = LoggerVerbosity.Diagnostic;
Assert.IsTrue (b.Build (proj), "Build should have succeeded.");
- var apk = Path.Combine (Root, b.ProjectDirectory,
- proj.IntermediateOutputPath, "android", "bin", "UnnamedProject.UnnamedProject.apk");
- using (var zipFile = ZipHelper.OpenZip (apk)) {
- var data = ZipHelper.ReadFileFromZip (zipFile, "environment");
- Assert.IsNotNull (data, "environment should exist in the apk.");
- var env = Encoding.ASCII.GetString (data);
- var lines = env.Split (new char [] { '\n' });
-
- Assert.IsTrue (lines.Any (x =>
- string.IsNullOrEmpty (sequencePointsMode)
- ? !x.Contains ("MONO_DEBUG")
- : x.Contains ("MONO_DEBUG") && x.Contains ("gen-compact-seq-points")),
- "environment {0} contain MONO_DEBUG=gen-compact-seq-points",
- string.IsNullOrEmpty (sequencePointsMode) ? "should not" : "should");
- }
+ string javaEnv = Path.Combine (Root, b.ProjectDirectory,
+ proj.IntermediateOutputPath, "android", "src", "mono", "android", "app", "XamarinAndroidEnvironmentVariables.java");
+ Assert.IsTrue (File.Exists (javaEnv), $"Java environment source does not exist at {javaEnv}");
+
+ string[] lines = File.ReadAllLines (javaEnv);
+ Assert.IsTrue (lines.Any (x =>
+ string.IsNullOrEmpty (sequencePointsMode)
+ ? !x.Contains ("MONO_DEBUG")
+ : x.Contains ("MONO_DEBUG") && x.Contains ("gen-compact-seq-points")),
+ "environment {0} contain MONO_DEBUG=gen-compact-seq-points",
+ string.IsNullOrEmpty (sequencePointsMode) ? "should not" : "should");
+
+ string dexFile = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath, "android", "bin", "classes.dex");
+ Assert.IsTrue (File.Exists (dexFile), $"dex file does not exist at {dexFile}");
+ Assert.IsTrue (DexUtils.ContainsClass ("Lmono/android/app/XamarinAndroidEnvironmentVariables;", dexFile, b.AndroidSdkDirectory),
+ $"dex file {dexFile} does not contain the XamarinAndroidEnvironmentVariables class");
}
}
diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/PackagingTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/PackagingTest.cs
index 5be56daff8e..7d092cde444 100644
--- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/PackagingTest.cs
+++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/PackagingTest.cs
@@ -67,19 +67,26 @@ public void CheckBuildIdIsUnique ()
//NOTE: Windows is still generating mdb files here
extension = IsWindows ? "dll.mdb" : "pdb";
Assert.IsTrue (allFilesInArchive.Any (x => Path.GetFileName (x) == $"{proj.ProjectName}.{extension}"), $"{proj.ProjectName}.{extension} should exist in {archivePath}");
- foreach (var abi in new string [] { "armeabi-v7a", "x86" }) {
- using (var apk = ZipHelper.OpenZip (Path.Combine (outputPath, proj.PackageName + "-" + abi + "-Signed.apk"))) {
- var data = ZipHelper.ReadFileFromZip (apk, "environment");
- var env = Encoding.ASCII.GetString (data);
- var lines = env.Split (new char [] { '\n' });
- Assert.IsTrue (lines.Any (x => x.Contains ("XAMARIN_BUILD_ID")),
- "The environment should contain a XAMARIN_BUIL_ID");
- var buildID = lines.First (x => x.StartsWith ("XAMARIN_BUILD_ID", StringComparison.InvariantCultureIgnoreCase));
- buildIds.Add (abi, buildID);
- }
- }
- Assert.IsFalse (buildIds.Values.Any (x => buildIds.Values.Any (v => v != x)),
- "All the XAMARIN_BUILD_ID values should be the same");
+ string javaEnv = Path.Combine (Root, b.ProjectDirectory,
+ proj.IntermediateOutputPath, "android", "src", "mono", "android", "app", "XamarinAndroidEnvironmentVariables.java");
+ Assert.IsTrue (File.Exists (javaEnv), $"Java environment source does not exist at {javaEnv}");
+
+ string[] lines = File.ReadAllLines (javaEnv);
+
+ Assert.IsTrue (lines.Any (x => x.Contains ("\"XAMARIN_BUILD_ID\",")),
+ "The environment should contain a XAMARIN_BUILD_ID");
+
+ string buildID = lines.First (x => x.Contains ("\"XAMARIN_BUILD_ID\","))
+ .Trim ()
+ .Replace ("\", \"", "=")
+ .Replace ("\",", String.Empty)
+ .Replace ("\"", String.Empty);
+ buildIds.Add ("all", buildID);
+
+ string dexFile = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath, "android", "bin", "classes.dex");
+ Assert.IsTrue (File.Exists (dexFile), $"dex file does not exist at {dexFile}");
+ Assert.IsTrue (DexUtils.ContainsClass ("Lmono/android/app/XamarinAndroidEnvironmentVariables;", dexFile, b.AndroidSdkDirectory),
+ $"dex file {dexFile} does not contain the XamarinAndroidEnvironmentVariables class");
var msymDirectory = Path.Combine (Root, b.ProjectDirectory, proj.OutputPath, proj.PackageName + ".apk.mSYM");
Assert.IsTrue (File.Exists (Path.Combine (msymDirectory, "manifest.xml")), "manifest.xml should exist in", msymDirectory);
diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj
index f16e8a78db9..6ea2fd58700 100644
--- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj
+++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj
@@ -686,6 +686,9 @@
ResourcePatcher.java
+
+ XamarinAndroidEnvironmentVariables.java
+
diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets
index 5674548136a..e8fcb6e2ab2 100755
--- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets
+++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets
@@ -2341,10 +2341,21 @@ because xbuild doesn't support framework reference assemblies.
ResolvedAssemblies="@(_ResolvedAssemblies)"
ResolvedUserAssemblies="@(_ResolvedUserAssemblies)"
MainAssembly="$(MonoAndroidLinkerInputDir)$(TargetFileName)"
- OutputDirectory="$(IntermediateOutputPath)android\src\mono"
+ OutputDirectory="$(IntermediateOutputPath)android\src\mono"
+ EnvironmentOutputDirectory="$(IntermediateOutputPath)android\src\mono\android\app"
UseSharedRuntime="$(AndroidUseSharedRuntime)"
TargetFrameworkVersion="$(TargetFrameworkVersion)"
- Manifest="$(IntermediateOutputPath)android\AndroidManifest.xml" />
+ Manifest="$(IntermediateOutputPath)android\AndroidManifest.xml"
+ Environments="@(AndroidEnvironment);@(LibraryEnvironments)"
+ AndroidAotMode="$(AndroidAotMode)"
+ EnableLLVM="$(EnableLLVM)"
+ HttpClientHandlerType="$(AndroidHttpClientHandlerType)"
+ TlsProvider="$(AndroidTlsProvider)"
+ Debug="$(AndroidIncludeDebugSymbols)"
+ AndroidSequencePointsMode="$(_SequencePointsMode)"
+ EnableSGenConcurrent="$(AndroidEnableSGenConcurrent)">
+
+
@@ -2866,7 +2877,6 @@ because xbuild doesn't support framework reference assemblies.
BundleAssemblies="$(BundleAssemblies)"
BundleNativeLibraries="$(_BundleResultNativeLibraries)"
EmbedAssemblies="$(EmbedAssembliesIntoApk)"
- Environments="@(AndroidEnvironment);@(LibraryEnvironments)"
ResolvedUserAssemblies="@(_ResolvedUserAssemblies);@(_AndroidResolvedSatellitePaths)"
ResolvedFrameworkAssemblies="@(_ShrunkFrameworkAssemblies)"
NativeLibraries="@(AndroidNativeLibrary)"
@@ -2879,18 +2889,13 @@ because xbuild doesn't support framework reference assemblies.
Debug="$(AndroidIncludeDebugSymbols)"
PreferNativeLibrariesWithDebugSymbols="$(AndroidPreferNativeLibrariesWithDebugSymbols)"
TypeMappings="$(_AndroidTypeMappingJavaToManaged);$(_AndroidTypeMappingManagedToJava)"
- AndroidAotMode="$(AndroidAotMode)"
- EnableLLVM="$(EnableLLVM)"
JavaSourceFiles="@(AndroidJavaSource)"
JavaLibraries="@(AndroidJavaLibrary)"
AndroidSequencePointsMode="$(_SequencePointsMode)"
LibraryProjectJars="@(ExtractedJarImports)"
AndroidEmbedProfilers="$(AndroidEmbedProfilers)"
- HttpClientHandlerType="$(AndroidHttpClientHandlerType)"
TlsProvider="$(AndroidTlsProvider)"
- UncompressedFileExtensions="$(AndroidStoreUncompressedFileExtensions)"
- EnableSGenConcurrent="$(AndroidEnableSGenConcurrent)">
-
+ UncompressedFileExtensions="$(AndroidStoreUncompressedFileExtensions)">
diff --git a/src/monodroid/CMakeLists.txt b/src/monodroid/CMakeLists.txt
index 2be6fac7403..5ccddcd5cbd 100644
--- a/src/monodroid/CMakeLists.txt
+++ b/src/monodroid/CMakeLists.txt
@@ -89,6 +89,9 @@ set(TEST_COMPILER_ARGS
finline-limit=300
fvisibility=hidden
fstack-protector
+ fno-rtti
+ fno-exceptions
+ flto
Wa,--noexecstack
Wformat
Werror=format-security
@@ -238,6 +241,7 @@ set(SOURCES_DIR ${TOP_DIR}/jni)
set(MONODROID_SOURCES
${MONODROID_SOURCES}
${MONO_PATH}/support/zlib-helper.c
+ ${SOURCES_DIR}/new_delete.cc
${SOURCES_DIR}/android-system.cc
${SOURCES_DIR}/cpu-arch-detect.cc
${SOURCES_DIR}/debug-constants.cc
diff --git a/src/monodroid/jni/android-system.cc b/src/monodroid/jni/android-system.cc
index a0855415a09..48537359bf5 100644
--- a/src/monodroid/jni/android-system.cc
+++ b/src/monodroid/jni/android-system.cc
@@ -1,8 +1,8 @@
-#include
-#include
-#include
-#include
-#include
+#include
+#include
+#include
+#include
+#include
#include
#ifdef ANDROID
@@ -23,6 +23,7 @@
#include "android-system.h"
#include "monodroid.h"
#include "monodroid-glue-internal.h"
+#include "jni-wrappers.h"
using namespace xamarin::android;
using namespace xamarin::android::internal;
@@ -40,7 +41,7 @@ constexpr char AndroidSystem::MONO_SGEN_SO[];
constexpr char AndroidSystem::MONO_SGEN_ARCH_SO[];
#if defined (WINDOWS)
-pthread_mutex_t AndroidSystem::readdir_mutex = PTHREAD_MUTEX_INITIALIZER;
+std::mutex AndroidSystem::readdir_mutex;
char *AndroidSystem::libmonoandroid_directory_path = nullptr;
#endif
@@ -396,12 +397,12 @@ AndroidSystem::get_libmonosgen_path ()
// storage location before loading it.
copy_native_libraries_to_internal_location ();
- if (!embedded_dso_mode) {
+ if (!is_embedded_dso_mode_enabled ()) {
for (i = 0; i < MAX_OVERRIDES; ++i)
TRY_LIBMONOSGEN (override_dirs [i]);
}
#endif
- if (!embedded_dso_mode) {
+ if (!is_embedded_dso_mode_enabled ()) {
for (i = 0; i < app_lib_directories_size; i++) {
TRY_LIBMONOSGEN (app_lib_directories [i]);
}
@@ -450,7 +451,7 @@ AndroidSystem::get_libmonosgen_path ()
log_fatal (LOG_DEFAULT, "Cannot find '%s'. Looked in the following locations:", MONO_SGEN_SO);
#ifndef RELEASE
- if (!embedded_dso_mode) {
+ if (!is_embedded_dso_mode_enabled ()) {
for (i = 0; i < MAX_OVERRIDES; ++i) {
if (override_dirs [i] == NULL)
continue;
@@ -493,14 +494,14 @@ AndroidSystem::load_dso (const char *path, int dl_flags, mono_bool skip_exists_c
return NULL;
log_info (LOG_ASSEMBLY, "Trying to load shared library '%s'", path);
- if (!skip_exists_check && !embedded_dso_mode && !utils.file_exists (path)) {
+ if (!skip_exists_check && !is_embedded_dso_mode_enabled () && !utils.file_exists (path)) {
log_info (LOG_ASSEMBLY, "Shared library '%s' not found", path);
return NULL;
}
void *handle = dlopen (path, dl_flags);
- if (handle == NULL)
- log_info (LOG_ASSEMBLY, "Failed to load shared library '%s'. %s", path, dlerror ());
+ if (handle == NULL && utils.should_log (LOG_ASSEMBLY))
+ log_info_nocheck (LOG_ASSEMBLY, "Failed to load shared library '%s'. %s", path, dlerror ());
return handle;
}
@@ -583,7 +584,7 @@ AndroidSystem::get_full_dso_path_on_disk (const char *dso_name, mono_bool *needs
assert (needs_free);
*needs_free = FALSE;
- if (embedded_dso_mode)
+ if (is_embedded_dso_mode_enabled ())
return NULL;
char *dso_path = nullptr;
@@ -731,89 +732,95 @@ AndroidSystem::get_gref_gc_threshold ()
}
void
-AndroidSystem::setup_environment_from_line (const char *line)
+AndroidSystem::setup_environment (jstring_wrapper& name, jstring_wrapper& value)
{
- char **entry;
- const char *k, *v;
+ const char *k = name.get_cstr ();
- if (line == NULL || !isprint (line [0]))
+ if (k == nullptr || *k == '\0')
return;
- entry = utils.monodroid_strsplit (line, "=", 2);
+ const char *v = value.get_cstr ();
+ if (v == nullptr || *v == '\0')
+ v = "";
- if ((k = entry [0]) && *k &&
- (v = entry [1]) && *v) {
- if (islower (k [0])) {
- add_system_property (k, v);
- } else {
- setenv (k, v, 1);
+ if (isupper (k [0]) || k [0] == '_') {
+ if (k [0] == '_') {
+ if (strcmp (k, "__XA_DSO_IN_APK") == 0) {
+ knownEnvVars.DSOInApk = true;
+ return;
+ }
}
- }
-
- utils.monodroid_strfreev (entry);
-}
-void
-AndroidSystem::setup_environment_from_file (const char *apk, int index, int apk_count, void *user_data)
-{
- unzFile file;
- if ((file = unzOpen (apk)) == nullptr)
+ setenv (k, v, 1);
return;
+ }
- if (unzLocateFile (file, "environment", 0) == UNZ_OK) {
- unz_file_info info;
+ if (k [0] == 'm') {
+ if (strcmp (k, "mono.aot") == 0) {
+ if (*v == '\0') {
+ knownEnvVars.MonoAOT = MonoAotMode::MONO_AOT_MODE_NONE;
+ return;
+ }
- if (unzGetCurrentFileInfo (file, &info, nullptr, 0, nullptr, 0, nullptr, 0) == UNZ_OK &&
- unzOpenCurrentFile (file) == UNZ_OK) {
- char *contents = new char [info.uncompressed_size+1];
- if (contents != NULL &&
- unzReadCurrentFile (file, contents, info.uncompressed_size) > 0) {
+ switch (v [0]) {
+ case 'n':
+ knownEnvVars.MonoAOT = MonoAotMode::MONO_AOT_MODE_NORMAL;
+ break;
- int i;
- char *line = contents;
- contents [info.uncompressed_size] = '\0';
+ case 'h':
+ knownEnvVars.MonoAOT = MonoAotMode::MONO_AOT_MODE_HYBRID;
+ break;
- for (i = 0; i < info.uncompressed_size; ++i) {
- if (contents [i] != '\n')
- continue;
+ case 'f':
+ knownEnvVars.MonoAOT = MonoAotMode::MONO_AOT_MODE_FULL;
+ break;
- contents [i] = '\0';
- setup_environment_from_line (line);
- line = &contents [i+1];
- }
+ default:
+ knownEnvVars.MonoAOT = MonoAotMode::MONO_AOT_MODE_UNKNOWN;
+ break;
+ }
- if (line < (contents + info.uncompressed_size))
- setup_environment_from_line (line);
+ if (knownEnvVars.MonoAOT != MonoAotMode::MONO_AOT_MODE_UNKNOWN)
+ log_info (LOG_DEFAULT, "Mono AOT mode: %s", v);
+ else
+ log_warn (LOG_DEFAULT, "Unknown Mono AOT mode: %s", v);
- free (contents);
- }
+ return;
+ }
- unzCloseCurrentFile (file);
+ if (strcmp (k, "mono.llvm") == 0) {
+ knownEnvVars.MonoLLVM = true;
+ return;
}
}
- unzClose (file);
+ add_system_property (k, v);
}
void
-AndroidSystem::for_each_apk (JNIEnv *env, jobjectArray runtimeApks, void (AndroidSystem::*handler) (const char *apk, int index, int apk_count, void *user_data), void *user_data)
+AndroidSystem::setup_environment (JNIEnv *env, jobjectArray environmentVariables)
{
- int i;
- jsize apksLength = env->GetArrayLength (runtimeApks);
- for (i = 0; i < apksLength; ++i) {
- jstring e = reinterpret_cast (env->GetObjectArrayElement (runtimeApks, i));
- const char *apk = env->GetStringUTFChars (e, nullptr);
-
+ jsize envvarsLength = env->GetArrayLength (environmentVariables);
+ if (envvarsLength == 0)
+ return;
- (this->*handler) (apk, i, apksLength, user_data);
- env->ReleaseStringUTFChars (e, apk);
+ jstring_wrapper name (env), value (env);
+ for (jsize i = 0; (i + 1) < envvarsLength; i += 2) {
+ name = reinterpret_cast (env->GetObjectArrayElement (environmentVariables, i));
+ value = reinterpret_cast (env->GetObjectArrayElement (environmentVariables, i + 1));
+ setup_environment (name, value);
}
}
void
-AndroidSystem::setup_environment (JNIEnv *env, jobjectArray runtimeApks)
+AndroidSystem::for_each_apk (JNIEnv *env, jstring_array_wrapper &runtimeApks, void (AndroidSystem::*handler) (const char *apk, int index, int apk_count, void *user_data), void *user_data)
{
- for_each_apk (env, runtimeApks, &AndroidSystem::setup_environment_from_file, NULL);
+ size_t apksLength = runtimeApks.get_length ();
+ for (size_t i = 0; i < apksLength; ++i) {
+ jstring_wrapper &e = runtimeApks [i];
+
+ (this->*handler) (e.get_cstr (), i, apksLength, user_data);
+ }
}
void
@@ -827,7 +834,7 @@ AndroidSystem::setup_process_args_apk (const char *apk, int index, int apk_count
}
void
-AndroidSystem::setup_process_args (JNIEnv *env, jobjectArray runtimeApks)
+AndroidSystem::setup_process_args (JNIEnv *env, jstring_array_wrapper &runtimeApks)
{
for_each_apk (env, runtimeApks, &AndroidSystem::setup_process_args_apk, NULL);
}
@@ -841,7 +848,7 @@ AndroidSystem::add_apk_libdir (const char *apk, int index, int apk_count, void *
}
void
-AndroidSystem::setup_apk_directories (JNIEnv *env, unsigned short running_on_cpu, jobjectArray runtimeApks)
+AndroidSystem::setup_apk_directories (JNIEnv *env, unsigned short running_on_cpu, jstring_array_wrapper &runtimeApks)
{
// Man, the cast is ugly...
for_each_apk (env, runtimeApks, &AndroidSystem::add_apk_libdir, const_cast (static_cast (android_abi_names [running_on_cpu])));
@@ -858,7 +865,7 @@ AndroidSystem::readdir_r (_WDIR *dirp, struct _wdirent *entry, struct _wdirent *
{
int error_code = 0;
- pthread_mutex_lock (&readdir_mutex);
+ std::lock_guard lock (readdir_mutex);
errno = 0;
entry = _wreaddir (dirp);
*result = entry;
@@ -866,7 +873,6 @@ AndroidSystem::readdir_r (_WDIR *dirp, struct _wdirent *entry, struct _wdirent *
if (entry == NULL && errno != 0)
error_code = -1;
- pthread_mutex_unlock (&readdir_mutex);
return error_code;
}
diff --git a/src/monodroid/jni/android-system.h b/src/monodroid/jni/android-system.h
index 898b9ff1641..32f8f6fcb1b 100644
--- a/src/monodroid/jni/android-system.h
+++ b/src/monodroid/jni/android-system.h
@@ -2,14 +2,20 @@
#ifndef __ANDROID_SYSTEM_H
#define __ANDROID_SYSTEM_H
-#include
-#include
+#include
+#include
#include
#include
#include "dylib-mono.h"
#include "util.h"
#include "cpu-arch.h"
+#include "cppcompat.h"
+
+namespace xamarin { namespace android {
+ class jstring_wrapper;
+ class jstring_array_wrapper;
+}}
namespace xamarin { namespace android { namespace internal
{
@@ -20,13 +26,20 @@ namespace xamarin { namespace android { namespace internal
struct BundledProperty *next;
};
+ struct KnownEnvironmentVariables
+ {
+ bool DSOInApk = false;
+ MonoAotMode MonoAOT = MonoAotMode::MONO_AOT_MODE_NONE;
+ bool MonoLLVM = false;
+ };
+
class AndroidSystem
{
private:
static BundledProperty *bundled_properties;
static const char* android_abi_names[CPU_KIND_X86_64+1];
#if defined (WINDOWS)
- static pthread_mutex_t readdir_mutex;
+ static std::mutex readdir_mutex;
static char *libmonoandroid_directory_path;
#endif
@@ -73,8 +86,8 @@ namespace xamarin { namespace android { namespace internal
public:
void add_system_property (const char *name, const char *value);
- void setup_environment (JNIEnv *env, jobjectArray runtimeApks);
- void setup_process_args (JNIEnv *env, jobjectArray runtimeApks);
+ void setup_environment (JNIEnv *env, jobjectArray environmentVariables);
+ void setup_process_args (JNIEnv *env, jstring_array_wrapper &runtimeApks);
int monodroid_get_system_property (const char *name, char **value);
int monodroid_get_system_property_from_overrides (const char *name, char ** value);
int monodroid_read_file_into_memory (const char *path, char **value);
@@ -83,7 +96,7 @@ namespace xamarin { namespace android { namespace internal
char* get_bundled_app (JNIEnv *env, jstring dir);
int count_override_assemblies ();
int get_gref_gc_threshold ();
- void setup_apk_directories (JNIEnv *env, unsigned short running_on_cpu, jobjectArray runtimeApks);
+ void setup_apk_directories (JNIEnv *env, unsigned short running_on_cpu, jstring_array_wrapper &runtimeApks);
void* load_dso (const char *path, int dl_flags, mono_bool skip_exists_check);
void* load_dso_from_any_directories (const char *name, int dl_flags);
char* get_full_dso_path_on_disk (const char *dso_name, mono_bool *needs_free);
@@ -119,10 +132,24 @@ namespace xamarin { namespace android { namespace internal
int setenv (const char *name, const char *value, int overwrite);
#endif
+ bool is_mono_llvm_enabled () const
+ {
+ return knownEnvVars.MonoLLVM;
+ }
+
+ bool is_embedded_dso_mode_enabled () const
+ {
+ return knownEnvVars.DSOInApk;
+ }
+
+ MonoAotMode get_mono_aot_mode () const
+ {
+ return knownEnvVars.MonoAOT;
+ }
+
private:
int get_max_gref_count_from_system ();
- void setup_environment_from_line (const char *line);
- void setup_environment_from_file (const char *apk, int index, int apk_count, void *user_data);
+ void setup_environment (jstring_wrapper& name, jstring_wrapper& value);
BundledProperty* lookup_system_property (const char *name);
void setup_process_args_apk (const char *apk, int index, int apk_count, void *user_data);
int _monodroid__system_property_get (const char *name, char *sp_value, size_t sp_value_len);
@@ -130,7 +157,7 @@ namespace xamarin { namespace android { namespace internal
void copy_native_libraries_to_internal_location ();
void copy_file_to_internal_location (char *to_dir, char *from_dir, char *file);
void add_apk_libdir (const char *apk, int index, int apk_count, void *user_data);
- void for_each_apk (JNIEnv *env, jobjectArray runtimeApks, void (AndroidSystem::*handler) (const char *apk, int index, int apk_count, void *user_data), void *user_data);
+ void for_each_apk (JNIEnv *env, jstring_array_wrapper &runtimeApks, void (AndroidSystem::*handler) (const char *apk, int index, int apk_count, void *user_data), void *user_data);
char* get_full_dso_path (const char *base_dir, const char *dso_path, mono_bool *needs_free);
void* load_dso_from_specified_dirs (const char **directories, int num_entries, const char *dso_name, int dl_flags);
void* load_dso_from_app_lib_dirs (const char *name, int dl_flags);
@@ -148,6 +175,7 @@ namespace xamarin { namespace android { namespace internal
#endif // !ANDROID
private:
int max_gref_count = 0;
+ KnownEnvironmentVariables knownEnvVars;
};
}}}
#endif // !__ANDROID_SYSTEM_H
diff --git a/src/monodroid/jni/cppcompat.h b/src/monodroid/jni/cppcompat.h
index 274c7cea6a2..c7a4c863876 100644
--- a/src/monodroid/jni/cppcompat.h
+++ b/src/monodroid/jni/cppcompat.h
@@ -2,6 +2,8 @@
#ifndef __CPP_COMPAT_H
#define __CPP_COMPAT_H
+#include
+
// Since Android doesn't currently have any standard C++ library
// and we don't want to use any implementation of it shipped in
// source form with the NDK (for space reasons), this header will
@@ -20,5 +22,50 @@ namespace std
{
return static_cast::type&&>(arg);
}
+
+ template
+ class lock_guard
+ {
+ public:
+ using mutex_type = TMutex;
+
+ public:
+ lock_guard (const lock_guard&) = delete;
+
+ explicit lock_guard (mutex_type& _mutex)
+ : _mutex (_mutex)
+ {
+ _mutex.lock ();
+ }
+
+ ~lock_guard ()
+ {
+ _mutex.unlock ();
+ }
+
+ lock_guard& operator= (const lock_guard&) = delete;
+
+ private:
+ mutex_type &_mutex;
+ };
+
+ class mutex
+ {
+ public:
+ mutex () noexcept = default;
+ ~mutex () noexcept = default;
+
+ void lock () noexcept
+ {
+ pthread_mutex_lock (&_pmutex);
+ }
+
+ void unlock () noexcept
+ {
+ pthread_mutex_unlock (&_pmutex);
+ }
+ private:
+ pthread_mutex_t _pmutex = PTHREAD_MUTEX_INITIALIZER;
+ };
}
#endif
diff --git a/src/monodroid/jni/debug.cc b/src/monodroid/jni/debug.cc
index 98fcee6c7ae..3ab558362de 100644
--- a/src/monodroid/jni/debug.cc
+++ b/src/monodroid/jni/debug.cc
@@ -195,8 +195,8 @@ Debug::handle_server_connection (void)
flags = 1;
rv = setsockopt (listen_socket, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof (flags));
- if (rv == -1) {
- log_info (LOG_DEFAULT, "Could not set SO_REUSEADDR on the listening socket (%s)", strerror (errno));
+ if (rv == -1 && utils.should_log (LOG_DEFAULT)) {
+ log_info_nocheck (LOG_DEFAULT, "Could not set SO_REUSEADDR on the listening socket (%s)", strerror (errno));
// not a fatal failure
}
diff --git a/src/monodroid/jni/dylib-mono.cc b/src/monodroid/jni/dylib-mono.cc
index a4b5b713e50..2fcfc182f52 100644
--- a/src/monodroid/jni/dylib-mono.cc
+++ b/src/monodroid/jni/dylib-mono.cc
@@ -60,6 +60,11 @@ bool DylibMono::init (void *libmono_handle)
#define LOAD_SYMBOL(symbol) LOAD_SYMBOL_CAST(symbol, monodroid_ ##symbol ##_fptr)
#define LOAD_SYMBOL_NO_PREFIX(symbol) LOAD_SYMBOL_CAST(symbol, symbol ##_fptr)
+ timing_period total_time;
+ if (XA_UNLIKELY (utils.should_log (LOG_TIMING))) {
+ total_time.mark_start ();
+ }
+
LOAD_SYMBOL(mono_add_internal_call)
LOAD_SYMBOL(mono_assembly_get_image)
LOAD_SYMBOL(mono_assembly_load_from_full)
@@ -138,6 +143,13 @@ bool DylibMono::init (void *libmono_handle)
LOAD_SYMBOL_CAST(mono_use_llvm, int*)
LOAD_SYMBOL_NO_PREFIX(mono_aot_register_module)
+ if (XA_UNLIKELY (utils.should_log (LOG_TIMING))) {
+ total_time.mark_end ();
+
+ timing_diff diff (total_time);
+ log_info_nocheck (LOG_TIMING, "DylibMono.init: end, total time; elapsed: %lis:%lu::%lu", diff.sec, diff.ms, diff.ns);
+ }
+
if (symbols_missing) {
log_fatal (LOG_DEFAULT, "Failed to load some Mono symbols, aborting...");
exit (FATAL_EXIT_MONO_MISSING_SYMBOLS);
diff --git a/src/monodroid/jni/dylib-mono.h b/src/monodroid/jni/dylib-mono.h
index 5548165d212..6c84d313942 100644
--- a/src/monodroid/jni/dylib-mono.h
+++ b/src/monodroid/jni/dylib-mono.h
@@ -344,7 +344,9 @@ enum MonoAotMode {
MONO_AOT_MODE_HYBRID,
/* Enables full AOT mode, JIT is disabled and not allowed,
* equivalent to mono_jit_set_aot_only (true) */
- MONO_AOT_MODE_FULL
+ MONO_AOT_MODE_FULL,
+
+ MONO_AOT_MODE_UNKNOWN = 0xBADBAD
};
#ifndef __cplusplus
typedef int MonoAotMode;
diff --git a/src/monodroid/jni/embedded-assemblies.cc b/src/monodroid/jni/embedded-assemblies.cc
index 0e68779dd5a..48fbea6c36c 100644
--- a/src/monodroid/jni/embedded-assemblies.cc
+++ b/src/monodroid/jni/embedded-assemblies.cc
@@ -1,7 +1,7 @@
#include
#include
-#include
-#include
+#include
+#include
#include
#include
#include
@@ -72,7 +72,7 @@ open_from_bundles (MonoAssemblyName *aname, char **assemblies_path, void *user_d
MonoAssembly *a = NULL;
int name_len = culture == NULL ? 0 : strlen (culture) + 1;
- name_len += std::strlen (reinterpret_cast (mono->assembly_name_get_name (aname)));
+ name_len += strlen (reinterpret_cast (mono->assembly_name_get_name (aname)));
name = static_cast (utils.xmalloc (name_len + sizeof (".exe") + 1));
if (culture != NULL && strlen (culture) > 0)
sprintf (name, "%s/%s", culture, (const char*) mono->assembly_name_get_name (aname));
@@ -108,8 +108,8 @@ open_from_bundles (MonoAssemblyName *aname, char **assemblies_path, void *user_d
}
}
free (name);
- if (a) {
- log_info (LOG_ASSEMBLY, "open_from_bundles: loaded assembly: %p\n", a);
+ if (a && utils.should_log (LOG_ASSEMBLY)) {
+ log_info_nocheck (LOG_ASSEMBLY, "open_from_bundles: loaded assembly: %p\n", a);
}
return a;
}
@@ -139,7 +139,7 @@ monodroid_embedded_assemblies_install_preload_hook (DylibMono *imports)
static int
TypeMappingInfo_compare_key (const void *a, const void *b)
{
- return std::strcmp (reinterpret_cast (a), reinterpret_cast (b));
+ return strcmp (reinterpret_cast (a), reinterpret_cast (b));
}
MONO_API const char *
@@ -148,7 +148,7 @@ monodroid_typemap_java_to_managed (const char *java)
struct TypeMappingInfo *info;
for (info = java_to_managed_maps; info != NULL; info = info->next) {
/* log_warn (LOG_DEFAULT, "# jonp: checking file: %s!%s for type '%s'", info->source_apk, info->source_entry, java); */
- const char *e = reinterpret_cast (std::bsearch (java, info->mapping, info->num_entries, info->entry_length, TypeMappingInfo_compare_key));
+ const char *e = reinterpret_cast (bsearch (java, info->mapping, info->num_entries, info->entry_length, TypeMappingInfo_compare_key));
if (e == NULL)
continue;
return e + info->value_offset;
@@ -162,7 +162,7 @@ monodroid_typemap_managed_to_java (const char *managed)
struct TypeMappingInfo *info;
for (info = managed_to_java_maps; info != NULL; info = info->next) {
/* log_warn (LOG_DEFAULT, "# jonp: checking file: %s!%s for type '%s'", info->source_apk, info->source_entry, managed); */
- const char *e = reinterpret_cast (std::bsearch (managed, info->mapping, info->num_entries, info->entry_length, TypeMappingInfo_compare_key));
+ const char *e = reinterpret_cast (bsearch (managed, info->mapping, info->num_entries, info->entry_length, TypeMappingInfo_compare_key));
if (e == NULL)
continue;
return e + info->value_offset;
@@ -480,7 +480,7 @@ gather_bundled_assemblies_from_apk (
psize = (unsigned int*) &cur->size;
*psize = info.uncompressed_size;
- if ((log_categories & LOG_ASSEMBLY) != 0) {
+ if (utils.should_log (LOG_ASSEMBLY)) {
const char *p = (const char*) cur->data;
char header[9];
@@ -489,7 +489,7 @@ gather_bundled_assemblies_from_apk (
header[i] = isprint (p [i]) ? p [i] : '.';
header [sizeof(header)-1] = '\0';
- log_info (LOG_ASSEMBLY, "file-offset: % 8x start: %08p end: %08p len: % 12i zip-entry: %s name: %s [%s]",
+ log_info_nocheck (LOG_ASSEMBLY, "file-offset: % 8x start: %08p end: %08p len: % 12i zip-entry: %s name: %s [%s]",
(int) offset, cur->data, cur->data + *psize, (int) info.uncompressed_size, cur_entry_name, cur->name, header);
}
diff --git a/src/monodroid/jni/globals.h b/src/monodroid/jni/globals.h
index 3220ed02fe1..a759a47bbbd 100644
--- a/src/monodroid/jni/globals.h
+++ b/src/monodroid/jni/globals.h
@@ -6,6 +6,7 @@
#include "util.h"
#include "debug.h"
#include "monodroid-glue-internal.h"
+#include "cppcompat.h"
extern xamarin::android::DylibMono monoFunctions;
extern xamarin::android::Util utils;
diff --git a/src/monodroid/jni/jni-wrappers.h b/src/monodroid/jni/jni-wrappers.h
new file mode 100644
index 00000000000..9a7cfed4cd7
--- /dev/null
+++ b/src/monodroid/jni/jni-wrappers.h
@@ -0,0 +1,179 @@
+// Dear Emacs, this is a -*- C++ -*- header
+#ifndef __JNI_WRAPPERS_H
+#define __JNI_WRAPPERS_H
+
+#include
+#include
+#include
+
+#ifdef __cplusplus
+
+namespace xamarin { namespace android
+{
+ class jstring_array_wrapper;
+
+ class jstring_wrapper
+ {
+ public:
+ explicit jstring_wrapper (JNIEnv *env) noexcept
+ : env (env),
+ jstr (nullptr)
+ {
+ assert (env);
+ }
+
+ explicit jstring_wrapper (JNIEnv *env, const jobject jo) noexcept
+ : env (env),
+ jstr (reinterpret_cast (jo))
+ {
+ assert (env);
+ }
+
+ explicit jstring_wrapper (JNIEnv *env, const jstring js) noexcept
+ : env (env),
+ jstr (js)
+ {
+ assert (env);
+ }
+
+ jstring_wrapper (const jstring_wrapper&) = delete;
+
+ ~jstring_wrapper () noexcept
+ {
+ release ();
+ }
+
+ jstring_wrapper& operator=(const jstring_wrapper&) = delete;
+
+ const char* get_cstr () noexcept
+ {
+ if (cstr == nullptr && env != nullptr)
+ cstr = env->GetStringUTFChars (jstr, nullptr);
+
+ return cstr;
+ }
+
+ jstring_wrapper& operator= (const jobject new_jo) noexcept
+ {
+ assign (reinterpret_cast (new_jo));
+ return *this;
+ }
+
+ jstring_wrapper& operator= (const jstring new_js) noexcept
+ {
+ assign (new_js);
+ return *this;
+ }
+
+ protected:
+ void release () noexcept
+ {
+ if (jstr == nullptr || cstr == nullptr || env == nullptr)
+ return;
+ env->ReleaseStringUTFChars (jstr, cstr);
+ jobjectRefType type = env->GetObjectRefType (jstr);
+ switch (type) {
+ case JNILocalRefType:
+ env->DeleteLocalRef (jstr);
+ break;
+
+ case JNIGlobalRefType:
+ env->DeleteGlobalRef (jstr);
+ break;
+
+ case JNIWeakGlobalRefType:
+ env->DeleteWeakGlobalRef (jstr);
+ break;
+
+ case JNIInvalidRefType: // To hush compiler warning
+ break;
+ }
+
+ jstr = nullptr;
+ cstr = nullptr;
+ }
+
+ void assign (const jstring new_js) noexcept
+ {
+ release ();
+ if (new_js == nullptr)
+ return;
+
+ jstr = new_js;
+ cstr = nullptr;
+ }
+
+ friend class jstring_array_wrapper;
+
+ private:
+ jstring_wrapper ()
+ : env (nullptr),
+ jstr (nullptr)
+ {}
+
+ private:
+ JNIEnv *env;
+ jstring jstr;
+ const char *cstr = nullptr;
+ };
+
+ class jstring_array_wrapper
+ {
+ public:
+ explicit jstring_array_wrapper (JNIEnv *env) noexcept
+ : env (env),
+ arr (nullptr),
+ len (0)
+ {
+ assert (env);
+ }
+
+ explicit jstring_array_wrapper (JNIEnv *env, jobjectArray arr)
+ : env (env),
+ arr (arr)
+ {
+ assert (env);
+ assert (arr);
+ len = env->GetArrayLength (arr);
+ if (len > sizeof (static_wrappers) / sizeof (jstring_wrapper))
+ wrappers = new jstring_wrapper [len];
+ else
+ wrappers = static_wrappers;
+ }
+
+ ~jstring_array_wrapper () noexcept
+ {
+ if (wrappers != nullptr && wrappers != static_wrappers)
+ delete[] wrappers;
+ }
+
+ size_t get_length () const noexcept
+ {
+ return len;
+ }
+
+ jstring_wrapper& operator[] (size_t index) noexcept
+ {
+ if (index >= len)
+ return invalid_wrapper;
+
+ if (wrappers [index].env == nullptr) {
+ wrappers [index].env = env;
+ wrappers [index].jstr = reinterpret_cast (env->GetObjectArrayElement (arr, index));
+ }
+
+ return wrappers [index];
+ }
+
+ private:
+ JNIEnv *env;
+ jobjectArray arr;
+ size_t len;
+ jstring_wrapper *wrappers;
+ jstring_wrapper static_wrappers[5];
+ jstring_wrapper invalid_wrapper;
+ };
+}}
+
+#endif // __cplusplus
+#endif // __JNI_WRAPPERS_H
diff --git a/src/monodroid/jni/mono_android_Runtime.h b/src/monodroid/jni/mono_android_Runtime.h
index 8bd4ae1bf3c..e634391795e 100644
--- a/src/monodroid/jni/mono_android_Runtime.h
+++ b/src/monodroid/jni/mono_android_Runtime.h
@@ -10,10 +10,10 @@ extern "C" {
/*
* Class: mono_android_Runtime
* Method: init
- * Signature: (Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/ClassLoader;[Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)V
+ * Signature: (Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/ClassLoader;[Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;I;Ljava/lang/String)V
*/
JNIEXPORT void JNICALL Java_mono_android_Runtime_init
- (JNIEnv *, jclass, jstring, jobjectArray, jstring, jobjectArray, jobject, jobjectArray, jobjectArray, jstring);
+ (JNIEnv *, jclass, jstring, jobjectArray, jstring, jobjectArray, jobject, jobjectArray, jobjectArray, jstring, jint, jobjectArray);
/*
* Class: mono_android_Runtime
diff --git a/src/monodroid/jni/monodroid-glue-internal.h b/src/monodroid/jni/monodroid-glue-internal.h
index 8bc69047202..cf27decf1fc 100644
--- a/src/monodroid/jni/monodroid-glue-internal.h
+++ b/src/monodroid/jni/monodroid-glue-internal.h
@@ -13,7 +13,6 @@ namespace xamarin { namespace android { namespace internal
extern char *external_override_dir;
extern char *external_legacy_override_dir;
extern char *runtime_libdir;
- extern int embedded_dso_mode;
class MonodroidRuntime
{
diff --git a/src/monodroid/jni/monodroid-glue.cc b/src/monodroid/jni/monodroid-glue.cc
index bf16bdbe05d..76b3b90c71e 100644
--- a/src/monodroid/jni/monodroid-glue.cc
+++ b/src/monodroid/jni/monodroid-glue.cc
@@ -1,4 +1,3 @@
-
#include
#include
#include
@@ -159,23 +158,15 @@ monodroid_get_system_property (const char *name, char **value)
}
static char*
-get_primary_override_dir (JNIEnv *env, jstring home)
+get_primary_override_dir (JNIEnv *env, jstring_wrapper &home)
{
- const char *v;
- char *p;
-
- v = env->GetStringUTFChars (home, NULL);
- p = utils.path_combine (v, ".__override__");
- env->ReleaseStringUTFChars (home, v);
-
- return p;
+ return utils.path_combine (home.get_cstr (), ".__override__");
}
// TODO: these must be moved to some class
char *xamarin::android::internal::primary_override_dir;
char *xamarin::android::internal::external_override_dir;
char *xamarin::android::internal::external_legacy_override_dir;
-int xamarin::android::internal::embedded_dso_mode = 0;
/* Set of Windows-specific utility/reimplementation of Unix functions */
#ifdef WINDOWS
@@ -230,7 +221,7 @@ setup_bundled_app (const char *dso_name)
static int dlopen_flags = RTLD_LAZY;
void *libapp = NULL;
- if (embedded_dso_mode) {
+ if (androidSystem.is_embedded_dso_mode_enabled ()) {
log_info (LOG_DEFAULT, "bundle app: embedded DSO mode");
libapp = androidSystem.load_dso_from_any_directories (dso_name, dlopen_flags);
} else {
@@ -247,7 +238,7 @@ setup_bundled_app (const char *dso_name)
if (libapp == NULL) {
log_info (LOG_DEFAULT, "No libapp!");
- if (!embedded_dso_mode) {
+ if (!androidSystem.is_embedded_dso_mode_enabled ()) {
log_fatal (LOG_BUNDLE, "bundled app initialization error");
exit (FATAL_EXIT_CANNOT_LOAD_BUNDLE);
} else {
@@ -273,10 +264,13 @@ typedef struct {
static MonoDroidProfiler monodroid_profiler;
static jclass TimeZone_class;
-static jmethodID TimeZone_getDefault;
-static jmethodID TimeZone_getID;
-static int is_running_on_desktop = 0;
+static constexpr bool is_running_on_desktop =
+#if ANDROID
+ false;
+#else
+ true;
+#endif
MONO_API int
_monodroid_max_gref_get (void)
@@ -437,8 +431,8 @@ open_from_update_dir (MonoAssemblyName *aname, char **assemblies_path, void *use
}
}
free (pname);
- if (result) {
- log_info (LOG_ASSEMBLY, "open_from_update_dir: loaded assembly: %p\n", result);
+ if (result && utils.should_log (LOG_ASSEMBLY)) {
+ log_info_nocheck (LOG_ASSEMBLY, "open_from_update_dir: loaded assembly: %p\n", result);
}
return result;
}
@@ -471,16 +465,12 @@ should_register_file (const char *filename, void *user_data)
}
static void
-gather_bundled_assemblies (JNIEnv *env, jobjectArray runtimeApks, mono_bool register_debug_symbols, int *out_user_assemblies_count)
+gather_bundled_assemblies (JNIEnv *env, jstring_array_wrapper &runtimeApks, mono_bool register_debug_symbols, int *out_user_assemblies_count)
{
- jsize i;
- int prev_num_assemblies = 0;
- jsize apksLength = env->GetArrayLength (runtimeApks);
-
monodroid_embedded_assemblies_set_register_debug_symbols (register_debug_symbols);
monodroid_embedded_assemblies_set_should_register (should_register_file, NULL);
#ifndef RELEASE
- for (i = 0; i < AndroidSystem::MAX_OVERRIDES; ++i) {
+ for (size_t i = 0; i < AndroidSystem::MAX_OVERRIDES; ++i) {
const char *p = androidSystem.get_override_dir (i);
if (!utils.directory_exists (p))
continue;
@@ -488,22 +478,18 @@ gather_bundled_assemblies (JNIEnv *env, jobjectArray runtimeApks, mono_bool regi
try_load_typemaps_from_directory (p);
}
#endif
- for (i = apksLength - 1; i >= 0; --i) {
- int cur_num_assemblies;
- const char *apk_file;
- jstring apk = reinterpret_cast (env->GetObjectArrayElement (runtimeApks, i));
- apk_file = env->GetStringUTFChars (apk, NULL);
+ int prev_num_assemblies = 0;
+ for (int32_t i = runtimeApks.get_length () - 1; i >= 0; --i) {
+ int cur_num_assemblies;
+ jstring_wrapper &apk_file = runtimeApks [i];
- cur_num_assemblies = monodroid_embedded_assemblies_register_from (&monoFunctions, apk_file);
+ cur_num_assemblies = monodroid_embedded_assemblies_register_from (&monoFunctions, apk_file.get_cstr ());
- if (strstr (apk_file, "/Mono.Android.DebugRuntime") == NULL &&
- strstr (apk_file, "/Mono.Android.Platform.ApiLevel_") == NULL)
+ if (strstr (apk_file.get_cstr (), "/Mono.Android.DebugRuntime") == nullptr &&
+ strstr (apk_file.get_cstr (), "/Mono.Android.Platform.ApiLevel_") == nullptr)
*out_user_assemblies_count += (cur_num_assemblies - prev_num_assemblies);
prev_num_assemblies = cur_num_assemblies;
-
- env->ReleaseStringUTFChars (apk, apk_file);
- env->DeleteLocalRef (apk);
}
}
@@ -592,38 +578,6 @@ JNI_OnLoad (JavaVM *vm, void *reserved)
vm->GetEnv ((void**)&env, JNI_VERSION_1_6);
osBridge.initialize_on_onload (vm, env);
- TimeZone_class = reinterpret_cast (osBridge.lref_to_gref (env, env->FindClass ("java/util/TimeZone")));
- if (!TimeZone_class) {
- log_fatal (LOG_DEFAULT, "Fatal error: Could not find java.util.TimeZone class!");
- exit (FATAL_EXIT_MISSING_TIMEZONE_MEMBERS);
- }
-
- TimeZone_getDefault = env->GetStaticMethodID (TimeZone_class, "getDefault", "()Ljava/util/TimeZone;");
- if (!TimeZone_getDefault) {
- log_fatal (LOG_DEFAULT, "Fatal error: Could not find java.util.TimeZone.getDefault() method!");
- exit (FATAL_EXIT_MISSING_TIMEZONE_MEMBERS);
- }
-
- TimeZone_getID = env->GetMethodID (TimeZone_class, "getID", "()Ljava/lang/String;");
- if (!TimeZone_getID) {
- log_fatal (LOG_DEFAULT, "Fatal error: Could not find java.util.TimeZone.getDefault() method!");
- exit (FATAL_EXIT_MISSING_TIMEZONE_MEMBERS);
- }
-
- /* When running on Android, as per http://developer.android.com/reference/java/lang/System.html#getProperty(java.lang.String)
- * the value of java.version is deemed "(Not useful on Android)" and is hardcoded to return zero. We can thus use this fact
- * to distinguish between running on a normal JVM and an Android VM.
- */
- jclass System_class = env->FindClass ("java/lang/System");
- jmethodID System_getProperty = env->GetStaticMethodID (System_class, "getProperty", "(Ljava/lang/String;)Ljava/lang/String;");
- jstring System_javaVersionArg = env->NewStringUTF ("java.version");
- jstring System_javaVersion = reinterpret_cast (env->CallStaticObjectMethod (System_class, System_getProperty, System_javaVersionArg));
- const char* javaVersion = env->GetStringUTFChars (System_javaVersion, NULL);
- is_running_on_desktop = atoi (javaVersion) != 0;
- env->ReleaseStringUTFChars (System_javaVersion, javaVersion);
- env->DeleteLocalRef (System_javaVersionArg);
- env->DeleteLocalRef (System_javaVersion);
- env->DeleteLocalRef (System_class);
return JNI_VERSION_1_6;
}
@@ -762,39 +716,6 @@ parse_runtime_args (char *runtime_args, RuntimeOptions *options)
}
#endif // def DEBUG
-static void
-load_assembly (MonoDomain *domain, JNIEnv *env, jstring assembly)
-{
- timing_period total_time;
- if (XA_UNLIKELY (utils.should_log (LOG_TIMING)))
- total_time.mark_start ();
-
- const char *assm_name;
- MonoAssemblyName *aname;
-
- assm_name = env->GetStringUTFChars (assembly, NULL);
- aname = monoFunctions.assembly_name_new (assm_name);
- env->ReleaseStringUTFChars (assembly, assm_name);
-
- if (domain != monoFunctions.domain_get ()) {
- MonoDomain *current = monoFunctions.domain_get ();
- monoFunctions.domain_set (domain, FALSE);
- monoFunctions.assembly_load_full (aname, NULL, NULL, 0);
- monoFunctions.domain_set (current, FALSE);
- } else {
- monoFunctions.assembly_load_full (aname, NULL, NULL, 0);
- }
-
- monoFunctions.assembly_name_free (aname);
-
- if (XA_UNLIKELY (utils.should_log (LOG_TIMING))) {
- total_time.mark_end ();
-
- timing_diff diff (total_time);
- log_info (LOG_TIMING, "Assembly load: %s loaded; elapsed: %lis.%03llu::%llu", assm_name, diff.sec, diff.ms, diff.ns);
- }
-}
-
static void
set_debug_options (void)
{
@@ -806,11 +727,11 @@ set_debug_options (void)
}
#ifdef ANDROID
+#ifdef DEBUG
static const char *soft_breakpoint_kernel_list[] = {
"2.6.32.21-g1e30168", NULL
};
-#ifdef DEBUG
static int
enable_soft_breakpoints (void)
{
@@ -1023,34 +944,8 @@ mono_runtime_init (char *runtime_args)
#endif
}
-static int
-GetAndroidSdkVersion (JNIEnv *env, jobject loader)
-{
- jclass lrefVersion = env->FindClass ("android/os/Build$VERSION");
- if (lrefVersion == NULL) {
- // Try to load the class from the loader instead.
- // Needed by Android designer that uses dynamic loaders
- env->ExceptionClear ();
- jclass classLoader = env->FindClass ("java/lang/ClassLoader");
- jmethodID classLoader_loadClass = env->GetMethodID (classLoader, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
- //env->ExceptionDescribe ();
- jstring versionClassName = env->NewStringUTF ("android.os.Build$VERSION");
-
- lrefVersion = (jclass)env->CallObjectMethod (loader, classLoader_loadClass, versionClassName);
-
- env->DeleteLocalRef (classLoader);
- env->DeleteLocalRef (versionClassName);
- }
- jfieldID SDK_INT = env->GetStaticFieldID (lrefVersion, "SDK_INT", "I");
- int version = env->GetStaticIntField (lrefVersion, SDK_INT);
-
- env->DeleteLocalRef (lrefVersion);
-
- return version;
-}
-
static MonoDomain*
-create_domain (JNIEnv *env, jobjectArray runtimeApks, jstring assembly, jobject loader, mono_bool is_root_domain)
+create_domain (JNIEnv *env, jclass runtimeClass, jstring_array_wrapper &runtimeApks, jstring assembly, jobject loader, bool is_root_domain)
{
MonoDomain *domain;
int user_assemblies_count = 0;;
@@ -1068,7 +963,7 @@ create_domain (JNIEnv *env, jobjectArray runtimeApks, jstring assembly, jobject
domain = monoFunctions.jit_init_version (const_cast ("RootDomain"), const_cast ("mobile"));
} else {
MonoDomain* root_domain = monoFunctions.get_root_domain ();
- char *domain_name = utils.monodroid_strdup_printf ("MonoAndroidDomain%d", GetAndroidSdkVersion (env, loader));
+ char *domain_name = utils.monodroid_strdup_printf ("MonoAndroidDomain%d", android_api_level);
domain = utils.monodroid_create_appdomain (root_domain, domain_name, /*shadow_copy:*/ 1, /*shadow_directory:*/ androidSystem.get_override_dir (0));
free (domain_name);
}
@@ -1078,7 +973,7 @@ create_domain (JNIEnv *env, jobjectArray runtimeApks, jstring assembly, jobject
// tell the IDE that the project likely need to be recompiled.
char* corlib_error_message = monoFunctions.check_corlib_version ();
if (corlib_error_message == NULL) {
- if (!monodroid_get_system_property ("xamarin.studio.fakefaultycorliberrormessage", &corlib_error_message)) {
+ if (!androidSystem.monodroid_get_system_property ("xamarin.studio.fakefaultycorliberrormessage", &corlib_error_message)) {
free (corlib_error_message);
corlib_error_message = NULL;
}
@@ -1095,40 +990,22 @@ create_domain (JNIEnv *env, jobjectArray runtimeApks, jstring assembly, jobject
MonoAssemblyName *aname = monoFunctions.assembly_name_new ("System");
monoFunctions.assembly_load_full (aname, NULL, NULL, 0);
monoFunctions.assembly_name_free (aname);
- } else {
- // Inflate environment from user app assembly
- load_assembly (domain, env, assembly);
}
return domain;
}
-static void
-load_assemblies (MonoDomain *domain, JNIEnv *env, jobjectArray assemblies)
-{
- jsize i;
- jsize assembliesLength = env->GetArrayLength (assemblies);
- /* skip element 0, as that's loaded in create_domain() */
- for (i = 1; i < assembliesLength; ++i) {
- jstring assembly = reinterpret_cast (env->GetObjectArrayElement (assemblies, i));
- load_assembly (domain, env, assembly);
- env->DeleteLocalRef (assembly);
- }
-}
-
static jclass System;
static jmethodID System_identityHashCode;
static int
-LocalRefsAreIndirect (JNIEnv *env, int version)
+LocalRefsAreIndirect (JNIEnv *env, jclass runtimeClass, int version)
{
if (version < 14)
return 0;
- System = reinterpret_cast (env->NewGlobalRef (env->FindClass ("java/lang/System")));
-
- System_identityHashCode = env->GetStaticMethodID (System,
- "identityHashCode", "(Ljava/lang/Object;)I");
+ System = utils.get_class_from_runtime_field(env, runtimeClass, "java_lang_System", true);
+ System_identityHashCode = env->GetStaticMethodID (System, "identityHashCode", "(Ljava/lang/Object;)I");
return 1;
}
@@ -1143,12 +1020,13 @@ _monodroid_get_identity_hash_code (JNIEnv *env, void *v)
MONO_API void*
_monodroid_timezone_get_default_id (void)
{
- JNIEnv *env = osBridge.ensure_jnienv ();
- jobject d = env->CallStaticObjectMethod (TimeZone_class, TimeZone_getDefault);
- jstring id = reinterpret_cast (env->CallObjectMethod (d, TimeZone_getID));
- const char *mutf8 = env->GetStringUTFChars (id, NULL);
-
- char *def_id = utils.monodroid_strdup_printf ("%s", mutf8);
+ JNIEnv *env = osBridge.ensure_jnienv ();
+ jmethodID getDefault = env->GetStaticMethodID (TimeZone_class, "getDefault", "()Ljava/util/TimeZone;");
+ jmethodID getID = env->GetMethodID (TimeZone_class, "getID", "()Ljava/lang/String;");
+ jobject d = env->CallStaticObjectMethod (TimeZone_class, getDefault);
+ jstring id = reinterpret_cast (env->CallObjectMethod (d, getID));
+ const char *mutf8 = env->GetStringUTFChars (id, NULL);
+ char *def_id = utils.monodroid_strdup_printf ("%s", mutf8);
env->ReleaseStringUTFChars (id, mutf8);
env->DeleteLocalRef (id);
@@ -1202,6 +1080,23 @@ _monodroid_get_display_dpi (float *x_dpi, float *y_dpi)
return -1;
}
+ MonoDomain *domain = nullptr;
+ if (!runtime_GetDisplayDPI) {
+ domain = monoFunctions.get_root_domain ();
+ MonoAssembly *assm = utils.monodroid_load_assembly (domain, "Mono.Android");;
+
+ MonoImage *image = nullptr;
+ if (assm != nullptr)
+ image = monoFunctions.assembly_get_image (assm);
+
+ MonoClass *environment = nullptr;
+ if (image != nullptr)
+ environment = utils.monodroid_get_class_from_image (domain, image, "Android.Runtime", "AndroidEnvironment");
+
+ if (environment != nullptr)
+ runtime_GetDisplayDPI = monoFunctions.class_get_method_from_name (environment, "GetDisplayDPI", 2);
+ }
+
if (!runtime_GetDisplayDPI) {
*x_dpi = DEFAULT_X_DPI;
*y_dpi = DEFAULT_Y_DPI;
@@ -1210,7 +1105,7 @@ _monodroid_get_display_dpi (float *x_dpi, float *y_dpi)
args [0] = x_dpi;
args [1] = y_dpi;
- utils.monodroid_runtime_invoke (monoFunctions.get_root_domain (), runtime_GetDisplayDPI, NULL, args, &exc);
+ utils.monodroid_runtime_invoke (domain != nullptr ? domain : monoFunctions.get_root_domain (), runtime_GetDisplayDPI, NULL, args, &exc);
if (exc) {
*x_dpi = DEFAULT_X_DPI;
*y_dpi = DEFAULT_Y_DPI;
@@ -1230,15 +1125,13 @@ lookup_bridge_info (MonoDomain *domain, MonoImage *image, const OSBridge::MonoJa
}
static void
-init_android_runtime (MonoDomain *domain, JNIEnv *env, jobject loader)
+init_android_runtime (MonoDomain *domain, JNIEnv *env, jclass runtimeClass, jobject loader)
{
MonoAssembly *assm;
MonoClass *runtime;
- MonoClass *environment;
MonoImage *image;
MonoMethod *method;
jclass lrefLoaderClass;
- jobject lrefIGCUserPeer;
int i;
struct JnienvInitializeArgs init = {};
@@ -1250,7 +1143,7 @@ init_android_runtime (MonoDomain *domain, JNIEnv *env, jobject loader)
init.logCategories = log_categories;
init.version = env->GetVersion ();
init.androidSdkVersion = android_api_level;
- init.localRefsAreIndirect = LocalRefsAreIndirect (env, init.androidSdkVersion);
+ init.localRefsAreIndirect = LocalRefsAreIndirect (env, runtimeClass, init.androidSdkVersion);
init.isRunningOnDesktop = is_running_on_desktop;
// GC threshold is 90% of the max GREF count
@@ -1258,11 +1151,9 @@ init_android_runtime (MonoDomain *domain, JNIEnv *env, jobject loader)
log_warn (LOG_GC, "GREF GC Threshold: %i", init.grefGcThreshold);
- jclass lrefClass = env->FindClass ("java/lang/Class");
- init.grefClass = reinterpret_cast (env->NewGlobalRef (lrefClass));
- init.Class_getName = env->GetMethodID (lrefClass, "getName", "()Ljava/lang/String;");
- init.Class_forName = env->GetStaticMethodID (lrefClass, "forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;");
- env->DeleteLocalRef (lrefClass);
+ init.grefClass = utils.get_class_from_runtime_field (env, runtimeClass, "java_lang_Class", true);
+ init.Class_getName = env->GetMethodID (init.grefClass, "getName", "()Ljava/lang/String;");
+ init.Class_forName = env->GetStaticMethodID (init.grefClass, "forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;");
assm = utils.monodroid_load_assembly (domain, "Mono.Android");
image = monoFunctions.assembly_get_image (assm);
@@ -1273,7 +1164,6 @@ init_android_runtime (MonoDomain *domain, JNIEnv *env, jobject loader)
runtime = utils.monodroid_get_class_from_image (domain, image, "Android.Runtime", "JNIEnv");
method = monoFunctions.class_get_method_from_name (runtime, "Initialize", 1);
- environment = utils.monodroid_get_class_from_image (domain, image, "Android.Runtime", "AndroidEnvironment");
if (method == 0) {
log_fatal (LOG_DEFAULT, "INTERNAL ERROR: Unable to find Android.Runtime.JNIEnv.Initialize!");
@@ -1291,7 +1181,6 @@ init_android_runtime (MonoDomain *domain, JNIEnv *env, jobject loader)
}
MonoClass *android_runtime_jnienv = runtime;
MonoClassField *bridge_processing_field = monoFunctions.class_get_field_from_name (runtime, const_cast ("BridgeProcessing"));
- runtime_GetDisplayDPI = monoFunctions.class_get_method_from_name (environment, "GetDisplayDPI", 2);
if (!android_runtime_jnienv || !bridge_processing_field) {
log_fatal (LOG_DEFAULT, "INTERNAL_ERROR: Unable to find Android.Runtime.JNIEnv.BridgeProcessing");
exit (FATAL_EXIT_CANNOT_FIND_JNIENV);
@@ -1303,13 +1192,11 @@ init_android_runtime (MonoDomain *domain, JNIEnv *env, jobject loader)
init.grefLoader = env->NewGlobalRef (loader);
- lrefIGCUserPeer = env->FindClass ("mono/android/IGCUserPeer");
- init.grefIGCUserPeer = env->NewGlobalRef (lrefIGCUserPeer);
- env->DeleteLocalRef (lrefIGCUserPeer);
+ init.grefIGCUserPeer = utils.get_class_from_runtime_field(env, runtimeClass, "mono_android_IGCUserPeer", true);
- osBridge.initialize_on_runtime_init (env);
+ osBridge.initialize_on_runtime_init (env, runtimeClass);
- log_warn (LOG_DEFAULT, "Calling into managed runtime init");
+ log_info (LOG_DEFAULT, "Calling into managed runtime init");
timing_period partial_time;
if (XA_UNLIKELY (utils.should_log (LOG_TIMING)))
@@ -1321,7 +1208,7 @@ init_android_runtime (MonoDomain *domain, JNIEnv *env, jobject loader)
partial_time.mark_end ();
timing_diff diff (partial_time);
- log_info (LOG_TIMING, "Runtime.init: end native-to-managed transition; elapsed: %lis.%03llu::%llu", diff.sec, diff.ms, diff.ns);
+ log_info_nocheck (LOG_TIMING, "Runtime.init: end native-to-managed transition; elapsed: %lis:%lu::%lu", diff.sec, diff.ms, diff.ns);
}
}
@@ -1357,48 +1244,6 @@ propagate_uncaught_exception (MonoDomain *domain, JNIEnv *env, jobject javaThrea
utils.monodroid_runtime_invoke (domain, method, NULL, args, NULL);
}
-static void
-register_packages (MonoDomain *domain, JNIEnv *env, jobjectArray assemblies)
-{
- jsize i;
- jsize assembliesLength = env->GetArrayLength (assemblies);
- for (i = 0; i < assembliesLength; ++i) {
- const char *filename;
- char *basename;
- MonoAssembly *a;
- MonoImage *image;
- MonoClass *c;
- MonoMethod *m;
- jstring assembly = reinterpret_cast (env->GetObjectArrayElement (assemblies, i));
-
- filename = env->GetStringUTFChars (assembly, NULL);
- basename = utils.monodroid_strdup_printf ("%s", filename);
- (*strrchr (basename, '.')) = '\0';
- a = monoFunctions.domain_assembly_open (domain, basename);
- if (a == NULL) {
- log_fatal (LOG_ASSEMBLY, "Could not load assembly '%s' during startup registration.", basename);
- log_fatal (LOG_ASSEMBLY, "This might be due to an invalid debug installation.");
- log_fatal (LOG_ASSEMBLY, "A common cause is to 'adb install' the app directly instead of doing from the IDE.");
- exit (FATAL_EXIT_MISSING_ASSEMBLY);
- }
-
-
- free (basename);
- env->ReleaseStringUTFChars (assembly, filename);
- env->DeleteLocalRef (assembly);
-
- image = monoFunctions.assembly_get_image (a);
-
- c = utils.monodroid_get_class_from_image (domain, image, "Java.Interop", "__TypeRegistrations");
- if (c == NULL)
- continue;
- m = monoFunctions.class_get_method_from_name (c, "RegisterPackages", 0);
- if (m == NULL)
- continue;
- utils.monodroid_runtime_invoke (domain, m, NULL, NULL, NULL);
- }
-}
-
#if DEBUG
static void
setup_gc_logging (void)
@@ -1461,8 +1306,8 @@ monodroid_dlopen (const char *name, int flags, char **err, void *user_data)
basename = monodroid_strdup_printf ("libaot-%s", basename);
h = androidSystem.load_dso_from_any_directories (basename, dl_flags);
- if (h != NULL)
- log_info (LOG_ASSEMBLY, "Loaded AOT image '%s'", basename);
+ if (h != NULL && XA_UNLIKELY (utils.should_log (LOG_ASSEMBLY)))
+ log_info_nocheck (LOG_ASSEMBLY, "Loaded AOT image '%s'", basename);
done_and_out:
if (!h && err) {
@@ -1490,36 +1335,32 @@ monodroid_dlsym (void *handle, const char *name, char **err, void *user_data)
}
static void
-set_environment_variable_for_directory_full (JNIEnv *env, const char *name, jstring value, int createDirectory, int mode )
+set_environment_variable_for_directory (JNIEnv *env, const char *name, jstring_wrapper &value, bool createDirectory, int mode )
{
- const char *v;
-
- v = env->GetStringUTFChars (value, NULL);
if (createDirectory) {
- int rv = utils.create_directory (v, mode);
+ int rv = utils.create_directory (value.get_cstr (), mode);
if (rv < 0 && errno != EEXIST)
log_warn (LOG_DEFAULT, "Failed to create directory for environment variable %s. %s", name, strerror (errno));
}
- setenv (name, v, 1);
- env->ReleaseStringUTFChars (value, v);
+ setenv (name, value.get_cstr (), 1);
}
static void
-set_environment_variable_for_directory (JNIEnv *env, const char *name, jstring value)
+set_environment_variable_for_directory (JNIEnv *env, const char *name, jstring_wrapper &value)
{
- set_environment_variable_for_directory_full (env, name, value, 1, DEFAULT_DIRECTORY_MODE);
+ set_environment_variable_for_directory (env, name, value, true, DEFAULT_DIRECTORY_MODE);
}
static void
-set_environment_variable (JNIEnv *env, const char *name, jstring value)
+set_environment_variable (JNIEnv *env, const char *name, jstring_wrapper &value)
{
- set_environment_variable_for_directory_full (env, name, value, 0, 0);
+ set_environment_variable_for_directory (env, name, value, false, 0);
}
static void
-create_xdg_directory (const char *home, const char *relativePath, const char *environmentVariableName)
+create_xdg_directory (jstring_wrapper& home, const char *relativePath, const char *environmentVariableName)
{
- char *dir = utils.monodroid_strdup_printf ("%s/%s", home, relativePath);
+ char *dir = utils.monodroid_strdup_printf ("%s/%s", home.get_cstr (), relativePath);
log_info (LOG_DEFAULT, "Creating XDG directory: %s", dir);
int rv = utils.create_directory (dir, DEFAULT_DIRECTORY_MODE);
if (rv < 0 && errno != EEXIST)
@@ -1530,12 +1371,10 @@ create_xdg_directory (const char *home, const char *relativePath, const char *en
}
static void
-create_xdg_directories_and_environment (JNIEnv *env, jstring homeDir)
+create_xdg_directories_and_environment (JNIEnv *env, jstring_wrapper &homeDir)
{
- const char *home = env->GetStringUTFChars (homeDir, NULL);
- create_xdg_directory (home, ".local/share", "XDG_DATA_HOME");
- create_xdg_directory (home, ".config", "XDG_CONFIG_HOME");
- env->ReleaseStringUTFChars (homeDir, home);
+ create_xdg_directory (homeDir, ".local/share", "XDG_DATA_HOME");
+ create_xdg_directory (homeDir, ".config", "XDG_CONFIG_HOME");
}
#if DEBUG
@@ -1657,16 +1496,12 @@ static void
set_profile_options (JNIEnv *env)
{
char *value;
- char *output;
- char **args, **ptr;
-
if (utils.monodroid_get_namespaced_system_property (Debug::DEBUG_MONO_PROFILE_PROPERTY, &value) == 0)
return;
- output = NULL;
-
- args = utils.monodroid_strsplit (value, ",", -1);
- for (ptr = args; ptr && *ptr; ptr++) {
+ char *output = nullptr;
+ char **args = utils.monodroid_strsplit (value, ",", -1);
+ for (char **ptr = args; ptr && *ptr; ptr++) {
const char *arg = *ptr;
if (!strncmp (arg, "output=", sizeof ("output=")-1)) {
const char *p = arg + (sizeof ("output=")-1);
@@ -1865,6 +1700,9 @@ This is a hack to set llvm::DisablePrettyStackTrace to true and avoid this sourc
static void
disable_external_signal_handlers (void)
{
+ if (!androidSystem.is_mono_llvm_enabled ())
+ return;
+
void *llvm = androidSystem.load_dso ("libLLVM.so", RTLD_LAZY, TRUE);
if (llvm) {
bool *disable_signals = reinterpret_cast (dlsym (llvm, "_ZN4llvm23DisablePrettyStackTraceE"));
@@ -1879,11 +1717,10 @@ disable_external_signal_handlers (void)
MONO_API void
_monodroid_counters_dump (const char *format, ...)
{
- va_list args;
-
if (counters == NULL)
return;
+ va_list args;
fprintf (counters, "\n");
va_start (args, format);
@@ -1902,17 +1739,15 @@ monodroid_Mono_UnhandledException_internal (MonoException *ex)
}
static MonoDomain*
-create_and_initialize_domain (JNIEnv* env, jobjectArray runtimeApks, jobjectArray assemblies, jobject loader, mono_bool is_root_domain)
+create_and_initialize_domain (JNIEnv* env, jclass runtimeClass, jstring_array_wrapper &runtimeApks, jobjectArray assemblies, jobject loader, bool is_root_domain)
{
- MonoDomain* domain = create_domain (env, runtimeApks, reinterpret_cast (env->GetObjectArrayElement (assemblies, 0)), loader, is_root_domain);
+ MonoDomain* domain = create_domain (env, runtimeClass, runtimeApks, reinterpret_cast (env->GetObjectArrayElement (assemblies, 0)), loader, is_root_domain);
// When running on desktop, the root domain is only a dummy so don't initialize it
if (is_running_on_desktop && is_root_domain)
return domain;
- load_assemblies (domain, env, assemblies);
- init_android_runtime (domain, env, loader);
- register_packages (domain, env, assemblies);
+ init_android_runtime (domain, env, runtimeClass, loader);
osBridge.add_monodroid_domain (domain);
@@ -1920,17 +1755,11 @@ create_and_initialize_domain (JNIEnv* env, jobjectArray runtimeApks, jobjectArra
}
JNIEXPORT void JNICALL
-Java_mono_android_Runtime_init (JNIEnv *env, jclass klass, jstring lang, jobjectArray runtimeApks, jstring runtimeNativeLibDir, jobjectArray appDirs, jobject loader, jobjectArray externalStorageDirs, jobjectArray assemblies, jstring packageName)
+Java_mono_android_Runtime_init (JNIEnv *env, jclass klass, jstring lang, jobjectArray runtimeApksJava,
+ jstring runtimeNativeLibDir, jobjectArray appDirs, jobject loader,
+ jobjectArray externalStorageDirs, jobjectArray assemblies, jstring packageName,
+ jint apiLevel, jobjectArray environmentVariables)
{
- char *runtime_args = NULL;
- char *connect_args;
- jstring libdir_s;
- const char *libdir, *esd;
- char *counters_path;
- const char *pkgName;
- char *aotMode;
- int i;
-
init_logging_categories ();
timing_period total_time;
@@ -1938,34 +1767,38 @@ Java_mono_android_Runtime_init (JNIEnv *env, jclass klass, jstring lang, jobject
total_time.mark_start ();
}
- android_api_level = GetAndroidSdkVersion (env, loader);
+ android_api_level = apiLevel;
- pkgName = env->GetStringUTFChars (packageName, NULL);
- utils.monodroid_store_package_name (pkgName); /* Will make a copy of the string */
- env->ReleaseStringUTFChars (packageName, pkgName);
+ TimeZone_class = utils.get_class_from_runtime_field (env, klass, "java_util_TimeZone", true);
- disable_external_signal_handlers ();
+ jstring_wrapper jstr (env, packageName);
+ utils.monodroid_store_package_name (jstr.get_cstr ());
+
+ jstr = lang;
+ set_environment_variable (env, "LANG", jstr);
+
+ androidSystem.setup_environment (env, environmentVariables);
- jstring homeDir = reinterpret_cast (env->GetObjectArrayElement (appDirs, 0));
- set_environment_variable (env, "LANG", lang);
- set_environment_variable_for_directory (env, "HOME", homeDir);
- set_environment_variable_for_directory (env, "TMPDIR", reinterpret_cast (env->GetObjectArrayElement (appDirs, 1)));
- create_xdg_directories_and_environment (env, homeDir);
+ jstr = reinterpret_cast (env->GetObjectArrayElement (appDirs, 1));
+ set_environment_variable_for_directory (env, "TMPDIR", jstr);
- androidSystem.setup_environment (env, runtimeApks);
+ jstr = reinterpret_cast (env->GetObjectArrayElement (appDirs, 0));
+ set_environment_variable_for_directory (env, "HOME", jstr);
+ create_xdg_directories_and_environment (env, jstr);
+ primary_override_dir = get_primary_override_dir (env, jstr);
- if (android_api_level < 23 || getenv ("__XA_DSO_IN_APK") == NULL) {
+ disable_external_signal_handlers ();
+
+ jstring_array_wrapper runtimeApks (env, runtimeApksJava);
+ if (android_api_level < 23 || !androidSystem.is_embedded_dso_mode_enabled ()) {
log_info (LOG_DEFAULT, "Setting up for DSO lookup in app data directories");
- libdir_s = reinterpret_cast (env->GetObjectArrayElement (appDirs, 2));
- libdir = env->GetStringUTFChars (libdir_s, NULL);
+ jstr = env->GetObjectArrayElement (appDirs, 2);
AndroidSystem::app_lib_directories_size = 1;
AndroidSystem::app_lib_directories = (const char**) xcalloc (AndroidSystem::app_lib_directories_size, sizeof(char*));
- AndroidSystem::app_lib_directories [0] = utils.monodroid_strdup_printf ("%s", libdir);
- env->ReleaseStringUTFChars (libdir_s, libdir);
+ AndroidSystem::app_lib_directories [0] = strdup (jstr.get_cstr ());
} else {
log_info (LOG_DEFAULT, "Setting up for DSO lookup directly in the APK");
- embedded_dso_mode = 1;
- AndroidSystem::app_lib_directories_size = env->GetArrayLength (runtimeApks);
+ AndroidSystem::app_lib_directories_size = runtimeApks.get_length ();
AndroidSystem::app_lib_directories = (const char**) xcalloc (AndroidSystem::app_lib_directories_size, sizeof(char*));
unsigned short built_for_cpu = 0, running_on_cpu = 0;
@@ -1974,16 +1807,13 @@ Java_mono_android_Runtime_init (JNIEnv *env, jclass klass, jstring lang, jobject
androidSystem.setup_apk_directories (env, running_on_cpu, runtimeApks);
}
- primary_override_dir = get_primary_override_dir (env, reinterpret_cast (env->GetObjectArrayElement (appDirs, 0)));
- esd = env->GetStringUTFChars (reinterpret_cast (env->GetObjectArrayElement (externalStorageDirs, 0)), NULL);
- external_override_dir = utils.monodroid_strdup_printf ("%s", esd);
- env->ReleaseStringUTFChars (reinterpret_cast (env->GetObjectArrayElement (externalStorageDirs, 0)), esd);
+ jstr = env->GetObjectArrayElement (externalStorageDirs, 0);
+ external_override_dir = strdup (jstr.get_cstr ());
- esd = env->GetStringUTFChars (reinterpret_cast (env->GetObjectArrayElement (externalStorageDirs, 1)), nullptr);
- external_legacy_override_dir = utils.monodroid_strdup_printf ("%s", esd);
- env->ReleaseStringUTFChars (reinterpret_cast (env->GetObjectArrayElement (externalStorageDirs, 1)), esd);
+ jstr = env->GetObjectArrayElement (externalStorageDirs, 1);
+ external_legacy_override_dir = strdup (jstr.get_cstr ());
- init_reference_logging(primary_override_dir);
+ init_reference_logging (primary_override_dir);
androidSystem.create_update_dir (primary_override_dir);
#if DEBUG
@@ -1994,7 +1824,7 @@ Java_mono_android_Runtime_init (JNIEnv *env, jclass klass, jstring lang, jobject
#ifndef RELEASE
androidSystem.set_override_dir (1, external_override_dir);
androidSystem.set_override_dir (2, external_legacy_override_dir);
- for (i = 0; i < AndroidSystem::MAX_OVERRIDES; ++i) {
+ for (uint32_t i = 0; i < AndroidSystem::MAX_OVERRIDES; ++i) {
const char *p = androidSystem.get_override_dir (i);
if (!utils.directory_exists (p))
continue;
@@ -2004,10 +1834,8 @@ Java_mono_android_Runtime_init (JNIEnv *env, jclass klass, jstring lang, jobject
setup_bundled_app ("libmonodroid_bundle_app.so");
if (runtimeNativeLibDir != NULL) {
- const char *rd;
- rd = env->GetStringUTFChars (runtimeNativeLibDir, NULL);
- runtime_libdir = utils.monodroid_strdup_printf ("%s", rd);
- env->ReleaseStringUTFChars (runtimeNativeLibDir, rd);
+ jstr = runtimeNativeLibDir;
+ runtime_libdir = strdup (jstr.get_cstr ());
log_warn (LOG_DEFAULT, "Using runtime path: %s", runtime_libdir);
}
@@ -2018,7 +1846,7 @@ Java_mono_android_Runtime_init (JNIEnv *env, jclass klass, jstring lang, jobject
* symbols against the Mono library we're loading.
*/
int sgen_dlopen_flags = RTLD_LAZY | RTLD_GLOBAL;
- if (embedded_dso_mode) {
+ if (androidSystem.is_embedded_dso_mode_enabled ()) {
libmonosgen_handle = androidSystem.load_dso_from_any_directories (AndroidSystem::MONO_SGEN_SO, sgen_dlopen_flags);
}
@@ -2030,13 +1858,11 @@ Java_mono_android_Runtime_init (JNIEnv *env, jclass klass, jstring lang, jobject
exit (FATAL_EXIT_CANNOT_FIND_MONO);
}
androidSystem.setup_process_args (env, runtimeApks);
-#ifndef WINDOWS
- _monodroid_getifaddrs_init ();
-#endif
- if ((log_categories & LOG_TIMING) != 0) {
+ if (XA_UNLIKELY (utils.should_log (LOG_TIMING))) {
monoFunctions.counters_enable (XA_LOG_COUNTERS);
- counters_path = utils.path_combine (androidSystem.get_override_dir (0), "counters.txt");
+ char *counters_path = utils.path_combine (androidSystem.get_override_dir (0), "counters.txt");
+ log_info_nocheck (LOG_TIMING, "counters path: %s", counters_path);
counters = utils.monodroid_fopen (counters_path, "a");
utils.set_world_accessable (counters_path);
free (counters_path);
@@ -2048,9 +1874,10 @@ Java_mono_android_Runtime_init (JNIEnv *env, jclass klass, jstring lang, jobject
set_trace_options ();
+#if defined (DEBUG) && !defined (WINDOWS)
+ char *connect_args;
utils.monodroid_get_namespaced_system_property (Debug::DEBUG_MONO_CONNECT_PROPERTY, &connect_args);
-#if defined (DEBUG) && !defined (WINDOWS)
if (connect_args) {
int res = debug.start_connection (connect_args);
if (res != 2) {
@@ -2072,44 +1899,48 @@ Java_mono_android_Runtime_init (JNIEnv *env, jclass klass, jstring lang, jobject
monoFunctions.config_parse_memory (reinterpret_cast (monodroid_config));
monoFunctions.register_machine_config (reinterpret_cast (monodroid_machine_config));
- log_info (LOG_DEFAULT, "Probing for mono.aot AOT mode\n");
-
- if (monodroid_get_system_property ("mono.aot", &aotMode) > 0) {
- MonoAotMode mode = static_cast (0);
- if (strcmp (aotMode, "normal") == 0)
- mode = MonoAotMode::MONO_AOT_MODE_NORMAL;
- else if (strcmp (aotMode, "hybrid") == 0)
- mode = MonoAotMode::MONO_AOT_MODE_HYBRID;
- else if (strcmp (aotMode, "full") == 0)
- mode = MonoAotMode::MONO_AOT_MODE_FULL;
- else
- log_warn (LOG_DEFAULT, "Unknown mono.aot property value: %s\n", aotMode);
-
- if (mode != MonoAotMode::MONO_AOT_MODE_NORMAL) {
- log_info (LOG_DEFAULT, "Enabling %s AOT mode in Mono\n", aotMode);
- monoFunctions.jit_set_aot_mode (mode);
- }
+ log_info (LOG_DEFAULT, "Probing for Mono AOT mode\n");
+
+ MonoAotMode mode = androidSystem.get_mono_aot_mode ();
+ if (mode == MonoAotMode::MONO_AOT_MODE_UNKNOWN)
+ mode = MonoAotMode::MONO_AOT_MODE_NONE;
+
+ if (mode != MonoAotMode::MONO_AOT_MODE_NORMAL && mode != MonoAotMode::MONO_AOT_MODE_NONE) {
+ log_info (LOG_DEFAULT, "Enabling AOT mode in Mono");
+ monoFunctions.jit_set_aot_mode (mode);
}
log_info (LOG_DEFAULT, "Probing if we should use LLVM\n");
- if (monodroid_get_system_property ("mono.llvm", NULL) > 0) {
+ if (androidSystem.is_mono_llvm_enabled ()) {
char *args [1];
args[0] = const_cast ("--llvm");
- log_info (LOG_DEFAULT, "Found mono.llvm property, enabling LLVM mode in Mono\n");
+ log_info (LOG_DEFAULT, "Enabling LLVM mode in Mono\n");
monoFunctions.jit_parse_options (1, args);
monoFunctions.set_use_llvm (true);
}
+ char *runtime_args = nullptr;
utils.monodroid_get_namespaced_system_property (Debug::DEBUG_MONO_EXTRA_PROPERTY, &runtime_args);
#if TRACE
__android_log_print (ANDROID_LOG_INFO, "*jonp*", "debug.mono.extra=%s", runtime_args);
#endif
+ timing_period partial_time;
+ if (XA_UNLIKELY (utils.should_log (LOG_TIMING)))
+ partial_time.mark_start ();
+
mono_runtime_init (runtime_args);
+ if (XA_UNLIKELY (utils.should_log (LOG_TIMING))) {
+ partial_time.mark_end ();
+
+ timing_diff diff (partial_time);
+ log_info_nocheck (LOG_TIMING, "Runtime.init: Mono runtime init; elapsed: %lis:%lu::%lu", diff.sec, diff.ms, diff.ns);
+ }
+
/* the first assembly is used to initialize the AppDomain name */
- create_and_initialize_domain (env, runtimeApks, assemblies, loader, /*is_root_domain:*/ 1);
+ create_and_initialize_domain (env, klass, runtimeApks, assemblies, loader, /*is_root_domain:*/ true);
free (runtime_args);
@@ -2123,7 +1954,7 @@ Java_mono_android_Runtime_init (JNIEnv *env, jclass klass, jstring lang, jobject
total_time.mark_end ();
timing_diff diff (total_time);
- log_info (LOG_TIMING, "Runtime.init: end, total time; elapsed: %lis.%03llu::%llu", diff.sec, diff.ms, diff.ns);
+ log_info_nocheck (LOG_TIMING, "Runtime.init: end, total time; elapsed: %lis:%lu::%lu", diff.sec, diff.ms, diff.ns);
_monodroid_counters_dump ("## Runtime.init: end");
}
}
@@ -2170,7 +2001,7 @@ JNICALL Java_mono_android_Runtime_register (JNIEnv *env, jclass klass, jstring m
total_time.mark_end ();
timing_diff diff (total_time);
- log_info (LOG_TIMING, "Runtime.register: end time; elapsed: %lis.%03llu::%llu", diff.sec, diff.ms, diff.ns);
+ log_info_nocheck (LOG_TIMING, "Runtime.register: end time; elapsed: %lis:%lu::%lu", diff.sec, diff.ms, diff.ns);
_monodroid_counters_dump ("## Runtime.register: type=%s\n", type);
}
@@ -2192,13 +2023,15 @@ reinitialize_android_runtime_type_manager (JNIEnv *env)
}
JNIEXPORT jint
-JNICALL Java_mono_android_Runtime_createNewContext (JNIEnv *env, jclass klass, jobjectArray runtimeApks, jobjectArray assemblies, jobject loader)
+JNICALL Java_mono_android_Runtime_createNewContext (JNIEnv *env, jclass klass, jobjectArray runtimeApksJava, jobjectArray assemblies, jobject loader)
{
log_info (LOG_DEFAULT, "CREATING NEW CONTEXT");
reinitialize_android_runtime_type_manager (env);
MonoDomain *root_domain = monoFunctions.get_root_domain ();
monoFunctions.jit_thread_attach (root_domain);
- MonoDomain *domain = create_and_initialize_domain (env, runtimeApks, assemblies, loader, /*is_root_domain:*/ 0);
+
+ jstring_array_wrapper runtimeApks (env, runtimeApksJava);
+ MonoDomain *domain = create_and_initialize_domain (env, klass, runtimeApks, assemblies, loader, /*is_root_domain:*/ false);
monoFunctions.domain_set (domain, FALSE);
int domain_id = monoFunctions.domain_get_id (domain);
current_context_id = domain_id;
diff --git a/src/monodroid/jni/monodroid.h b/src/monodroid/jni/monodroid.h
index c80f72408e1..5d44a06034f 100644
--- a/src/monodroid/jni/monodroid.h
+++ b/src/monodroid/jni/monodroid.h
@@ -25,7 +25,13 @@
#ifdef __cplusplus
#define MONO_API extern "C" MONO_API_DEF
#else
-#define MONO_API MONO_API_DEF
+
+/* Use our own definition, to stay consistent */
+#if defined (MONO_API)
+#undef MONO_API
#endif
+#define MONO_API MONO_API_DEF
+
+#endif /* __cplusplus */
#endif /* defined __MONODROID_H */
diff --git a/src/monodroid/jni/new_delete.cc b/src/monodroid/jni/new_delete.cc
new file mode 100644
index 00000000000..e7e68e24be8
--- /dev/null
+++ b/src/monodroid/jni/new_delete.cc
@@ -0,0 +1,79 @@
+#include
+#include
+
+extern "C" {
+#include "java-interop-util.h"
+}
+
+static void*
+do_alloc (size_t size)
+{
+ return ::malloc (size == 0 ? 1 : size);
+}
+
+void*
+operator new (size_t size)
+{
+ void* p = do_alloc (size);
+ if (p == nullptr) {
+ log_fatal (LOG_DEFAULT, "Out of memory in the `new` operator");
+ exit (FATAL_EXIT_OUT_OF_MEMORY);
+ }
+
+ return p;
+}
+
+void*
+operator new (size_t size, const std::nothrow_t&) noexcept
+{
+ return do_alloc (size);
+}
+
+void*
+operator new[] (size_t size)
+{
+ return ::operator new (size);
+}
+
+void*
+operator new[] (size_t size, const std::nothrow_t&) noexcept
+{
+ return do_alloc (size);
+}
+
+void
+operator delete (void* ptr) noexcept
+{
+ if (ptr)
+ ::free (ptr);
+}
+
+void
+operator delete (void* ptr, const std::nothrow_t&) noexcept
+{
+ ::operator delete (ptr);
+}
+
+void
+operator delete (void* ptr, size_t) noexcept
+{
+ ::operator delete (ptr);
+}
+
+void
+operator delete[] (void* ptr) noexcept
+{
+ ::operator delete (ptr);
+}
+
+void
+operator delete[] (void* ptr, const std::nothrow_t&) noexcept
+{
+ ::operator delete[] (ptr);
+}
+
+void
+operator delete[] (void* ptr, size_t) noexcept
+{
+ ::operator delete[] (ptr);
+}
diff --git a/src/monodroid/jni/osbridge.cc b/src/monodroid/jni/osbridge.cc
index 0530abbc8c6..4d13913de1a 100644
--- a/src/monodroid/jni/osbridge.cc
+++ b/src/monodroid/jni/osbridge.cc
@@ -1,5 +1,5 @@
-#include
-#include
+#include
+#include
#include
#if defined (LINUX) || defined (__linux__) || defined (__linux)
@@ -927,8 +927,10 @@ OSBridge::gc_cross_references (int num_sccs, MonoGCBridgeSCC **sccs, int num_xre
}
}
- for (i = 0; i < num_xrefs; ++i)
- log_info (LOG_GC, "xref [%d] %d -> %d", i, xrefs [i].src_scc_index, xrefs [i].dst_scc_index);
+ if (utils.should_log (LOG_GC)) {
+ for (i = 0; i < num_xrefs; ++i)
+ log_info_nocheck (LOG_GC, "xref [%d] %d -> %d", i, xrefs [i].src_scc_index, xrefs [i].dst_scc_index);
+ }
}
#endif
@@ -1062,10 +1064,10 @@ OSBridge::initialize_on_onload (JavaVM *vm, JNIEnv *env)
}
void
-OSBridge::initialize_on_runtime_init (JNIEnv *env)
+OSBridge::initialize_on_runtime_init (JNIEnv *env, jclass runtimeClass)
{
assert (env != nullptr);
- GCUserPeer_class = reinterpret_cast (lref_to_gref (env, env->FindClass ("mono/android/GCUserPeer")));
+ GCUserPeer_class = utils.get_class_from_runtime_field(env, runtimeClass, "mono_android_GCUserPeer", true);
GCUserPeer_ctor = env->GetMethodID (GCUserPeer_class, "", "()V");
assert ( (GCUserPeer_class && GCUserPeer_ctor) || !"Failed to load mono.android.GCUserPeer!" );
}
diff --git a/src/monodroid/jni/osbridge.h b/src/monodroid/jni/osbridge.h
index a7914b4fb3c..ef82970a72f 100644
--- a/src/monodroid/jni/osbridge.h
+++ b/src/monodroid/jni/osbridge.h
@@ -107,7 +107,7 @@ namespace xamarin { namespace android { namespace internal
int get_gref_gc_threshold ();
JNIEnv* ensure_jnienv ();
void initialize_on_onload (JavaVM *vm, JNIEnv *env);
- void initialize_on_runtime_init (JNIEnv *env);
+ void initialize_on_runtime_init (JNIEnv *env, jclass runtimeClass);
void add_monodroid_domain (MonoDomain *domain);
void remove_monodroid_domain (MonoDomain *domain);
void on_destroy_contexts ();
diff --git a/src/monodroid/jni/util.cc b/src/monodroid/jni/util.cc
index 36798593a5f..bee3add5faf 100644
--- a/src/monodroid/jni/util.cc
+++ b/src/monodroid/jni/util.cc
@@ -34,6 +34,8 @@ using timestruct = timespec;
using timestruct = timeval;
#endif
+static const char hex_chars [] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
void timing_point::mark ()
{
int ret;
@@ -246,14 +248,52 @@ Util::recv_uninterrupted (int fd, void *buf, int len)
return total;
}
+#if WINDOWS
+//
+// This version should be removed once MXE we have on mac can build the glorious version in the
+// #else below.
+//
+// Currently mxe fails with:
+//
+// Cannot export _ZN7xamarin7android4Util19package_hash_to_hexIiIEEEvjT_DpT0_: symbol wrong type (4 vs 3)
+// Cannot export _ZN7xamarin7android4Util19package_hash_to_hexIiIiEEEvjT_DpT0_: symbol wrong type (4 vs 3)
+// Cannot export _ZN7xamarin7android4Util19package_hash_to_hexIiIiiEEEvjT_DpT0_: symbol wrong type (4 vs 3)
+// Cannot export _ZN7xamarin7android4Util19package_hash_to_hexIiIiiiEEEvjT_DpT0_: symbol wrong type (4 vs 3)
+// Cannot export _ZN7xamarin7android4Util19package_hash_to_hexIiIiiiiEEEvjT_DpT0_: symbol wrong type (4 vs 3)
+// Cannot export _ZN7xamarin7android4Util19package_hash_to_hexIiIiiiiiEEEvjT_DpT0_: symbol wrong type (4 vs 3)
+// Cannot export _ZN7xamarin7android4Util19package_hash_to_hexIiIiiiiiiEEEvjT_DpT0_: symbol wrong type (4 vs 3)
+// Cannot export _ZN7xamarin7android4Util19package_hash_to_hexIiIiiiiiiiEEEvjT_DpT0_: symbol wrong type (4 vs 3)
+// collect2 : error : ld returned 1 exit status
+// [/Users/builder/jenkins/workspace/xamarin-android-pr-builder-debug/xamarin-android/src/monodroid/monodroid.csproj]
+//
+void Util::package_hash_to_hex (uint32_t hash)
+{
+ for (uint32_t idx = 0; idx < 8; idx++) {
+ package_property_suffix [idx] = hex_chars [(hash & (0xF0000000 >> idx * 4)) >> ((7 - idx) * 4)];
+ }
+ package_property_suffix[sizeof (package_property_suffix) / sizeof (char) - 1] = 0x00;
+}
+#else
+template
+inline void
+Util::package_hash_to_hex (IdxType /* idx */)
+{
+ package_property_suffix[sizeof (package_property_suffix) / sizeof (char) - 1] = 0x00;
+}
+
+template
+inline void
+Util::package_hash_to_hex (uint32_t hash, IdxType idx, Indices... indices)
+{
+ package_property_suffix [idx] = hex_chars [(hash & (0xF0000000 >> idx * 4)) >> ((7 - idx) * 4)];
+ package_hash_to_hex (hash, indices...);
+}
+#endif
+
void
Util::monodroid_store_package_name (const char *name)
{
- const char *ch;
- int hash;
-
- memset (package_property_suffix, 0, sizeof (package_property_suffix));
- if (!name || strlen (name) == 0)
+ if (!name || *name == '\0')
return;
/* Android properties can be at most 32 bytes long (!) and so we mustn't append the package name
@@ -262,11 +302,21 @@ Util::monodroid_store_package_name (const char *name)
* as a stream of bytes assumming it's an ASCII string using a simplified version of the hash
* algorithm used by BCL's String.GetHashCode ()
*/
- ch = name;
- hash = 0;
+ const char *ch = name;
+ uint32_t hash = 0;
while (*ch)
hash = (hash << 5) - (hash + *ch++);
- snprintf (package_property_suffix, sizeof (package_property_suffix), "%08x", hash);
+
+#if WINDOWS
+ package_hash_to_hex (hash);
+#else
+ // In C++14 or newer we could use std::index_sequence, but in C++11 it's a bit too much ado
+ // for this simple case, so a manual sequence it is.
+ //
+ // And yes, I know it could be done in a simple loop or in even simpler 8 lines of code, but
+ // that would be boring, wouldn't it? :)
+ package_hash_to_hex (hash, 0, 1, 2, 3, 4, 5, 6, 7);
+#endif
log_info (LOG_DEFAULT, "Generated hash 0x%s for package name %s", package_property_suffix, name);
}
@@ -283,13 +333,13 @@ Util::monodroid_get_namespaced_system_property (const char *name, char **value)
log_info (LOG_DEFAULT, "Trying to get property %s.%s", name, package_property_suffix);
char *propname = monodroid_strdup_printf ("%s.%s", name, package_property_suffix);
if (propname) {
- result = monodroid_get_system_property (propname, &local_value);
+ result = androidSystem.monodroid_get_system_property (propname, &local_value);
free (propname);
}
}
if (result <= 0 || !local_value)
- result = monodroid_get_system_property (name, &local_value);
+ result = androidSystem.monodroid_get_system_property (name, &local_value);
if (result > 0) {
if (strlen (local_value) == 0) {
@@ -642,6 +692,22 @@ Util::is_path_rooted (const char *path)
#endif
}
+jclass
+Util::get_class_from_runtime_field (JNIEnv *env, jclass runtime, const char *name, bool make_gref)
+{
+ static constexpr char java_lang_class_sig[] = "Ljava/lang/Class;";
+
+ jfieldID fieldID = env->GetStaticFieldID (runtime, name, java_lang_class_sig);
+ if (fieldID == nullptr)
+ return nullptr;
+
+ jobject field = env->GetStaticObjectField (runtime, fieldID);
+ if (field == nullptr)
+ return nullptr;
+
+ return reinterpret_cast (make_gref ? osBridge.lref_to_gref (env, field) : field);
+}
+
extern "C" void
monodroid_strfreev (char **str_array)
{
diff --git a/src/monodroid/jni/util.h b/src/monodroid/jni/util.h
index 2a82a2d7078..e6dbc1ca9b8 100644
--- a/src/monodroid/jni/util.h
+++ b/src/monodroid/jni/util.h
@@ -43,9 +43,11 @@ typedef struct dirent monodroid_dirent_t;
#include
#include
#include
+#include
#include "monodroid.h"
#include "dylib-mono.h"
+#include "jni-wrappers.h"
#ifdef __cplusplus
extern "C" {
@@ -83,8 +85,8 @@ namespace xamarin { namespace android
{
struct timing_point
{
- time_t sec = 0;
- uint64_t ns = 0;
+ time_t sec;
+ uint64_t ns;
void mark ();
};
@@ -118,10 +120,12 @@ namespace xamarin { namespace android
class Util
{
- public:
- explicit Util ()
- : package_property_suffix {0}
- {}
+#if defined (ANDROID) || defined (LINUX)
+ using timestruct = timespec;
+#else
+ using timestruct = timeval;
+#endif
+ static constexpr uint32_t ms_in_nsec = 1000000ULL;
public:
FILE *monodroid_fopen (const char* filename, const char* mode);
@@ -151,6 +155,8 @@ namespace xamarin { namespace android
bool file_exists (const char *file);
bool directory_exists (const char *directory);
bool file_copy (const char *to, const char *from);
+ jclass get_class_from_runtime_field (JNIEnv *env, jclass runtime, const char *name, bool make_gref = false);
+
#ifdef WINDOWS
/* Those two conversion functions are only properly implemented on Windows
* because that's the only place where they should be useful.
@@ -192,6 +198,16 @@ namespace xamarin { namespace android
void add_to_vector (char ***vector, int size, char *token);
void monodroid_property_set (MonoDomain *domain, MonoProperty *property, void *obj, void **params, MonoObject **exc);
+#if WINDOWS
+ void package_hash_to_hex (uint32_t hash);
+#else
+ template
+ void package_hash_to_hex (IdxType idx);
+
+ template
+ void package_hash_to_hex (uint32_t hash, IdxType idx, Indices... indices);
+#endif
+
int make_directory (const char *path, int mode)
{
#if WINDOWS
diff --git a/src/monodroid/jni/xamarin_getifaddrs.cc b/src/monodroid/jni/xamarin_getifaddrs.cc
index 684f67ad882..66e349b2696 100644
--- a/src/monodroid/jni/xamarin_getifaddrs.cc
+++ b/src/monodroid/jni/xamarin_getifaddrs.cc
@@ -26,6 +26,7 @@ extern "C" {
#include "logger.h"
}
+#include "globals.h"
#include "xamarin_getifaddrs.h"
/* Some of these aren't defined in android's rtnetlink.h (as of ndk 16). We define values for all of
@@ -269,6 +270,8 @@ typedef void (*freeifaddrs_impl_fptr)(struct _monodroid_ifaddrs *ifa);
static getifaddrs_impl_fptr getifaddrs_impl = NULL;
static freeifaddrs_impl_fptr freeifaddrs_impl = NULL;
+static bool initialized;
+static std::mutex init_lock;
void
_monodroid_getifaddrs_init ()
@@ -279,6 +282,14 @@ _monodroid_getifaddrs_init ()
int
_monodroid_getifaddrs (struct _monodroid_ifaddrs **ifap)
{
+ if (!initialized) {
+ std::lock_guard lock (init_lock);
+ if (!initialized) {
+ _monodroid_getifaddrs_init ();
+ initialized = true;
+ }
+ }
+
int ret = -1;
if (getifaddrs_impl)
@@ -361,10 +372,11 @@ get_ifaddrs_impl (int (**getifaddrs_impl) (struct _monodroid_ifaddrs **ifap), vo
*freeifaddrs_impl = reinterpret_cast (dlsym (libc, "freeifaddrs"));
}
- if (!*getifaddrs_impl)
+ if (!*getifaddrs_impl) {
log_info (LOG_NET, "This libc does not have getifaddrs/freeifaddrs, using Xamarin's\n");
- else
+ } else {
log_info (LOG_NET, "This libc has getifaddrs/freeifaddrs\n");
+ }
}
static void
@@ -540,20 +552,22 @@ parse_netlink_reply (netlink_session *session, struct _monodroid_ifaddrs **ifadd
}
#if DEBUG
- log_debug (LOG_NETLINK, "response flags:");
- if (netlink_reply.msg_flags == 0)
- log_debug (LOG_NETLINK, " [NONE]");
- else {
- if (netlink_reply.msg_flags & MSG_EOR)
- log_debug (LOG_NETLINK, " MSG_EOR");
- if (netlink_reply.msg_flags & MSG_TRUNC)
- log_debug (LOG_NETLINK, " MSG_TRUNC");
- if (netlink_reply.msg_flags & MSG_CTRUNC)
- log_debug (LOG_NETLINK, " MSG_CTRUNC");
- if (netlink_reply.msg_flags & MSG_OOB)
- log_debug (LOG_NETLINK, " MSG_OOB");
- if (netlink_reply.msg_flags & MSG_ERRQUEUE)
- log_debug (LOG_NETLINK, " MSG_ERRQUEUE");
+ if (utils.should_log (LOG_NETLINK)) {
+ log_debug_nocheck (LOG_NETLINK, "response flags:");
+ if (netlink_reply.msg_flags == 0)
+ log_debug_nocheck (LOG_NETLINK, " [NONE]");
+ else {
+ if (netlink_reply.msg_flags & MSG_EOR)
+ log_debug_nocheck (LOG_NETLINK, " MSG_EOR");
+ if (netlink_reply.msg_flags & MSG_TRUNC)
+ log_debug_nocheck (LOG_NETLINK, " MSG_TRUNC");
+ if (netlink_reply.msg_flags & MSG_CTRUNC)
+ log_debug_nocheck (LOG_NETLINK, " MSG_CTRUNC");
+ if (netlink_reply.msg_flags & MSG_OOB)
+ log_debug_nocheck (LOG_NETLINK, " MSG_OOB");
+ if (netlink_reply.msg_flags & MSG_ERRQUEUE)
+ log_debug_nocheck (LOG_NETLINK, " MSG_ERRQUEUE");
+ }
}
#endif
@@ -784,11 +798,13 @@ calculate_address_netmask (struct _monodroid_ifaddrs *ifa, struct ifaddrmsg *net
if (prefix_bytes + 2 < data_length)
/* Set the rest of the mask bits in the byte following the last 0xFF value */
netmask_data [prefix_bytes + 1] = 0xff << (8 - (prefix_length % 8));
- log_debug (LOG_NETLINK, " netmask is: ");
- for (i = 0; i < data_length; i++) {
- log_debug (LOG_NETLINK, "%s%u", i == 0 ? " " : ".", (unsigned char)ifa->ifa_netmask->sa_data [i]);
+ if (utils.should_log (LOG_NETLINK)) {
+ log_debug_nocheck (LOG_NETLINK, " netmask is: ");
+ for (i = 0; i < data_length; i++) {
+ log_debug_nocheck (LOG_NETLINK, "%s%u", i == 0 ? " " : ".", (unsigned char)ifa->ifa_netmask->sa_data [i]);
+ }
+ log_debug_nocheck (LOG_NETLINK, "\n");
}
- log_debug (LOG_NETLINK, "\n");
}
}
@@ -975,8 +991,10 @@ get_link_info (const struct nlmsghdr *message)
if (!ifa->ifa_name) {
goto error;
}
- log_debug (LOG_NETLINK, " interface name (payload length: %d; string length: %d)\n", RTA_PAYLOAD (attribute), strlen (ifa->ifa_name));
- log_debug (LOG_NETLINK, " %s\n", ifa->ifa_name);
+ if (utils.should_log (LOG_NETLINK)) {
+ log_debug_nocheck (LOG_NETLINK, " interface name (payload length: %d; string length: %d)\n", RTA_PAYLOAD (attribute), strlen (ifa->ifa_name));
+ log_debug_nocheck (LOG_NETLINK, " %s\n", ifa->ifa_name);
+ }
break;
case IFLA_BROADCAST:
@@ -1094,10 +1112,13 @@ struct enumvalue iflas[] = {
static void
print_ifla_name (int id)
{
+ if (!utils.should_log (LOG_NETLINK))
+ return;
+
int i = 0;
while (1) {
if (iflas [i].value == -1 && iflas [i].name == 0) {
- log_info (LOG_NETLINK, "Unknown ifla->name: unknown id %d\n", id);
+ log_info_nocheck (LOG_NETLINK, "Unknown ifla->name: unknown id %d\n", id);
break;
}
@@ -1105,7 +1126,7 @@ print_ifla_name (int id)
i++;
continue;
}
- log_info (LOG_NETLINK, "ifla->name: %s (%d)\n", iflas [i].name, iflas [i].value);
+ log_info_nocheck (LOG_NETLINK, "ifla->name: %s (%d)\n", iflas [i].name, iflas [i].value);
break;
}
}
@@ -1113,11 +1134,14 @@ print_ifla_name (int id)
static void
print_address_list (const char title[], struct _monodroid_ifaddrs *list)
{
+ if (!utils.should_log (LOG_NETLINK))
+ return;
+
struct _monodroid_ifaddrs *cur;
char *msg, *tmp;
if (!list) {
- log_info (LOG_NETLINK, "monodroid-net", "No list to print in %s", __FUNCTION__);
+ log_info_nocheck (LOG_NETLINK, "monodroid-net", "No list to print in %s", __FUNCTION__);
return;
}
@@ -1132,7 +1156,7 @@ print_address_list (const char title[], struct _monodroid_ifaddrs *list)
cur = cur->ifa_next;
}
- log_info (LOG_NETLINK, "%s: %s", title, msg ? msg : "[no addresses]");
+ log_info_nocheck (LOG_NETLINK, "%s: %s", title, msg ? msg : "[no addresses]");
free (msg);
}
#endif
diff --git a/src/monodroid/monodroid.targets b/src/monodroid/monodroid.targets
index 366b643152e..484f5a3a1a0 100644
--- a/src/monodroid/monodroid.targets
+++ b/src/monodroid/monodroid.targets
@@ -26,7 +26,7 @@