From 8842c12a3bcad1578eed81643c38ef3d7903dbff Mon Sep 17 00:00:00 2001 From: Bhagirath Mehta Date: Fri, 12 Jun 2026 08:59:06 -0500 Subject: [PATCH 1/3] android: initialize EventPropertiesStorage.eventType to fix null getType() EventPropertiesStorage's default constructor initialized every member except eventType, so EventProperties.getType() returned null on a freshly constructed object instead of its documented empty-string default (#1329). On Android/Java this surfaced as a NullPointerException for callers. - EventPropertiesStorage(): initialize eventType = "" (matching eventName and the other members). - EventsUnitTest: add newEventPropertiesGetTypeReturnsEmptyString as a regression test (getType() on a new EventProperties is non-null and ""). Resolves #1329. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../applications/events/EventPropertiesStorage.java | 1 + .../microsoft/applications/events/EventsUnitTest.java | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/lib/android_build/maesdk/src/main/java/com/microsoft/applications/events/EventPropertiesStorage.java b/lib/android_build/maesdk/src/main/java/com/microsoft/applications/events/EventPropertiesStorage.java index b5b7929e8..9641caa67 100644 --- a/lib/android_build/maesdk/src/main/java/com/microsoft/applications/events/EventPropertiesStorage.java +++ b/lib/android_build/maesdk/src/main/java/com/microsoft/applications/events/EventPropertiesStorage.java @@ -21,6 +21,7 @@ class EventPropertiesStorage { EventPropertiesStorage() { eventName = ""; + eventType = ""; eventLatency = EventLatency.Normal; eventPersistence = EventPersistence.Normal; eventPopSample = 100; diff --git a/lib/android_build/maesdk/src/test/java/com/microsoft/applications/events/EventsUnitTest.java b/lib/android_build/maesdk/src/test/java/com/microsoft/applications/events/EventsUnitTest.java index 24bfa90ea..0f346877c 100644 --- a/lib/android_build/maesdk/src/test/java/com/microsoft/applications/events/EventsUnitTest.java +++ b/lib/android_build/maesdk/src/test/java/com/microsoft/applications/events/EventsUnitTest.java @@ -390,4 +390,15 @@ public void requestException() throws java.io.IOException, PackageManager.NameNo } } + @Test + public void newEventPropertiesGetTypeReturnsEmptyString() { + // Regression test for #1329: getType() on a freshly constructed + // EventProperties must return its documented default of "" (an empty + // string), not null -- EventPropertiesStorage previously left eventType + // uninitialized. + EventProperties props = new EventProperties("MyEvent", DiagnosticLevel.DIAG_LEVEL_OPTIONAL); + assertNotNull(props.getType()); + assertEquals("", props.getType()); + } + } From a332db7d9ddefe6d02a7ba0f797ab50b55d676fa Mon Sep 17 00:00:00 2001 From: Bhagirath Mehta Date: Sat, 13 Jun 2026 16:50:21 -0500 Subject: [PATCH 2/3] Don't forward an empty event type to native SetType (Android) Code review of the #1329 fix found a native-path regression. Making Java getType() return "" (instead of null) fixes the Java-side NPE, but the JNI converter forwarded the type to native whenever the jstring was non-null: if (jstrEventType != NULL) eventProperties.SetType(JStringToStdString(env, jstrEventType)); Before #1329, getType() returned null for a default EventProperties, so SetType was skipped and native eventType stayed at its "" default. Now the non-null "" reaches native SetType(""), which fails validateEventName (length < 4) and, for EVERY typeless event, logs "Invalid event type!" and broadcasts an EVT_REJECTED DebugEvent to all registered listeners (EventProperties.cpp SetType -> ILManager::DispatchEventBroadcast) -- a false-positive rejection signal indistinguishable from a genuinely rejected event. Fix: in the JNI converter (the sole native SetType chokepoint), treat an empty type as "unset" and only call SetType for a non-empty string, restoring the pre-#1329 native behavior while keeping the corrected Java API contract. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- lib/jni/JniConvertors.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/jni/JniConvertors.cpp b/lib/jni/JniConvertors.cpp index 87b7cb15b..d944ddff8 100644 --- a/lib/jni/JniConvertors.cpp +++ b/lib/jni/JniConvertors.cpp @@ -159,8 +159,17 @@ EventProperties GetEventProperties(JNIEnv* env, const jstring& jstrEventName, co const jobjectArray& jEventPropertyStringKeyArray, const jobjectArray& jEventPropertyValueArray) { EventProperties eventProperties; eventProperties.SetName(JStringToStdString(env, jstrEventName)); - if (jstrEventType != NULL) - eventProperties.SetType(JStringToStdString(env, jstrEventType)); + if (jstrEventType != NULL) { + // An empty type means "unset" (the native default). Before #1329 the + // Java getType() returned null for a default EventProperties, so this + // branch was skipped. getType() now returns "" to fix a Java-side NPE; + // forwarding SetType("") here would fail native event-name validation + // and broadcast a spurious EVT_REJECTED for every typeless event, so + // only set a non-empty type. + std::string eventType = JStringToStdString(env, jstrEventType); + if (!eventType.empty()) + eventProperties.SetType(eventType); + } eventProperties.SetLatency(static_cast(jEventLatency)); eventProperties.SetPersistence(static_cast(jEventPersistence)); eventProperties.SetPopsample(static_cast(jEventPopSample)); From 43b5be81792ae69cbb6c8d4e27a025f82d512f65 Mon Sep 17 00:00:00 2001 From: Bhagirath Mehta Date: Sat, 13 Jun 2026 17:22:20 -0500 Subject: [PATCH 3/3] Address Copilot on #1483: test EventPropertiesStorage directly (no native) The regression test constructed EventProperties, whose constructor calls setName() -> native Utils.validateEventName(). These are JVM unit tests (@RunWith(MockitoJUnitRunner)) with no native library loaded, so it would throw UnsatisfiedLinkError instead of exercising the regression. Test the pure-Java EventPropertiesStorage (same package) directly -- the exact class the #1329 fix initialized (eventType = ""). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../applications/events/EventsUnitTest.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/android_build/maesdk/src/test/java/com/microsoft/applications/events/EventsUnitTest.java b/lib/android_build/maesdk/src/test/java/com/microsoft/applications/events/EventsUnitTest.java index 0f346877c..513354682 100644 --- a/lib/android_build/maesdk/src/test/java/com/microsoft/applications/events/EventsUnitTest.java +++ b/lib/android_build/maesdk/src/test/java/com/microsoft/applications/events/EventsUnitTest.java @@ -391,14 +391,16 @@ public void requestException() throws java.io.IOException, PackageManager.NameNo } @Test - public void newEventPropertiesGetTypeReturnsEmptyString() { - // Regression test for #1329: getType() on a freshly constructed - // EventProperties must return its documented default of "" (an empty - // string), not null -- EventPropertiesStorage previously left eventType - // uninitialized. - EventProperties props = new EventProperties("MyEvent", DiagnosticLevel.DIAG_LEVEL_OPTIONAL); - assertNotNull(props.getType()); - assertEquals("", props.getType()); + public void newEventPropertiesStorageEventTypeDefaultsToEmptyString() { + // Regression test for #1329: EventPropertiesStorage previously left + // eventType uninitialized (null), so EventProperties.getType() (which + // returns mStorage.eventType) returned null instead of its documented + // "" default. Exercise the pure-Java storage directly: constructing an + // EventProperties here would call setName() -> native validateEventName(), + // which is not loaded in these JVM (MockitoJUnitRunner) unit tests. + EventPropertiesStorage storage = new EventPropertiesStorage(); + assertNotNull(storage.eventType); + assertEquals("", storage.eventType); } }