Update pedometer to jni and jnigen:0.5.0 (#1863)

Updates the pedometer sample to the latest version of jni and jnigen.
pull/1867/head
Hossein Yousefi 1 year ago committed by GitHub
parent d4c470e9c1
commit aff3b0979e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -26,7 +26,7 @@ subprojects {
project.evaluationDependsOn(':app') project.evaluationDependsOn(':app')
} }
task clean(type: Delete) { tasks.register("clean", Delete) {
delete rootProject.buildDir delete rootProject.buildDir
} }

@ -141,22 +141,19 @@ class _AndroidStepsRepo implements StepsRepo {
final end = final end =
DateTime(now.year, now.month, now.day, h + 1).millisecondsSinceEpoch; DateTime(now.year, now.month, now.day, h + 1).millisecondsSinceEpoch;
final request = hc.AggregateRequest( final request = hc.AggregateRequest(
hc.Set.of1( {hc.StepsRecord.COUNT_TOTAL}
hc.AggregateMetric.type(hc.Long.type), .toJSet(hc.AggregateMetric.type(jni.JLong.type)),
hc.StepsRecord.COUNT_TOTAL,
),
hc.TimeRangeFilter.between( hc.TimeRangeFilter.between(
hc.Instant.ofEpochMilli(start), hc.Instant.ofEpochMilli(start),
hc.Instant.ofEpochMilli(end), hc.Instant.ofEpochMilli(end),
), ),
hc.Set.of(jni.JObject.type), jni.JSet.hash(jni.JObject.type),
); );
futures.add(client.aggregate(request)); futures.add(client.aggregate(request));
} }
final data = await Future.wait(futures); final data = await Future.wait(futures);
return data.asMap().entries.map((entry) { return data.asMap().entries.map((entry) {
final stepsLong = final stepsLong = entry.value.get0(hc.StepsRecord.COUNT_TOTAL);
entry.value.get0(hc.Long.type, hc.StepsRecord.COUNT_TOTAL);
final steps = stepsLong.isNull ? 0 : stepsLong.intValue(); final steps = stepsLong.isNull ? 0 : stepsLong.intValue();
return Steps(entry.key.toString().padLeft(2, '0'), steps); return Steps(entry.key.toString().padLeft(2, '0'), steps);
}).toList(); }).toList();

@ -44,7 +44,7 @@ dependencies:
cupertino_icons: ^1.0.2 cupertino_icons: ^1.0.2
ffi: ^2.0.1 ffi: ^2.0.1
intl: ^0.18.0 intl: ^0.18.0
jni: ^0.3.0 jni: ^0.5.0
fl_chart: ^0.62.0 fl_chart: ^0.62.0
dev_dependencies: dev_dependencies:

@ -1,10 +1,8 @@
android_sdk_config: android_sdk_config:
add_gradle_deps: true add_gradle_deps: true
add_gradle_sources: true
android_example: 'example/' android_example: 'example/'
summarizer:
backend: asm
suspend_fun_to_async: true suspend_fun_to_async: true
output: output:
@ -15,8 +13,6 @@ output:
path: lib/health_connect.dart path: lib/health_connect.dart
structure: single_file structure: single_file
class_path:
- 'classes.jar'
classes: classes:
- 'androidx.health.connect.client.HealthConnectClient' - 'androidx.health.connect.client.HealthConnectClient'
- 'androidx.health.connect.client.PermissionController' - 'androidx.health.connect.client.PermissionController'
@ -26,8 +22,6 @@ classes:
- 'android.content.Intent' - 'android.content.Intent'
- 'android.app.Activity' - 'android.app.Activity'
- 'java.time.Instant' - 'java.time.Instant'
- 'java.lang.Long'
- 'java.util.Set'
- 'androidx.health.connect.client.request' - 'androidx.health.connect.client.request'
- 'androidx.health.connect.client.aggregate.AggregationResult' - 'androidx.health.connect.client.aggregate.AggregationResult'
- 'androidx.health.connect.client.aggregate.AggregateMetric' - 'androidx.health.connect.client.aggregate.AggregateMetric'

File diff suppressed because it is too large Load Diff

@ -11,12 +11,12 @@ dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
plugin_platform_interface: ^2.0.2 plugin_platform_interface: ^2.0.2
jni: ^0.3.0 jni: ^0.5.0
ffi: ^2.0.1 ffi: ^2.0.1
dev_dependencies: dev_dependencies:
ffigen: ^8.0.0 ffigen: ^8.0.0
jnigen: ^0.4.0 jnigen: ^0.5.0
flutter_test: flutter_test:
sdk: flutter sdk: flutter
flutter_lints: ^2.0.0 flutter_lints: ^2.0.0

@ -39,6 +39,66 @@
#define __ENVP_CAST (void**) #define __ENVP_CAST (void**)
#endif #endif
/// Locking functions for windows and pthread.
#if defined _WIN32
#include <windows.h>
typedef CRITICAL_SECTION MutexLock;
static inline void init_lock(MutexLock* lock) {
InitializeCriticalSection(lock);
}
static inline void acquire_lock(MutexLock* lock) {
EnterCriticalSection(lock);
}
static inline void release_lock(MutexLock* lock) {
LeaveCriticalSection(lock);
}
static inline void _destroyLock(MutexLock* lock) {
DeleteCriticalSection(lock);
}
#elif defined __DARWIN__ || defined __LINUX__ || defined __ANDROID__ || \
defined __GNUC__
#include <pthread.h>
typedef pthread_mutex_t MutexLock;
static inline void init_lock(MutexLock* lock) {
pthread_mutex_init(lock, NULL);
}
static inline void acquire_lock(MutexLock* lock) {
pthread_mutex_lock(lock);
}
static inline void release_lock(MutexLock* lock) {
pthread_mutex_unlock(lock);
}
static inline void _destroyLock(MutexLock* lock) {
pthread_mutex_destroy(lock);
}
#else
#error "No locking support; Possibly unsupported platform"
#endif
typedef struct JniLocks {
MutexLock classLoadingLock;
MutexLock methodLoadingLock;
MutexLock fieldLoadingLock;
} JniLocks;
/// Represents the error when dart-jni layer has already spawned singleton VM.
#define DART_JNI_SINGLETON_EXISTS (-99);
/// Stores the global state of the JNI. /// Stores the global state of the JNI.
typedef struct JniContext { typedef struct JniContext {
JavaVM* jvm; JavaVM* jvm;
@ -46,13 +106,14 @@ typedef struct JniContext {
jmethodID loadClassMethod; jmethodID loadClassMethod;
jobject currentActivity; jobject currentActivity;
jobject appContext; jobject appContext;
JniLocks locks;
} JniContext; } JniContext;
// jniEnv for this thread, used by inline functions in this header, // jniEnv for this thread, used by inline functions in this header,
// therefore declared as extern. // therefore declared as extern.
extern thread_local JNIEnv* jniEnv; extern thread_local JNIEnv* jniEnv;
extern JniContext jni; extern JniContext* jni;
/// Types used by JNI API to distinguish between primitive types. /// Types used by JNI API to distinguish between primitive types.
enum JniType { enum JniType {
@ -73,19 +134,19 @@ enum JniType {
/// If [exception] is null, it means the result is valid. /// If [exception] is null, it means the result is valid.
/// It's assumed that the caller knows the expected type in [result]. /// It's assumed that the caller knows the expected type in [result].
typedef struct JniResult { typedef struct JniResult {
jvalue result; jvalue value;
jthrowable exception; jthrowable exception;
} JniResult; } JniResult;
/// Similar to [JniResult] but for class lookups. /// Similar to [JniResult] but for class lookups.
typedef struct JniClassLookupResult { typedef struct JniClassLookupResult {
jclass classRef; jclass value;
jthrowable exception; jthrowable exception;
} JniClassLookupResult; } JniClassLookupResult;
/// Similar to [JniResult] but for method/field ID lookups. /// Similar to [JniResult] but for method/field ID lookups.
typedef struct JniPointerResult { typedef struct JniPointerResult {
void* id; const void* value;
jthrowable exception; jthrowable exception;
} JniPointerResult; } JniPointerResult;
@ -102,7 +163,7 @@ typedef struct JniExceptionDetails {
/// Flutter embedding checks for pending JNI exceptions before an FFI transition, which requires us /// Flutter embedding checks for pending JNI exceptions before an FFI transition, which requires us
/// to check for and clear the exception before returning to dart code, which requires these functions /// to check for and clear the exception before returning to dart code, which requires these functions
/// to return result types. /// to return result types.
typedef struct JniAccessors { typedef struct JniAccessorsStruct {
JniClassLookupResult (*getClass)(char* internalName); JniClassLookupResult (*getClass)(char* internalName);
JniPointerResult (*getFieldID)(jclass cls, char* fieldName, char* signature); JniPointerResult (*getFieldID)(jclass cls, char* fieldName, char* signature);
JniPointerResult (*getStaticFieldID)(jclass cls, JniPointerResult (*getStaticFieldID)(jclass cls,
@ -115,10 +176,10 @@ typedef struct JniAccessors {
char* methodName, char* methodName,
char* signature); char* signature);
JniResult (*newObject)(jclass cls, jmethodID ctor, jvalue* args); JniResult (*newObject)(jclass cls, jmethodID ctor, jvalue* args);
JniPointerResult (*newPrimitiveArray)(jsize length, int type); JniResult (*newPrimitiveArray)(jsize length, int type);
JniPointerResult (*newObjectArray)(jsize length, JniResult (*newObjectArray)(jsize length,
jclass elementClass, jclass elementClass,
jobject initialElement); jobject initialElement);
JniResult (*getArrayElement)(jarray array, int index, int type); JniResult (*getArrayElement)(jarray array, int index, int type);
JniResult (*callMethod)(jobject obj, JniResult (*callMethod)(jobject obj,
jmethodID methodID, jmethodID methodID,
@ -131,62 +192,81 @@ typedef struct JniAccessors {
JniResult (*getField)(jobject obj, jfieldID fieldID, int callType); JniResult (*getField)(jobject obj, jfieldID fieldID, int callType);
JniResult (*getStaticField)(jclass cls, jfieldID fieldID, int callType); JniResult (*getStaticField)(jclass cls, jfieldID fieldID, int callType);
JniExceptionDetails (*getExceptionDetails)(jthrowable exception); JniExceptionDetails (*getExceptionDetails)(jthrowable exception);
} JniAccessors; } JniAccessorsStruct;
FFI_PLUGIN_EXPORT JniAccessors* GetAccessors(); FFI_PLUGIN_EXPORT JniAccessorsStruct* GetAccessors();
FFI_PLUGIN_EXPORT JavaVM* GetJavaVM(void); FFI_PLUGIN_EXPORT JavaVM* GetJavaVM(void);
FFI_PLUGIN_EXPORT JNIEnv* GetJniEnv(void); FFI_PLUGIN_EXPORT JNIEnv* GetJniEnv(void);
FFI_PLUGIN_EXPORT JNIEnv* SpawnJvm(JavaVMInitArgs* args); /// Spawn a JVM with given arguments.
///
/// Returns JNI_OK on success, and one of the documented JNI error codes on
/// failure. It returns DART_JNI_SINGLETON_EXISTS if an attempt to spawn multiple
/// JVMs is made, even if the underlying API potentially supports multiple VMs.
FFI_PLUGIN_EXPORT int SpawnJvm(JavaVMInitArgs* args);
FFI_PLUGIN_EXPORT jclass LoadClass(const char* name); /// Load class through platform-specific mechanism.
///
/// Currently uses application classloader on android,
/// and JNIEnv->FindClass on other platforms.
FFI_PLUGIN_EXPORT jclass FindClass(const char* name);
/// Returns Application classLoader (on Android),
/// which can be used to load application and platform classes.
///
/// On other platforms, NULL is returned.
FFI_PLUGIN_EXPORT jobject GetClassLoader(void); FFI_PLUGIN_EXPORT jobject GetClassLoader(void);
/// Returns application context on Android.
///
/// On other platforms, NULL is returned.
FFI_PLUGIN_EXPORT jobject GetApplicationContext(void); FFI_PLUGIN_EXPORT jobject GetApplicationContext(void);
/// Returns current activity of the app on Android.
FFI_PLUGIN_EXPORT jobject GetCurrentActivity(void); FFI_PLUGIN_EXPORT jobject GetCurrentActivity(void);
// Migration note: Below inline functions are required by C bindings, but can be moved to dartjni.c static inline void attach_thread() {
// once migration to pure dart bindings is complete. if (jniEnv == NULL) {
(*jni->jvm)->AttachCurrentThread(jni->jvm, __ENVP_CAST & jniEnv, NULL);
// `static inline` because `inline` doesn't work, it may still not }
// inline the function in which case a linker error may be produced. }
//
// There has to be a better way to do this. Either to force inlining on target
// platforms, or just leave it as normal function.
static inline void __load_class_into(jclass* cls, const char* name) { /// Load class into [cls] using platform specific mechanism
static inline void load_class_platform(jclass* cls, const char* name) {
#ifdef __ANDROID__ #ifdef __ANDROID__
jstring className = (*jniEnv)->NewStringUTF(jniEnv, name); jstring className = (*jniEnv)->NewStringUTF(jniEnv, name);
*cls = (*jniEnv)->CallObjectMethod(jniEnv, jni.classLoader, *cls = (*jniEnv)->CallObjectMethod(jniEnv, jni->classLoader,
jni.loadClassMethod, className); jni->loadClassMethod, className);
(*jniEnv)->DeleteLocalRef(jniEnv, className); (*jniEnv)->DeleteLocalRef(jniEnv, className);
#else #else
*cls = (*jniEnv)->FindClass(jniEnv, name); *cls = (*jniEnv)->FindClass(jniEnv, name);
#endif #endif
} }
static inline void load_class(jclass* cls, const char* name) { static inline void load_class_local_ref(jclass* cls, const char* name) {
if (*cls == NULL) { if (*cls == NULL) {
__load_class_into(cls, name); acquire_lock(&jni->locks.classLoadingLock);
if (*cls == NULL) {
load_class_platform(cls, name);
}
release_lock(&jni->locks.classLoadingLock);
} }
} }
static inline void load_class_gr(jclass* cls, const char* name) { static inline void load_class_global_ref(jclass* cls, const char* name) {
if (*cls == NULL) { if (*cls == NULL) {
jclass tmp; jclass tmp = NULL;
__load_class_into(&tmp, name); acquire_lock(&jni->locks.classLoadingLock);
*cls = (*jniEnv)->NewGlobalRef(jniEnv, tmp); if (*cls == NULL) {
(*jniEnv)->DeleteLocalRef(jniEnv, tmp); load_class_platform(&tmp, name);
} if (!(*jniEnv)->ExceptionCheck(jniEnv)) {
} *cls = (*jniEnv)->NewGlobalRef(jniEnv, tmp);
(*jniEnv)->DeleteLocalRef(jniEnv, tmp);
static inline void attach_thread() { }
if (jniEnv == NULL) { }
(*jni.jvm)->AttachCurrentThread(jni.jvm, __ENVP_CAST & jniEnv, NULL); release_lock(&jni->locks.classLoadingLock);
} }
} }
@ -195,7 +275,11 @@ static inline void load_method(jclass cls,
const char* name, const char* name,
const char* sig) { const char* sig) {
if (*res == NULL) { if (*res == NULL) {
*res = (*jniEnv)->GetMethodID(jniEnv, cls, name, sig); acquire_lock(&jni->locks.methodLoadingLock);
if (*res == NULL) {
*res = (*jniEnv)->GetMethodID(jniEnv, cls, name, sig);
}
release_lock(&jni->locks.methodLoadingLock);
} }
} }
@ -204,7 +288,11 @@ static inline void load_static_method(jclass cls,
const char* name, const char* name,
const char* sig) { const char* sig) {
if (*res == NULL) { if (*res == NULL) {
*res = (*jniEnv)->GetStaticMethodID(jniEnv, cls, name, sig); acquire_lock(&jni->locks.methodLoadingLock);
if (*res == NULL) {
*res = (*jniEnv)->GetStaticMethodID(jniEnv, cls, name, sig);
}
release_lock(&jni->locks.methodLoadingLock);
} }
} }
@ -213,7 +301,11 @@ static inline void load_field(jclass cls,
const char* name, const char* name,
const char* sig) { const char* sig) {
if (*res == NULL) { if (*res == NULL) {
*res = (*jniEnv)->GetFieldID(jniEnv, cls, name, sig); acquire_lock(&jni->locks.fieldLoadingLock);
if (*res == NULL) {
*res = (*jniEnv)->GetFieldID(jniEnv, cls, name, sig);
}
release_lock(&jni->locks.fieldLoadingLock);
} }
} }
@ -222,7 +314,11 @@ static inline void load_static_field(jclass cls,
const char* name, const char* name,
const char* sig) { const char* sig) {
if (*res == NULL) { if (*res == NULL) {
*res = (*jniEnv)->GetStaticFieldID(jniEnv, cls, name, sig); acquire_lock(&jni->locks.fieldLoadingLock);
if (*res == NULL) {
*res = (*jniEnv)->GetStaticFieldID(jniEnv, cls, name, sig);
}
release_lock(&jni->locks.fieldLoadingLock);
} }
} }
@ -234,17 +330,18 @@ static inline jobject to_global_ref(jobject ref) {
// These functions are useful for C+Dart bindings, and not required for pure dart bindings. // These functions are useful for C+Dart bindings, and not required for pure dart bindings.
FFI_PLUGIN_EXPORT JniContext GetJniContext(); FFI_PLUGIN_EXPORT JniContext* GetJniContextPtr();
/// For use by jni_gen's generated code /// For use by jni_gen's generated code
/// don't use these. /// don't use these.
// these 2 fn ptr vars will be defined by generated code library // these 2 fn ptr vars will be defined by generated code library
extern JniContext (*context_getter)(void); extern JniContext* (*context_getter)(void);
extern JNIEnv* (*env_getter)(void); extern JNIEnv* (*env_getter)(void);
// this function will be exported by generated code library // this function will be exported by generated code library
// it will set above 2 variables. // it will set above 2 variables.
FFI_PLUGIN_EXPORT void setJniGetters(struct JniContext (*cg)(void), FFI_PLUGIN_EXPORT void setJniGetters(struct JniContext* (*cg)(void),
JNIEnv* (*eg)(void)); JNIEnv* (*eg)(void));
static inline void load_env() { static inline void load_env() {
@ -261,6 +358,15 @@ static inline jthrowable check_exception() {
return to_global_ref(exception); return to_global_ref(exception);
} }
static inline JniResult to_global_ref_result(jobject ref) {
JniResult result;
result.exception = check_exception();
if (result.exception == NULL) {
result.value.l = to_global_ref(ref);
}
return result;
}
FFI_PLUGIN_EXPORT intptr_t InitDartApiDL(void* data); FFI_PLUGIN_EXPORT intptr_t InitDartApiDL(void* data);
JNIEXPORT void JNICALL JNIEXPORT void JNICALL

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save