Skip to content

Commit 33ce1f4

Browse files
committed
Merge Expensify custom changes into upstream 0.72.0-rc.1
2 parents 30b5de0 + 3fa098e commit 33ce1f4

File tree

81 files changed

+1464
-129
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+1464
-129
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,3 +142,5 @@ package-lock.json
142142

143143
# Temporary files created by Metro to check the health of the file watcher
144144
.metro-health-check*
145+
146+
react-native-*.tgz
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#include "NativePerformanceObserver.h"
9+
#include <glog/logging.h>
10+
11+
namespace facebook::react {
12+
13+
NativePerformanceObserver::NativePerformanceObserver(
14+
std::shared_ptr<CallInvoker> jsInvoker)
15+
: NativePerformanceObserverCxxSpec(std::move(jsInvoker)) {}
16+
17+
void NativePerformanceObserver::startReporting(
18+
jsi::Runtime &rt,
19+
std::string entryType) {
20+
LOG(INFO) << "Started reporting perf entry type: " << entryType;
21+
}
22+
23+
void NativePerformanceObserver::stopReporting(
24+
jsi::Runtime &rt,
25+
std::string entryType) {
26+
LOG(INFO) << "Stopped reporting perf entry type: " << entryType;
27+
}
28+
29+
std::vector<RawPerformanceEntry> NativePerformanceObserver::getPendingEntries(
30+
jsi::Runtime &rt) {
31+
return std::vector<RawPerformanceEntry>{};
32+
}
33+
34+
void NativePerformanceObserver::setOnPerformanceEntryCallback(
35+
jsi::Runtime &rt,
36+
std::optional<AsyncCallback<>> callback) {
37+
callback_ = callback;
38+
LOG(INFO) << "setOnPerformanceEntryCallback: "
39+
<< (callback ? "non-empty" : "empty");
40+
}
41+
42+
} // namespace facebook::react
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#pragma once
9+
10+
#include <FBReactNativeSpec/FBReactNativeSpecJSI.h>
11+
#include <functional>
12+
#include <memory>
13+
#include <optional>
14+
#include <string>
15+
#include <vector>
16+
17+
namespace facebook::react {
18+
19+
#pragma mark - Structs
20+
21+
using RawPerformanceEntry = NativePerformanceObserverCxxBaseRawPerformanceEntry<
22+
std::string,
23+
int32_t,
24+
double,
25+
double,
26+
// For "event" entries only:
27+
std::optional<double>,
28+
std::optional<double>,
29+
std::optional<double>>;
30+
31+
template <>
32+
struct Bridging<RawPerformanceEntry>
33+
: NativePerformanceObserverCxxBaseRawPerformanceEntryBridging<
34+
std::string,
35+
int32_t,
36+
double,
37+
double,
38+
std::optional<double>,
39+
std::optional<double>,
40+
std::optional<double>> {};
41+
42+
#pragma mark - implementation
43+
44+
class NativePerformanceObserver
45+
: public NativePerformanceObserverCxxSpec<NativePerformanceObserver>,
46+
std::enable_shared_from_this<NativePerformanceObserver> {
47+
public:
48+
NativePerformanceObserver(std::shared_ptr<CallInvoker> jsInvoker);
49+
50+
void startReporting(jsi::Runtime &rt, std::string entryType);
51+
52+
void stopReporting(jsi::Runtime &rt, std::string entryType);
53+
54+
std::vector<RawPerformanceEntry> getPendingEntries(jsi::Runtime &rt);
55+
56+
void setOnPerformanceEntryCallback(
57+
jsi::Runtime &rt,
58+
std::optional<AsyncCallback<>> callback);
59+
60+
private:
61+
std::optional<AsyncCallback<>> callback_;
62+
};
63+
64+
} // namespace facebook::react
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @flow strict
8+
* @format
9+
*/
10+
11+
import type {TurboModule} from '../TurboModule/RCTExport';
12+
13+
import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry';
14+
15+
export const RawPerformanceEntryTypeValues = {
16+
UNDEFINED: 0,
17+
};
18+
19+
export type RawPerformanceEntryType = number;
20+
21+
export type RawPerformanceEntry = {|
22+
name: string,
23+
entryType: RawPerformanceEntryType,
24+
startTime: number,
25+
duration: number,
26+
// For "event" entries only:
27+
processingStart?: number,
28+
processingEnd?: number,
29+
interactionId?: number,
30+
|};
31+
32+
export interface Spec extends TurboModule {
33+
+startReporting: (entryType: string) => void;
34+
+stopReporting: (entryType: string) => void;
35+
+getPendingEntries: () => $ReadOnlyArray<RawPerformanceEntry>;
36+
+setOnPerformanceEntryCallback: (callback?: () => void) => void;
37+
}
38+
39+
export default (TurboModuleRegistry.get<Spec>(
40+
'NativePerformanceObserverCxx',
41+
): ?Spec);
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @format
8+
* @flow strict
9+
*/
10+
11+
import type {
12+
RawPerformanceEntry,
13+
RawPerformanceEntryType,
14+
} from './NativePerformanceObserver';
15+
16+
import warnOnce from '../Utilities/warnOnce';
17+
import NativePerformanceObserver from './NativePerformanceObserver';
18+
19+
export type HighResTimeStamp = number;
20+
// TODO: Extend once new types (such as event) are supported.
21+
// TODO: Get rid of the "undefined" once there is at least one type supported.
22+
export type PerformanceEntryType = 'undefined';
23+
24+
export class PerformanceEntry {
25+
name: string;
26+
entryType: PerformanceEntryType;
27+
startTime: HighResTimeStamp;
28+
duration: number;
29+
30+
constructor(init: {
31+
name: string,
32+
entryType: PerformanceEntryType,
33+
startTime: HighResTimeStamp,
34+
duration: number,
35+
}) {
36+
this.name = init.name;
37+
this.entryType = init.entryType;
38+
this.startTime = init.startTime;
39+
this.duration = init.duration;
40+
}
41+
42+
// $FlowIgnore: Flow(unclear-type)
43+
toJSON(): Object {
44+
return {
45+
name: this.name,
46+
entryType: this.entryType,
47+
startTime: this.startTime,
48+
duration: this.duration,
49+
};
50+
}
51+
}
52+
53+
function rawToPerformanceEntryType(
54+
type: RawPerformanceEntryType,
55+
): PerformanceEntryType {
56+
return 'undefined';
57+
}
58+
59+
function rawToPerformanceEntry(entry: RawPerformanceEntry): PerformanceEntry {
60+
return new PerformanceEntry({
61+
name: entry.name,
62+
entryType: rawToPerformanceEntryType(entry.entryType),
63+
startTime: entry.startTime,
64+
duration: entry.duration,
65+
});
66+
}
67+
68+
export type PerformanceEntryList = $ReadOnlyArray<PerformanceEntry>;
69+
70+
export class PerformanceObserverEntryList {
71+
_entries: PerformanceEntryList;
72+
73+
constructor(entries: PerformanceEntryList) {
74+
this._entries = entries;
75+
}
76+
77+
getEntries(): PerformanceEntryList {
78+
return this._entries;
79+
}
80+
81+
getEntriesByType(type: PerformanceEntryType): PerformanceEntryList {
82+
return this._entries.filter(entry => entry.entryType === type);
83+
}
84+
85+
getEntriesByName(
86+
name: string,
87+
type?: PerformanceEntryType,
88+
): PerformanceEntryList {
89+
if (type === undefined) {
90+
return this._entries.filter(entry => entry.name === name);
91+
} else {
92+
return this._entries.filter(
93+
entry => entry.name === name && entry.entryType === type,
94+
);
95+
}
96+
}
97+
}
98+
99+
export type PerformanceObserverCallback = (
100+
list: PerformanceObserverEntryList,
101+
observer: PerformanceObserver,
102+
) => void;
103+
104+
export type PerformanceObserverInit =
105+
| {
106+
entryTypes: Array<PerformanceEntryType>,
107+
}
108+
| {
109+
type: PerformanceEntryType,
110+
};
111+
112+
let _observedEntryTypeRefCount: Map<PerformanceEntryType, number> = new Map();
113+
114+
let _observers: Set<PerformanceObserver> = new Set();
115+
116+
let _onPerformanceEntryCallbackIsSet: boolean = false;
117+
118+
function warnNoNativePerformanceObserver() {
119+
warnOnce(
120+
'missing-native-performance-observer',
121+
'Missing native implementation of PerformanceObserver',
122+
);
123+
}
124+
125+
/**
126+
* Implementation of the PerformanceObserver interface for RN,
127+
* corresponding to the standard in https://www.w3.org/TR/performance-timeline/
128+
*
129+
* @example
130+
* const observer = new PerformanceObserver((list, _observer) => {
131+
* const entries = list.getEntries();
132+
* entries.forEach(entry => {
133+
* reportEvent({
134+
* eventName: entry.name,
135+
* startTime: entry.startTime,
136+
* endTime: entry.startTime + entry.duration,
137+
* processingStart: entry.processingStart,
138+
* processingEnd: entry.processingEnd,
139+
* interactionId: entry.interactionId,
140+
* });
141+
* });
142+
* });
143+
* observer.observe({ type: "event" });
144+
*/
145+
export default class PerformanceObserver {
146+
_callback: PerformanceObserverCallback;
147+
_entryTypes: $ReadOnlySet<PerformanceEntryType>;
148+
149+
constructor(callback: PerformanceObserverCallback) {
150+
this._callback = callback;
151+
}
152+
153+
observe(options: PerformanceObserverInit) {
154+
if (!NativePerformanceObserver) {
155+
warnNoNativePerformanceObserver();
156+
return;
157+
}
158+
if (!_onPerformanceEntryCallbackIsSet) {
159+
NativePerformanceObserver.setOnPerformanceEntryCallback(
160+
onPerformanceEntry,
161+
);
162+
_onPerformanceEntryCallbackIsSet = true;
163+
}
164+
if (options.entryTypes) {
165+
this._entryTypes = new Set(options.entryTypes);
166+
} else {
167+
this._entryTypes = new Set([options.type]);
168+
}
169+
this._entryTypes.forEach(type => {
170+
if (!_observedEntryTypeRefCount.has(type)) {
171+
NativePerformanceObserver.startReporting(type);
172+
}
173+
_observedEntryTypeRefCount.set(
174+
type,
175+
(_observedEntryTypeRefCount.get(type) ?? 0) + 1,
176+
);
177+
});
178+
_observers.add(this);
179+
}
180+
181+
disconnect(): void {
182+
if (!NativePerformanceObserver) {
183+
warnNoNativePerformanceObserver();
184+
return;
185+
}
186+
this._entryTypes.forEach(type => {
187+
const entryTypeRefCount = _observedEntryTypeRefCount.get(type) ?? 0;
188+
if (entryTypeRefCount === 1) {
189+
_observedEntryTypeRefCount.delete(type);
190+
NativePerformanceObserver.stopReporting(type);
191+
} else if (entryTypeRefCount !== 0) {
192+
_observedEntryTypeRefCount.set(type, entryTypeRefCount - 1);
193+
}
194+
});
195+
_observers.delete(this);
196+
if (_observers.size === 0) {
197+
NativePerformanceObserver.setOnPerformanceEntryCallback(undefined);
198+
_onPerformanceEntryCallbackIsSet = false;
199+
}
200+
}
201+
202+
static supportedEntryTypes: $ReadOnlyArray<PerformanceEntryType> =
203+
// TODO: add types once they are fully supported
204+
Object.freeze([]);
205+
}
206+
207+
// This is a callback that gets scheduled and periodically called from the native side
208+
function onPerformanceEntry() {
209+
if (!NativePerformanceObserver) {
210+
return;
211+
}
212+
const rawEntries = NativePerformanceObserver.getPendingEntries();
213+
const entries = rawEntries.map(rawToPerformanceEntry);
214+
_observers.forEach(observer => {
215+
const entriesForObserver: PerformanceEntryList = entries.filter(entry =>
216+
observer._entryTypes.has(entry.entryType),
217+
);
218+
observer._callback(
219+
new PerformanceObserverEntryList(entriesForObserver),
220+
observer,
221+
);
222+
});
223+
}

0 commit comments

Comments
 (0)