1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 /** Binder utilities. Consumers of this library must link to "libbinder_ndk". */
18 
19 #ifndef ART_LIBARTTOOLS_INCLUDE_BINDER_UTILS_TOOLS_BINDER_UTILS_H_
20 #define ART_LIBARTTOOLS_INCLUDE_BINDER_UTILS_TOOLS_BINDER_UTILS_H_
21 
22 #include <string>
23 
24 #include "android-base/result.h"
25 #include "android-base/strings.h"
26 #include "android/binder_auto_utils.h"
27 
28 namespace art {
29 namespace tools {
30 
EscapeErrorMessage(const std::string & message)31 static std::string EscapeErrorMessage(const std::string& message) {
32   return android::base::StringReplace(message, std::string("\0", /*n=*/1), "\\0", /*all=*/true);
33 }
34 
35 // Indicates an error that should never happen (e.g., illegal arguments passed by service-art
36 // internally). System server should crash if this kind of error happens.
Fatal(const std::string & message)37 [[maybe_unused]] static ndk::ScopedAStatus Fatal(const std::string& message) {
38   return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_STATE,
39                                                           EscapeErrorMessage(message).c_str());
40 }
41 
42 // Indicates an error that service-art should handle (e.g., I/O errors, sub-process crashes).
43 // The scope of the error depends on the function that throws it, so service-art should catch the
44 // error at every call site and take different actions.
45 // Ideally, this should be a checked exception or an additional return value that forces service-art
46 // to handle it, but `ServiceSpecificException` (a separate runtime exception type) is the best
47 // approximate we have given the limitation of Java and Binder.
NonFatal(const std::string & message)48 [[maybe_unused]] static ndk::ScopedAStatus NonFatal(const std::string& message) {
49   constexpr int32_t kServiceArtNonFatalErrorCode = 1;
50   return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
51       kServiceArtNonFatalErrorCode, EscapeErrorMessage(message).c_str());
52 }
53 
54 }  // namespace tools
55 }  // namespace art
56 
57 #define OR_RETURN_ERROR(func, expr)                           \
58   ({                                                          \
59     decltype(expr)&& __or_return_error_tmp = (expr);          \
60     if (!__or_return_error_tmp.ok()) {                        \
61       return (func)(__or_return_error_tmp.error().message()); \
62     }                                                         \
63     std::move(__or_return_error_tmp).value();                 \
64   })
65 
66 #define OR_RETURN_FATAL(expr)     OR_RETURN_ERROR(Fatal, expr)
67 #define OR_RETURN_NON_FATAL(expr) OR_RETURN_ERROR(NonFatal, expr)
68 #define OR_LOG_AND_RETURN_OK(expr)     \
69   OR_RETURN_ERROR(                     \
70       [](const std::string& message) { \
71         LOG(ERROR) << message;         \
72         return ScopedAStatus::ok();    \
73       },                               \
74       expr)
75 
76 #define ASSERT_STATUS_OK(expr)                                                               \
77   ({                                                                                         \
78     ndk::ScopedAStatus __assert_status_ok_status = (expr);                                   \
79     ASSERT_TRUE(__assert_status_ok_status.isOk()) << __assert_status_ok_status.getMessage(); \
80   })
81 
82 #endif  // ART_LIBARTTOOLS_INCLUDE_BINDER_UTILS_TOOLS_BINDER_UTILS_H_
83