1 /*
2  * Copyright (C) 2017 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 #ifndef ANDROID_PACKAGES_MODULES_NEURALNETWORKS_RUNTIME_TEST_PREPARED_MODEL_CALLBACK_H
18 #define ANDROID_PACKAGES_MODULES_NEURALNETWORKS_RUNTIME_TEST_PREPARED_MODEL_CALLBACK_H
19 
20 #include <HalInterfaces.h>
21 #include <Utils.h>
22 #include <android-base/thread_annotations.h>
23 #include <nnapi/Types.h>
24 
25 #include <condition_variable>
26 #include <functional>
27 #include <mutex>
28 #include <thread>
29 #include <vector>
30 
31 /*
32  * The Callback classes are used internally by the NeuralNetworks runtime to
33  * synchronize between different threads. An asynchronous task is launched
34  * paired with a callback object. When a client thread requires the output being
35  * generated by the asynchronous task, the client thread can wait for the result
36  * and be blocked until it has completed. Any wait may safely be called
37  * concurrently, even on the same callback object. When the asynchronous task
38  * has finished its workload, it must immediately call "notify*". If the
39  * asynchronous task has failed to launch, the function that tried to launch the
40  * asynchronous task must immediately call "notify*". This "notify*" call
41  * awakens any client threads waiting on the callback object.
42  *
43  * These classes exist to enable synchronization across HIDL. When
44  * synchronization is only required in the same process, consider using
45  * std::future, std::mutex, std::condition_variable, or std::experimental::latch
46  * instead.
47  */
48 
49 namespace android::nn {
50 
51 /**
52  * The PreparedModelCallback class is used to receive the error status of
53  * preparing a model as well as the prepared model from a task executing
54  * asynchronously with respect to the runtime. If a calling thread calls wait
55  * or get* on a PreparedModelCallback object and the corresponding asynchronous
56  * task has not finished preparing the model, the calling thread will block
57  * until the asynchronous task has called notify*.
58  *
59  * If the callback object is notified more than once, only the results of the
60  * first call to notify* are used, and the results from subsequent calls are
61  * discarded.
62  *
63  * This callback object is passed as an argument to IDevice::prepareModel*.
64  */
65 class PreparedModelCallback : public V1_3::IPreparedModelCallback {
66    public:
67     /**
68      * IPreparedModelCallback::notify marks the callback object with the return
69      * status of the asynchronous model preparation along with the prepared
70      * model, and allows all prior and future wait calls on the
71      * PreparedModelCallback object to proceed.
72      *
73      * One of IPreparedModelCallback::notify, IPreparedModelCallback::notify_1_2,
74      * or IPreparedModelCallback::notify_1_3 must be called on a given
75      * PreparedModelCallback object.
76      *
77      * If the callback object is notified more than once, only the results of
78      * the first call to notify* are used, and the results from subsequent calls
79      * are discarded.
80      *
81      * @param status Error status returned from asynchronously preparing the
82      *     model; will be:
83      *     - NONE if the asynchronous preparation was successful
84      *     - DEVICE_UNAVAILABLE if driver is offline or busy
85      *     - GENERAL_FAILURE if there is an unspecified error
86      *     - INVALID_ARGUMENT if the input model is invalid
87      * @param preparedModel Returned model that has been prepared for execution,
88      *     nullptr if the model was unable to be prepared.
89      */
90     hardware::Return<void> notify(V1_0::ErrorStatus status,
91                                   const sp<V1_0::IPreparedModel>& preparedModel) override;
92 
93     /**
94      * IPreparedModelCallback::notify_1_2 marks the callback object with the
95      * return status of the asynchronous model preparation along with the
96      * prepared model, and allows all prior and future wait calls on the
97      * PreparedModelCallback object to proceed.
98      *
99      * One of IPreparedModelCallback::notify, IPreparedModelCallback::notify_1_2,
100      * or IPreparedModelCallback::notify_1_3 must be called on a given
101      * PreparedModelCallback object.
102      *
103      * If the callback object is notified more than once, only the results of
104      * the first call to notify* are used, and the results from subsequent calls
105      * are discarded.
106      *
107      * @param status Error status returned from asynchronously preparing the
108      *     model; will be:
109      *     - NONE if the asynchronous preparation was successful
110      *     - DEVICE_UNAVAILABLE if driver is offline or busy
111      *     - GENERAL_FAILURE if there is an unspecified error
112      *     - INVALID_ARGUMENT if the input model is invalid
113      * @param preparedModel Returned model that has been prepared for execution,
114      *     nullptr if the model was unable to be prepared.
115      */
116     hardware::Return<void> notify_1_2(V1_0::ErrorStatus status,
117                                       const sp<V1_2::IPreparedModel>& preparedModel) override;
118 
119     /**
120      * IPreparedModelCallback::notify_1_3 marks the callback object with the
121      * return status of the asynchronous model preparation along with the
122      * prepared model, and allows all prior and future wait calls on the
123      * PreparedModelCallback object to proceed.
124      *
125      * One of IPreparedModelCallback::notify, IPreparedModelCallback::notify_1_2,
126      * or IPreparedModelCallback::notify_1_3 must be called on a given
127      * PreparedModelCallback object.
128      *
129      * If the callback object is notified more than once, only the results of
130      * the first call to notify* are used, and the results from subsequent calls
131      * are discarded.
132      *
133      * @param status Error status returned from asynchronously preparing the
134      *     model; will be:
135      *     - NONE if the asynchronous preparation was successful
136      *     - DEVICE_UNAVAILABLE if driver is offline or busy
137      *     - GENERAL_FAILURE if there is an unspecified error
138      *     - INVALID_ARGUMENT if the input model is invalid
139      *     - MISSED_DEADLINE_* if the deadline could not be met
140      *     - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
141      * @param preparedModel Returned model that has been prepared for execution,
142      *     nullptr if the model was unable to be prepared.
143      */
144     hardware::Return<void> notify_1_3(V1_3::ErrorStatus status,
145                                       const sp<V1_3::IPreparedModel>& preparedModel) override;
146 
147     /**
148      * Mark the callback object as a dead object. This acts as a call to notify.
149      */
150     void notifyAsDeadObject();
151 
152     /**
153      * PreparedModelCallback::wait blocks until notify* has been called on the
154      * callback object.
155      */
156     void wait() const;
157 
158     /**
159      * Retrieves the error status returned from the asynchronous task launched
160      * by IDevice::prepareModel*. If IDevice::prepareModel* has not finished
161      * asynchronously preparing the model, this call will block until the
162      * asynchronous task notifies the object.
163      *
164      * @return status Error status returned from asynchronously preparing the
165      *     model; will be:
166      *     - NONE if the asynchronous preparation was successful
167      *     - DEVICE_UNAVAILABLE if driver is offline or busy
168      *     - GENERAL_FAILURE if there is an unspecified error
169      *     - INVALID_ARGUMENT if the input model is invalid
170      *     - MISSED_DEADLINE_* if the deadline could not be met
171      *     - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
172      *     - DEAD_OBJECT if the driver crashed without returning a result
173      */
174     ErrorStatus getStatus() const;
175 
176     /**
177      * Retrieves the model that has been prepared for execution from the
178      * asynchronous task launched by IDevice::prepareModel*. If
179      * IDevice::prepareModel* has not finished asynchronously preparing the
180      * model, this call will block until the asynchronous task notifies the
181      * object.
182      *
183      * @return preparedModel Returned model that has been prepared for
184      *     execution, nullptr if the model was unable to be prepared.
185      */
186     sp<V1_0::IPreparedModel> getPreparedModel() const;
187 
188     /**
189      * Queries whether the object is dead.
190      *
191      * @return 'true' if dead, 'false' otherwise.
192      */
193     bool isDeadObject() const;
194 
195    private:
196     hardware::Return<void> notifyInternal(bool deadObject, ErrorStatus errorStatus,
197                                           const sp<V1_0::IPreparedModel>& preparedModel);
198 
199     mutable std::mutex mMutex;
200     mutable std::condition_variable mCondition;
201     bool mNotified GUARDED_BY(mMutex) = false;
202     bool mDeadObject = false;
203     ErrorStatus mErrorStatus = ErrorStatus::GENERAL_FAILURE;
204     sp<V1_0::IPreparedModel> mPreparedModel;
205 };
206 
207 }  // namespace android::nn
208 
209 #endif  // ANDROID_PACKAGES_MODULES_NEURALNETWORKS_RUNTIME_TEST_PREPARED_MODEL_CALLBACK_H
210