Add tests for null repeated and nested fields in VendorAtom

Atom print logs: https://paste.googleplex.com/5503671994417152

Bug: 237423972
Bug: 237424483
Test: build, flash, and run aidl_stats_client on device
Test: atest VtsAidlHalStatsTargetTest
Test: atest VtsVendorAtomJavaTest
Change-Id: I99523f9f7f57a66d6f10bdaea71dfd8df6efb566
Merged-In: I99523f9f7f57a66d6f10bdaea71dfd8df6efb566
diff --git a/stats/aidl/vts/java/Android.bp b/stats/aidl/vts/java/Android.bp
new file mode 100644
index 0000000..9159c3f
--- /dev/null
+++ b/stats/aidl/vts/java/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+    name: "VtsVendorAtomJavaTest",
+    test_suites: ["device-tests"],
+    srcs: ["VtsVendorAtomJavaTest.java"],
+    static_libs: [
+        "junit",
+        "android.frameworks.stats-V2-java",
+        "compatibility-device-util-axt",
+    ],
+    libs: [
+        "android.test.runner",
+    ],
+}
diff --git a/stats/aidl/vts/java/AndroidManifest.xml b/stats/aidl/vts/java/AndroidManifest.xml
new file mode 100644
index 0000000..ba2a7bd
--- /dev/null
+++ b/stats/aidl/vts/java/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.test.stats">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.test.stats"
+        android:label="Java tests for stats aidl">
+    </instrumentation>
+</manifest>
\ No newline at end of file
diff --git a/stats/aidl/vts/java/AndroidTest.xml b/stats/aidl/vts/java/AndroidTest.xml
new file mode 100644
index 0000000..2c1cd60
--- /dev/null
+++ b/stats/aidl/vts/java/AndroidTest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs VTS stats hal tests.">
+    <option name="test-suite-tag" value="vts" />
+
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="VtsVendorAtomJavaTest.apk" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.test.stats" />
+        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+        <option name="hidden-api-checks" value="false"/>
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/stats/aidl/vts/java/VtsVendorAtomJavaTest.java b/stats/aidl/vts/java/VtsVendorAtomJavaTest.java
new file mode 100644
index 0000000..2c496c3
--- /dev/null
+++ b/stats/aidl/vts/java/VtsVendorAtomJavaTest.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2022 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.stats;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.frameworks.stats.IStats;
+import android.frameworks.stats.VendorAtom;
+import android.frameworks.stats.VendorAtomValue;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+import java.util.NoSuchElementException;
+import java.util.Optional;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class VtsVendorAtomJavaTest {
+    private static final String TAG = "VtsTest";
+    Optional<IStats> statsService;
+
+    @Before
+    public void setUp() {
+        try {
+            final String[] instances = ServiceManager.getDeclaredInstances(IStats.DESCRIPTOR);
+            assertEquals(1, instances.length);
+            assertEquals(instances[0], "default");
+
+            final String instanceName = IStats.DESCRIPTOR + "/default";
+            if (!ServiceManager.isDeclared(instanceName)) {
+                Log.e(TAG, "IStats is not registered");
+                statsService = Optional.empty();
+            } else {
+                statsService = Optional.ofNullable(
+                    IStats.Stub.asInterface(ServiceManager.waitForDeclaredService(instanceName)));
+            }
+            assertTrue(statsService.isPresent());
+        } catch (SecurityException e) {
+            Log.e(TAG, "Failed to connect to IStats service", e);
+        } catch (NullPointerException e) {
+            Log.e(TAG, "Failed to connect to IStats service", e);
+        }
+    }
+
+    /*
+     * Test IStats::reportVendorAtom with all VendorAtomValue types, including empty string in
+     * repeated string array and empty int array.
+     */
+    @Test
+    public void testReportVendorAtom() {
+        VendorAtom atom = new VendorAtom();
+        atom.reverseDomainName = "";
+        atom.atomId = 104999;
+        atom.values = new VendorAtomValue[12];
+
+        atom.values[0] = VendorAtomValue.intValue(7);
+        atom.values[1] = VendorAtomValue.longValue(70000);
+        atom.values[2] = VendorAtomValue.floatValue((float) 8.5);
+        atom.values[3] = VendorAtomValue.stringValue("test");
+        atom.values[4] = VendorAtomValue.boolValue(true);
+        atom.values[5] = VendorAtomValue.repeatedIntValue(new int[] {1, 2});
+        atom.values[6] = VendorAtomValue.repeatedLongValue(new long[] {430000, 500000, 1000001});
+        atom.values[7] =
+            VendorAtomValue.repeatedFloatValue(new float[] {(float) 7.9, (float) 1.2, (float) 5.4});
+        atom.values[8] =
+            VendorAtomValue.repeatedStringValue(new java.lang.String[] {"test1", "", "test2"});
+        atom.values[9] = VendorAtomValue.repeatedIntValue(new int[] {});
+        atom.values[10] = VendorAtomValue.repeatedBoolValue(new boolean[] {false, true});
+        atom.values[11] = VendorAtomValue.byteArrayValue(new byte[] {5, 10, 21});
+
+        try {
+            statsService.get().reportVendorAtom(atom);
+        } catch (NoSuchElementException e) {
+            Log.e(TAG, "Failed to get IStats service", e);
+            fail();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to log atom to IStats service", e);
+            fail();
+        }
+    }
+
+    /*
+     * Test IStats::reportVendorAtom with null fields.
+     */
+    @Test
+    public void testReportVendorAtomNull() {
+        VendorAtom atom = new VendorAtom();
+        atom.reverseDomainName = "";
+        atom.atomId = 104999;
+        atom.values = new VendorAtomValue[9];
+
+        atom.values[0] = VendorAtomValue.intValue(8);
+        atom.values[1] = VendorAtomValue.repeatedIntValue(null);
+        atom.values[2] = VendorAtomValue.repeatedLongValue(null);
+        atom.values[3] = VendorAtomValue.repeatedFloatValue(null);
+        atom.values[4] = VendorAtomValue.repeatedStringValue(null);
+        atom.values[5] =
+            VendorAtomValue.repeatedStringValue(new java.lang.String[] {null, "test2", null});
+        atom.values[6] = VendorAtomValue.repeatedBoolValue(null);
+        atom.values[7] = VendorAtomValue.byteArrayValue(null);
+        atom.values[8] = VendorAtomValue.stringValue("test");
+
+        try {
+            statsService.get().reportVendorAtom(atom);
+        } catch (NoSuchElementException e) {
+            Log.e(TAG, "Failed to get IStats service", e);
+            fail();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to log atom to IStats service", e);
+            fail();
+        }
+    }
+}