Add AStatus to libbinder_ndk.

This object encapsulates the way that Java AIDL (the SDK) Statuses work
by wrapping the C++ Status class which also encapsulates this.

Test: runtests.sh
Bug: 111445392
Change-Id: I6cc9bd20cf4f83f49d1a546ae7b1e10734fc6535
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h
index e871ed1..8628025 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h
@@ -66,6 +66,17 @@
  */
 binder_status_t AParcel_readNullableStrongBinder(const AParcel* parcel, AIBinder** binder);
 
+/**
+ * Writes an AStatus object to the next location in a non-null parcel.
+ */
+binder_status_t AParcel_writeStatusHeader(AParcel* parcel, const AStatus* status);
+
+/**
+ * Reads an AStatus from the next location in a non-null parcel. Ownership is passed to the caller
+ * of this function.
+ */
+binder_status_t AParcel_readStatusHeader(const AParcel* parcel, AStatus** status);
+
 // @START
 /**
  * Writes int32_t value to the next location in a non-null parcel.
diff --git a/libs/binder/ndk/include_ndk/android/binder_status.h b/libs/binder/ndk/include_ndk/android/binder_status.h
index bc8e44a..d9c36d2 100644
--- a/libs/binder/ndk/include_ndk/android/binder_status.h
+++ b/libs/binder/ndk/include_ndk/android/binder_status.h
@@ -89,6 +89,93 @@
  */
 typedef int32_t binder_exception_t;
 
+/**
+ * This is a helper class that encapsulates a standard way to keep track of and chain binder errors
+ * along with service specific errors.
+ *
+ * It is not required to be used in order to parcel/receive transactions, but it is required in
+ * order to be compatible with standard AIDL transactions.
+ */
+struct AStatus;
+typedef struct AStatus AStatus;
+
+/**
+ * New status which is considered a success.
+ */
+__attribute__((warn_unused_result)) AStatus* AStatus_newOk();
+
+/**
+ * New status with exception code.
+ */
+__attribute__((warn_unused_result)) AStatus* AStatus_fromExceptionCode(
+        binder_exception_t exception);
+
+/**
+ * New status with exception code and message.
+ */
+__attribute__((warn_unused_result)) AStatus* AStatus_fromExceptionCodeWithMessage(
+        binder_exception_t exception, const char* message);
+
+/**
+ * New status with a service speciic error.
+ *
+ * This is considered to be EX_TRANSACTION_FAILED with extra information.
+ */
+__attribute__((warn_unused_result)) AStatus* AStatus_fromServiceSpecificError(
+        int32_t serviceSpecific);
+
+/**
+ * New status with a service specific error and message.
+ *
+ * This is considered to be EX_TRANSACTION_FAILED with extra information.
+ */
+__attribute__((warn_unused_result)) AStatus* AStatus_fromServiceSpecificErrorWithMessage(
+        int32_t serviceSpecific, const char* message);
+
+/**
+ * New status with binder_status_t. This is typically for low level failures when a binder_status_t
+ * is returned by an API on AIBinder or AParcel, and that is to be returned from a method returning
+ * an AStatus instance.
+ */
+__attribute__((warn_unused_result)) AStatus* AStatus_fromStatus(binder_status_t status);
+
+/**
+ * Whether this object represents a successful transaction.
+ */
+bool AStatus_isOk(const AStatus* status);
+
+/**
+ * The exception that this status object represents.
+ */
+binder_exception_t AStatus_getExceptionCode(const AStatus* status);
+
+/**
+ * The service specific error if this object represents one. If this object represents a different
+ * kind of exception or is ok, this function will return 0. Just because this function returns 0
+ * does not mean that the transaction was a success.
+ */
+int32_t AStatus_getServiceSpecificError(const AStatus* status);
+
+/**
+ * The status if this object represents one. If this object represents a different kind of exception
+ * or is ok, this function will return 0. Just because this function returns 0 does not mean that
+ * the transaction was a success.
+ */
+binder_status_t AStatus_getStatus(const AStatus* status);
+
+/**
+ * If there is a message associated with this status, this will return that message. If there is no
+ * message, this will return an empty string.
+ *
+ * The returned string has the lifetime of the status object passed into this function.
+ */
+const char* AStatus_getMessage(const AStatus* status);
+
+/**
+ * Deletes memory associated with the status instance.
+ */
+void AStatus_delete(AStatus** status);
+
 __END_DECLS
 
 /** @} */
diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp
index e506847..a063657 100644
--- a/libs/binder/ndk/parcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -62,6 +62,17 @@
     *binder = ret.get();
     return PruneStatusT(status);
 }
+binder_status_t AParcel_writeStatusHeader(AParcel* parcel, const AStatus* status) {
+    return PruneStatusT(status->get()->writeToParcel(parcel->get()));
+}
+binder_status_t AParcel_readStatusHeader(const AParcel* parcel, AStatus** status) {
+    ::android::binder::Status bstatus;
+    binder_status_t ret = PruneStatusT(bstatus.readFromParcel(*parcel->get()));
+    if (ret == EX_NONE) {
+        *status = new AStatus(std::move(bstatus));
+    }
+    return ret;
+}
 
 // See gen_parcel_helper.py. These auto-generated read/write methods use the same types for
 // libbinder and this library.
diff --git a/libs/binder/ndk/status.cpp b/libs/binder/ndk/status.cpp
index 626a9b2..deb0392 100644
--- a/libs/binder/ndk/status.cpp
+++ b/libs/binder/ndk/status.cpp
@@ -22,6 +22,59 @@
 using ::android::status_t;
 using ::android::binder::Status;
 
+AStatus* AStatus_newOk() {
+    return new AStatus();
+}
+
+AStatus* AStatus_fromExceptionCode(binder_exception_t exception) {
+    return new AStatus(Status::fromExceptionCode(exception));
+}
+
+AStatus* AStatus_fromExceptionCodeWithMessage(binder_exception_t exception, const char* message) {
+    return new AStatus(Status::fromExceptionCode(exception, message));
+}
+
+AStatus* AStatus_fromServiceSpecificError(int32_t serviceSpecific) {
+    return new AStatus(Status::fromServiceSpecificError(serviceSpecific));
+}
+
+AStatus* AStatus_fromServiceSpecificErrorWithMessage(int32_t serviceSpecific, const char* message) {
+    return new AStatus(Status::fromServiceSpecificError(serviceSpecific, message));
+}
+
+AStatus* AStatus_fromStatus(binder_status_t status) {
+    return new AStatus(Status::fromStatusT(status));
+}
+
+bool AStatus_isOk(const AStatus* status) {
+    return status->get()->isOk();
+}
+
+binder_exception_t AStatus_getExceptionCode(const AStatus* status) {
+    return PruneException(status->get()->exceptionCode());
+}
+
+int32_t AStatus_getServiceSpecificError(const AStatus* status) {
+    return status->get()->serviceSpecificErrorCode();
+}
+
+binder_status_t AStatus_getStatus(const AStatus* status) {
+    return PruneStatusT(status->get()->transactionError());
+}
+
+const char* AStatus_getMessage(const AStatus* status) {
+    return status->get()->exceptionMessage().c_str();
+}
+
+void AStatus_delete(AStatus** status) {
+    if (status == nullptr) {
+        return;
+    }
+
+    delete *status;
+    *status = nullptr;
+}
+
 binder_status_t PruneStatusT(status_t status) {
     if (status > 0) return status;
 
diff --git a/libs/binder/ndk/status_internal.h b/libs/binder/ndk/status_internal.h
index 41b124c..8c32baf 100644
--- a/libs/binder/ndk/status_internal.h
+++ b/libs/binder/ndk/status_internal.h
@@ -21,6 +21,17 @@
 #include <binder/Status.h>
 #include <utils/Errors.h>
 
+struct AStatus {
+    AStatus() {} // ok
+    AStatus(::android::binder::Status&& status) : mStatus(std::move(status)) {}
+
+    ::android::binder::Status* get() { return &mStatus; }
+    const ::android::binder::Status* get() const { return &mStatus; }
+
+private:
+    ::android::binder::Status mStatus;
+};
+
 // This collapses the statuses into the declared range.
 binder_status_t PruneStatusT(android::status_t status);