Skip to content

Commit

Permalink
[monodroid, java-runtime] Add local date time offset monovm prop (#7331)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
mdh1418 authored and jonathanpeppers committed Sep 27, 2022
1 parent 0515d1d commit 2925015
Show file tree
Hide file tree
Showing 8 changed files with 35 additions and 11 deletions.
2 changes: 1 addition & 1 deletion Configuration.props
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
<!-- Should correspond to the first value from `$(API_LEVELS)` in `build-tools/api-xml-adjuster/Makefile` -->
<AndroidFirstFrameworkVersion Condition="'$(AndroidFirstFrameworkVersion)' == ''">v4.4</AndroidFirstFrameworkVersion>
<AndroidFirstApiLevel Condition="'$(AndroidFirstApiLevel)' == ''">19</AndroidFirstApiLevel>
<AndroidJavaRuntimeApiLevel Condition="'$(AndroidJavaRuntimeApiLevel)' == ''">21</AndroidJavaRuntimeApiLevel>
<AndroidJavaRuntimeApiLevel Condition="'$(AndroidJavaRuntimeApiLevel)' == ''">26</AndroidJavaRuntimeApiLevel>
<!-- The min API level supported by Microsoft.Android.Sdk, should refactor/remove when this value is the same as $(AndroidFirstApiLevel) -->
<AndroidMinimumDotNetApiLevel Condition="'$(AndroidMinimumDotNetApiLevel)' == ''">21</AndroidMinimumDotNetApiLevel>
<AndroidFirstPlatformId Condition="'$(AndroidFirstPlatformId)' == ''">$(AndroidFirstApiLevel)</AndroidFirstPlatformId>
Expand Down
12 changes: 12 additions & 0 deletions src/java-runtime/java/mono/android/MonoPackageManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

import java.io.*;
import java.lang.String;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.Calendar;
import java.util.Locale;
import java.util.HashSet;
import java.util.zip.*;
Expand Down Expand Up @@ -42,6 +45,14 @@ public static void LoadApplication (Context context, ApplicationInfo runtimePack
String dataDir = getNativeLibraryPath (context);
ClassLoader loader = context.getClassLoader ();
String runtimeDir = getNativeLibraryPath (runtimePackage);
int localDateTimeOffset;

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
localDateTimeOffset = OffsetDateTime.now().getOffset().getTotalSeconds();
}
else {
localDateTimeOffset = (Calendar.getInstance ().get (Calendar.ZONE_OFFSET) + Calendar.getInstance ().get (Calendar.DST_OFFSET)) / 1000;
}

//
// Should the order change here, src/monodroid/jni/SharedConstants.hh must be updated accordingly
Expand Down Expand Up @@ -106,6 +117,7 @@ public static void LoadApplication (Context context, ApplicationInfo runtimePack
apks,
runtimeDir,
appDirs,
localDateTimeOffset,
loader,
MonoPackageManager_Resources.Assemblies,
Build.VERSION.SDK_INT,
Expand Down
1 change: 1 addition & 0 deletions src/java-runtime/java/mono/android/Runtime.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public static native void initInternal (
String[] runtimeApks,
String runtimeDataDir,
String[] appDirs,
int localDateTimeOffset,
ClassLoader loader,
String[] assemblies,
int apiLevel,
Expand Down
4 changes: 2 additions & 2 deletions src/monodroid/jni/mono_android_Runtime.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions src/monodroid/jni/monodroid-glue-internal.hh
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,8 @@ namespace xamarin::android::internal
public:
void Java_mono_android_Runtime_register (JNIEnv *env, jstring managedType, jclass nativeClass, jstring methods);
void Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass klass, jstring lang, jobjectArray runtimeApksJava,
jstring runtimeNativeLibDir, jobjectArray appDirs, jobject loader,
jobjectArray assembliesJava, jint apiLevel, jboolean isEmulator,
jstring runtimeNativeLibDir, jobjectArray appDirs, jint localDateTimeOffset,
jobject loader, jobjectArray assembliesJava, jint apiLevel, jboolean isEmulator,
jboolean haveSplitApks);
#if !defined (ANDROID)
jint Java_mono_android_Runtime_createNewContextWithData (JNIEnv *env, jclass klass, jobjectArray runtimeApksJava, jobjectArray assembliesJava,
Expand Down
10 changes: 6 additions & 4 deletions src/monodroid/jni/monodroid-glue.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2152,8 +2152,8 @@ MonodroidRuntime::install_logging_handlers ()

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

{
MonoVMProperties monovm_props { home };
MonoVMProperties monovm_props { home, localDateTimeOffset };

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

JNIEXPORT void JNICALL
Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass klass, jstring lang, jobjectArray runtimeApksJava,
jstring runtimeNativeLibDir, jobjectArray appDirs, jobject loader,
jstring runtimeNativeLibDir, jobjectArray appDirs, jint localDateTimeOffset, jobject loader,
jobjectArray assembliesJava, jint apiLevel, jboolean isEmulator,
jboolean haveSplitApks)
{
Expand All @@ -2476,6 +2477,7 @@ Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass klass, jstring lang,
runtimeApksJava,
runtimeNativeLibDir,
appDirs,
localDateTimeOffset,
loader,
assembliesJava,
apiLevel,
Expand Down
2 changes: 2 additions & 0 deletions src/monodroid/jni/monovm-properties.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ using namespace xamarin::android::internal;
MonoVMProperties::property_array MonoVMProperties::_property_keys {
RUNTIME_IDENTIFIER_KEY,
APP_CONTEXT_BASE_DIRECTORY_KEY,
LOCAL_DATE_TIME_OFFSET_KEY,
};

MonoVMProperties::property_array MonoVMProperties::_property_values {
SharedConstants::runtime_identifier,
nullptr,
nullptr,
};
11 changes: 9 additions & 2 deletions src/monodroid/jni/monovm-properties.hh
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,30 @@ namespace xamarin::android::internal
{
class MonoVMProperties final
{
constexpr static size_t PROPERTY_COUNT = 2;
constexpr static size_t PROPERTY_COUNT = 3;

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

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

constexpr static char LOCAL_DATE_TIME_OFFSET_KEY[] = "System.TimeZoneInfo.LocalDateTimeOffset";
constexpr static size_t LOCAL_DATE_TIME_OFFSET_INDEX = 2;

using property_array = const char*[PROPERTY_COUNT];

public:
explicit MonoVMProperties (jstring_wrapper& filesDir)
explicit MonoVMProperties (jstring_wrapper& filesDir, jint localDateTimeOffset)
{
static_assert (PROPERTY_COUNT == N_PROPERTY_KEYS);
static_assert (PROPERTY_COUNT == N_PROPERTY_VALUES);

_property_values[APP_CONTEXT_BASE_DIRECTORY_INDEX] = strdup (filesDir.get_cstr ());

static_local_string<32> localDateTimeOffsetBuffer;
localDateTimeOffsetBuffer.append (localDateTimeOffset);
_property_values[LOCAL_DATE_TIME_OFFSET_INDEX] = strdup (localDateTimeOffsetBuffer.get ());
}

constexpr int property_count () const
Expand Down

0 comments on commit 2925015

Please sign in to comment.