Skip to content

Commit 5c749b9

Browse files
committed
android: make native telemetry validation reliable
Initialize the private native test SDK with Android HTTP, Room, PAL, and cache-path state so tests exercise valid platform services without cross-library JNI callbacks. Harden Android HTTP singleton lifetime and cancellation results; fail explicitly when the default client is unavailable. Validate batched disk records consistently, use writable session-test paths, and fix epoll and Android PAL JNI defects exposed by the full device run. Files changed: Android test bridge/configuration, HttpClient_Android, LogManagerImpl, OfflineStorageHandler, Android PAL, and related unit tests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: c4cfcad8-1637-4e46-86cf-6bf200244b04
1 parent ccf5896 commit 5c749b9

14 files changed

Lines changed: 117 additions & 60 deletions

File tree

‎lib/android_build/app/src/androidTest/java/com/microsoft/applications/events/maesdktest/SDKUnitNativeTest.java‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,8 @@ public void runNativeTests() {
260260
OfflineRoom.connectContext(appContext);
261261

262262
TestStub stub = new TestStub();
263-
int result = stub.runNativeTests(this);
263+
int result =
264+
stub.runNativeTests(this, client, appContext, System.getProperty("java.io.tmpdir"));
264265
assertEquals(0, result);
265266
Log.i("MAE", "Test finished");
266267
}

‎lib/android_build/app/src/main/cpp/native-lib.cpp‎

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010

1111
#include "LogManager.hpp"
1212
#include "api/LogManagerImpl.hpp"
13+
#include "config/RuntimeConfig_Default.hpp"
14+
#include "http/HttpClient_Android.hpp"
15+
#include "offline/OfflineStorage_Room.hpp"
16+
#include "pal/PAL.hpp"
1317

1418
LOGMANAGER_INSTANCE
1519

@@ -114,13 +118,14 @@ int RunTests::run_all_tests(JNIEnv* env, jobject java_logger)
114118
{
115119
int argc = 2;
116120
char command_name[] = "maesdk-test";
117-
char filter[] = "--gtest_filter=*";
121+
// Java HTTP callbacks target the AAR's shared SDK, not this test binary's
122+
// private static SDK copy. Exercise that transport through instrumentation.
123+
char filter[] = "--gtest_filter=-HttpClientTests.*";
118124
char* argv[] = {command_name, filter};
119125
::testing::InitGoogleTest(&argc, argv);
120126
::testing::TestEventListeners& listeners =
121127
::testing::UnitTest::GetInstance()->listeners();
122128
listeners.Append(new AndroidLogger(env, java_logger));
123-
auto logger = Microsoft::Applications::Events::LogManager::Initialize("0123456789abcdef0123456789abcdef-01234567-0123-0123-0123-0123456789ab-0123");
124129
return RUN_ALL_TESTS();
125130
}
126131

@@ -129,9 +134,27 @@ extern "C" JNIEXPORT jint JNICALL
129134
Java_com_microsoft_applications_events_maesdktest_TestStub_runNativeTests(
130135
JNIEnv* env,
131136
jobject /* stub */,
132-
jobject logger)
137+
jobject logger,
138+
jobject http_client,
139+
jobject app_context,
140+
jstring cache_file_path)
133141
{
134-
return RunTests::run_all_tests(env, logger);
142+
auto path = env->GetStringUTFChars(cache_file_path, nullptr);
143+
Microsoft::Applications::Events::HttpClient_Android::SetCacheFilePath(path);
144+
env->ReleaseStringUTFChars(cache_file_path, path);
145+
Microsoft::Applications::Events::HttpClient_Android::CreateClientInstance(env, http_client);
146+
Microsoft::Applications::Events::OfflineStorage_Room::ConnectJVM(env, app_context);
147+
148+
JavaVM* java_vm = nullptr;
149+
env->GetJavaVM(&java_vm);
150+
Microsoft::Applications::Events::ILogConfiguration pal_config;
151+
pal_config[CFG_PTR_ANDROID_JVM] = static_cast<void*>(java_vm);
152+
pal_config[CFG_JOBJECT_ANDROID_ACTIVITY] = reinterpret_cast<void*>(app_context);
153+
Microsoft::Applications::Events::RuntimeConfig_Default runtime_config(pal_config);
154+
PAL::GetPAL().initialize(runtime_config);
155+
const int result = RunTests::run_all_tests(env, logger);
156+
PAL::GetPAL().shutdown();
157+
return result;
135158
}
136159

137160

@@ -154,4 +177,3 @@ Java_com_microsoft_applications_events_maesdktest_SDKUnitNativeTest_nativeGetDat
154177
auto property = GetEventProperty(env, jProperty);
155178
return static_cast<int>(property.dataCategory);
156179
}
157-

‎lib/android_build/app/src/main/java/com/microsoft/applications/events/maesdktest/MainActivity.java‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ protected void onCreate(Bundle savedInstanceState) {
4444
// Example of a call to a native method
4545
TextView tv = findViewById(R.id.sample_text);
4646
try {
47-
Integer result = testStub.executorRun(dummyLogger);
47+
Integer result =
48+
testStub.executorRun(dummyLogger, m_client, getApplicationContext());
4849
tv.setText(String.format(Locale.ROOT, "Tests returned %d", result));
4950
} catch (ExecutionException e) {
5051
tv.setText("Woopsy");
@@ -53,4 +54,3 @@ protected void onCreate(Bundle savedInstanceState) {
5354
}
5455
}
5556
}
56-

‎lib/android_build/app/src/main/java/com/microsoft/applications/events/maesdktest/TestStub.java‎

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
//
55
package com.microsoft.applications.events.maesdktest;
66

7+
import android.content.Context;
8+
import com.microsoft.applications.events.HttpClient;
79
import java.util.concurrent.Callable;
810
import java.util.concurrent.ExecutionException;
911
import java.util.concurrent.ExecutorService;
@@ -13,9 +15,13 @@
1315
public class TestStub {
1416
class CallTests implements Callable<Integer> {
1517
MaeUnitLogger logger;
18+
HttpClient httpClient;
19+
Context appContext;
1620

17-
CallTests(MaeUnitLogger logger) {
21+
CallTests(MaeUnitLogger logger, HttpClient httpClient, Context appContext) {
1822
this.logger = logger;
23+
this.httpClient = httpClient;
24+
this.appContext = appContext;
1925
}
2026

2127
/**
@@ -26,17 +32,21 @@ class CallTests implements Callable<Integer> {
2632
*/
2733
@Override
2834
public Integer call() throws Exception {
29-
return Integer.valueOf(runNativeTests(logger));
35+
return Integer.valueOf(
36+
runNativeTests(logger, httpClient, appContext, System.getProperty("java.io.tmpdir")));
3037
}
3138
}
3239

33-
public Integer executorRun(MaeUnitLogger logger) throws ExecutionException, InterruptedException {
40+
public Integer executorRun(MaeUnitLogger logger, HttpClient httpClient, Context appContext)
41+
throws ExecutionException, InterruptedException {
3442
ExecutorService executorService = Executors.newFixedThreadPool(2);
3543

36-
FutureTask<Integer> tests = new FutureTask<Integer>(new CallTests(logger));
44+
FutureTask<Integer> tests =
45+
new FutureTask<Integer>(new CallTests(logger, httpClient, appContext));
3746
executorService.execute(tests);
3847
return tests.get();
3948
}
4049

41-
public native int runNativeTests(MaeUnitLogger logger);
50+
public native int runNativeTests(
51+
MaeUnitLogger logger, HttpClient httpClient, Context appContext, String cacheFilePath);
4252
}

‎lib/android_build/maesdk/src/main/java/com/microsoft/applications/events/LogConfigurationKey.java‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ public enum LogConfigurationKey {
2323
/** Enable database compression. */
2424
CFG_BOOL_ENABLE_DB_COMPRESS("enableDBCompression", Boolean.class),
2525

26+
/** Batch records when flushing the RAM queue to disk storage. */
27+
CFG_BOOL_ENABLE_BATCHED_STORAGE_FLUSH("enableBatchedStorageFlush", Boolean.class),
28+
2629
/** Enable WAL journal. */
2730
CFG_BOOL_ENABLE_WAL_JOURNAL("enableWALJournal", Boolean.class),
2831

@@ -187,4 +190,3 @@ public Class getValueType() {
187190
return valueType;
188191
}
189192
}
190-

‎lib/api/LogManagerImpl.cpp‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,11 @@ namespace MAT_NS_BEGIN
294294
if (m_httpClient == nullptr)
295295
{
296296
m_httpClient = HttpClientFactory::Create();
297+
if (m_httpClient == nullptr)
298+
{
299+
LOG_ERROR("The default HTTP client has not been initialized.");
300+
MATSDK_THROW(std::invalid_argument("configuration"));
301+
}
297302
m_httpClient->ApplySettings(m_logConfiguration);
298303
}
299304
else

‎lib/http/HttpClient_Android.cpp‎

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,7 @@ namespace MAT_NS_BEGIN
283283
if (request->m_callback)
284284
{
285285
auto failure = new HttpResponse(request->m_id);
286+
failure->SetResult(HttpResult_Aborted);
286287
request->m_callback->OnHttpResponse(failure);
287288
}
288289
}
@@ -441,19 +442,27 @@ namespace MAT_NS_BEGIN
441442
jobject java_client)
442443
{
443444
auto client = std::make_shared<HttpClient_Android>();
444-
s_client = client;
445-
446445
client->SetClient(env, java_client);
446+
447+
std::lock_guard<std::mutex> lock(s_clientMutex);
448+
s_client = std::move(client);
447449
}
448450

449451
void HttpClient_Android::SetJavaVM(JavaVM* vm)
450452
{
451453
HttpClient_Android::s_java_vm = vm;
452454
}
453455

454-
void HttpClient_Android::DeleteClientInstance(JNIEnv* env)
456+
void HttpClient_Android::DeleteClientInstance(JNIEnv* env, jobject java_client)
455457
{
456-
s_client.reset();
458+
std::shared_ptr<HttpClient_Android> client;
459+
{
460+
std::lock_guard<std::mutex> lock(s_clientMutex);
461+
if (s_client && env->IsSameObject(s_client->m_client, java_client))
462+
{
463+
client = std::move(s_client);
464+
}
465+
}
457466
}
458467

459468
void HttpClient_Android::SetCacheFilePath(std::string&& path)
@@ -471,7 +480,8 @@ namespace MAT_NS_BEGIN
471480
std::shared_ptr<HttpClient_Android>
472481
HttpClient_Android::GetClientInstance()
473482
{
474-
return std::shared_ptr<HttpClient_Android>(s_client);
483+
std::lock_guard<std::mutex> lock(s_clientMutex);
484+
return s_client;
475485
}
476486

477487
bool HttpClient_Android::CheckException(JNIEnv* env, HttpRequest* request)
@@ -486,6 +496,7 @@ namespace MAT_NS_BEGIN
486496
return true;
487497
}
488498

499+
std::mutex HttpClient_Android::s_clientMutex;
489500
std::shared_ptr<HttpClient_Android> HttpClient_Android::s_client;
490501
std::string HttpClient_Android::s_cache_file_path;
491502

@@ -504,9 +515,10 @@ extern "C" JNIEXPORT void
504515
extern "C" JNIEXPORT void
505516

506517
JNICALL
507-
Java_com_microsoft_applications_events_HttpClient_deleteClientInstance(JNIEnv* env)
518+
Java_com_microsoft_applications_events_HttpClient_deleteClientInstance(JNIEnv* env,
519+
jobject java_client)
508520
{
509-
Microsoft::Applications::Events::HttpClient_Android::DeleteClientInstance(env);
521+
Microsoft::Applications::Events::HttpClient_Android::DeleteClientInstance(env, java_client);
510522
}
511523

512524
extern "C" JNIEXPORT void

‎lib/http/HttpClient_Android.hpp‎

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,7 @@ namespace MAT_NS_BEGIN
3838

3939
HttpResult GetResult() const override
4040
{
41-
switch (m_response)
42-
{
43-
case 0:
44-
return HttpResult_LocalFailure;
45-
case -1:
46-
return HttpResult_NetworkFailure;
47-
default:
48-
return HttpResult_OK;
49-
}
41+
return m_result;
5042
}
5143

5244
unsigned int GetStatusCode() const override
@@ -67,6 +59,14 @@ namespace MAT_NS_BEGIN
6759
void SetResponse(int response)
6860
{
6961
m_response = response;
62+
m_result = response == 0
63+
? HttpResult_LocalFailure
64+
: response == -1 ? HttpResult_NetworkFailure : HttpResult_OK;
65+
}
66+
67+
void SetResult(HttpResult result)
68+
{
69+
m_result = result;
7070
}
7171

7272
void AddHeader(std::string&& key, std::string&& value)
@@ -84,6 +84,7 @@ namespace MAT_NS_BEGIN
8484
HttpHeaders m_headers;
8585
std::vector<uint8_t, std::allocator<uint8_t>> m_body;
8686
int m_response = 0;
87+
HttpResult m_result = HttpResult_LocalFailure;
8788
};
8889

8990
public:
@@ -186,7 +187,7 @@ namespace MAT_NS_BEGIN
186187

187188
static void CreateClientInstance(JNIEnv* env,
188189
jobject java_client);
189-
static void DeleteClientInstance(JNIEnv* env);
190+
static void DeleteClientInstance(JNIEnv* env, jobject java_client);
190191
static void SetCacheFilePath(std::string&& path);
191192
static const std::string& GetCacheFilePath();
192193
static std::shared_ptr<HttpClient_Android> GetClientInstance();
@@ -204,6 +205,7 @@ namespace MAT_NS_BEGIN
204205
jmethodID m_execute_id = nullptr;
205206
static JavaVM* s_java_vm;
206207
std::atomic<uint64_t> m_id;
208+
static std::mutex s_clientMutex;
207209
static std::shared_ptr<HttpClient_Android> s_client;
208210
static std::string s_cache_file_path;
209211

‎lib/offline/OfflineStorageHandler.cpp‎

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -302,16 +302,26 @@ namespace MAT_NS_BEGIN {
302302
recordsToRecover.erase(memoryOnlyBegin, recordsToRecover.end());
303303
ReturnRecordsToMemory(memoryOnlyRecords);
304304

305+
recordsToRecover.erase(
306+
std::remove_if(recordsToRecover.begin(), recordsToRecover.end(),
307+
[this](StorageRecord const& record)
308+
{
309+
if (IsValidDiskStorageRecord(record))
310+
{
311+
return false;
312+
}
313+
ReportInvalidDiskRecord(record);
314+
return true;
315+
}),
316+
recordsToRecover.end());
317+
305318
const size_t batchSaved = recordsToRecover.empty()
306319
? 0
307320
: m_offlineStorageDisk->StoreRecords(recordsToRecover);
308-
// StoreRecords() removes permanently-invalid records before
309-
// returning, so compare against the remaining valid records.
310-
const size_t validBatchSize = recordsToRecover.size();
311-
if (batchSaved != validBatchSize)
321+
if (batchSaved != recordsToRecover.size())
312322
{
313323
LOG_WARN("Flush: disk store failed for the batch of %zu records; returning it to the queue for retry",
314-
validBatchSize);
324+
recordsToRecover.size());
315325
ReturnRecordsToMemory(recordsToRecover);
316326
recordsToRecover.clear();
317327
break;

‎lib/pal/posix/SystemInformationImpl_Android.cpp‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,10 @@ namespace PAL_NS_BEGIN {
7575
jmethodID getDefaultLocaleMid = pEnv->GetStaticMethodID(localeClass, "getDefault", "()Ljava/util/Locale;");
7676

7777
// public abstract Resources getResources ()
78-
jmethodID getResourceMid = pEnv->GetMethodID(contextClass, "getResources", "()Landroid/content/res/Resources");
78+
jmethodID getResourceMid = pEnv->GetMethodID(contextClass, "getResources", "()Landroid/content/res/Resources;");
7979

8080
// public abstract Configuration getConfiguration ()
81-
jmethodID getConfigurationMid = pEnv->GetMethodID(resourcesClass, "getConfiguration", "()Landroid/content/res/Configuration");
81+
jmethodID getConfigurationMid = pEnv->GetMethodID(resourcesClass, "getConfiguration", "()Landroid/content/res/Configuration;");
8282

8383
// public abstract boolean isLayoutSizeAtLeast (int layoutSize)
8484
jmethodID isLayoutSizeAtLeastMid = pEnv->GetMethodID(configurationClass, "isLayoutSizeAtLeast", "(I)Z");

0 commit comments

Comments
 (0)