1 /*
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 
26 namespace android::power {
27 
checkUnsupported(const ndk::ScopedAStatus & ndkStatus)28 static bool checkUnsupported(const ndk::ScopedAStatus& ndkStatus) {
29     return ndkStatus.getExceptionCode() == EX_UNSUPPORTED_OPERATION ||
30             ndkStatus.getStatus() == STATUS_UNKNOWN_TRANSACTION;
31 }
32 
checkUnsupported(const binder::Status & status)33 static 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.
39 template <typename T>
40 class HalResult {
41 public:
ok(T && value)42     static HalResult<T> ok(T&& value) { return HalResult(std::forward<T>(value)); }
ok(T & value)43     static HalResult<T> ok(T& value) { return HalResult<T>::ok(T{value}); }
failed(std::string msg)44     static HalResult<T> failed(std::string msg) { return HalResult(msg, /* unsupported= */ false); }
unsupported()45     static HalResult<T> unsupported() { return HalResult("", /* unsupported= */ true); }
46 
fromStatus(const binder::Status & status,T && data)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 
fromStatus(const binder::Status & status,T & data)57     static HalResult<T> fromStatus(const binder::Status& status, T& data) {
58         return HalResult<T>::fromStatus(status, T{data});
59     }
60 
fromStatus(const ndk::ScopedAStatus & ndkStatus,T && data)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 
fromStatus(const ndk::ScopedAStatus & ndkStatus,T & data)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>
fromReturn(hardware::Return<R> & ret,T && data)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>
fromReturn(hardware::Return<R> & ret,T & data)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>
fromReturn(hardware::Return<R> & ret,hardware::power::V1_0::Status status,T && data)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>
fromReturn(hardware::Return<R> & ret,hardware::power::V1_0::Status status,T & data)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.
value()100     const T& value() const { return mValue.value(); }
isOk()101     bool isOk() const { return !mUnsupported && mValue.has_value(); }
isFailed()102     bool isFailed() const { return !mUnsupported && !mValue.has_value(); }
isUnsupported()103     bool isUnsupported() const { return mUnsupported; }
errorMessage()104     const char* errorMessage() const { return mErrorMessage.c_str(); }
105 
106 private:
107     std::optional<T> mValue;
108     std::string mErrorMessage;
109     bool mUnsupported;
110 
HalResult(T && value)111     explicit HalResult(T&& value)
112           : mValue{std::move(value)}, mErrorMessage(), mUnsupported(false) {}
HalResult(std::string errorMessage,bool unsupported)113     explicit HalResult(std::string errorMessage, bool unsupported)
114           : mValue(), mErrorMessage(std::move(errorMessage)), mUnsupported(unsupported) {}
115 };
116 
117 // Empty result
118 template <>
119 class HalResult<void> {
120 public:
ok()121     static HalResult<void> ok() { return HalResult(); }
failed(std::string msg)122     static HalResult<void> failed(std::string msg) { return HalResult(std::move(msg)); }
unsupported()123     static HalResult<void> unsupported() { return HalResult(/* unsupported= */ true); }
124 
fromStatus(const binder::Status & status)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 
fromStatus(const ndk::ScopedAStatus & ndkStatus)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>
fromReturn(hardware::Return<R> & ret)146     static HalResult<void> fromReturn(hardware::Return<R>& ret) {
147         return ret.isOk() ? HalResult<void>::ok() : HalResult<void>::failed(ret.description());
148     }
149 
isOk()150     bool isOk() const { return !mUnsupported && !mFailed; }
isFailed()151     bool isFailed() const { return !mUnsupported && mFailed; }
isUnsupported()152     bool isUnsupported() const { return mUnsupported; }
errorMessage()153     const char* errorMessage() const { return mErrorMessage.c_str(); }
154 
155 private:
156     std::string mErrorMessage;
157     bool mFailed;
158     bool mUnsupported;
159 
160     explicit HalResult(bool unsupported = false)
mErrorMessage()161           : mErrorMessage(), mFailed(false), mUnsupported(unsupported) {}
HalResult(std::string errorMessage)162     explicit HalResult(std::string errorMessage)
163           : mErrorMessage(std::move(errorMessage)), mFailed(true), mUnsupported(false) {}
164 };
165 } // namespace android::power
166