Return<T>::description() provide more descriptive text than numbers

Test: libhidl_test
Change-Id: Ib7c591f261bb335b9fe348dd2fb0695a94bdf468
diff --git a/base/Status.cpp b/base/Status.cpp
index e7320a8..449aff3 100644
--- a/base/Status.cpp
+++ b/base/Status.cpp
@@ -13,15 +13,71 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #define LOG_TAG "HidlStatus"
+#include <android-base/logging.h>
 
 #include <hidl/Status.h>
 
-#include <android-base/logging.h>
+#include <unordered_map>
 
 namespace android {
 namespace hardware {
 
+static std::string statusToString(status_t s) {
+    const std::unordered_map<status_t, std::string> statusStrings{{
+        #define STATUS_TO_STRING_PAIR(STATUS) {STATUS, #STATUS}
+        STATUS_TO_STRING_PAIR(OK),
+        STATUS_TO_STRING_PAIR(UNKNOWN_ERROR),
+        STATUS_TO_STRING_PAIR(NO_MEMORY),
+        STATUS_TO_STRING_PAIR(INVALID_OPERATION),
+        STATUS_TO_STRING_PAIR(BAD_VALUE),
+        STATUS_TO_STRING_PAIR(BAD_TYPE),
+        STATUS_TO_STRING_PAIR(NAME_NOT_FOUND),
+        STATUS_TO_STRING_PAIR(PERMISSION_DENIED),
+        STATUS_TO_STRING_PAIR(NO_INIT),
+        STATUS_TO_STRING_PAIR(ALREADY_EXISTS),
+        STATUS_TO_STRING_PAIR(DEAD_OBJECT),
+        STATUS_TO_STRING_PAIR(FAILED_TRANSACTION),
+        STATUS_TO_STRING_PAIR(BAD_INDEX),
+        STATUS_TO_STRING_PAIR(NOT_ENOUGH_DATA),
+        STATUS_TO_STRING_PAIR(WOULD_BLOCK),
+        STATUS_TO_STRING_PAIR(TIMED_OUT),
+        STATUS_TO_STRING_PAIR(UNKNOWN_TRANSACTION),
+        STATUS_TO_STRING_PAIR(FDS_NOT_ALLOWED),
+        STATUS_TO_STRING_PAIR(UNEXPECTED_NULL)
+    }};
+    auto it = statusStrings.find(s);
+    if (it != statusStrings.end()) {
+        return it->second;
+    }
+    std::string str = std::to_string(s);
+    char *err = strerror(-s);
+    if (err != NULL) {
+        str.append(1, ' ').append(err);
+    }
+    return str;
+}
+
+static std::string exceptionToString(int32_t ex) {
+    const std::unordered_map<int32_t, std::string> exceptionStrings{{
+        #define EXCEPTION_TO_STRING_PAIR(EXCEPTION) {Status::Exception::EXCEPTION, #EXCEPTION}
+        EXCEPTION_TO_STRING_PAIR(EX_NONE),
+        EXCEPTION_TO_STRING_PAIR(EX_SECURITY),
+        EXCEPTION_TO_STRING_PAIR(EX_BAD_PARCELABLE),
+        EXCEPTION_TO_STRING_PAIR(EX_ILLEGAL_ARGUMENT),
+        EXCEPTION_TO_STRING_PAIR(EX_NULL_POINTER),
+        EXCEPTION_TO_STRING_PAIR(EX_ILLEGAL_STATE),
+        EXCEPTION_TO_STRING_PAIR(EX_NETWORK_MAIN_THREAD),
+        EXCEPTION_TO_STRING_PAIR(EX_UNSUPPORTED_OPERATION),
+        EXCEPTION_TO_STRING_PAIR(EX_SERVICE_SPECIFIC),
+        EXCEPTION_TO_STRING_PAIR(EX_HAS_REPLY_HEADER),
+        EXCEPTION_TO_STRING_PAIR(EX_TRANSACTION_FAILED)
+    }};
+    auto it = exceptionStrings.find(ex);
+    return it == exceptionStrings.end() ? std::to_string(ex) : it->second;
+}
+
 Status Status::ok() {
     return Status();
 }
@@ -86,11 +142,11 @@
     if (s.exceptionCode() == Status::EX_NONE) {
         stream << "No error";
     } else {
-        stream << "Status(" << s.exceptionCode() << "): '";
+        stream << "Status(" << exceptionToString(s.exceptionCode()) << "): '";
         if (s.exceptionCode() == Status::EX_SERVICE_SPECIFIC) {
             stream << s.serviceSpecificErrorCode() << ": ";
         } else if (s.exceptionCode() == Status::EX_TRANSACTION_FAILED) {
-            stream << s.transactionError() << ": ";
+            stream << statusToString(s.transactionError()) << ": ";
         }
         stream << s.exceptionMessage() << "'";
     }