• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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_ML_NN_RUNTIME_VERSIONED_INTERFACES_H
18 #define ANDROID_ML_NN_RUNTIME_VERSIONED_INTERFACES_H
19 
20 #include "HalInterfaces.h"
21 
22 #include <android-base/macros.h>
23 #include <cstddef>
24 #include <functional>
25 #include <memory>
26 #include <optional>
27 #include <shared_mutex>
28 #include <string>
29 #include <tuple>
30 #include <utility>
31 #include "Callbacks.h"
32 
33 namespace android {
34 namespace nn {
35 
36 // forward declarations
37 class ExecutionBurstController;
38 class IDeviceDeathHandler;
39 class IModelSlicer;
40 class IPreparedModelDeathHandler;
41 class VersionedIPreparedModel;
42 
43 /**
44  * Each class (VersionedIDevice, VersionedIPreparedModel) wraps a HIDL interface
45  * of any version to abstract away version differences. It allows the remainder
46  * of the runtime to always use the most up-to-date version of all HIDL types.
47  * As such, any reference to a HIDL type in the rest of the runtime
48  * will--by default--be the latest HIDL version.
49  *
50  * Each class will attempt to call the latest version of each interface method
51  * if possible. If the latest method is unavailable, the versioned class
52  * will attempt to upcast the type (e.g., V1_1::Model to V1_0::Model), and
53  * invoke the latest interface method possible. If the versioned class
54  * fails to find a matching applicable function, it will return an error.
55  */
56 
57 /** This class wraps an IDevice object of any version. */
58 class VersionedIDevice {
59     DISALLOW_IMPLICIT_CONSTRUCTORS(VersionedIDevice);
60 
61     // forward declaration of nested class
62     class Core;
63 
64    public:
65     /**
66      * Create a VersionedIDevice object.
67      *
68      * Prefer using this function over the constructor, as it adds more
69      * protections.
70      *
71      * @param serviceName The name of the service that provides "device".
72      * @param device A device object that is at least version 1.0 of the IDevice
73      *               interface.
74      * @return A valid VersionedIDevice object, otherwise nullptr.
75      */
76     static std::shared_ptr<VersionedIDevice> create(std::string serviceName,
77                                                     sp<V1_0::IDevice> device);
78 
79     /**
80      * Constructor for the VersionedIDevice object.
81      *
82      * VersionedIDevice will default to using the latest version of all IDevice
83      * interface methods automatically.
84      *
85      * @param serviceName The name of the service that provides core.getDevice<V1_0::IDevice>().
86      * @param core An object that encapsulates a V1_0::IDevice, any appropriate downcasts to
87      *             newer interfaces, and a hidl_death_recipient that will proactively handle
88      *             the case when the service containing the IDevice object crashes.
89      */
90     VersionedIDevice(std::string serviceName, Core core);
91 
92     /**
93      * Gets the capabilities of a driver.
94      *
95      * @return status Error status of the call, must be:
96      *                - NONE if successful
97      *                - DEVICE_UNAVAILABLE if driver is offline or busy
98      *                - GENERAL_FAILURE if there is an unspecified error
99      * @return capabilities Capabilities of the driver.
100      */
101     std::pair<ErrorStatus, Capabilities> getCapabilities();
102 
103     /**
104      * Gets information about extensions supported by the driver implementation.
105      *
106      * Extensions of category ExtensionCategory::BASE must not appear
107      * in the list.
108      *
109      * All extension operations and operands must be fully supported for the
110      * extension to appear in the list of supported extensions.
111      *
112      * @return status Error status of the call, must be:
113      *     - NONE if successful
114      *     - DEVICE_UNAVAILABLE if driver is offline or busy
115      *     - GENERAL_FAILURE if there is an unspecified error
116      * @return extensions A list of supported extensions.
117      */
118     std::pair<ErrorStatus, hidl_vec<Extension>> getSupportedExtensions();
119 
120     /**
121      * Gets the supported operations in a model.
122      *
123      * getSupportedOperations indicates which operations of a model are fully
124      * supported by the vendor driver. If an operation may not be supported for
125      * any reason, getSupportedOperations must return false for that operation.
126      *
127      * @param model A model whose operations--and their corresponding
128      *              operands--are to be verified by the driver.
129      * @param slicer When the model is not compliant with the HAL version of the
130      *               vendor driver, the slicer (if any) is employed to query the
131      *               vendor driver about which of the subset of compliant
132      *               operations are supported.  See the IModelSlicer class in
133      *               Utils.h for more details.
134      * @return status Error status of the call, must be:
135      *                - NONE if successful
136      *                - DEVICE_UNAVAILABLE if driver is offline or busy
137      *                - GENERAL_FAILURE if there is an unspecified error
138      *                - INVALID_ARGUMENT if provided model is invalid
139      * @return supportedOperations A list of supported operations, where true
140      *                             indicates the operation is supported and
141      *                             false indicates the operation is not
142      *                             supported. The index of "supported"
143      *                             corresponds with the index of the operation
144      *                             it is describing.
145      */
146     std::pair<ErrorStatus, hidl_vec<bool>> getSupportedOperations(const Model& model,
147                                                                   IModelSlicer* slicer = nullptr);
148 
149     /**
150      * Synchronously creates a prepared model for execution and optionally saves it
151      * into cache files.
152      *
153      * prepareModel is used to make any necessary transformations or alternative
154      * representations to a model for execution, possibly including
155      * transformations on the constant data, optimization on the model's graph,
156      * or compilation into the device's native binary format. The model itself
157      * is not changed.
158      *
159      * Optionally, caching information may be provided for the driver to save
160      * the prepared model to cache files for faster model compilation time
161      * when the same model preparation is requested in the future. There are
162      * two types of cache file handles provided to the driver: model cache
163      * and data cache. For more information on the two types of cache handles,
164      * refer to getNumberOfCacheFilesNeeded.
165      *
166      * The file descriptors must be opened with read and write permission. A file may
167      * have any size, and the corresponding file descriptor may have any offset. The
168      * driver must truncate a file to zero size before writing to that file. The file
169      * descriptors may be closed by the client once the asynchronous preparation has
170      * finished. The driver must dup a file descriptor if it wants to get access to
171      * the cache file later.
172      *
173      * The model is prepared synchronously with respect to the caller. The
174      * prepareModel function must verify the inputs to the preparedModel
175      * function related to preparing the model (as opposed to saving the
176      * prepared model to cache) are correct. If there is an error, prepareModel
177      * must immediately return the appropriate ErrorStatus value and nullptr for
178      * the VersionedIPreparedModel. If the inputs to the prepareModel function
179      * that are related to preparing the model are valid and there is no error,
180      * prepareModel must prepare the model.
181      *
182      * If the model was prepared successfully, prepareModel must return
183      * ErrorStatus::NONE and the produced VersionedIPreparedModel object. If an
184      * error occurred preparing the model, prepareModel must return the
185      * appropriate ErrorStatus value and nullptr for the
186      * VersionedIPreparedModel.
187      *
188      * Optionally, the driver may save the prepared model to cache during
189      * preparation. Any error that occurs when saving to cache must not affect
190      * the status of preparing the model. Even if the input arguments related to
191      * the cache may be invalid, or the driver may fail to save to cache, the
192      * prepareModel function must finish preparing the model. The driver may
193      * choose not to save to cache even if the caching information is provided
194      * and valid.
195      *
196      * The only information that may be unknown to the model at this stage is
197      * the shape of the tensors, which may only be known at execution time. As
198      * such, some driver services may return partially prepared models, where
199      * the prepared model may only be finished when it is paired with a set of
200      * inputs to the model. Note that the same prepared model object may be
201      * used with different shapes of inputs on different (possibly concurrent)
202      * executions.
203      *
204      * Multiple threads may call prepareModel on the same model concurrently.
205      *
206      * @param model The model to be prepared for execution.
207      * @param preference Indicates the intended execution behavior of a prepared
208      *     model.
209      * @param modelCache A vector of handles with each entry holding exactly one
210      *     cache file descriptor for the security-sensitive cache. The length of
211      *     the vector must either be 0 indicating that caching information is not provided,
212      *     or match the numModelCache returned from getNumberOfCacheFilesNeeded. The cache
213      *     handles will be provided in the same order when retrieving the
214      *     preparedModel from cache files with prepareModelFromCache.
215      * @param dataCache A vector of handles with each entry holding exactly one
216      *     cache file descriptor for the constants' cache. The length of
217      *     the vector must either be 0 indicating that caching information is not provided,
218      *     or match the numDataCache returned from getNumberOfCacheFilesNeeded. The cache
219      *     handles will be provided in the same order when retrieving the
220      *     preparedModel from cache files with prepareModelFromCache.
221      * @param token A caching token of length Constant::BYTE_SIZE_OF_CACHE_TOKEN
222      *     identifying the prepared model. The same token will be provided when retrieving
223      *     the prepared model from the cache files with prepareModelFromCache.
224      *     Tokens should be chosen to have a low rate of collision for a particular
225      *     application. The driver cannot detect a collision; a collision will result
226      *     in a failed execution or in a successful execution that produces incorrect
227      *     output values. If both modelCache and dataCache are empty indicating that
228      *     caching information is not provided, this token must be ignored.
229      * @return A pair of:
230      *     - status Error status of preparing the model; must be:
231      *         - NONE if preparation succeeded
232      *         - DEVICE_UNAVAILABLE if driver is offline or busy
233      *         - GENERAL_FAILURE if there is an unspecified error
234      *         - INVALID_ARGUMENT if one of the input arguments related to
235      *             preparing the model is invalid
236      *     - preparedModel A VersionedIPreparedModel object representing a model
237      *         that has been prepared for execution, else nullptr.
238      */
239     std::pair<ErrorStatus, std::shared_ptr<VersionedIPreparedModel>> prepareModel(
240             const Model& model, ExecutionPreference preference,
241             const hidl_vec<hidl_handle>& modelCache, const hidl_vec<hidl_handle>& dataCache,
242             const hidl_array<uint8_t, static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>&
243                     token);
244 
245     /**
246      * Creates a prepared model from cache files for execution.
247      *
248      * prepareModelFromCache is used to retrieve a prepared model directly from
249      * cache files to avoid slow model compilation time. There are
250      * two types of cache file handles provided to the driver: model cache
251      * and data cache. For more information on the two types of cache handles,
252      * refer to getNumberOfCacheFilesNeeded.
253      *
254      * The file descriptors must be opened with read and write permission. A file may
255      * have any size, and the corresponding file descriptor may have any offset. The
256      * driver must truncate a file to zero size before writing to that file. The file
257      * descriptors may be closed by the client once the asynchronous preparation has
258      * finished. The driver must dup a file descriptor if it wants to get access to
259      * the cache file later.
260      *
261      * The model is prepared synchronously with respect to the caller. The
262      * prepareModelFromCache function must verify the inputs to the
263      * prepareModelFromCache function are correct, and that the
264      * security-sensitive cache has not been modified since it was last written
265      * by the driver. If there is an error, or if compilation caching is not
266      * supported, or if the security-sensitive cache has been modified,
267      * prepareModelFromCache must return the appropriate ErrorStatus value and
268      * nullptr for the VersionedIPreparedModel. If the inputs to the
269      * prepareModelFromCache function are valid, the security-sensitive cache is
270      * not modified, and there is no error, prepareModelFromCache must prepare
271      * the model.
272      *
273      * If the model was prepared successfully, prepareModelFromCache must return
274      * ErrorStatus::NONE and the produced VersionedIPreparedModel object. If an
275      * error occurred preparing the model, prepareModelFromCache must return the
276      * appropriate ErrorStatus value and nullptr for the
277      * VersionedIPreparedModel.
278      *
279      * The only information that may be unknown to the model at this stage is
280      * the shape of the tensors, which may only be known at execution time. As
281      * such, some driver services may return partially prepared models, where
282      * the prepared model may only be finished when it is paired with a set of
283      * inputs to the model. Note that the same prepared model object may be
284      * used with different shapes of inputs on different (possibly concurrent)
285      * executions.
286      *
287      * @param modelCache A vector of handles with each entry holding exactly one
288      *     cache file descriptor for the security-sensitive cache. The length of
289      *     the vector must match the numModelCache returned from getNumberOfCacheFilesNeeded.
290      *     The cache handles will be provided in the same order as with prepareModel_1_2.
291      * @param dataCache A vector of handles with each entry holding exactly one
292      *     cache file descriptor for the constants' cache. The length of the vector
293      *     must match the numDataCache returned from getNumberOfCacheFilesNeeded.
294      *     The cache handles will be provided in the same order as with prepareModel_1_2.
295      * @param token A caching token of length Constant::BYTE_SIZE_OF_CACHE_TOKEN
296      *     identifying the prepared model. It is the same token provided when saving
297      *     the cache files with prepareModel_1_2. Tokens should be chosen
298      *     to have a low rate of collision for a particular application. The driver
299      *     cannot detect a collision; a collision will result in a failed execution
300      *     or in a successful execution that produces incorrect output values.
301      * @return A pair of:
302      *     - status Error status of preparing the model; must be:
303      *         - NONE if preparation succeeded
304      *         - DEVICE_UNAVAILABLE if driver is offline or busy
305      *         - GENERAL_FAILURE if caching is not supported or if there is an
306      *             unspecified error
307      *         - INVALID_ARGUMENT if one of the input arguments is invalid
308      *     - preparedModel A VersionedIPreparedModel object representing a model
309      *        that has been prepared for execution, else nullptr.
310      */
311     std::pair<ErrorStatus, std::shared_ptr<VersionedIPreparedModel>> prepareModelFromCache(
312             const hidl_vec<hidl_handle>& modelCache, const hidl_vec<hidl_handle>& dataCache,
313             const hidl_array<uint8_t, static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>&
314                     token);
315 
316     /**
317      * Returns the current status of a driver.
318      *
319      * @return status Status of the driver, one of:
320      *                - DeviceStatus::AVAILABLE
321      *                - DeviceStatus::BUSY
322      *                - DeviceStatus::OFFLINE
323      *                - DeviceStatus::UNKNOWN
324      */
325     DeviceStatus getStatus();
326 
327     /**
328      * Returns the feature level of a driver.
329      *
330      * @return featureLevel The API level of the most advanced feature this driver implements.
331      *                      For example, if the driver implements the features introduced in
332      *                      Android P, the value would be 28.
333      *                      Return -1 if the driver is offline or busy, or the query resulted in
334      *                      an unspecified error.
335      */
336     int64_t getFeatureLevel();
337 
338     /**
339      * Returns the device type of a driver.
340      *
341      * @return deviceType The type of a given device, which can help application developers
342      *                    developers to distribute Machine Learning workloads and other workloads
343      *                    such as graphical rendering. E.g., for an app which renders AR scenes
344      *                    based on real time object detection results, the developer could choose
345      *                    an ACCELERATOR type device for ML workloads, and reserve GPU for
346      *                    graphical rendering.
347      *                    Return -1 if the driver is offline or busy, or the query resulted in
348      *                    an unspecified error.
349      */
350     int32_t getType() const;
351 
352     /**
353      * Get the version string of the driver implementation.
354      *
355      * The version string must be a unique token among the set of version strings of
356      * drivers of a specific device. The token identifies the device driver's
357      * implementation. The token must not be confused with the feature level which is solely
358      * defined by the interface version. This API is opaque to the Android framework, but the
359      * Android framework may use the information for debugging or to pass on to NNAPI applications.
360      *
361      * Application developers sometimes have specific requirements to ensure good user experiences,
362      * and they need more information to make intelligent decisions when the Android framework
363      * cannot. For example, combined with the device name and other information, the token can help
364      * NNAPI applications filter devices based on their needs:
365      *     - An application demands a certain level of performance, but a specific version of
366      *       the driver cannot meet that requirement because of a performance regression.
367      *       The application can blacklist the driver based on the version provided.
368      *     - An application has a minimum precision requirement, but certain versions of
369      *       the driver cannot meet that requirement because of bugs or certain optimizations.
370      *       The application can filter out versions of these drivers.
371      *
372      * @return status Error status returned from querying the version string. Must be:
373      *     - NONE if the query was successful
374      *     - DEVICE_UNAVAILABLE if driver is offline or busy
375      *     - GENERAL_FAILURE if the query resulted in an
376      *       unspecified error
377      * @return version The version string of the device implementation.
378      *     Must have nonzero length if the query is successful, and must be an empty string if not.
379      */
380     std::pair<ErrorStatus, hidl_string> getVersionString();
381 
382     /**
383      * Gets the caching requirements of the driver implementation.
384      *
385      * There are two types of cache file descriptors provided to the driver: model cache
386      * and data cache.
387      *
388      * The data cache is for caching constant data, possibly including preprocessed
389      * and transformed tensor buffers. Any modification to the data cache should
390      * have no worse effect than generating bad output values at execution time.
391      *
392      * The model cache is for caching security-sensitive data such as compiled
393      * executable machine code in the device's native binary format. A modification
394      * to the model cache may affect the driver's execution behavior, and a malicious
395      * client could make use of this to execute beyond the granted permission. Thus,
396      * the driver must always check whether the model cache is corrupted before
397      * preparing the model from cache.
398      *
399      * getNumberOfCacheFilesNeeded returns how many of each type of cache files the driver
400      * implementation needs to cache a single prepared model. Returning 0 for both types
401      * indicates compilation caching is not supported by this driver. The driver may
402      * still choose not to cache certain compiled models even if it reports that caching
403      * is supported.
404      *
405      * If the device reports that caching is not supported, the user may avoid calling
406      * IDevice::prepareModelFromCache or providing cache file descriptors to
407      * IDevice::prepareModel_1_2.
408      *
409      * @return status Error status of the call, must be:
410      *     - NONE if successful
411      *     - DEVICE_UNAVAILABLE if driver is offline or busy
412      *     - GENERAL_FAILURE if there is an unspecified error
413      * @return numModelCache An unsigned integer indicating how many files for model cache
414      *                       the driver needs to cache a single prepared model. It must
415      *                       be less than or equal to Constant::MAX_NUMBER_OF_CACHE_FILES.
416      * @return numDataCache An unsigned integer indicating how many files for data cache
417      *                      the driver needs to cache a single prepared model. It must
418      *                      be less than or equal to Constant::MAX_NUMBER_OF_CACHE_FILES.
419      */
420     std::tuple<ErrorStatus, uint32_t, uint32_t> getNumberOfCacheFilesNeeded();
421 
422     /**
423      * Returns the name of the service that implements the driver
424      *
425      * @return serviceName The name of the service.
426      */
getServiceName()427     std::string getServiceName() const { return mServiceName; }
428 
429     /**
430      * Returns whether this handle to an IDevice object is valid or not.
431      *
432      * @return bool true if V1_0::IDevice (which could be V1_1::IDevice) is
433      *              valid, false otherwise.
434      */
435     bool operator!=(nullptr_t) const;
436 
437     /**
438      * Returns whether this handle to an IDevice object is valid or not.
439      *
440      * @return bool true if V1_0::IDevice (which could be V1_1::IDevice) is
441      *              invalid, false otherwise.
442      */
443     bool operator==(nullptr_t) const;
444 
445    private:
446     /**
447      * This is a utility class for VersionedIDevice that encapsulates a
448      * V1_0::IDevice, any appropriate downcasts to newer interfaces, and a
449      * hidl_death_recipient that will proactively handle the case when the
450      * service containing the IDevice object crashes.
451      *
452      * This is a convenience class to help VersionedIDevice recover from an
453      * IDevice object crash: It bundles together all the data that needs to
454      * change when recovering from a crash, and simplifies the process of
455      * instantiating that data (at VersionedIDevice creation time) and
456      * re-instantiating that data (at crash recovery time).
457      */
458     class Core {
459        public:
460         /**
461          * Constructor for the Core object.
462          *
463          * Core is constructed with a V1_0::IDevice object, which represents a
464          * device that is at least v1.0 of the interface. The constructor
465          * downcasts to the latest version of the IDevice interface, allowing
466          * VersionedIDevice to default to using the latest version of all
467          * IDevice interface methods automatically.
468          *
469          * @param device A device object that is at least version 1.0 of the IDevice
470          *               interface.
471          * @param deathHandler A hidl_death_recipient that will proactively handle
472          *                     the case when the service containing the IDevice
473          *                     object crashes.
474          */
475         Core(sp<V1_0::IDevice> device, sp<IDeviceDeathHandler> deathHandler);
476 
477         /**
478          * Destructor for the Core object.
479          *
480          * This destructor unlinksToDeath this object's hidl_death_recipient as it
481          * no longer needs to handle the case where the IDevice's service crashes.
482          */
483         ~Core();
484 
485         // Support move but not copy
486         Core(Core&&) noexcept;
487         Core& operator=(Core&&) noexcept;
488         Core(const Core&) = delete;
489         Core& operator=(const Core&) = delete;
490 
491         /**
492          * Create a Core object.
493          *
494          * Prefer using this function over the constructor, as it adds more
495          * protections.
496          *
497          * This call linksToDeath a hidl_death_recipient that can
498          * proactively handle the case when the service containing the IDevice
499          * object crashes.
500          *
501          * @param device A device object that is at least version 1.0 of the IDevice
502          *               interface.
503          * @return A valid Core object, otherwise nullopt.
504          */
505         static std::optional<Core> create(sp<V1_0::IDevice> device);
506 
507         /**
508          * Returns sp<*::IDevice> that is a downcast of the sp<V1_0::IDevice>
509          * passed to the constructor.  This will be nullptr if that IDevice is
510          * not actually of the specified downcast type.
511          */
512         template <typename T_IDevice>
513         sp<T_IDevice> getDevice() const;
514         template <>
getDevice()515         sp<V1_0::IDevice> getDevice() const {
516             return mDeviceV1_0;
517         }
518         template <>
getDevice()519         sp<V1_1::IDevice> getDevice() const {
520             return mDeviceV1_1;
521         }
522         template <>
getDevice()523         sp<V1_2::IDevice> getDevice() const {
524             return mDeviceV1_2;
525         }
526 
527         /**
528          * Returns sp<*::IDevice> (as per getDevice()) and the
529          * hidl_death_recipient that will proactively handle the case when the
530          * service containing the IDevice object crashes.
531          */
532         template <typename T_IDevice>
533         std::pair<sp<T_IDevice>, sp<IDeviceDeathHandler>> getDeviceAndDeathHandler() const;
534 
535        private:
536         /**
537          * All versions of IDevice are necessary because the driver could be v1.0,
538          * v1.1, or a later version. All these pointers logically represent the same
539          * object.
540          *
541          * The general strategy is: HIDL returns a V1_0 device object, which
542          * (if not nullptr) could be v1.0, v1.1, or a greater version. The V1_0
543          * object is then "dynamically cast" to a V1_1 object. If successful,
544          * mDeviceV1_1 will point to the same object as mDeviceV1_0; otherwise,
545          * mDeviceV1_1 will be nullptr.
546          *
547          * In general:
548          * * If the device is truly v1.0, mDeviceV1_0 will point to a valid object
549          *   and mDeviceV1_1 will be nullptr.
550          * * If the device is truly v1.1 or later, both mDeviceV1_0 and mDeviceV1_1
551          *   will point to the same valid object.
552          *
553          * Idiomatic usage: if mDeviceV1_1 is non-null, do V1_1 dispatch; otherwise,
554          * do V1_0 dispatch.
555          */
556         sp<V1_0::IDevice> mDeviceV1_0;
557         sp<V1_1::IDevice> mDeviceV1_1;
558         sp<V1_2::IDevice> mDeviceV1_2;
559 
560         /**
561          * HIDL callback to be invoked if the service for mDeviceV1_0 crashes.
562          *
563          * nullptr if this Core instance is a move victim and hence has no
564          * callback to be unlinked.
565          */
566         sp<IDeviceDeathHandler> mDeathHandler;
567     };
568 
569     // This method retrieves the appropriate mCore.mDevice* field, under a read lock.
570     template <typename T_IDevice>
getDevice()571     sp<T_IDevice> getDevice() const EXCLUDES(mMutex) {
572         std::shared_lock lock(mMutex);
573         return mCore.getDevice<T_IDevice>();
574     }
575 
576     // This method retrieves the appropriate mCore.mDevice* fields, under a read lock.
577     template <typename T_IDevice>
getDeviceAndDeathHandler()578     auto getDeviceAndDeathHandler() const EXCLUDES(mMutex) {
579         std::shared_lock lock(mMutex);
580         return mCore.getDeviceAndDeathHandler<T_IDevice>();
581     }
582 
583     // This method calls the function fn in a manner that supports recovering
584     // from a driver crash: If the driver implementation is dead because the
585     // driver crashed either before the call to fn or during the call to fn, we
586     // will attempt to obtain a new instance of the same driver and call fn
587     // again.
588     //
589     // If a callback is provided, this method protects it against driver death
590     // and waits for it (callback->wait()).
591     template <typename T_Return, typename T_IDevice, typename T_Callback = std::nullptr_t>
592     Return<T_Return> recoverable(const char* context,
593                                  const std::function<Return<T_Return>(const sp<T_IDevice>&)>& fn,
594                                  const T_Callback& callback = nullptr) const EXCLUDES(mMutex);
595 
596     // The name of the service that implements the driver.
597     const std::string mServiceName;
598 
599     // Guards access to mCore.
600     mutable std::shared_mutex mMutex;
601 
602     // Data that can be rewritten during driver recovery.  Guarded againt
603     // synchronous access by a mutex: Any number of concurrent read accesses is
604     // permitted, but a write access excludes all other accesses.
605     mutable Core mCore GUARDED_BY(mMutex);
606 };
607 
608 /** This class wraps an IPreparedModel object of any version. */
609 class VersionedIPreparedModel {
610     DISALLOW_IMPLICIT_CONSTRUCTORS(VersionedIPreparedModel);
611 
612    public:
613     /**
614      * Constructor for the VersionedIPreparedModel object.
615      *
616      * This constructor should not be used directly. Instead,
617      * VersionedIPreparedModel should be created via
618      * VersionedIDevice::prepareModel*.
619      *
620      * VersionedIPreparedModel is constructed with the V1_0::IPreparedModel object, which
621      * represents a device that is at least v1.0 of the interface. The constructor downcasts
622      * to the latest version of the IPreparedModel interface, and will default to using the
623      * latest version of all IPreparedModel interface methods automatically.
624      *
625      * @param preparedModel A prepared model object that is least version 1.0 of the
626      *                      IPreparedModel interface.
627      * @param deathHandler A hidl_death_recipient that will proactively handle
628      *                     the case when the service containing the IDevice
629      *                     object crashes.
630      */
631     VersionedIPreparedModel(sp<V1_0::IPreparedModel> preparedModel,
632                             sp<IPreparedModelDeathHandler> deathHandler);
633 
634     /**
635      * Destructor for the VersionedIPreparedModel object.
636      *
637      * This destructor unlinksToDeath this object's hidl_death_recipient as it
638      * no longer needs to handle the case where the IPreparedModel's service
639      * crashes.
640      */
641     ~VersionedIPreparedModel();
642 
643     /**
644      * Launches an asynchronous execution on a prepared model.
645      *
646      * The execution is performed asynchronously with respect to the caller.
647      * execute must verify the inputs to the function are correct. If there is
648      * an error, execute must immediately invoke the callback with the
649      * appropriate ErrorStatus value, then return with the same ErrorStatus. If
650      * the inputs to the function are valid and there is no error, execute must
651      * launch an asynchronous task to perform the execution in the background,
652      * and immediately return with ErrorStatus::NONE. If the asynchronous task
653      * fails to launch, execute must immediately invoke the callback with
654      * ErrorStatus::GENERAL_FAILURE, then return with
655      * ErrorStatus::GENERAL_FAILURE.
656      *
657      * When the asynchronous task has finished its execution, it must
658      * immediately invoke the callback object provided as an input to the
659      * execute function. This callback must be provided with the ErrorStatus of
660      * the execution.
661      *
662      * If the prepared model was prepared from a model wherein all
663      * tensor operands have fully specified dimensions, and the inputs
664      * to the function are valid, then the execution should launch
665      * and complete successfully (ErrorStatus::NONE). There must be
666      * no failure unless the device itself is in a bad state.
667      *
668      * Multiple threads can call the execute and ExecuteSynchronously functions
669      * on the same VersionedIPreparedModel object concurrently with different
670      * requests.
671      *
672      * @param request The input and output information on which the prepared
673      *                model is to be executed.
674      * @param measure Specifies whether or not to measure duration of the execution.
675      * @param callback A callback object used to return the error status of
676      *                 the execution. The callback object's notify function must
677      *                 be called exactly once, even if the execution was
678      *                 unsuccessful.
679      * @return status Error status of the call, must be:
680      *                - NONE if task is successfully launched
681      *                - DEVICE_UNAVAILABLE if driver is offline or busy
682      *                - GENERAL_FAILURE if there is an unspecified error
683      *                - OUTPUT_INSUFFICIENT_SIZE if provided output buffer is
684      *                  not large enough to store the resultant values
685      *                - INVALID_ARGUMENT if one of the input arguments is
686      *                  invalid
687      */
688     ErrorStatus execute(const Request& request, MeasureTiming timing,
689                         const sp<ExecutionCallback>& callback);
690 
691     /**
692      * Performs a synchronous execution on a prepared model.
693      *
694      * The execution is performed synchronously with respect to the caller.
695      * executeSynchronously must verify the inputs to the function are
696      * correct. If there is an error, executeSynchronously must immediately
697      * return with the appropriate ErrorStatus value. If the inputs to the
698      * function are valid and there is no error, executeSynchronously must
699      * perform the execution, and must not return until the execution is
700      * complete.
701      *
702      * If the prepared model was prepared from a model wherein all tensor
703      * operands have fully specified dimensions, and the inputs to the function
704      * are valid, then the execution should complete successfully
705      * (ErrorStatus::NONE). There must be no failure unless the device itself is
706      * in a bad state.
707      *
708      * Any number of calls to the execute and executeSynchronously
709      * functions, in any combination, may be made concurrently, even on the same
710      * VersionedIPreparedModel object.
711      *
712      * @param request The input and output information on which the prepared
713      *                model is to be executed.
714      * @param measure Specifies whether or not to measure duration of the execution.
715      * @return status Error status of the execution, must be:
716      *                - NONE if execution is performed successfully
717      *                - DEVICE_UNAVAILABLE if driver is offline or busy
718      *                - GENERAL_FAILURE if there is an unspecified error
719      *                - OUTPUT_INSUFFICIENT_SIZE if at least one output
720      *                  operand buffer is not large enough to store the
721      *                  corresponding output
722      *                - INVALID_ARGUMENT if one of the input arguments is
723      *                  invalid
724      * @return outputShapes A list of shape information of model output operands.
725      *                      The index into "outputShapes" corresponds with the index
726      *                      of the output operand in the Request outputs vector.
727      *                      outputShapes nust be empty unless the status is either
728      *                      NONE or OUTPUT_INSUFFICIENT_SIZE. outputShaps may be
729      *                      empty if the status is NONE and all model output operands
730      *                      are fully-specified at execution time. outputShapes must
731      *                      have the same number of elements as the number of model
732      *                      output operands if the status is OUTPUT_INSUFFICIENT_SIZE,
733      *                      or if the status is NONE and the model has at least one
734      *                      output operand that is not fully-specified.
735      * @return Timing Duration of execution. Unless measure is YES and status is
736      *                NONE, all times must be reported as UINT64_MAX. A driver may
737      *                choose to report any time as UINT64_MAX, indicating that
738      *                measurement is not available.
739      */
740     std::tuple<ErrorStatus, hidl_vec<OutputShape>, Timing> executeSynchronously(
741             const Request& request, MeasureTiming measure);
742 
743     /**
744      * Creates a burst controller on a prepared model.
745      *
746      * @param blocking 'true' if the FMQ should block until data is available.
747      * @return ExecutionBurstController Execution burst controller object.
748      *                                  nullptr is returned if the burst cannot
749      *                                  be configured for any reason.
750      */
751     std::shared_ptr<ExecutionBurstController> configureExecutionBurst(bool blocking) const;
752 
753     /**
754      * Returns whether this handle to an IPreparedModel object is valid or not.
755      *
756      * @return bool true if V1_0::IPreparedModel (which could be V1_2::IPreparedModel) is
757      *              valid, false otherwise.
758      */
759     bool operator!=(nullptr_t) const;
760 
761     /**
762      * Returns whether this handle to an IPreparedModel object is valid or not.
763      *
764      * @return bool true if V1_0::IPreparedModel (which could be V1_2::IPreparedModel) is
765      *              invalid, false otherwise.
766      */
767     bool operator==(nullptr_t) const;
768 
769    private:
770     /**
771      * All versions of IPreparedModel are necessary because the preparedModel could be v1.0,
772      * v1.2, or a later version. All these pointers logically represent the same object.
773      *
774      * The general strategy is: HIDL returns a V1_0 prepared model object, which
775      * (if not nullptr) could be v1.0, v1.2, or a greater version. The V1_0
776      * object is then "dynamically cast" to a V1_2 object. If successful,
777      * mPreparedModelV1_2 will point to the same object as mPreparedModelV1_0; otherwise,
778      * mPreparedModelV1_2 will be nullptr.
779      *
780      * In general:
781      * * If the prepared model is truly v1.0, mPreparedModelV1_0 will point to a valid object
782      *   and mPreparedModelV1_2 will be nullptr.
783      * * If the prepared model is truly v1.2 or later, both mPreparedModelV1_0 and
784      *   mPreparedModelV1_2 will point to the same valid object.
785      *
786      * Idiomatic usage: if mPreparedModelV1_2 is non-null, do V1_2 dispatch; otherwise,
787      * do V1_0 dispatch.
788      */
789     sp<V1_0::IPreparedModel> mPreparedModelV1_0;
790     sp<V1_2::IPreparedModel> mPreparedModelV1_2;
791 
792     /**
793      * HIDL callback to be invoked if the service for mPreparedModelV1_0 crashes.
794      */
795     const sp<IPreparedModelDeathHandler> mDeathHandler;
796 };
797 
798 }  // namespace nn
799 }  // namespace android
800 
801 #endif  // ANDROID_ML_NN_RUNTIME_VERSIONED_INTERFACES_H
802