1 /*
2 * Copyright (C) 2019 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 #define LOG_TAG "Callbacks"
18
19 #include "1.2/Callbacks.h"
20
21 #include <android-base/logging.h>
22
23 #include <limits>
24
25 namespace android::hardware::neuralnetworks::V1_2::implementation {
26
27 using V1_0::ErrorStatus;
28
29 constexpr Timing kNoTiming = {.timeOnDevice = std::numeric_limits<uint64_t>::max(),
30 .timeInDriver = std::numeric_limits<uint64_t>::max()};
31
32 // PreparedModelCallback methods begin here
33
notify(ErrorStatus errorStatus,const sp<V1_0::IPreparedModel> & preparedModel)34 Return<void> PreparedModelCallback::notify(ErrorStatus errorStatus,
35 const sp<V1_0::IPreparedModel>& preparedModel) {
36 {
37 std::lock_guard<std::mutex> hold(mMutex);
38
39 // quick-return if object has already been notified
40 if (mNotified) {
41 return Void();
42 }
43
44 // store results and mark as notified
45 mErrorStatus = errorStatus;
46 mPreparedModel = preparedModel;
47 mNotified = true;
48 }
49
50 mCondition.notify_all();
51 return Void();
52 }
53
notify_1_2(ErrorStatus errorStatus,const sp<V1_2::IPreparedModel> & preparedModel)54 Return<void> PreparedModelCallback::notify_1_2(ErrorStatus errorStatus,
55 const sp<V1_2::IPreparedModel>& preparedModel) {
56 return notify(errorStatus, preparedModel);
57 }
58
wait() const59 void PreparedModelCallback::wait() const {
60 std::unique_lock<std::mutex> lock(mMutex);
61 mCondition.wait(lock, [this] { return mNotified; });
62 }
63
getStatus() const64 ErrorStatus PreparedModelCallback::getStatus() const {
65 wait();
66 return mErrorStatus;
67 }
68
getPreparedModel() const69 sp<V1_0::IPreparedModel> PreparedModelCallback::getPreparedModel() const {
70 wait();
71 return mPreparedModel;
72 }
73
74 // ExecutionCallback methods begin here
75
notify(ErrorStatus errorStatus)76 Return<void> ExecutionCallback::notify(ErrorStatus errorStatus) {
77 notifyInternal(errorStatus, {}, kNoTiming);
78 return Void();
79 }
80
notify_1_2(ErrorStatus errorStatus,const hidl_vec<OutputShape> & outputShapes,const Timing & timing)81 Return<void> ExecutionCallback::notify_1_2(ErrorStatus errorStatus,
82 const hidl_vec<OutputShape>& outputShapes,
83 const Timing& timing) {
84 if (errorStatus == ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) {
85 // outputShapes must not be empty if OUTPUT_INSUFFICIENT_SIZE.
86 if (outputShapes.size() == 0) {
87 LOG(ERROR) << "Notified with empty output shape vector when OUTPUT_INSUFFICIENT_SIZE";
88 notifyInternal(ErrorStatus::GENERAL_FAILURE, {}, kNoTiming);
89 return Void();
90 }
91 } else if (errorStatus != ErrorStatus::NONE) {
92 // outputShapes must be empty if errorStatus is neither NONE nor OUTPUT_INSUFFICIENT_SIZE.
93 if (outputShapes.size() != 0) {
94 LOG(ERROR) << "Notified with non-empty output shape vector when error status is "
95 "neither NONE nor OUTPUT_INSUFFICIENT_SIZE";
96 notifyInternal(ErrorStatus::GENERAL_FAILURE, {}, kNoTiming);
97 return Void();
98 }
99 }
100 notifyInternal(errorStatus, outputShapes, timing);
101 return Void();
102 }
103
wait() const104 void ExecutionCallback::wait() const {
105 std::unique_lock<std::mutex> lock(mMutex);
106 mCondition.wait(lock, [this] { return mNotified; });
107 }
108
getStatus() const109 ErrorStatus ExecutionCallback::getStatus() const {
110 wait();
111 return mErrorStatus;
112 }
113
getOutputShapes() const114 const std::vector<OutputShape>& ExecutionCallback::getOutputShapes() const {
115 wait();
116 return mOutputShapes;
117 }
118
getTiming() const119 Timing ExecutionCallback::getTiming() const {
120 wait();
121 return mTiming;
122 }
123
notifyInternal(ErrorStatus errorStatus,const hidl_vec<OutputShape> & outputShapes,const Timing & timing)124 void ExecutionCallback::notifyInternal(ErrorStatus errorStatus,
125 const hidl_vec<OutputShape>& outputShapes,
126 const Timing& timing) {
127 {
128 std::lock_guard<std::mutex> hold(mMutex);
129
130 // quick-return if object has already been notified
131 if (mNotified) {
132 return;
133 }
134
135 mErrorStatus = errorStatus;
136 mOutputShapes = outputShapes;
137 mTiming = timing;
138 mNotified = true;
139 }
140 mCondition.notify_all();
141 }
142
143 } // namespace android::hardware::neuralnetworks::V1_2::implementation
144