blob: 7fe3822be0568e24b63f7e115eb5f294cec7ee23 [file] [log] [blame]
Matt Buckley6c18e6d2024-02-07 23:39:50 +00001/*
2 * Copyright (C) 2024 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#pragma once
18
19#include <android/binder_auto_utils.h>
20#include <android/binder_status.h>
21#include <android/hardware/power/1.0/IPower.h>
22#include <binder/Status.h>
23#include <hidl/HidlSupport.h>
24#include <string>
25
26namespace android::power {
27
28static bool checkUnsupported(const ndk::ScopedAStatus& ndkStatus) {
29 return ndkStatus.getExceptionCode() == EX_UNSUPPORTED_OPERATION ||
30 ndkStatus.getStatus() == STATUS_UNKNOWN_TRANSACTION;
31}
32
33static bool checkUnsupported(const binder::Status& status) {
34 return status.exceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION ||
35 status.transactionError() == UNKNOWN_TRANSACTION;
36}
37
38// Result of a call to the Power HAL wrapper, holding data if successful.
39template <typename T>
40class HalResult {
41public:
42 static HalResult<T> ok(T&& value) { return HalResult(std::forward<T>(value)); }
43 static HalResult<T> ok(T& value) { return HalResult<T>::ok(T{value}); }
44 static HalResult<T> failed(std::string msg) { return HalResult(msg, /* unsupported= */ false); }
45 static HalResult<T> unsupported() { return HalResult("", /* unsupported= */ true); }
46
47 static HalResult<T> fromStatus(const binder::Status& status, T&& data) {
48 if (checkUnsupported(status)) {
49 return HalResult<T>::unsupported();
50 }
51 if (status.isOk()) {
52 return HalResult<T>::ok(std::forward<T>(data));
53 }
54 return HalResult<T>::failed(std::string(status.toString8().c_str()));
55 }
56
57 static HalResult<T> fromStatus(const binder::Status& status, T& data) {
58 return HalResult<T>::fromStatus(status, T{data});
59 }
60
61 static HalResult<T> fromStatus(const ndk::ScopedAStatus& ndkStatus, T&& data) {
62 if (checkUnsupported(ndkStatus)) {
63 return HalResult<T>::unsupported();
64 }
65 if (ndkStatus.isOk()) {
66 return HalResult<T>::ok(std::forward<T>(data));
67 }
68 return HalResult<T>::failed(std::string(ndkStatus.getDescription()));
69 }
70
71 static HalResult<T> fromStatus(const ndk::ScopedAStatus& ndkStatus, T& data) {
72 return HalResult<T>::fromStatus(ndkStatus, T{data});
73 }
74
75 template <typename R>
76 static HalResult<T> fromReturn(hardware::Return<R>& ret, T&& data) {
77 return ret.isOk() ? HalResult<T>::ok(std::forward<T>(data))
78 : HalResult<T>::failed(ret.description());
79 }
80
81 template <typename R>
82 static HalResult<T> fromReturn(hardware::Return<R>& ret, T& data) {
83 return HalResult<T>::fromReturn(ret, T{data});
84 }
85
86 template <typename R>
87 static HalResult<T> fromReturn(hardware::Return<R>& ret, hardware::power::V1_0::Status status,
88 T&& data) {
89 return ret.isOk() ? HalResult<T>::fromStatus(status, std::forward<T>(data))
90 : HalResult<T>::failed(ret.description());
91 }
92
93 template <typename R>
94 static HalResult<T> fromReturn(hardware::Return<R>& ret, hardware::power::V1_0::Status status,
95 T& data) {
96 return HalResult<T>::fromReturn(ret, status, T{data});
97 }
98
99 // This will throw std::bad_optional_access if this result is not ok.
100 const T& value() const { return mValue.value(); }
101 bool isOk() const { return !mUnsupported && mValue.has_value(); }
102 bool isFailed() const { return !mUnsupported && !mValue.has_value(); }
103 bool isUnsupported() const { return mUnsupported; }
104 const char* errorMessage() const { return mErrorMessage.c_str(); }
105
106private:
107 std::optional<T> mValue;
108 std::string mErrorMessage;
109 bool mUnsupported;
110
111 explicit HalResult(T&& value)
112 : mValue{std::move(value)}, mErrorMessage(), mUnsupported(false) {}
113 explicit HalResult(std::string errorMessage, bool unsupported)
114 : mValue(), mErrorMessage(std::move(errorMessage)), mUnsupported(unsupported) {}
115};
116
117// Empty result
118template <>
119class HalResult<void> {
120public:
121 static HalResult<void> ok() { return HalResult(); }
122 static HalResult<void> failed(std::string msg) { return HalResult(std::move(msg)); }
123 static HalResult<void> unsupported() { return HalResult(/* unsupported= */ true); }
124
125 static HalResult<void> fromStatus(const binder::Status& status) {
126 if (checkUnsupported(status)) {
127 return HalResult<void>::unsupported();
128 }
129 if (status.isOk()) {
130 return HalResult<void>::ok();
131 }
132 return HalResult<void>::failed(std::string(status.toString8().c_str()));
133 }
134
135 static HalResult<void> fromStatus(const ndk::ScopedAStatus& ndkStatus) {
136 if (ndkStatus.isOk()) {
137 return HalResult<void>::ok();
138 }
139 if (checkUnsupported(ndkStatus)) {
140 return HalResult<void>::unsupported();
141 }
142 return HalResult<void>::failed(ndkStatus.getDescription());
143 }
144
145 template <typename R>
146 static HalResult<void> fromReturn(hardware::Return<R>& ret) {
147 return ret.isOk() ? HalResult<void>::ok() : HalResult<void>::failed(ret.description());
148 }
149
150 bool isOk() const { return !mUnsupported && !mFailed; }
151 bool isFailed() const { return !mUnsupported && mFailed; }
152 bool isUnsupported() const { return mUnsupported; }
153 const char* errorMessage() const { return mErrorMessage.c_str(); }
154
155private:
156 std::string mErrorMessage;
157 bool mFailed;
158 bool mUnsupported;
159
160 explicit HalResult(bool unsupported = false)
161 : mErrorMessage(), mFailed(false), mUnsupported(unsupported) {}
162 explicit HalResult(std::string errorMessage)
163 : mErrorMessage(std::move(errorMessage)), mFailed(true), mUnsupported(false) {}
164};
165} // namespace android::power