diff --git a/packages/react-native-executorch/android/src/main/cpp/ETInstallerModule.cpp b/packages/react-native-executorch/android/src/main/cpp/ETInstallerModule.cpp index d69af8634b..1a637b15d1 100644 --- a/packages/react-native-executorch/android/src/main/cpp/ETInstallerModule.cpp +++ b/packages/react-native-executorch/android/src/main/cpp/ETInstallerModule.cpp @@ -2,6 +2,8 @@ #include +#include "EmulatorDetection.h" + #include #include @@ -64,8 +66,10 @@ void ETInstallerModule::injectJSIBindings() { return std::vector(dataBytePtr, dataBytePtr + size); }; + auto _isEmulator = isEmulator(); + RnExecutorchInstaller::injectJSIBindings(jsiRuntime_, jsCallInvoker_, - fetchDataByUrl); + fetchDataByUrl, _isEmulator); } } // namespace rnexecutorch diff --git a/packages/react-native-executorch/android/src/main/cpp/EmulatorDetection.h b/packages/react-native-executorch/android/src/main/cpp/EmulatorDetection.h new file mode 100644 index 0000000000..63cc17e398 --- /dev/null +++ b/packages/react-native-executorch/android/src/main/cpp/EmulatorDetection.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include + +namespace rnexecutorch { + +inline bool isEmulator() { + auto readProp = [](const char *key) -> std::string { +#if __ANDROID_API__ >= 26 + const prop_info *pi = __system_property_find(key); + if (pi == nullptr) { + return ""; + } + std::string result; + __system_property_read_callback( + pi, + [](void *cookie, const char * /*__name*/, const char *value, + uint32_t /*__serial*/) { + *static_cast(cookie) = value; + }, + &result); + return result; +#else + char value[PROP_VALUE_MAX] = {0}; + __system_property_get(key, value); + return {value}; +#endif + }; + + std::string fp = readProp("ro.build.fingerprint"); + std::string hw = readProp("ro.hardware"); + return fp.find("generic") == 0 || hw == "goldfish" || hw == "ranchu"; +} + +} // namespace rnexecutorch diff --git a/packages/react-native-executorch/common/rnexecutorch/RnExecutorchInstaller.cpp b/packages/react-native-executorch/common/rnexecutorch/RnExecutorchInstaller.cpp index 1239642c5e..da75ab951c 100644 --- a/packages/react-native-executorch/common/rnexecutorch/RnExecutorchInstaller.cpp +++ b/packages/react-native-executorch/common/rnexecutorch/RnExecutorchInstaller.cpp @@ -34,9 +34,12 @@ FetchUrlFunc_t fetchUrlFunc; void RnExecutorchInstaller::injectJSIBindings( jsi::Runtime *jsiRuntime, std::shared_ptr jsCallInvoker, - FetchUrlFunc_t fetchDataFromUrl) { + FetchUrlFunc_t fetchDataFromUrl, bool isEmulator) { fetchUrlFunc = fetchDataFromUrl; + jsiRuntime->global().setProperty(*jsiRuntime, "__rne_isEmulator", + jsi::Value(isEmulator)); + jsiRuntime->global().setProperty( *jsiRuntime, "loadStyleTransfer", RnExecutorchInstaller::loadModel( diff --git a/packages/react-native-executorch/common/rnexecutorch/RnExecutorchInstaller.h b/packages/react-native-executorch/common/rnexecutorch/RnExecutorchInstaller.h index bd01abf256..0f94036f64 100644 --- a/packages/react-native-executorch/common/rnexecutorch/RnExecutorchInstaller.h +++ b/packages/react-native-executorch/common/rnexecutorch/RnExecutorchInstaller.h @@ -24,7 +24,7 @@ class RnExecutorchInstaller { static void injectJSIBindings(jsi::Runtime *jsiRuntime, std::shared_ptr jsCallInvoker, - FetchUrlFunc_t fetchDataFromUrl); + FetchUrlFunc_t fetchDataFromUrl, bool isEmulator); private: template @@ -56,72 +56,67 @@ class RnExecutorchInstaller { // access), then dispatch the heavy model construction to a background // thread and return a Promise. auto constructorArgs = - meta::createConstructorArgsWithCallInvoker( - args, runtime, jsCallInvoker); + meta::createConstructorArgsWithCallInvoker(args, runtime, + jsCallInvoker); return Promise::createPromise( runtime, jsCallInvoker, - [jsCallInvoker, - constructorArgs = - std::move(constructorArgs)](std::shared_ptr promise) { - threads::GlobalThreadPool::detach( - [jsCallInvoker, promise, - constructorArgs = std::move(constructorArgs)]() { - try { - auto modelImplementationPtr = std::apply( - [](auto &&...unpackedArgs) { - return std::make_shared( - std::forward( - unpackedArgs)...); - }, - std::move(constructorArgs)); + [jsCallInvoker, constructorArgs = std::move(constructorArgs)]( + std::shared_ptr promise) { + threads::GlobalThreadPool::detach([jsCallInvoker, promise, + constructorArgs = std::move( + constructorArgs)]() { + try { + auto modelImplementationPtr = std::apply( + [](auto &&...unpackedArgs) { + return std::make_shared( + std::forward( + unpackedArgs)...); + }, + std::move(constructorArgs)); - auto modelHostObject = - std::make_shared>( - modelImplementationPtr, jsCallInvoker); + auto modelHostObject = + std::make_shared>( + modelImplementationPtr, jsCallInvoker); - auto memoryLowerBound = - modelImplementationPtr->getMemoryLowerBound(); + auto memoryLowerBound = + modelImplementationPtr->getMemoryLowerBound(); - jsCallInvoker->invokeAsync( - [promise, modelHostObject, - memoryLowerBound](jsi::Runtime &rt) { - auto jsiObject = - jsi::Object::createFromHostObject( - rt, modelHostObject); - jsiObject.setExternalMemoryPressure( - rt, memoryLowerBound); - promise->resolve(std::move(jsiObject)); - }); - } catch (const rnexecutorch::RnExecutorchError &e) { - auto code = e.getNumericCode(); - auto msg = std::string(e.what()); - jsCallInvoker->invokeAsync( - [promise, code, msg](jsi::Runtime &rt) { - jsi::Object errorData(rt); - errorData.setProperty(rt, "code", code); - errorData.setProperty( - rt, "message", - jsi::String::createFromUtf8(rt, msg)); - promise->reject( - jsi::Value(rt, std::move(errorData))); - }); - } catch (const std::runtime_error &e) { - jsCallInvoker->invokeAsync( - [promise, msg = std::string(e.what())]() { - promise->reject(msg); - }); - } catch (const std::exception &e) { - jsCallInvoker->invokeAsync( - [promise, msg = std::string(e.what())]() { - promise->reject(msg); - }); - } catch (...) { - jsCallInvoker->invokeAsync([promise]() { - promise->reject(std::string("Unknown error")); + jsCallInvoker->invokeAsync([promise, modelHostObject, + memoryLowerBound]( + jsi::Runtime &rt) { + auto jsiObject = jsi::Object::createFromHostObject( + rt, modelHostObject); + jsiObject.setExternalMemoryPressure(rt, memoryLowerBound); + promise->resolve(std::move(jsiObject)); + }); + } catch (const rnexecutorch::RnExecutorchError &e) { + auto code = e.getNumericCode(); + auto msg = std::string(e.what()); + jsCallInvoker->invokeAsync([promise, code, + msg](jsi::Runtime &rt) { + jsi::Object errorData(rt); + errorData.setProperty(rt, "code", code); + errorData.setProperty( + rt, "message", jsi::String::createFromUtf8(rt, msg)); + promise->reject(jsi::Value(rt, std::move(errorData))); + }); + } catch (const std::runtime_error &e) { + jsCallInvoker->invokeAsync( + [promise, msg = std::string(e.what())]() { + promise->reject(msg); + }); + } catch (const std::exception &e) { + jsCallInvoker->invokeAsync( + [promise, msg = std::string(e.what())]() { + promise->reject(msg); }); - } + } catch (...) { + jsCallInvoker->invokeAsync([promise]() { + promise->reject(std::string("Unknown error")); }); + } + }); }); }); } diff --git a/packages/react-native-executorch/ios/RnExecutorch/ETInstaller.mm b/packages/react-native-executorch/ios/RnExecutorch/ETInstaller.mm index dcb40b29d8..2a8bc519ba 100644 --- a/packages/react-native-executorch/ios/RnExecutorch/ETInstaller.mm +++ b/packages/react-native-executorch/ios/RnExecutorch/ETInstaller.mm @@ -4,6 +4,7 @@ #import #import +#import #include #include @@ -41,8 +42,9 @@ @implementation ETInstaller throw std::runtime_error("Error fetching data from a url"); } }; + bool isEmulator = TARGET_OS_SIMULATOR; rnexecutorch::RnExecutorchInstaller::injectJSIBindings( - jsiRuntime, jsCallInvoker, fetchUrl); + jsiRuntime, jsCallInvoker, fetchUrl, isEmulator); NSLog(@"Successfully installed JSI bindings for react-native-executorch!"); return @true; diff --git a/packages/react-native-executorch/src/constants/resourceFetcher.ts b/packages/react-native-executorch/src/constants/resourceFetcher.ts index 58a57fdd93..ae6c5f1a3b 100644 --- a/packages/react-native-executorch/src/constants/resourceFetcher.ts +++ b/packages/react-native-executorch/src/constants/resourceFetcher.ts @@ -1,2 +1,4 @@ export const DOWNLOAD_EVENT_ENDPOINT = 'https://ai.swmansion.com/telemetry/downloads/api/downloads'; + +export const LIB_VERSION: string = require('../../package.json').version; diff --git a/packages/react-native-executorch/src/index.ts b/packages/react-native-executorch/src/index.ts index f9d9e32be9..3f6b9fc4ce 100644 --- a/packages/react-native-executorch/src/index.ts +++ b/packages/react-native-executorch/src/index.ts @@ -105,6 +105,8 @@ declare global { symbols: string, independentCharacters?: boolean ) => Promise; + // eslint-disable-next-line camelcase + var __rne_isEmulator: boolean; } // eslint-disable no-var @@ -124,7 +126,8 @@ if ( global.loadSpeechToText == null || global.loadTextToSpeechKokoro == null || global.loadOCR == null || - global.loadVerticalOCR == null + global.loadVerticalOCR == null || + global.__rne_isEmulator == null ) { if (!ETInstallerNativeModule) { throw new Error( diff --git a/packages/react-native-executorch/src/utils/ResourceFetcherUtils.ts b/packages/react-native-executorch/src/utils/ResourceFetcherUtils.ts index 689775f93d..ced27a0b8e 100644 --- a/packages/react-native-executorch/src/utils/ResourceFetcherUtils.ts +++ b/packages/react-native-executorch/src/utils/ResourceFetcherUtils.ts @@ -1,6 +1,9 @@ import { ResourceSource } from '..'; import { getModelNameForUrl } from '../constants/modelUrls'; -import { DOWNLOAD_EVENT_ENDPOINT } from '../constants/resourceFetcher'; +import { + DOWNLOAD_EVENT_ENDPOINT, + LIB_VERSION, +} from '../constants/resourceFetcher'; /** * Http status codes @@ -206,6 +209,10 @@ export namespace ResourceFetcherUtils { return 'UNKNOWN'; } + export function isEmulator(): boolean { + return global.__rne_isEmulator; + } + function getModelNameFromUri(uri: string): string { const knownName = getModelNameForUrl(uri); if (knownName) { @@ -228,6 +235,8 @@ export namespace ResourceFetcherUtils { body: JSON.stringify({ modelName: getModelNameFromUri(uri), countryCode: getCountryCode(), + isEmulator: isEmulator(), + libVersion: LIB_VERSION, }), }); } catch (e) {}