Skip to content

Commit dc5cdd5

Browse files
mkopcinsmsluszniak
andauthored
feat: added emulator detection (#1021)
## Description Added emulator/simulator detection for logging purposes ### Introduces a breaking change? - [ ] Yes - [x] No ### Type of change - [ ] Bug fix (change which fixes an issue) - [x] New feature (change which adds functionality) - [ ] Documentation update (improves or adds clarity to existing documentation) - [ ] Other (chores, tests, code style improvements etc.) ### Tested on - [x] iOS - [x] Android ### Testing instructions 1. Launch any example app (i.e. apps/computer-vision) 2. Connect to Ru machine via ssh, then `cd telemetry && docker compose logs --follow api` 3. Download any model (make sure the model is not currently downloaded) 4. You should see a log looking something like this: ``` api-1 | /downloads { api-1 | modelName: 'efficientnet-v2-s-quantized', api-1 | countryCode: 'US', api-1 | isEmulator: true, api-1 | libVersion: '0.9.0' api-1 | } ``` ### Screenshots <!-- Add screenshots here, if applicable --> ### Related issues <!-- Link related issues here using #issue-number --> ### Checklist - [ ] I have performed a self-review of my code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have updated the documentation accordingly - [ ] My changes generate no new warnings ### Additional notes <!-- Include any additional information, assumptions, or context that reviewers might need to understand this PR. --> --------- Co-authored-by: Mateusz Sluszniak <56299341+msluszniak@users.noreply.github.com>
1 parent 3fe7c12 commit dc5cdd5

File tree

8 files changed

+118
-64
lines changed

8 files changed

+118
-64
lines changed

packages/react-native-executorch/android/src/main/cpp/ETInstallerModule.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
#include <rnexecutorch/RnExecutorchInstaller.h>
44

5+
#include "EmulatorDetection.h"
6+
57
#include <jni.h>
68
#include <jsi/jsi.h>
79

@@ -64,8 +66,10 @@ void ETInstallerModule::injectJSIBindings() {
6466
return std::vector<std::byte>(dataBytePtr, dataBytePtr + size);
6567
};
6668

69+
auto _isEmulator = isEmulator();
70+
6771
RnExecutorchInstaller::injectJSIBindings(jsiRuntime_, jsCallInvoker_,
68-
fetchDataByUrl);
72+
fetchDataByUrl, _isEmulator);
6973
}
7074
} // namespace rnexecutorch
7175

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#pragma once
2+
3+
#include <string>
4+
#include <sys/system_properties.h>
5+
6+
namespace rnexecutorch {
7+
8+
inline bool isEmulator() {
9+
auto readProp = [](const char *key) -> std::string {
10+
#if __ANDROID_API__ >= 26
11+
const prop_info *pi = __system_property_find(key);
12+
if (pi == nullptr) {
13+
return "";
14+
}
15+
std::string result;
16+
__system_property_read_callback(
17+
pi,
18+
[](void *cookie, const char * /*__name*/, const char *value,
19+
uint32_t /*__serial*/) {
20+
*static_cast<std::string *>(cookie) = value;
21+
},
22+
&result);
23+
return result;
24+
#else
25+
char value[PROP_VALUE_MAX] = {0};
26+
__system_property_get(key, value);
27+
return {value};
28+
#endif
29+
};
30+
31+
std::string fp = readProp("ro.build.fingerprint");
32+
std::string hw = readProp("ro.hardware");
33+
return fp.find("generic") == 0 || hw == "goldfish" || hw == "ranchu";
34+
}
35+
36+
} // namespace rnexecutorch

packages/react-native-executorch/common/rnexecutorch/RnExecutorchInstaller.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,12 @@ FetchUrlFunc_t fetchUrlFunc;
3434

3535
void RnExecutorchInstaller::injectJSIBindings(
3636
jsi::Runtime *jsiRuntime, std::shared_ptr<react::CallInvoker> jsCallInvoker,
37-
FetchUrlFunc_t fetchDataFromUrl) {
37+
FetchUrlFunc_t fetchDataFromUrl, bool isEmulator) {
3838
fetchUrlFunc = fetchDataFromUrl;
3939

40+
jsiRuntime->global().setProperty(*jsiRuntime, "__rne_isEmulator",
41+
jsi::Value(isEmulator));
42+
4043
jsiRuntime->global().setProperty(
4144
*jsiRuntime, "loadStyleTransfer",
4245
RnExecutorchInstaller::loadModel<models::style_transfer::StyleTransfer>(

packages/react-native-executorch/common/rnexecutorch/RnExecutorchInstaller.h

Lines changed: 54 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class RnExecutorchInstaller {
2424
static void
2525
injectJSIBindings(jsi::Runtime *jsiRuntime,
2626
std::shared_ptr<react::CallInvoker> jsCallInvoker,
27-
FetchUrlFunc_t fetchDataFromUrl);
27+
FetchUrlFunc_t fetchDataFromUrl, bool isEmulator);
2828

2929
private:
3030
template <typename ModelT>
@@ -56,72 +56,67 @@ class RnExecutorchInstaller {
5656
// access), then dispatch the heavy model construction to a background
5757
// thread and return a Promise.
5858
auto constructorArgs =
59-
meta::createConstructorArgsWithCallInvoker<ModelT>(
60-
args, runtime, jsCallInvoker);
59+
meta::createConstructorArgsWithCallInvoker<ModelT>(args, runtime,
60+
jsCallInvoker);
6161

6262
return Promise::createPromise(
6363
runtime, jsCallInvoker,
64-
[jsCallInvoker,
65-
constructorArgs =
66-
std::move(constructorArgs)](std::shared_ptr<Promise> promise) {
67-
threads::GlobalThreadPool::detach(
68-
[jsCallInvoker, promise,
69-
constructorArgs = std::move(constructorArgs)]() {
70-
try {
71-
auto modelImplementationPtr = std::apply(
72-
[](auto &&...unpackedArgs) {
73-
return std::make_shared<ModelT>(
74-
std::forward<decltype(unpackedArgs)>(
75-
unpackedArgs)...);
76-
},
77-
std::move(constructorArgs));
64+
[jsCallInvoker, constructorArgs = std::move(constructorArgs)](
65+
std::shared_ptr<Promise> promise) {
66+
threads::GlobalThreadPool::detach([jsCallInvoker, promise,
67+
constructorArgs = std::move(
68+
constructorArgs)]() {
69+
try {
70+
auto modelImplementationPtr = std::apply(
71+
[](auto &&...unpackedArgs) {
72+
return std::make_shared<ModelT>(
73+
std::forward<decltype(unpackedArgs)>(
74+
unpackedArgs)...);
75+
},
76+
std::move(constructorArgs));
7877

79-
auto modelHostObject =
80-
std::make_shared<ModelHostObject<ModelT>>(
81-
modelImplementationPtr, jsCallInvoker);
78+
auto modelHostObject =
79+
std::make_shared<ModelHostObject<ModelT>>(
80+
modelImplementationPtr, jsCallInvoker);
8281

83-
auto memoryLowerBound =
84-
modelImplementationPtr->getMemoryLowerBound();
82+
auto memoryLowerBound =
83+
modelImplementationPtr->getMemoryLowerBound();
8584

86-
jsCallInvoker->invokeAsync(
87-
[promise, modelHostObject,
88-
memoryLowerBound](jsi::Runtime &rt) {
89-
auto jsiObject =
90-
jsi::Object::createFromHostObject(
91-
rt, modelHostObject);
92-
jsiObject.setExternalMemoryPressure(
93-
rt, memoryLowerBound);
94-
promise->resolve(std::move(jsiObject));
95-
});
96-
} catch (const rnexecutorch::RnExecutorchError &e) {
97-
auto code = e.getNumericCode();
98-
auto msg = std::string(e.what());
99-
jsCallInvoker->invokeAsync(
100-
[promise, code, msg](jsi::Runtime &rt) {
101-
jsi::Object errorData(rt);
102-
errorData.setProperty(rt, "code", code);
103-
errorData.setProperty(
104-
rt, "message",
105-
jsi::String::createFromUtf8(rt, msg));
106-
promise->reject(
107-
jsi::Value(rt, std::move(errorData)));
108-
});
109-
} catch (const std::runtime_error &e) {
110-
jsCallInvoker->invokeAsync(
111-
[promise, msg = std::string(e.what())]() {
112-
promise->reject(msg);
113-
});
114-
} catch (const std::exception &e) {
115-
jsCallInvoker->invokeAsync(
116-
[promise, msg = std::string(e.what())]() {
117-
promise->reject(msg);
118-
});
119-
} catch (...) {
120-
jsCallInvoker->invokeAsync([promise]() {
121-
promise->reject(std::string("Unknown error"));
85+
jsCallInvoker->invokeAsync([promise, modelHostObject,
86+
memoryLowerBound](
87+
jsi::Runtime &rt) {
88+
auto jsiObject = jsi::Object::createFromHostObject(
89+
rt, modelHostObject);
90+
jsiObject.setExternalMemoryPressure(rt, memoryLowerBound);
91+
promise->resolve(std::move(jsiObject));
92+
});
93+
} catch (const rnexecutorch::RnExecutorchError &e) {
94+
auto code = e.getNumericCode();
95+
auto msg = std::string(e.what());
96+
jsCallInvoker->invokeAsync([promise, code,
97+
msg](jsi::Runtime &rt) {
98+
jsi::Object errorData(rt);
99+
errorData.setProperty(rt, "code", code);
100+
errorData.setProperty(
101+
rt, "message", jsi::String::createFromUtf8(rt, msg));
102+
promise->reject(jsi::Value(rt, std::move(errorData)));
103+
});
104+
} catch (const std::runtime_error &e) {
105+
jsCallInvoker->invokeAsync(
106+
[promise, msg = std::string(e.what())]() {
107+
promise->reject(msg);
108+
});
109+
} catch (const std::exception &e) {
110+
jsCallInvoker->invokeAsync(
111+
[promise, msg = std::string(e.what())]() {
112+
promise->reject(msg);
122113
});
123-
}
114+
} catch (...) {
115+
jsCallInvoker->invokeAsync([promise]() {
116+
promise->reject(std::string("Unknown error"));
124117
});
118+
}
119+
});
125120
});
126121
});
127122
}

packages/react-native-executorch/ios/RnExecutorch/ETInstaller.mm

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#import <React/RCTCallInvoker.h>
66
#import <ReactCommon/RCTTurboModule.h>
7+
#import <TargetConditionals.h>
78
#include <rnexecutorch/RnExecutorchInstaller.h>
89
#include <stdexcept>
910

@@ -41,8 +42,9 @@ @implementation ETInstaller
4142
throw std::runtime_error("Error fetching data from a url");
4243
}
4344
};
45+
bool isEmulator = TARGET_OS_SIMULATOR;
4446
rnexecutorch::RnExecutorchInstaller::injectJSIBindings(
45-
jsiRuntime, jsCallInvoker, fetchUrl);
47+
jsiRuntime, jsCallInvoker, fetchUrl, isEmulator);
4648

4749
NSLog(@"Successfully installed JSI bindings for react-native-executorch!");
4850
return @true;
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
export const DOWNLOAD_EVENT_ENDPOINT =
22
'https://ai.swmansion.com/telemetry/downloads/api/downloads';
3+
4+
export const LIB_VERSION: string = require('../../package.json').version;

packages/react-native-executorch/src/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ declare global {
105105
symbols: string,
106106
independentCharacters?: boolean
107107
) => Promise<any>;
108+
// eslint-disable-next-line camelcase
109+
var __rne_isEmulator: boolean;
108110
}
109111
// eslint-disable no-var
110112

@@ -124,7 +126,8 @@ if (
124126
global.loadSpeechToText == null ||
125127
global.loadTextToSpeechKokoro == null ||
126128
global.loadOCR == null ||
127-
global.loadVerticalOCR == null
129+
global.loadVerticalOCR == null ||
130+
global.__rne_isEmulator == null
128131
) {
129132
if (!ETInstallerNativeModule) {
130133
throw new Error(

packages/react-native-executorch/src/utils/ResourceFetcherUtils.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import { ResourceSource } from '..';
22
import { getModelNameForUrl } from '../constants/modelUrls';
3-
import { DOWNLOAD_EVENT_ENDPOINT } from '../constants/resourceFetcher';
3+
import {
4+
DOWNLOAD_EVENT_ENDPOINT,
5+
LIB_VERSION,
6+
} from '../constants/resourceFetcher';
47

58
/**
69
* Http status codes
@@ -206,6 +209,10 @@ export namespace ResourceFetcherUtils {
206209
return 'UNKNOWN';
207210
}
208211

212+
export function isEmulator(): boolean {
213+
return global.__rne_isEmulator;
214+
}
215+
209216
function getModelNameFromUri(uri: string): string {
210217
const knownName = getModelNameForUrl(uri);
211218
if (knownName) {
@@ -228,6 +235,8 @@ export namespace ResourceFetcherUtils {
228235
body: JSON.stringify({
229236
modelName: getModelNameFromUri(uri),
230237
countryCode: getCountryCode(),
238+
isEmulator: isEmulator(),
239+
libVersion: LIB_VERSION,
231240
}),
232241
});
233242
} catch (e) {}

0 commit comments

Comments
 (0)