[Android] Expose IDataViewer as public Java API - #1534
KartikDhawaniya wants to merge 4 commits into
Conversation
|
@microsoft-github-policy-service agree company="Microsoft" |
There was a problem hiding this comment.
🟡 Changes recommended
The public interface change breaks source compatibility, and callback lifecycle documentation and unregistration coverage need correction.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Adds a public Android/JNI bridge for registering product-owned IDataViewer implementations.
Changes:
- Adds the Java callback API and LogManager registration methods.
- Implements JNI proxy lifecycle, callback forwarding, and cleanup.
- Adds shrinker rules and instrumentation coverage.
File summaries
| File | Description |
|---|---|
lib/jni/LogManager_jni.cpp |
Manages viewer registration and cleanup. |
lib/jni/JavaDataViewerProxy.hpp |
Declares the JNI viewer proxy. |
lib/jni/JavaDataViewerProxy.cpp |
Implements Java callback forwarding. |
lib/CMakeLists.txt |
Builds the new proxy source. |
lib/android_build/maesdk/src/main/java/com/microsoft/applications/events/LogManagerProvider.java |
Implements Java registration APIs. |
lib/android_build/maesdk/src/main/java/com/microsoft/applications/events/ILogManager.java |
Exposes registration publicly. |
lib/android_build/maesdk/src/main/java/com/microsoft/applications/events/IDataViewer.java |
Defines the callback contract. |
lib/android_build/maesdk/consumer-rules.pro |
Preserves reverse-JNI callback methods. |
lib/android_build/app/src/androidTest/java/com/microsoft/applications/events/maesdktest/LogManagerDDVUnitTest.java |
Tests registration and dispatch behavior. |
Review details
- Files reviewed: 9/9 changed files
- Comments generated: 3
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| * Callbacks can occur on an SDK worker thread and should return promptly. Implementations must not | ||
| * register or unregister viewers from within a callback. |
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
103ad8e to
866832b
Compare
|
I reviewed whether this API is necessary and proportionate. The capability is justified, but the PR should not merge unchanged. Android currently has no Java mechanism for registering a product-owned implementation of the native The JNI bridge is therefore a reasonable direction, but the existing inline findings are merge blockers:
With those addressed, the scope is proportionate to the demonstrated gap. |
Preserves source compatibility, fixes reentrant dispatch, and strengthens the unregistration test. registerDataViewer and unregisterDataViewer become default methods on ILogManager returning false. Adding abstract methods to a public interface would break every consumer-owned implementation and test double on upgrade, despite the change being additive in intent. LogManagerImpl overrides both, so the native path is unaffected. DispatchDataViewerEvent now iterates a snapshot of the viewer collection rather than the member vector. m_dataViewerMapLock is recursive, so a viewer that reenters the SDK from ReceiveData - closing the owning LogManager, which unregisters every viewer - was admitted back in and erased the vector while dispatch was still walking it, invalidating the iterator. Exposing IDataViewer to arbitrary Java implementations makes that reachable from outside the SDK, so the hazard is fixed rather than only documented. Holding shared_ptr copies also keeps each viewer alive across its own callback. The IDataViewer contract now prohibits closing the owning manager from a callback, and a unit test covers a viewer that unregisters everything from ReceiveData. The instrumentation test asserted only the native return value of unregisterDataViewer, so a bridge that dropped its bookkeeping entry but left the proxy registered in DataViewerCollection would have passed. It now drives a second dispatch after unregistering, using the still registered throwing viewer as the witness that a dispatch really occurred, and asserts the unregistered viewer's callback count does not increase. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
IDataViewer returns the endpoint by const reference, so the referent must outlive the call and must not be mutated while a caller holds it. The proxy updated a shared member under a mutex and then returned a reference to it, releasing the lock on return: two concurrent callers could read and write the same string at once, so the mutex gave no protection. Use a thread_local buffer instead, which gives each calling thread its own storage and removes the need for the lock. Behaviour is unchanged: the endpoint is still read from Java on every call, so a viewer that changes endpoints still reports the current one. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Callback dispatch can deadlock through inverted locks, and JNI allocation failures can leave pending exceptions uncleared.
Get a fresh assessment by requesting another Copilot review.
Review effort: Balanced
Findings: 1
Open (3)
| // erase from the very vector being iterated here and invalidate the iterator. | ||
| // Holding shared_ptr copies additionally keeps each viewer alive for the duration of | ||
| // its own callback, even if that callback drops the last other reference to it. | ||
| const auto viewers = m_dataViewerCollection; |
| } | ||
|
|
||
| auto packet = env->NewByteArray(static_cast<jsize>(packetData.size())); | ||
| if (packet == nullptr || ClearPendingException(env, "receiveData allocation")) |



Summary
Expose the native 1DS
IDataViewerextension point through the Android Java/JNI API so Android consumers can register a product-owned viewer without changing the bundledDefaultDataViewerimplementation.This enables consumers such as Teams Android to keep broad Network Security Configuration cleartext traffic disabled while owning any product-specific diagnostic transport outside the SDK.
Changes
IDataViewercallback contract.registerDataViewerandunregisterDataViewertoILogManagerandLogManagerProvider.LogManagerImpl.IDataViewerproxy that:byte[];Scope
This is an additive Android API bridge over the existing native extension point. It does not change:
DefaultDataViewerAPIs; orValidation
:maesdk:assembleDebug:app:compileDebugAndroidTestJavaWithJavacarm64-v8a,armeabi-v7a,x86, andx86_64The instrumentation test was compiled but not executed because no Android device was connected.