Skip to content

Commit 984f648

Browse files
authored
[sdks] Use runtime logging features to intercept Console.{Out,Error} and runtime logs for instrumentation (mono#6083)
* [sdks] Fix Android pick of mono runtime * [android] Have Console.{Out,Error} go through the runtime log mechanism to ease their interception * [sdks] Intercept runtime logs instead of Console to send back for instrumentation * [sdks] Intercept Android test runner logging
1 parent 20de418 commit 984f648

File tree

6 files changed

+122
-114
lines changed

6 files changed

+122
-114
lines changed

mcs/class/corlib/System.IO/LogcatTextWriter.cs

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System;
44
using System.IO;
55
using System.Text;
6+
using System.Runtime.CompilerServices;
67
using System.Runtime.InteropServices;
78

89
namespace System.IO {
@@ -12,13 +13,14 @@ class LogcatTextWriter : TextWriter {
1213
const string LibLog = "/system/lib/liblog.so";
1314
const string LibLog64 = "/system/lib64/liblog.so";
1415

16+
readonly byte[] appname;
17+
1518
TextWriter stdout;
16-
readonly string appname;
1719
StringBuilder line = new StringBuilder ();
1820

1921
public LogcatTextWriter (string appname, TextWriter stdout)
2022
{
21-
this.appname = appname;
23+
this.appname = Encoding.UTF8.GetBytes (appname);
2224
this.stdout = stdout;
2325
}
2426

@@ -46,34 +48,22 @@ public override void WriteLine ()
4648
var o = line.ToString ();
4749
line.Clear ();
4850

49-
Log (LogLevel.Info, appname, o);
51+
unsafe {
52+
fixed (byte *b_appname = appname)
53+
fixed (byte *b_message = Encoding.UTF8.GetBytes(o)) {
54+
Log (b_appname, 1 << 5 /* G_LOG_LEVEL_MESSAGE */, b_message);
55+
}
56+
}
5057
stdout.WriteLine (o);
5158
}
5259

53-
enum LogLevel {
54-
Unknown,
55-
Default,
56-
Verbose,
57-
Debug,
58-
Info,
59-
Warn,
60-
Error,
61-
Fatal,
62-
Silent
63-
}
64-
6560
public static bool IsRunningOnAndroid ()
6661
{
6762
return File.Exists (LibLog) || File.Exists (LibLog64);
6863
}
6964

70-
[DllImport ("liblog")]
71-
static extern void __android_log_print (LogLevel level, string appname, string format, string args, IntPtr zero);
72-
73-
static void Log (LogLevel level, string appname, string log)
74-
{
75-
__android_log_print (level, appname, "%s", log, IntPtr.Zero);
76-
}
65+
[MethodImpl(MethodImplOptions.InternalCall)]
66+
static unsafe extern void Log (byte *appname, int level, byte *message);
7767
}
7868
}
7969

mono/metadata/icall-def.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,9 @@ ICALL(INOW_3, "RemoveWatch", ves_icall_System_IO_InotifyWatcher_RemoveWatch)
346346
ICALL_TYPE(KQUEM, "System.IO.KqueueMonitor", KQUEM_1)
347347
ICALL(KQUEM_1, "kevent_notimeout", ves_icall_System_IO_KqueueMonitor_kevent_notimeout)
348348

349+
ICALL_TYPE(LOGCATEXTWRITER, "System.IO.LogcatTextWriter", LOGCATEXTWRITER_1)
350+
HANDLES(ICALL(LOGCATEXTWRITER_1, "Log", ves_icall_System_IO_LogcatTextWriter_Log))
351+
349352
ICALL_TYPE(MMAPIMPL, "System.IO.MemoryMappedFiles.MemoryMapImpl", MMAPIMPL_1)
350353
ICALL(MMAPIMPL_1, "CloseMapping", mono_mmap_close)
351354
ICALL(MMAPIMPL_2, "ConfigureHandleInheritability", mono_mmap_configure_inheritability)

mono/metadata/icall.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7898,6 +7898,11 @@ ves_icall_System_Runtime_InteropServices_WindowsRuntime_UnsafeNativeMethods_Wind
78987898

78997899
#endif
79007900

7901+
ICALL_EXPORT void
7902+
ves_icall_System_IO_LogcatTextWriter_Log (const char *appname, gint32 level, const char *message)
7903+
{
7904+
g_log (appname, (GLogLevelFlags)level, message);
7905+
}
79017906

79027907
#ifndef DISABLE_ICALL_TABLES
79037908

mono/utils/mono-logger-internals.h

Lines changed: 14 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -12,34 +12,24 @@
1212
G_BEGIN_DECLS
1313

1414
typedef enum {
15-
MONO_TRACE_ASSEMBLY = (1<<0),
16-
MONO_TRACE_TYPE = (1<<1),
17-
MONO_TRACE_DLLIMPORT = (1<<2),
18-
MONO_TRACE_GC = (1<<3),
19-
MONO_TRACE_CONFIG = (1<<4),
20-
MONO_TRACE_AOT = (1<<5),
21-
MONO_TRACE_SECURITY = (1<<6),
22-
MONO_TRACE_THREADPOOL = (1<<7),
23-
MONO_TRACE_IO_THREADPOOL = (1<<8),
24-
MONO_TRACE_IO_LAYER = (1<<9),
25-
MONO_TRACE_W32HANDLE = (1<<10),
26-
MONO_TRACE_ALL = MONO_TRACE_ASSEMBLY |
27-
MONO_TRACE_TYPE |
28-
MONO_TRACE_DLLIMPORT |
29-
MONO_TRACE_GC |
30-
MONO_TRACE_CONFIG |
31-
MONO_TRACE_AOT |
32-
MONO_TRACE_SECURITY |
33-
MONO_TRACE_THREADPOOL |
34-
MONO_TRACE_IO_THREADPOOL |
35-
MONO_TRACE_IO_LAYER |
36-
MONO_TRACE_W32HANDLE
15+
MONO_TRACE_ASSEMBLY = (gint32)(1 << 0),
16+
MONO_TRACE_TYPE = (gint32)(1 << 1),
17+
MONO_TRACE_DLLIMPORT = (gint32)(1 << 2),
18+
MONO_TRACE_GC = (gint32)(1 << 3),
19+
MONO_TRACE_CONFIG = (gint32)(1 << 4),
20+
MONO_TRACE_AOT = (gint32)(1 << 5),
21+
MONO_TRACE_SECURITY = (gint32)(1 << 6),
22+
MONO_TRACE_THREADPOOL = (gint32)(1 << 7),
23+
MONO_TRACE_IO_THREADPOOL = (gint32)(1 << 8),
24+
MONO_TRACE_IO_LAYER = (gint32)(1 << 9),
25+
MONO_TRACE_W32HANDLE = (gint32)(1 << 10),
26+
MONO_TRACE_ALL = ~(gint32)(0)
3727
} MonoTraceMask;
3828

3929
MONO_API extern GLogLevelFlags mono_internal_current_level;
4030
MONO_API extern MonoTraceMask mono_internal_current_mask;
4131

42-
void
32+
MONO_API void
4333
mono_trace_init (void);
4434

4535
void
@@ -163,7 +153,7 @@ typedef void (*MonoLoggerOpen) (const char *, void *);
163153
typedef void (*MonoLoggerWrite) (const char *, GLogLevelFlags, mono_bool, const char *);
164154
typedef void (*MonoLoggerClose) (void);
165155

166-
typedef struct _MonoLogCallParm_ {
156+
typedef struct {
167157
MonoLoggerOpen opener; /* Routine to open logging */
168158
MonoLoggerWrite writer; /* Routine to write log data */
169159
MonoLoggerClose closer; /* Routine to close logging */

sdks/android/jni/runtime-bootstrap.c

Lines changed: 88 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ typedef struct MonoImage_ MonoImage;
6262
typedef struct MonoObject_ MonoObject;
6363
typedef struct MonoThread_ MonoThread;
6464

65+
/* Imported from `mono-logger.h` */
66+
typedef void (*MonoLogCallback) (const char *log_domain, const char *log_level, const char *message, int32_t fatal, void *user_data);
67+
6568
/*
6669
* The "err" variable contents must be allocated using g_malloc or g_strdup
6770
*/
@@ -93,6 +96,8 @@ typedef void (*mono_domain_set_config_fn) (MonoDomain *, const char *, const cha
9396
typedef int (*mono_runtime_set_main_args_fn) (int argc, char* argv[]);
9497
typedef MonoMethod* (*mono_class_get_methods_fn) (MonoClass* klass, void **iter);
9598
typedef const char* (*mono_method_get_name_fn) (MonoMethod *method);
99+
typedef void (*mono_trace_init_fn) (void);
100+
typedef void (*mono_trace_set_log_handler_fn) (MonoLogCallback callback, void *user_data);
96101

97102
static JavaVM *jvm;
98103

@@ -119,6 +124,8 @@ static mono_domain_set_config_fn mono_domain_set_config;
119124
static mono_runtime_set_main_args_fn mono_runtime_set_main_args;
120125
static mono_class_get_methods_fn mono_class_get_methods;
121126
static mono_method_get_name_fn mono_method_get_name;
127+
static mono_trace_init_fn mono_trace_init;
128+
static mono_trace_set_log_handler_fn mono_trace_set_log_handler;
122129

123130
static MonoAssembly *main_assembly;
124131
static void *runtime_bootstrap_dso;
@@ -131,13 +138,82 @@ static void* my_dlopen (const char *name, int flags, char **err, void *user_data
131138

132139

133140
//stuff
141+
142+
static void
143+
_runtime_log (const char *log_domain, const char *log_level, const char *message, int32_t fatal, void *user_data)
144+
{
145+
static jclass AndroidRunner_klass = NULL;
146+
static jmethodID AndroidRunner_WriteLineToInstrumentation_method = NULL;
147+
JNIEnv *env;
148+
jstring j_message;
149+
150+
if (jvm == NULL)
151+
__android_log_assert ("", "mono-sdks", "%s: jvm is NULL", __func__);
152+
153+
(*jvm)->GetEnv (jvm, (void**)&env, JNI_VERSION_1_6);
154+
155+
if (AndroidRunner_klass == NULL || AndroidRunner_WriteLineToInstrumentation_method == NULL) {
156+
AndroidRunner_klass = (*env)->FindClass (env, "org/mono/android/AndroidRunner");
157+
AndroidRunner_WriteLineToInstrumentation_method = (*env)->GetStaticMethodID (env, AndroidRunner_klass, "WriteLineToInstrumentation", "(Ljava/lang/String;)V");
158+
}
159+
160+
j_message = (*env)->NewStringUTF(env, message);
161+
162+
(*env)->CallStaticVoidMethod (env, AndroidRunner_klass, AndroidRunner_WriteLineToInstrumentation_method, j_message);
163+
164+
(*env)->DeleteLocalRef (env, j_message);
165+
166+
/* Still print it on the logcat */
167+
168+
android_LogPriority android_log_level;
169+
switch (*log_level) {
170+
case 'e': /* error */
171+
android_log_level = ANDROID_LOG_FATAL;
172+
break;
173+
case 'c': /* critical */
174+
android_log_level = ANDROID_LOG_ERROR;
175+
break;
176+
case 'w': /* warning */
177+
android_log_level = ANDROID_LOG_WARN;
178+
break;
179+
case 'm': /* message */
180+
android_log_level = ANDROID_LOG_INFO;
181+
break;
182+
case 'i': /* info */
183+
android_log_level = ANDROID_LOG_DEBUG;
184+
break;
185+
case 'd': /* debug */
186+
android_log_level = ANDROID_LOG_VERBOSE;
187+
break;
188+
default:
189+
android_log_level = ANDROID_LOG_UNKNOWN;
190+
break;
191+
}
192+
193+
__android_log_write (android_log_level, log_domain, message);
194+
if (android_log_level == ANDROID_LOG_FATAL)
195+
abort ();
196+
}
197+
134198
static void
135199
_log (const char *format, ...)
136200
{
137201
va_list args;
202+
char *buf;
203+
int nbuf;
204+
205+
errno = 0;
206+
138207
va_start (args, format);
139-
__android_log_vprint (ANDROID_LOG_INFO, "MONO", format, args);
208+
nbuf = vasprintf (&buf, format, args);
140209
va_end (args);
210+
211+
if (buf == NULL || nbuf == -1)
212+
__android_log_assert ("", "mono-sdks", "%s: vasprintf failed, error: \"%s\" (%d), nbuf = %d, buf = \"%s\"", __func__, strerror(errno), errno, nbuf, buf ? buf : "(null)");
213+
214+
_runtime_log ("mono-sdks", "debug", buf, 0, NULL);
215+
216+
free (buf);
141217
}
142218

143219
static void
@@ -243,10 +319,10 @@ Java_org_mono_android_AndroidRunner_runTests (JNIEnv* env, jobject thiz, jstring
243319
strncpy_str (env, data_dir, j_data_dir, sizeof(data_dir));
244320
strncpy_str (env, assemblies_dir, j_assembly_dir, sizeof(assemblies_dir));
245321

246-
_log ("-- file dir %s\n", file_dir);
247-
_log ("-- cache dir %s\n", cache_dir);
248-
_log ("-- data dir %s\n", data_dir);
249-
_log ("-- assembly dir %s\n", assemblies_dir);
322+
_log ("-- file dir %s", file_dir);
323+
_log ("-- cache dir %s", cache_dir);
324+
_log ("-- data dir %s", data_dir);
325+
_log ("-- assembly dir %s", assemblies_dir);
250326
prctl (PR_SET_DUMPABLE, 1);
251327

252328
snprintf (buff, sizeof(buff), "%s/libmonosgen-2.0.so", data_dir);
@@ -279,6 +355,8 @@ Java_org_mono_android_AndroidRunner_runTests (JNIEnv* env, jobject thiz, jstring
279355
mono_runtime_set_main_args = dlsym (libmono, "mono_runtime_set_main_args");
280356
mono_class_get_methods = dlsym (libmono, "mono_class_get_methods");
281357
mono_method_get_name = dlsym (libmono, "mono_method_get_name");
358+
mono_trace_init = dlsym (libmono, "mono_trace_init");
359+
mono_trace_set_log_handler = dlsym (libmono, "mono_trace_set_log_handler");
282360

283361
//MUST HAVE envs
284362
setenv ("TMPDIR", cache_dir, 1);
@@ -290,9 +368,13 @@ Java_org_mono_android_AndroidRunner_runTests (JNIEnv* env, jobject thiz, jstring
290368
create_and_set (file_dir, "home/.config", "XDG_CONFIG_HOME");
291369

292370
//Debug flags
293-
// setenv ("MONO_LOG_LEVEL", "debug", 1);
371+
setenv ("MONO_LOG_LEVEL", "info", 1);
372+
setenv ("MONO_LOG_MASK", "all", 1);
294373
// setenv ("MONO_VERBOSE_METHOD", "GetCallingAssembly", 1);
295374

375+
mono_trace_init ();
376+
mono_trace_set_log_handler (_runtime_log, NULL);
377+
296378
mono_set_assemblies_path (assemblies_dir);
297379
mono_set_crash_chaining (1);
298380
mono_set_signal_chaining (1);
@@ -558,24 +640,6 @@ _monodroid_get_dns_servers (void **dns_servers_array)
558640
return count;
559641
}
560642

561-
MONO_API void
562-
AndroidIntrumentationWriter_WriteLineToInstrumentation (char *chars)
563-
{
564-
JNIEnv *env;
565-
jclass AndroidRunner_klass;
566-
jmethodID AndroidRunner_WriteLineToInstrumentation_method;
567-
jstring j_chars;
568-
569-
(*jvm)->GetEnv (jvm, (void**)&env, JNI_VERSION_1_6);
570-
571-
AndroidRunner_klass = (*env)->FindClass (env, "org/mono/android/AndroidRunner");
572-
AndroidRunner_WriteLineToInstrumentation_method = (*env)->GetStaticMethodID (env, AndroidRunner_klass, "WriteLineToInstrumentation", "(Ljava/lang/String;)V");
573-
574-
j_chars = (*env)->NewStringUTF(env, chars);
575-
576-
(*env)->CallStaticVoidMethod (env, AndroidRunner_klass, AndroidRunner_WriteLineToInstrumentation_method, j_chars);
577-
}
578-
579643
JNIEXPORT jint JNICALL
580644
JNI_OnLoad (JavaVM *vm, void *reserved)
581645
{

sdks/android/managed/main.cs

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,6 @@ public class Driver
1414

1515
public static void RunTests ()
1616
{
17-
Console.SetOut (TextWriter.Synchronized (new AndroidIntrumentationWriter (Console.Out)));
18-
Console.SetError (TextWriter.Synchronized (new AndroidIntrumentationWriter (Console.Error)));
19-
2017
string assembly = File.ReadAllText ($"{AppDomain.CurrentDomain.BaseDirectory}/testassembly.txt");
2118

2219
Console.WriteLine ($"Testing assembly \"{assembly}\"");
@@ -40,45 +37,4 @@ public static void Main ()
4037
{
4138
Environment.Exit (1);
4239
}
43-
44-
class AndroidIntrumentationWriter : TextWriter
45-
{
46-
readonly StringBuilder Line = new StringBuilder ();
47-
48-
readonly TextWriter Inner;
49-
50-
public override Encoding Encoding => Inner.Encoding;
51-
52-
public AndroidIntrumentationWriter (TextWriter inner)
53-
{
54-
Inner = inner;
55-
}
56-
57-
public override void Write(char value)
58-
{
59-
if (value == '\n')
60-
WriteLine ();
61-
else
62-
Line.Append (value);
63-
}
64-
65-
public override void WriteLine ()
66-
{
67-
var l = Line.ToString ();
68-
Line.Clear ();
69-
70-
unsafe
71-
{
72-
fixed (byte *chars = Encoding.UTF8.GetBytes (l + '\0'))
73-
{
74-
WriteLineToInstrumentation (chars);
75-
}
76-
}
77-
78-
Inner.WriteLine (l);
79-
}
80-
81-
[DllImport ("__Internal", EntryPoint = "AndroidIntrumentationWriter_WriteLineToInstrumentation", CharSet = CharSet.Unicode)]
82-
static unsafe extern void WriteLineToInstrumentation (byte *chars);
83-
}
8440
}

0 commit comments

Comments
 (0)