Make libincident into a stable C API.

Test: atest GtsIncidentConfirmationTestCases GtsIncidentManagerTestCases libincident_test
Bug: 144187174
Change-Id: I65b5a13cfb6a57aa56f738e25a76c5ecb8e7a1a8
diff --git a/cmds/incident/Android.bp b/cmds/incident/Android.bp
index 9e9dac1..94855aa 100644
--- a/cmds/incident/Android.bp
+++ b/cmds/incident/Android.bp
@@ -26,7 +26,7 @@
         "libcutils",
         "liblog",
         "libutils",
-        "libincident",
+        "libincidentpriv",
     ],
 
     static_libs: [
diff --git a/cmds/incidentd/Android.bp b/cmds/incidentd/Android.bp
index 25e0328..cc724a6 100644
--- a/cmds/incidentd/Android.bp
+++ b/cmds/incidentd/Android.bp
@@ -54,7 +54,7 @@
         "libbinder",
         "libdebuggerd_client",
         "libdumputils",
-        "libincident",
+        "libincidentpriv",
         "liblog",
         "libprotoutil",
         "libservices",
@@ -128,7 +128,7 @@
         "libbinder",
         "libdebuggerd_client",
         "libdumputils",
-        "libincident",
+        "libincidentpriv",
         "liblog",
         "libprotobuf-cpp-full",
         "libprotoutil",
diff --git a/cmds/incidentd/TEST_MAPPING b/cmds/incidentd/TEST_MAPPING
new file mode 100644
index 0000000..f5b0b7a
--- /dev/null
+++ b/cmds/incidentd/TEST_MAPPING
@@ -0,0 +1,13 @@
+{
+  "presubmit": [
+    {
+      "name": "incidentd_test"
+    }
+  ],
+  "postsubmit": [
+  ],
+  "imports": [
+  ]
+}
+
+
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 2237bf2..6f71d97 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -278,7 +278,6 @@
         "tests/e2e/ValueMetric_pull_e2e_test.cpp",
         "tests/e2e/WakelockDuration_e2e_test.cpp",
         "tests/external/GpuStatsPuller_test.cpp",
-        "tests/external/IncidentReportArgs_test.cpp",
         "tests/external/puller_util_test.cpp",
         "tests/external/StatsCallbackPuller_test.cpp",
         "tests/external/StatsPuller_test.cpp",
diff --git a/cmds/statsd/src/subscriber/IncidentdReporter.cpp b/cmds/statsd/src/subscriber/IncidentdReporter.cpp
index d86e291..30c90b1 100644
--- a/cmds/statsd/src/subscriber/IncidentdReporter.cpp
+++ b/cmds/statsd/src/subscriber/IncidentdReporter.cpp
@@ -21,10 +21,8 @@
 #include "packages/UidMap.h"
 #include "stats_log_util.h"
 
-#include <android/os/IIncidentManager.h>
-#include <android/os/IncidentReportArgs.h>
 #include <android/util/ProtoOutputStream.h>
-#include <binder/IServiceManager.h>
+#include <incident/incident_report.h>
 
 #include <vector>
 
@@ -132,7 +130,7 @@
         return false;
     }
 
-    IncidentReportArgs incidentReport;
+    android::os::IncidentReportRequest incidentReport;
 
     vector<uint8_t> protoData;
     getProtoData(rule_id, metricId, dimensionKey, metricValue, configKey,
@@ -146,30 +144,21 @@
     uint8_t dest;
     switch (config.dest()) {
         case IncidentdDetails_Destination_AUTOMATIC:
-            dest = android::os::PRIVACY_POLICY_AUTOMATIC;
+            dest = INCIDENT_REPORT_PRIVACY_POLICY_AUTOMATIC;
             break;
         case IncidentdDetails_Destination_EXPLICIT:
-            dest = android::os::PRIVACY_POLICY_EXPLICIT;
+            dest = INCIDENT_REPORT_PRIVACY_POLICY_EXPLICIT;
             break;
         default:
-            dest = android::os::PRIVACY_POLICY_AUTOMATIC;
+            dest = INCIDENT_REPORT_PRIVACY_POLICY_AUTOMATIC;
     }
     incidentReport.setPrivacyPolicy(dest);
 
-    incidentReport.setReceiverPkg(config.receiver_pkg());
+    incidentReport.setReceiverPackage(config.receiver_pkg());
 
-    incidentReport.setReceiverCls(config.receiver_cls());
+    incidentReport.setReceiverClass(config.receiver_cls());
 
-    sp<IIncidentManager> service = interface_cast<IIncidentManager>(
-            defaultServiceManager()->getService(android::String16("incident")));
-    if (service == nullptr) {
-        ALOGW("Failed to fetch incident service.");
-        return false;
-    }
-    VLOG("Calling incidentd %p", service.get());
-    binder::Status s = service->reportIncident(incidentReport);
-    VLOG("Report incident status: %s", s.toString8().string());
-    return s.isOk();
+    return incidentReport.takeReport() == NO_ERROR;
 }
 
 }  // namespace statsd
diff --git a/libs/incident/Android.bp b/libs/incident/Android.bp
index 150f6dc..512b8c4 100644
--- a/libs/incident/Android.bp
+++ b/libs/incident/Android.bp
@@ -12,8 +12,9 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-cc_library_shared {
-    name: "libincident",
+
+cc_defaults {
+    name: "libincidentpriv_defaults",
 
     cflags: [
         "-Wall",
@@ -50,6 +51,70 @@
         ":libincident_aidl",
         "src/IncidentReportArgs.cpp",
     ],
+}
+
+cc_library_shared {
+    name: "libincidentpriv",
+    defaults: ["libincidentpriv_defaults"],
+    export_include_dirs: ["include_priv"],
+}
+
+cc_library_shared {
+    name: "libincident",
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-missing-field-initializers",
+        "-Wno-unused-variable",
+        "-Wunused-parameter",
+    ],
+
+    shared_libs: [
+        "libbinder",
+        "liblog",
+        "libutils",
+        "libincidentpriv",
+    ],
+
+    srcs: [
+        "src/incident_report.cpp",
+    ],
 
     export_include_dirs: ["include"],
+
+    stubs: {
+        symbol_file: "libincident.map.txt",
+        versions: [
+            "30",
+        ],
+    },
 }
+
+cc_test {
+    name: "libincident_test",
+    defaults: ["libincidentpriv_defaults"],
+    test_suites: ["device-tests"],
+
+    include_dirs: [
+        "frameworks/base/libs/incident/include",
+        "frameworks/base/libs/incident/include_priv",
+    ],
+
+    srcs: [
+        "tests/IncidentReportArgs_test.cpp",
+        "tests/IncidentReportRequest_test.cpp",
+        "tests/c_api_compile_test.c",
+    ],
+
+    shared_libs: [
+        "libincident",
+    ],
+
+    static_libs: [
+        "libgmock",
+    ],
+}
+
+
+
diff --git a/libs/incident/TEST_MAPPING b/libs/incident/TEST_MAPPING
new file mode 100644
index 0000000..b495135
--- /dev/null
+++ b/libs/incident/TEST_MAPPING
@@ -0,0 +1,21 @@
+{
+  "presubmit": [
+    {
+      "name": "libincident_c_api_test"
+    },
+    {
+      "name": "GtsIncidentConfirmationTestCases"
+    },
+    {
+      "name": "GtsIncidentManagerTestCases"
+    }
+  ],
+  "postsubmit": [
+  ],
+  "imports": [
+    {
+      "path": "frameworks/base/cmds/incidentd"
+    }
+  ]
+}
+
diff --git a/libs/incident/include/incident/incident_report.h b/libs/incident/include/incident/incident_report.h
new file mode 100644
index 0000000..49fe5b9
--- /dev/null
+++ b/libs/incident/include/incident/incident_report.h
@@ -0,0 +1,192 @@
+/**
+ * Copyright (c) 2020, 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.
+ */
+
+/**
+ * @file incident_report.h
+ */
+
+#ifndef ANDROID_INCIDENT_INCIDENT_REPORT_H
+#define ANDROID_INCIDENT_INCIDENT_REPORT_H
+
+#include <stdbool.h>
+
+#if __cplusplus
+#include <set>
+#include <string>
+#include <vector>
+
+extern "C" {
+#endif // __cplusplus
+
+struct AIncidentReportArgs;
+/**
+ * Opaque class to represent the arguments to an incident report request.
+ * Incident reports contain debugging data about the device at runtime.
+ * For more information see the android.os.IncidentManager java class.
+ */
+typedef struct AIncidentReportArgs AIncidentReportArgs;
+
+// Privacy policy enum value, sync with frameworks/base/core/proto/android/privacy.proto,
+// IncidentReportArgs.h and IncidentReportArgs.java.
+enum {
+    /**
+     * Flag marking fields and incident reports than can be taken
+     * off the device only via adb.
+     */
+    INCIDENT_REPORT_PRIVACY_POLICY_LOCAL = 0,
+
+    /**
+     * Flag marking fields and incident reports than can be taken
+     * off the device with contemporary consent.
+     */
+    INCIDENT_REPORT_PRIVACY_POLICY_EXPLICIT = 100,
+
+    /**
+     * Flag marking fields and incident reports than can be taken
+     * off the device with prior consent.
+     */
+    INCIDENT_REPORT_PRIVACY_POLICY_AUTOMATIC = 200,
+
+    /**
+     * Flag to indicate that a given field has not been marked
+     * with a privacy policy.
+     */
+    INCIDENT_REPORT_PRIVACY_POLICY_UNSET = 255
+};
+
+/**
+ * Allocate and initialize an AIncidentReportArgs object.
+ */
+AIncidentReportArgs* AIncidentReportArgs_init();
+
+/**
+ * Duplicate an existing AIncidentReportArgs object.
+ */
+AIncidentReportArgs* AIncidentReportArgs_clone(AIncidentReportArgs* that);
+
+/**
+ * Clean up and delete an AIncidentReportArgs object.
+ */
+void AIncidentReportArgs_delete(AIncidentReportArgs* args);
+
+/**
+ * Set this incident report to include all sections.
+ */
+void AIncidentReportArgs_setAll(AIncidentReportArgs* args, bool all);
+
+/**
+ * Set this incident report privacy policy spec.
+ */
+void AIncidentReportArgs_setPrivacyPolicy(AIncidentReportArgs* args, int privacyPolicy);
+
+/**
+ * Add this section to the incident report. The section IDs are the field numbers
+ * from the android.os.IncidentProto protobuf message.
+ */
+void AIncidentReportArgs_addSection(AIncidentReportArgs* args, int section);
+
+/**
+ * Set the apk package name that will be sent a broadcast when the incident
+ * report completes.  Must be called in conjunction with AIncidentReportArgs_setReceiverClass.
+ */
+void AIncidentReportArgs_setReceiverPackage(AIncidentReportArgs* args, char const* pkg);
+
+/**
+ * Set the fully qualified class name of the java BroadcastReceiver class that will be
+ * sent a broadcast when the report completes.  Must be called in conjunction with
+ * AIncidentReportArgs_setReceiverPackage.
+ */
+void AIncidentReportArgs_setReceiverClass(AIncidentReportArgs* args, char const* cls);
+
+/**
+ * Add protobuf data as a header to the incident report. The buffer should be a serialized
+ * android.os.IncidentHeaderProto object.
+ */
+void AIncidentReportArgs_addHeader(AIncidentReportArgs* args, uint8_t const* buf, size_t size);
+
+/**
+ * Initiate taking the report described in the args object.  Returns 0 on success,
+ * and non-zero otherwise.
+ */
+int AIncidentReportArgs_takeReport(AIncidentReportArgs* args);
+
+#if __cplusplus
+} // extern "C"
+
+namespace android {
+namespace os {
+
+class IncidentReportRequest {
+public:
+    inline IncidentReportRequest() {
+        mImpl = AIncidentReportArgs_init();
+    }
+
+    inline IncidentReportRequest(const IncidentReportRequest& that) {
+        mImpl = AIncidentReportArgs_clone(that.mImpl);
+    }
+
+    inline ~IncidentReportRequest() {
+        AIncidentReportArgs_delete(mImpl);
+    }
+
+    inline AIncidentReportArgs* getImpl() {
+        return mImpl;
+    }
+
+    inline void setAll(bool all) {
+        AIncidentReportArgs_setAll(mImpl, all);
+    }
+
+    inline void setPrivacyPolicy(int privacyPolicy) {
+        AIncidentReportArgs_setPrivacyPolicy(mImpl, privacyPolicy);
+    }
+
+    inline void addSection(int section) {
+        AIncidentReportArgs_addSection(mImpl, section);
+    }
+
+    inline void setReceiverPackage(const std::string& pkg) {
+        AIncidentReportArgs_setReceiverPackage(mImpl, pkg.c_str());
+    };
+
+    inline void setReceiverClass(const std::string& cls) {
+        AIncidentReportArgs_setReceiverClass(mImpl, cls.c_str());
+    };
+
+    inline void addHeader(const std::vector<uint8_t>& headerProto) {
+        AIncidentReportArgs_addHeader(mImpl, headerProto.data(), headerProto.size());
+    };
+
+    inline void addHeader(const uint8_t* buf, size_t size) {
+        AIncidentReportArgs_addHeader(mImpl, buf, size);
+    };
+
+    // returns a status_t
+    inline int takeReport() {
+        return AIncidentReportArgs_takeReport(mImpl);
+    }
+
+private:
+    AIncidentReportArgs* mImpl;
+};
+
+} // namespace os
+} // namespace android
+
+#endif // __cplusplus
+
+#endif // ANDROID_INCIDENT_INCIDENT_REPORT_H
diff --git a/libs/incident/include/android/os/IncidentReportArgs.h b/libs/incident/include_priv/android/os/IncidentReportArgs.h
similarity index 89%
rename from libs/incident/include/android/os/IncidentReportArgs.h
rename to libs/incident/include_priv/android/os/IncidentReportArgs.h
index 94b4ad6..0e61590 100644
--- a/libs/incident/include/android/os/IncidentReportArgs.h
+++ b/libs/incident/include_priv/android/os/IncidentReportArgs.h
@@ -14,9 +14,10 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_OS_DUMPSTATE_ARGS_H_
-#define ANDROID_OS_DUMPSTATE_ARGS_H_
+#ifndef ANDROID_OS_INCIDENT_REPORT_ARGS_H
+#define ANDROID_OS_INCIDENT_REPORT_ARGS_H
 
+#include <binder/IServiceManager.h>
 #include <binder/Parcel.h>
 #include <binder/Parcelable.h>
 #include <utils/String16.h>
@@ -29,7 +30,8 @@
 
 using namespace std;
 
-// DESTINATION enum value, sync with frameworks/base/core/proto/android/privacy.proto
+// DESTINATION enum value, sync with frameworks/base/core/proto/android/privacy.proto,
+// incident/incident_report.h and IncidentReportArgs.java
 const uint8_t PRIVACY_POLICY_LOCAL = 0;
 const uint8_t PRIVACY_POLICY_EXPLICIT = 100;
 const uint8_t PRIVACY_POLICY_AUTOMATIC = 200;
@@ -74,4 +76,4 @@
 }
 }
 
-#endif // ANDROID_OS_DUMPSTATE_ARGS_H_
+#endif // ANDROID_OS_INCIDENT_REPORT_ARGS_H
diff --git a/libs/incident/libincident.map.txt b/libs/incident/libincident.map.txt
new file mode 100644
index 0000000..f157763
--- /dev/null
+++ b/libs/incident/libincident.map.txt
@@ -0,0 +1,15 @@
+LIBINCIDENT {
+    global:
+        AIncidentReportArgs_init; # apex # introduced=30
+        AIncidentReportArgs_clone; # apex # introduced=30
+        AIncidentReportArgs_delete; # apex # introduced=30
+        AIncidentReportArgs_setAll; # apex # introduced=30
+        AIncidentReportArgs_setPrivacyPolicy; # apex # introduced=30
+        AIncidentReportArgs_addSection; # apex # introduced=30
+        AIncidentReportArgs_setReceiverPackage; # apex # introduced=30
+        AIncidentReportArgs_setReceiverClass; # apex # introduced=30
+        AIncidentReportArgs_addHeader; # apex # introduced=30
+        AIncidentReportArgs_takeReport; # apex # introduced=30
+    local:
+        *;
+};
diff --git a/libs/incident/src/incident_report.cpp b/libs/incident/src/incident_report.cpp
new file mode 100644
index 0000000..7897ddf
--- /dev/null
+++ b/libs/incident/src/incident_report.cpp
@@ -0,0 +1,83 @@
+/**
+ * Copyright (c) 2020, 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.
+ */
+
+#define LOG_TAG "libincident"
+
+#include <incident/incident_report.h>
+
+#include <android/os/IIncidentManager.h>
+#include <android/os/IncidentReportArgs.h>
+#include <binder/IServiceManager.h>
+#include <binder/Status.h>
+#include <log/log.h>
+
+using android::sp;
+using android::binder::Status;
+using android::os::IncidentReportArgs;
+using android::os::IIncidentManager;
+using std::string;
+using std::vector;
+
+AIncidentReportArgs* AIncidentReportArgs_init() {
+    return reinterpret_cast<AIncidentReportArgs*>(new IncidentReportArgs());
+}
+
+AIncidentReportArgs* AIncidentReportArgs_clone(AIncidentReportArgs* that) {
+    return reinterpret_cast<AIncidentReportArgs*>(
+            new IncidentReportArgs(*reinterpret_cast<IncidentReportArgs*>(that)));
+}
+
+void AIncidentReportArgs_delete(AIncidentReportArgs* args) {
+    delete reinterpret_cast<IncidentReportArgs*>(args);
+}
+
+void AIncidentReportArgs_setAll(AIncidentReportArgs* args, bool all) {
+    reinterpret_cast<IncidentReportArgs*>(args)->setAll(all);
+}
+
+void AIncidentReportArgs_setPrivacyPolicy(AIncidentReportArgs* args, int privacyPolicy) {
+    reinterpret_cast<IncidentReportArgs*>(args)->setPrivacyPolicy(privacyPolicy);
+}
+
+void AIncidentReportArgs_addSection(AIncidentReportArgs* args, int section) {
+    reinterpret_cast<IncidentReportArgs*>(args)->addSection(section);
+}
+
+void AIncidentReportArgs_setReceiverPackage(AIncidentReportArgs* args, char const* pkg) {
+    reinterpret_cast<IncidentReportArgs*>(args)->setReceiverPkg(string(pkg));
+}
+
+void AIncidentReportArgs_setReceiverClass(AIncidentReportArgs* args, char const* cls) {
+    reinterpret_cast<IncidentReportArgs*>(args)->setReceiverCls(string(cls));
+}
+
+void AIncidentReportArgs_addHeader(AIncidentReportArgs* args, uint8_t const* buf, size_t size) {
+    vector<uint8_t> vec(buf, buf+size);
+    reinterpret_cast<IncidentReportArgs*>(args)->addHeader(vec);
+}
+
+int AIncidentReportArgs_takeReport(AIncidentReportArgs* argp) {
+    IncidentReportArgs* args = reinterpret_cast<IncidentReportArgs*>(argp);
+
+    sp<IIncidentManager> service = android::interface_cast<IIncidentManager>(
+            android::defaultServiceManager()->getService(android::String16("incident")));
+    if (service == nullptr) {
+        ALOGW("Failed to fetch incident service.");
+        return false;
+    }
+    Status s = service->reportIncident(*args);
+    return s.transactionError();
+}
diff --git a/cmds/statsd/tests/external/IncidentReportArgs_test.cpp b/libs/incident/tests/IncidentReportArgs_test.cpp
similarity index 93%
rename from cmds/statsd/tests/external/IncidentReportArgs_test.cpp
rename to libs/incident/tests/IncidentReportArgs_test.cpp
index 38bc194..224b343 100644
--- a/cmds/statsd/tests/external/IncidentReportArgs_test.cpp
+++ b/libs/incident/tests/IncidentReportArgs_test.cpp
@@ -20,6 +20,8 @@
 namespace os {
 namespace statsd {
 
+// Checks that all of the inline methods on IncidentReportRequest and the real C functions
+// result in a working IncidentReportArgs.
 TEST(IncidentReportArgsTest, testSerialization) {
     IncidentReportArgs args;
     args.setAll(0);
diff --git a/libs/incident/tests/IncidentReportRequest_test.cpp b/libs/incident/tests/IncidentReportRequest_test.cpp
new file mode 100644
index 0000000..6d218b6
--- /dev/null
+++ b/libs/incident/tests/IncidentReportRequest_test.cpp
@@ -0,0 +1,65 @@
+// Copyright (C) 2018 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 <android/os/IncidentReportArgs.h>
+#include <incident/incident_report.h>
+
+#include <gtest/gtest.h>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+TEST(IncidentReportRequestTest, testWrite) {
+    IncidentReportRequest request;
+    request.setAll(0);
+    request.addSection(1000);
+    request.addSection(1001);
+
+    vector<uint8_t> header1;
+    header1.push_back(0x1);
+    header1.push_back(0x2);
+    vector<uint8_t> header2;
+    header1.push_back(0x22);
+    header1.push_back(0x33);
+
+    request.addHeader(header1);
+    request.addHeader(header2);
+
+    request.setPrivacyPolicy(1);
+
+    request.setReceiverPackage("com.android.os");
+    request.setReceiverClass("com.android.os.Receiver");
+
+    IncidentReportArgs* args = reinterpret_cast<IncidentReportArgs*>(request.getImpl());
+
+    EXPECT_EQ(0, args->all());
+    set<int> sections;
+    sections.insert(1000);
+    sections.insert(1001);
+    EXPECT_EQ(sections, args->sections());
+    EXPECT_EQ(1, args->getPrivacyPolicy());
+
+    EXPECT_EQ(string("com.android.os"), args->receiverPkg());
+    EXPECT_EQ(string("com.android.os.Receiver"), args->receiverCls());
+
+    vector<vector<uint8_t>> headers;
+    headers.push_back(header1);
+    headers.push_back(header2);
+    EXPECT_EQ(headers, args->headers());
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/libs/incident/tests/c_api_compile_test.c b/libs/incident/tests/c_api_compile_test.c
new file mode 100644
index 0000000..e1620df
--- /dev/null
+++ b/libs/incident/tests/c_api_compile_test.c
@@ -0,0 +1,11 @@
+#include <stdio.h>
+#include <incident/incident_report.h>
+
+/*
+ * This file ensures that incident/incident_report.h actually compiles with C,
+ * since there is no other place in the tree that actually uses it from C.
+ */
+int not_called() {
+    return 0;
+}
+