Skip to content

Commit 2925015

Browse files
mdh1418jonathanpeppers
authored andcommitted
[monodroid, java-runtime] Add local date time offset monovm prop (#7331)
Context: dotnet/runtime#74459 Context: dotnet/runtime#71004 Context: dotnet/runtime#54845 dotnet/runtime#54845 added support TimeZoneInfo support for Android. This was found to slow down initial use of `DateTimeOffset.Now` by ~277ms (dotnet/runtime#17004). dotnet/runtime#74459 started reducing this startup overhead by adding support for a new `System.TimeZoneInfo.LocalDateTimeOffset` property on `AppContext`: if `System.TimeZoneInfo.LocalDateTimeOffset` is set, it is used as the initial local DateTime Offset value. Update `mono.android.MonoPackageManager.LoadApplication()` and `libmono-android*.so` so that the `System.TimeZoneInfo.LocalDateTimeOffset` AppContext property is set during process startup. This can reduce `DateTimeOffset.Now` startup overhead from ~277ms to ~50ms. Note: `System.TimeZoneInfo.LocalDateTimeOffset` is fastest on API-26+ (Android 8.0+) targets, as it uses [`java.time.ZoneOffset.getTotalSeconds()`][0]. Note: `$(AndroidJavaRuntimeApiLevel)` is updated to API-26 so that `ZoneOffset.getTotalSeconds()` can be used. Care should be taken within `src/java-runtime` to ensure that Android API use is appropriately protected behind runtime version checks. [0]: https://developer.android.com/reference/kotlin/java/time/ZoneOffset#gettotalseconds
1 parent 0515d1d commit 2925015

File tree

8 files changed

+35
-11
lines changed

8 files changed

+35
-11
lines changed

Configuration.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
<!-- Should correspond to the first value from `$(API_LEVELS)` in `build-tools/api-xml-adjuster/Makefile` -->
2626
<AndroidFirstFrameworkVersion Condition="'$(AndroidFirstFrameworkVersion)' == ''">v4.4</AndroidFirstFrameworkVersion>
2727
<AndroidFirstApiLevel Condition="'$(AndroidFirstApiLevel)' == ''">19</AndroidFirstApiLevel>
28-
<AndroidJavaRuntimeApiLevel Condition="'$(AndroidJavaRuntimeApiLevel)' == ''">21</AndroidJavaRuntimeApiLevel>
28+
<AndroidJavaRuntimeApiLevel Condition="'$(AndroidJavaRuntimeApiLevel)' == ''">26</AndroidJavaRuntimeApiLevel>
2929
<!-- The min API level supported by Microsoft.Android.Sdk, should refactor/remove when this value is the same as $(AndroidFirstApiLevel) -->
3030
<AndroidMinimumDotNetApiLevel Condition="'$(AndroidMinimumDotNetApiLevel)' == ''">21</AndroidMinimumDotNetApiLevel>
3131
<AndroidFirstPlatformId Condition="'$(AndroidFirstPlatformId)' == ''">$(AndroidFirstApiLevel)</AndroidFirstPlatformId>

src/java-runtime/java/mono/android/MonoPackageManager.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
import java.io.*;
44
import java.lang.String;
5+
import java.time.OffsetDateTime;
6+
import java.time.ZoneOffset;
7+
import java.util.Calendar;
58
import java.util.Locale;
69
import java.util.HashSet;
710
import java.util.zip.*;
@@ -42,6 +45,14 @@ public static void LoadApplication (Context context, ApplicationInfo runtimePack
4245
String dataDir = getNativeLibraryPath (context);
4346
ClassLoader loader = context.getClassLoader ();
4447
String runtimeDir = getNativeLibraryPath (runtimePackage);
48+
int localDateTimeOffset;
49+
50+
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
51+
localDateTimeOffset = OffsetDateTime.now().getOffset().getTotalSeconds();
52+
}
53+
else {
54+
localDateTimeOffset = (Calendar.getInstance ().get (Calendar.ZONE_OFFSET) + Calendar.getInstance ().get (Calendar.DST_OFFSET)) / 1000;
55+
}
4556

4657
//
4758
// Should the order change here, src/monodroid/jni/SharedConstants.hh must be updated accordingly
@@ -106,6 +117,7 @@ public static void LoadApplication (Context context, ApplicationInfo runtimePack
106117
apks,
107118
runtimeDir,
108119
appDirs,
120+
localDateTimeOffset,
109121
loader,
110122
MonoPackageManager_Resources.Assemblies,
111123
Build.VERSION.SDK_INT,

src/java-runtime/java/mono/android/Runtime.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ public static native void initInternal (
2020
String[] runtimeApks,
2121
String runtimeDataDir,
2222
String[] appDirs,
23+
int localDateTimeOffset,
2324
ClassLoader loader,
2425
String[] assemblies,
2526
int apiLevel,

src/monodroid/jni/mono_android_Runtime.h

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/monodroid/jni/monodroid-glue-internal.hh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,8 +174,8 @@ namespace xamarin::android::internal
174174
public:
175175
void Java_mono_android_Runtime_register (JNIEnv *env, jstring managedType, jclass nativeClass, jstring methods);
176176
void Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass klass, jstring lang, jobjectArray runtimeApksJava,
177-
jstring runtimeNativeLibDir, jobjectArray appDirs, jobject loader,
178-
jobjectArray assembliesJava, jint apiLevel, jboolean isEmulator,
177+
jstring runtimeNativeLibDir, jobjectArray appDirs, jint localDateTimeOffset,
178+
jobject loader, jobjectArray assembliesJava, jint apiLevel, jboolean isEmulator,
179179
jboolean haveSplitApks);
180180
#if !defined (ANDROID)
181181
jint Java_mono_android_Runtime_createNewContextWithData (JNIEnv *env, jclass klass, jobjectArray runtimeApksJava, jobjectArray assembliesJava,

src/monodroid/jni/monodroid-glue.cc

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2152,8 +2152,8 @@ MonodroidRuntime::install_logging_handlers ()
21522152

21532153
inline void
21542154
MonodroidRuntime::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass klass, jstring lang, jobjectArray runtimeApksJava,
2155-
jstring runtimeNativeLibDir, jobjectArray appDirs, jobject loader,
2156-
jobjectArray assembliesJava, jint apiLevel, jboolean isEmulator,
2155+
jstring runtimeNativeLibDir, jobjectArray appDirs, jint localDateTimeOffset,
2156+
jobject loader, jobjectArray assembliesJava, jint apiLevel, jboolean isEmulator,
21572157
jboolean haveSplitApks)
21582158
{
21592159
char *mono_log_mask_raw = nullptr;
@@ -2180,7 +2180,7 @@ MonodroidRuntime::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass kl
21802180
mono_opt_aot_lazy_assembly_load = application_config.aot_lazy_load ? TRUE : FALSE;
21812181

21822182
{
2183-
MonoVMProperties monovm_props { home };
2183+
MonoVMProperties monovm_props { home, localDateTimeOffset };
21842184

21852185
// NOTE: the `const_cast` breaks the contract made to MonoVMProperties that the arrays it returns won't be
21862186
// modified, but it's "ok" since Mono doesn't modify them and by using `const char* const*` in MonoVMProperties
@@ -2455,6 +2455,7 @@ Java_mono_android_Runtime_init (JNIEnv *env, jclass klass, jstring lang, jobject
24552455
runtimeApksJava,
24562456
runtimeNativeLibDir,
24572457
appDirs,
2458+
0,
24582459
loader,
24592460
assembliesJava,
24602461
apiLevel,
@@ -2465,7 +2466,7 @@ Java_mono_android_Runtime_init (JNIEnv *env, jclass klass, jstring lang, jobject
24652466

24662467
JNIEXPORT void JNICALL
24672468
Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass klass, jstring lang, jobjectArray runtimeApksJava,
2468-
jstring runtimeNativeLibDir, jobjectArray appDirs, jobject loader,
2469+
jstring runtimeNativeLibDir, jobjectArray appDirs, jint localDateTimeOffset, jobject loader,
24692470
jobjectArray assembliesJava, jint apiLevel, jboolean isEmulator,
24702471
jboolean haveSplitApks)
24712472
{
@@ -2476,6 +2477,7 @@ Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass klass, jstring lang,
24762477
runtimeApksJava,
24772478
runtimeNativeLibDir,
24782479
appDirs,
2480+
localDateTimeOffset,
24792481
loader,
24802482
assembliesJava,
24812483
apiLevel,

src/monodroid/jni/monovm-properties.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ using namespace xamarin::android::internal;
55
MonoVMProperties::property_array MonoVMProperties::_property_keys {
66
RUNTIME_IDENTIFIER_KEY,
77
APP_CONTEXT_BASE_DIRECTORY_KEY,
8+
LOCAL_DATE_TIME_OFFSET_KEY,
89
};
910

1011
MonoVMProperties::property_array MonoVMProperties::_property_values {
1112
SharedConstants::runtime_identifier,
1213
nullptr,
14+
nullptr,
1315
};

src/monodroid/jni/monovm-properties.hh

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,30 @@ namespace xamarin::android::internal
1010
{
1111
class MonoVMProperties final
1212
{
13-
constexpr static size_t PROPERTY_COUNT = 2;
13+
constexpr static size_t PROPERTY_COUNT = 3;
1414

1515
constexpr static char RUNTIME_IDENTIFIER_KEY[] = "RUNTIME_IDENTIFIER";
1616
constexpr static size_t RUNTIME_IDENTIFIER_INDEX = 0;
1717

1818
constexpr static char APP_CONTEXT_BASE_DIRECTORY_KEY[] = "APP_CONTEXT_BASE_DIRECTORY";
1919
constexpr static size_t APP_CONTEXT_BASE_DIRECTORY_INDEX = 1;
2020

21+
constexpr static char LOCAL_DATE_TIME_OFFSET_KEY[] = "System.TimeZoneInfo.LocalDateTimeOffset";
22+
constexpr static size_t LOCAL_DATE_TIME_OFFSET_INDEX = 2;
23+
2124
using property_array = const char*[PROPERTY_COUNT];
2225

2326
public:
24-
explicit MonoVMProperties (jstring_wrapper& filesDir)
27+
explicit MonoVMProperties (jstring_wrapper& filesDir, jint localDateTimeOffset)
2528
{
2629
static_assert (PROPERTY_COUNT == N_PROPERTY_KEYS);
2730
static_assert (PROPERTY_COUNT == N_PROPERTY_VALUES);
2831

2932
_property_values[APP_CONTEXT_BASE_DIRECTORY_INDEX] = strdup (filesDir.get_cstr ());
33+
34+
static_local_string<32> localDateTimeOffsetBuffer;
35+
localDateTimeOffsetBuffer.append (localDateTimeOffset);
36+
_property_values[LOCAL_DATE_TIME_OFFSET_INDEX] = strdup (localDateTimeOffsetBuffer.get ());
3037
}
3138

3239
constexpr int property_count () const

0 commit comments

Comments
 (0)