Native test for qtaguid module

Add a native test to check the qtaguid module nolonger hold the fd of a
closed socket. The test does not work in java because android framework
will force untag the socket before closing it.

Bug: 36374484
Test: run this test as CTS test and all devices should pass
Signed-off-by: Chenbo Feng <fengc@google.com>
Change-Id: I9e015d412d1aec10d843dfee4b480169d1f6ff8e
diff --git a/tests/tests/net/native/Android.mk b/tests/tests/net/native/Android.mk
new file mode 100644
index 0000000..b798d87
--- /dev/null
+++ b/tests/tests/net/native/Android.mk
@@ -0,0 +1,15 @@
+# Copyright (C) 2017 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.
+
+include $(call all-subdir-makefiles)
diff --git a/tests/tests/net/native/qtaguid/Android.mk b/tests/tests/net/native/qtaguid/Android.mk
new file mode 100644
index 0000000..fed8520
--- /dev/null
+++ b/tests/tests/net/native/qtaguid/Android.mk
@@ -0,0 +1,43 @@
+# Copyright (C) 2017 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.
+
+# Build the unit tests.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := CtsNativeNetTestCases
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativetest
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+
+LOCAL_SRC_FILES := \
+    src/NativeSocketRefCnt.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+    libutils \
+    liblog \
+    libcutils \
+
+LOCAL_STATIC_LIBRARIES := \
+    libgtest
+
+LOCAL_CTS_TEST_PACKAGE := android.net.native
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+
+LOCAL_CFLAGS := -Werror -Wall
+
+include $(BUILD_CTS_EXECUTABLE)
diff --git a/tests/tests/net/native/qtaguid/AndroidTest.xml b/tests/tests/net/native/qtaguid/AndroidTest.xml
new file mode 100644
index 0000000..6f4e8f5
--- /dev/null
+++ b/tests/tests/net/native/qtaguid/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2017 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="Config for CTS Native Network xt_qtaguid test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+        <option name="cleanup" value="true" />
+        <option name="push" value="CtsNativeNetTestCases->/data/local/tmp/CtsNativeNetTestCases" />
+        <option name="append-bitness" value="true" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="CtsNativeNetTestCases" />
+        <option name="runtime-hint" value="1m" />
+    </test>
+</configuration>
diff --git a/tests/tests/net/native/qtaguid/src/NativeSocketRefCnt.cpp b/tests/tests/net/native/qtaguid/src/NativeSocketRefCnt.cpp
new file mode 100644
index 0000000..926a740
--- /dev/null
+++ b/tests/tests/net/native/qtaguid/src/NativeSocketRefCnt.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <string.h>
+#include <sys/socket.h>
+
+#include <gtest/gtest.h>
+#include <cutils/qtaguid.h>
+
+int getCtrlRefCnt(int tag, uid_t uid) {
+    FILE *fp;
+    fp = fopen("/proc/net/xt_qtaguid/ctrl", "r");
+    if (!fp)
+        return -ENOENT;
+    uint64_t full_tag = (uint64_t)tag << 32 | uid;
+    char pattern[40];
+    snprintf(pattern, sizeof(pattern), " tag=0x%" PRIx64 " (uid=%" PRIu32 ")", full_tag, uid);
+
+    size_t len;
+    char *line_buffer = NULL;
+    while(getline(&line_buffer, &len, fp) != -1) {
+        if (strstr(line_buffer, pattern) == NULL)
+            continue;
+        int res;
+        uint32_t ref_cnt;
+        pid_t dummy_pid;
+        uint64_t dummy_sk;
+        uint64_t k_tag;
+        uint32_t k_uid;
+        const int TOTAL_PARAM = 5;
+        res = sscanf(line_buffer, "sock=%" PRIx64 " tag=0x%" PRIx64 " (uid=%" PRIu32 ") "
+                     "pid=%u f_count=%u", &dummy_sk, &k_tag, &k_uid,
+                     &dummy_pid, &ref_cnt);
+        if (!(res == TOTAL_PARAM && k_tag == full_tag && k_uid == uid))
+            res = -EINVAL;
+        res = ref_cnt;
+        free(line_buffer);
+        return res;
+    }
+    free(line_buffer);
+    return -ENOENT;
+}
+
+TEST (NativeSocketRefCnt, close_socket_without_untag) {
+    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
+    uid_t uid = getuid();
+    int tag = arc4random();
+    EXPECT_EQ(0, qtaguid_tagSocket(sockfd, tag, uid));
+    EXPECT_GE(2, getCtrlRefCnt(tag, uid));
+    close(sockfd);
+    EXPECT_EQ(-ENOENT, getCtrlRefCnt(tag, uid));
+}
+
+TEST (NativeSocketRefCnt, close_socket_without_untag_ipv6) {
+    int sockfd = socket(AF_INET6, SOCK_STREAM, 0);
+    uid_t uid = getuid();
+    int tag = arc4random();
+    EXPECT_EQ(0, qtaguid_tagSocket(sockfd, tag, uid));
+    EXPECT_GE(2, getCtrlRefCnt(tag, uid));
+    close(sockfd);
+    EXPECT_EQ(-ENOENT, getCtrlRefCnt(tag, uid));
+}
+
+int main(int argc, char **argv) {
+      testing::InitGoogleTest(&argc, argv);
+
+      return RUN_ALL_TESTS();
+}