|
| 1 | +class AndroidEnvelopeWorker extends WorkerIsolate { |
| 2 | + AndroidEnvelopeWorker(super.config); |
| 3 | + |
| 4 | + static Future<SendPort> spawn(WorkerConfig config) async { |
| 5 | + // 1) Create a ReceivePort the worker can talk to immediately. |
| 6 | + final init = ReceivePort(); |
| 7 | + |
| 8 | + // 2) Pass BOTH the config and init.sendPort into the isolate. |
| 9 | + await Isolate.spawn<(WorkerConfig, SendPort)>( |
| 10 | + AndroidEnvelopeWorker.entryPoint, |
| 11 | + (config, init.sendPort), |
| 12 | + debugName: 'SentryAndroidEnvelopeWorker', |
| 13 | + ); |
| 14 | + |
| 15 | + // 3) First message from worker is its inbox SendPort. |
| 16 | + final SendPort workerInbox = await init.first as SendPort; |
| 17 | + return workerInbox; |
| 18 | + } |
| 19 | + |
| 20 | + void startMessageLoop() { |
| 21 | + final receivePort = ReceivePort(); |
| 22 | + |
| 23 | + // Handshake: tell host how to send messages to this worker. |
| 24 | + hostPort.send(receivePort.sendPort); |
| 25 | + |
| 26 | + receivePort.listen((message) { |
| 27 | + try { |
| 28 | + processMessage(message); |
| 29 | + } catch (e, st) { |
| 30 | + // sendError(e, st); |
| 31 | + } |
| 32 | + }); |
| 33 | + } |
| 34 | + |
| 35 | + void processMessage(dynamic message) { |
| 36 | + IsolateDiagnosticLog.log(SentryLevel.warning, |
| 37 | + 'EnvelopeWorker invoked; starting captureEnvelope'); |
| 38 | + |
| 39 | + if (message is TransferableTypedData) { |
| 40 | + final envelopeData = message.materialize().asUint8List(); |
| 41 | + _captureEnvelope(envelopeData, false); |
| 42 | + } |
| 43 | + } |
| 44 | + |
| 45 | + void _captureEnvelope( |
| 46 | + Uint8List envelopeData, bool containsUnhandledException) { |
| 47 | + JObject? id; |
| 48 | + JByteArray? byteArray; |
| 49 | + try { |
| 50 | + byteArray = JByteArray.from(envelopeData); |
| 51 | + id = native.InternalSentrySdk.captureEnvelope( |
| 52 | + byteArray, containsUnhandledException); |
| 53 | + |
| 54 | + if (id == null) { |
| 55 | + IsolateDiagnosticLog.log(SentryLevel.error, |
| 56 | + 'Native Android SDK returned null id when capturing envelope'); |
| 57 | + } |
| 58 | + } catch (exception, stackTrace) { |
| 59 | + IsolateDiagnosticLog.log(SentryLevel.error, 'Failed to capture envelope', |
| 60 | + exception: exception, stackTrace: stackTrace); |
| 61 | + // if (options.automatedTestMode) { |
| 62 | + // rethrow; |
| 63 | + // } |
| 64 | + } finally { |
| 65 | + byteArray?.release(); |
| 66 | + id?.release(); |
| 67 | + } |
| 68 | + } |
| 69 | + |
| 70 | + void send(Object message) => hostPort.send(message); |
| 71 | + |
| 72 | + static void entryPoint((WorkerConfig, SendPort) args) { |
| 73 | + final (config, hostPort) = args; |
| 74 | + |
| 75 | + final level = config.environment['logLevel'] as SentryLevel; |
| 76 | + final debug = config.environment['debug'] as bool; |
| 77 | + IsolateDiagnosticLog.configure(debug: debug, level: level); |
| 78 | + IsolateDiagnosticLog.log( |
| 79 | + SentryLevel.warning, 'AndroidEnvelopeWorker started'); |
| 80 | + |
| 81 | + // Construct worker with the hostPort we just received. |
| 82 | + final worker = AndroidEnvelopeWorker(config); |
| 83 | + |
| 84 | + // Start loop and complete the handshake by sending our inbox SendPort. |
| 85 | + final receivePort = ReceivePort(); |
| 86 | + hostPort.send(receivePort.sendPort); // <- completes init.first in spawn() |
| 87 | + |
| 88 | + // Option A: reuse startMessageLoop’s listener: |
| 89 | + receivePort.listen(worker.processMessage); |
| 90 | + |
| 91 | + // Option B: if you prefer your existing method, you can: |
| 92 | + // worker.startMessageLoop(); |
| 93 | + // but then remove the duplicate handshake above from startMessageLoop, or |
| 94 | + // let startMessageLoop accept the already-created receivePort. |
| 95 | + } |
| 96 | +} |
0 commit comments