Initial C library for libbinder.

This creates a simple wrapper around libbinder with a stable C ABI. It
also embeds the concept of an IBinder and IBinder transactions into the
ABI so that parts of their transactions can be changed and considered
implementation details of libbinder. With this basic class, you can
create a service, use it with primitive data types, but it does not yet
suppport the entire range of binder objects.

Follow-up items to handle/things still to consider
- b/112664205: make aidl-gen produce interfaces that use these (and
    think about interoperation with existing interfaces).
- using onServiceConnected/onServiceDisconnected in the NDK
- if libbinder/libbinder_ndk classes use the same descriptor, there will
  be problems in the same process (libbinder{_ndk} assumes binder class)
- sometimes getService takes 1s since there is a race for it getting
  registered
- add generic class which allows for easy implementation of a class like
  IFoo in this test.
- Parcel for additional types (and additional APIs, like data available)
- addition of APIs like AIBinder_ping/linkToDeath which all binders have
- embed Status into this API layer (so EX_HAS_REPLY_HEADER is handled)
- make remoteBinder/localBinder is const (and therefore isRemote)
- okay with associateClass or should just use interfaceDescriptor
- potentially changing out incStrong/decStrong
- adding @file/@addtogroup to comments

Bug: 111445392
Test: ndk/runtests.sh

Change-Id: Ifbca8f0fdf70a3213fe0d94320fc31eeb62408c4
diff --git a/libs/binder/ndk/test/Android.bp b/libs/binder/ndk/test/Android.bp
new file mode 100644
index 0000000..d242138
--- /dev/null
+++ b/libs/binder/ndk/test/Android.bp
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+// This test is a unit test of the low-level API that is presented here.
+// Actual users should use AIDL to generate these complicated stubs.
+
+cc_defaults {
+    name: "test_libbinder_ndk_defaults",
+    shared_libs: [
+        "libbase",
+    ],
+    strip: {
+        none: true,
+    },
+    cflags: [
+        "-O0",
+        "-g",
+    ],
+}
+
+cc_library_static {
+    name: "test_libbinder_ndk_library",
+    defaults: ["test_libbinder_ndk_defaults"],
+    export_include_dirs: ["include"],
+    shared_libs: ["libbinder_ndk"],
+    export_shared_lib_headers: ["libbinder_ndk"],
+    srcs: ["iface.cpp"],
+}
+
+cc_defaults {
+    name: "test_libbinder_ndk_test_defaults",
+    defaults: ["test_libbinder_ndk_defaults"],
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "libutils",
+    ],
+    static_libs: [
+        "libbinder_ndk",
+        "test_libbinder_ndk_library",
+    ],
+}
+
+cc_test {
+    name: "libbinder_ndk_test_client",
+    defaults: ["test_libbinder_ndk_test_defaults"],
+    srcs: ["main_client.cpp"],
+}
+
+cc_test {
+    name: "libbinder_ndk_test_server",
+    defaults: ["test_libbinder_ndk_test_defaults"],
+    srcs: ["main_server.cpp"],
+    gtest: false,
+}
diff --git a/libs/binder/ndk/test/iface.cpp b/libs/binder/ndk/test/iface.cpp
new file mode 100644
index 0000000..eed09f0
--- /dev/null
+++ b/libs/binder/ndk/test/iface.cpp
@@ -0,0 +1,145 @@
+/*
+ * 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-base/logging.h>
+#include <android/binder_manager.h>
+#include <iface/iface.h>
+
+using ::android::sp;
+using ::android::wp;
+
+const char* IFoo::kSomeInstanceName = "libbinder_ndk-test-IFoo";
+const char* kIFooDescriptor = "my-special-IFoo-class";
+
+struct IFoo_Class_Data {
+    sp<IFoo> foo;
+};
+
+void* IFoo_Class_onCreate(void* args) {
+    IFoo_Class_Data* foo = static_cast<IFoo_Class_Data*>(args);
+    // This is a foo, but we're currently not verifying that. So, the method newLocalBinder is
+    // coupled with this.
+    return static_cast<void*>(foo);
+}
+
+void IFoo_Class_onDestroy(void* userData) {
+    delete static_cast<IFoo_Class_Data*>(userData);
+}
+
+binder_status_t IFoo_Class_onTransact(AIBinder* binder, transaction_code_t code, const AParcel* in,
+                                      AParcel* out) {
+    binder_status_t stat = EX_UNSUPPORTED_OPERATION;
+
+    sp<IFoo> foo = static_cast<IFoo_Class_Data*>(AIBinder_getUserData(binder))->foo;
+    CHECK(foo != nullptr) << "Transaction made on already deleted object";
+
+    switch (code) {
+        case IFoo::DOFOO: {
+            int32_t valueIn;
+            stat = AParcel_readInt32(in, &valueIn);
+            if (stat != EX_NONE) break;
+            int32_t valueOut = foo->doubleNumber(valueIn);
+            stat = AParcel_writeInt32(out, valueOut);
+            break;
+        }
+    }
+
+    return stat;
+}
+
+AIBinder_Class* IFoo::kClass = AIBinder_Class_define(kIFooDescriptor, IFoo_Class_onCreate,
+                                                     IFoo_Class_onDestroy, IFoo_Class_onTransact);
+
+class BpFoo : public IFoo {
+public:
+    BpFoo(AIBinder* binder) : mBinder(binder) {}
+    virtual ~BpFoo() { AIBinder_decStrong(mBinder); }
+
+    virtual int32_t doubleNumber(int32_t in) {
+        AParcel* parcelIn;
+        CHECK(EX_NONE == AIBinder_prepareTransaction(mBinder, &parcelIn));
+
+        CHECK(EX_NONE == AParcel_writeInt32(parcelIn, in));
+
+        AParcel* parcelOut;
+        CHECK(EX_NONE ==
+              AIBinder_transact(mBinder, IFoo::DOFOO, &parcelIn, &parcelOut, 0 /*flags*/));
+
+        int32_t out;
+        CHECK(EX_NONE == AParcel_readInt32(parcelOut, &out));
+
+        CHECK(EX_NONE == AIBinder_finalizeTransaction(mBinder, &parcelOut));
+        return out;
+    }
+
+private:
+    // Always assumes one refcount
+    AIBinder* mBinder;
+};
+
+IFoo::~IFoo() {
+    AIBinder_Weak_delete(mWeakBinder);
+}
+
+binder_status_t IFoo::addService(const char* instance) {
+    AIBinder* binder = nullptr;
+
+    if (mWeakBinder != nullptr) {
+        // one strong ref count of binder
+        binder = AIBinder_Weak_promote(mWeakBinder);
+    }
+    if (binder == nullptr) {
+        // or one strong refcount here
+        binder = AIBinder_new(IFoo::kClass, static_cast<void*>(new IFoo_Class_Data{this}));
+        if (mWeakBinder != nullptr) {
+            AIBinder_Weak_delete(mWeakBinder);
+        }
+        mWeakBinder = AIBinder_Weak_new(binder);
+    }
+
+    binder_status_t status = AServiceManager_addService(binder, instance);
+    // Strong references we care about kept by remote process
+    AIBinder_decStrong(binder);
+    return status;
+}
+
+sp<IFoo> IFoo::getService(const char* instance) {
+    AIBinder* binder = AServiceManager_getService(instance); // maybe nullptr
+    AIBinder_associateClass(&binder, IFoo::kClass);
+
+    if (binder == nullptr) {
+        return nullptr;
+    }
+
+    if (AIBinder_isRemote(binder)) {
+        sp<IFoo> ret = new BpFoo(binder); // takes ownership of binder
+        return ret;
+    }
+
+    IFoo_Class_Data* data = static_cast<IFoo_Class_Data*>(AIBinder_getUserData(binder));
+
+    CHECK(data != nullptr); // always created with non-null data
+
+    sp<IFoo> ret = data->foo;
+
+    AIBinder* held = AIBinder_Weak_promote(ret->mWeakBinder);
+    CHECK(held == binder);
+    AIBinder_decStrong(held);
+
+    // IFoo only keeps a weak reference to AIBinder, so we can drop this
+    AIBinder_decStrong(binder);
+    return ret;
+}
diff --git a/libs/binder/ndk/test/include/iface/iface.h b/libs/binder/ndk/test/include/iface/iface.h
new file mode 100644
index 0000000..4c61e9d
--- /dev/null
+++ b/libs/binder/ndk/test/include/iface/iface.h
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android/binder_ibinder.h>
+#include <utils/RefBase.h>
+
+class IFoo : public virtual ::android::RefBase {
+public:
+    static const char* kSomeInstanceName;
+    static AIBinder_Class* kClass;
+
+    // Takes ownership of IFoo
+    binder_status_t addService(const char* instance);
+    static ::android::sp<IFoo> getService(const char* instance);
+
+    enum Call {
+        DOFOO = FIRST_CALL_TRANSACTION + 0,
+    };
+
+    virtual ~IFoo();
+    virtual int32_t doubleNumber(int32_t in) = 0;
+
+private:
+    AIBinder_Weak* mWeakBinder = nullptr; // maybe owns AIBinder
+};
diff --git a/libs/binder/ndk/test/main_client.cpp b/libs/binder/ndk/test/main_client.cpp
new file mode 100644
index 0000000..7c53e51
--- /dev/null
+++ b/libs/binder/ndk/test/main_client.cpp
@@ -0,0 +1,70 @@
+/*
+ * 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-base/logging.h>
+#include <android/binder_manager.h>
+#include <gtest/gtest.h>
+#include <iface/iface.h>
+
+using ::android::sp;
+
+constexpr char kExistingNonNdkService[] = "SurfaceFlinger";
+
+// This is too slow
+// TEST(NdkBinder, GetServiceThatDoesntExist) {
+//     sp<IFoo> foo = IFoo::getService("asdfghkl;");
+//     EXPECT_EQ(nullptr, foo.get());
+// }
+
+TEST(NdkBinder, DoubleNumber) {
+    sp<IFoo> foo = IFoo::getService(IFoo::kSomeInstanceName);
+    ASSERT_NE(foo, nullptr);
+    EXPECT_EQ(2, foo->doubleNumber(1));
+}
+
+TEST(NdkBinder, RetrieveNonNdkService) {
+    AIBinder* binder = AServiceManager_getService(kExistingNonNdkService);
+    ASSERT_NE(nullptr, binder);
+    AIBinder_decStrong(binder);
+}
+
+class MyTestFoo : public IFoo {
+    int32_t doubleNumber(int32_t in) override {
+        LOG(INFO) << "doubleNumber " << in;
+        return 2 * in;
+    }
+};
+
+TEST(NdkBinder, GetServiceInProcess) {
+    static const char* kInstanceName = "test-get-service-in-process";
+
+    sp<IFoo> foo = new MyTestFoo;
+    EXPECT_EQ(EX_NONE, foo->addService(kInstanceName));
+
+    sp<IFoo> getFoo = IFoo::getService(kInstanceName);
+    EXPECT_EQ(foo.get(), getFoo.get());
+
+    EXPECT_EQ(2, getFoo->doubleNumber(1));
+}
+
+TEST(NdkBinder, AddServiceMultipleTimes) {
+    static const char* kInstanceName1 = "test-multi-1";
+    static const char* kInstanceName2 = "test-multi-2";
+    sp<IFoo> foo = new MyTestFoo;
+    EXPECT_EQ(EX_NONE, foo->addService(kInstanceName1));
+    EXPECT_EQ(EX_NONE, foo->addService(kInstanceName2));
+    EXPECT_EQ(IFoo::getService(kInstanceName1), IFoo::getService(kInstanceName2));
+}
diff --git a/libs/binder/ndk/test/main_server.cpp b/libs/binder/ndk/test/main_server.cpp
new file mode 100644
index 0000000..f3da7da
--- /dev/null
+++ b/libs/binder/ndk/test/main_server.cpp
@@ -0,0 +1,43 @@
+/*
+ * 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-base/logging.h>
+#include <android/binder_process.h>
+#include <iface/iface.h>
+
+using ::android::sp;
+
+class MyFoo : public IFoo {
+    int32_t doubleNumber(int32_t in) override {
+        LOG(INFO) << "doubling " << in;
+        return 2 * in;
+    }
+};
+
+int main() {
+    ABinderProcess_setThreadPoolMaxThreadCount(0);
+
+    // Strong reference to MyFoo kept by service manager.
+    binder_status_t status = (new MyFoo)->addService(IFoo::kSomeInstanceName);
+
+    if (status != EX_NONE) {
+        LOG(FATAL) << "Could not register: " << status;
+    }
+
+    ABinderProcess_joinThreadPool();
+
+    return 1;
+}