Merge changes from topic "nnapi_aidl_interface"

* changes:
  Implement VTS tests for NNAPI AIDL interface
  Add utils for AIDL types conversions
  Create first version of NNAPI AIDL interface
  Add dynamic interface casting to NN utility code
This commit is contained in:
Lev Proleev
2021-02-10 16:45:19 +00:00
committed by Gerrit Code Review
113 changed files with 16209 additions and 6 deletions

View File

@@ -378,6 +378,13 @@
<regex-instance>.*</regex-instance>
</interface>
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.neuralnetworks</name>
<interface>
<name>IDevice</name>
<regex-instance>.*</regex-instance>
</interface>
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.nfc</name>
<version>1.2</version>

View File

@@ -44,6 +44,12 @@ bool valid(const Type& halObject) {
return result.has_value();
}
template <typename Type>
auto convertFromNonCanonical(const Type& nonCanonicalObject)
-> decltype(convert(nn::convert(nonCanonicalObject).value())) {
return convert(NN_TRY(nn::convert(nonCanonicalObject)));
}
} // namespace android::hardware::neuralnetworks::V1_0::utils
#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_H

View File

@@ -47,6 +47,12 @@ bool valid(const Type& halObject) {
return result.has_value();
}
template <typename Type>
auto convertFromNonCanonical(const Type& nonCanonicalObject)
-> decltype(convert(nn::convert(nonCanonicalObject).value())) {
return convert(NN_TRY(nn::convert(nonCanonicalObject)));
}
} // namespace android::hardware::neuralnetworks::V1_1::utils
#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_1_UTILS_H

View File

@@ -54,6 +54,12 @@ bool valid(const Type& halObject) {
return result.has_value();
}
template <typename Type>
auto convertFromNonCanonical(const Type& nonCanonicalObject)
-> decltype(convert(nn::convert(nonCanonicalObject).value())) {
return convert(NN_TRY(nn::convert(nonCanonicalObject)));
}
} // namespace android::hardware::neuralnetworks::V1_2::utils
#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_H

View File

@@ -43,6 +43,15 @@
namespace android::hardware::neuralnetworks::V1_2::utils {
namespace {
nn::GeneralResult<nn::SharedPreparedModel> prepareModelCallback(
V1_0::ErrorStatus status, const sp<V1_0::IPreparedModel>& preparedModel) {
if (const auto dynamicPreparedModel =
V1_2::IPreparedModel::castFrom(preparedModel).withDefault(nullptr)) {
return V1_2::utils::prepareModelCallback(status, dynamicPreparedModel);
}
return V1_0::utils::prepareModelCallback(status, preparedModel);
}
nn::GeneralResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
convertExecutionGeneralResultsHelper(const hidl_vec<OutputShape>& outputShapes,
const Timing& timing) {
@@ -72,7 +81,7 @@ nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> executi
Return<void> PreparedModelCallback::notify(V1_0::ErrorStatus status,
const sp<V1_0::IPreparedModel>& preparedModel) {
mData.put(V1_0::utils::prepareModelCallback(status, preparedModel));
mData.put(prepareModelCallback(status, preparedModel));
return Void();
}

View File

@@ -49,6 +49,12 @@ bool valid(const Type& halObject) {
return result.has_value();
}
template <typename Type>
auto convertFromNonCanonical(const Type& nonCanonicalObject)
-> decltype(convert(nn::convert(nonCanonicalObject).value())) {
return convert(NN_TRY(nn::convert(nonCanonicalObject)));
}
} // namespace android::hardware::neuralnetworks::V1_3::utils
#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_H

View File

@@ -28,6 +28,7 @@
#include <nnapi/IPreparedModel.h>
#include <nnapi/Result.h>
#include <nnapi/Types.h>
#include <nnapi/hal/1.0/Callbacks.h>
#include <nnapi/hal/1.0/Conversions.h>
#include <nnapi/hal/1.0/PreparedModel.h>
#include <nnapi/hal/1.2/Callbacks.h>
@@ -46,6 +47,20 @@
namespace android::hardware::neuralnetworks::V1_3::utils {
namespace {
nn::GeneralResult<nn::SharedPreparedModel> prepareModelCallback(
V1_0::ErrorStatus status, const sp<V1_0::IPreparedModel>& preparedModel) {
if (const auto dynamicPreparedModel =
V1_3::IPreparedModel::castFrom(preparedModel).withDefault(nullptr)) {
const auto currentVersionStatus = NN_TRY(convertFromNonCanonical(status));
return V1_3::utils::prepareModelCallback(currentVersionStatus, dynamicPreparedModel);
}
if (const auto dynamicPreparedModel =
V1_2::IPreparedModel::castFrom(preparedModel).withDefault(nullptr)) {
return V1_2::utils::prepareModelCallback(status, dynamicPreparedModel);
}
return V1_0::utils::prepareModelCallback(status, preparedModel);
}
nn::GeneralResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
convertExecutionGeneralResultsHelper(const hidl_vec<V1_2::OutputShape>& outputShapes,
const V1_2::Timing& timing) {
@@ -82,13 +97,13 @@ nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> executi
Return<void> PreparedModelCallback::notify(V1_0::ErrorStatus status,
const sp<V1_0::IPreparedModel>& preparedModel) {
mData.put(V1_0::utils::prepareModelCallback(status, preparedModel));
mData.put(prepareModelCallback(status, preparedModel));
return Void();
}
Return<void> PreparedModelCallback::notify_1_2(V1_0::ErrorStatus status,
const sp<V1_2::IPreparedModel>& preparedModel) {
mData.put(V1_2::utils::prepareModelCallback(status, preparedModel));
mData.put(prepareModelCallback(status, preparedModel));
return Void();
}

View File

@@ -57,6 +57,7 @@ cc_test {
"VtsHalNeuralNetworksV1_0_utils",
"VtsHalNeuralNetworksV1_2_utils",
"VtsHalNeuralNetworksV1_3_utils",
"android.hardware.neuralnetworks-V1-ndk_platform",
"android.hardware.neuralnetworks@1.0",
"android.hardware.neuralnetworks@1.1",
"android.hardware.neuralnetworks@1.2",

View File

@@ -0,0 +1,27 @@
aidl_interface {
name: "android.hardware.neuralnetworks",
vendor_available: true,
srcs: [
"android/hardware/neuralnetworks/*.aidl",
],
stability: "vintf",
imports: [
"android.hardware.common",
],
backend: {
java: {
enabled: false,
},
cpp: {
enabled: false,
},
ndk: {
apex_available: [
"//apex_available:platform",
"com.android.neuralnetworks",
"test_com.android.neuralnetworks",
],
min_sdk_version: "30",
},
},
}

View File

@@ -0,0 +1,22 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.neuralnetworks;
@VintfStability
parcelable BufferDesc {
int[] dimensions;
}

View File

@@ -0,0 +1,24 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.neuralnetworks;
@VintfStability
parcelable BufferRole {
int modelIndex;
int ioIndex;
float frequency;
}

View File

@@ -0,0 +1,26 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.neuralnetworks;
@VintfStability
parcelable Capabilities {
android.hardware.neuralnetworks.PerformanceInfo relaxedFloat32toFloat16PerformanceScalar;
android.hardware.neuralnetworks.PerformanceInfo relaxedFloat32toFloat16PerformanceTensor;
android.hardware.neuralnetworks.OperandPerformance[] operandPerformance;
android.hardware.neuralnetworks.PerformanceInfo ifPerformance;
android.hardware.neuralnetworks.PerformanceInfo whilePerformance;
}

View File

@@ -0,0 +1,24 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.neuralnetworks;
@VintfStability
parcelable DataLocation {
int poolIndex;
long offset;
long length;
}

View File

@@ -0,0 +1,23 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.neuralnetworks;
@VintfStability
parcelable DeviceBuffer {
android.hardware.neuralnetworks.IBuffer buffer;
int token;
}

View File

@@ -0,0 +1,25 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.neuralnetworks;
@Backing(type="int") @VintfStability
enum DeviceType {
OTHER = 1,
CPU = 2,
GPU = 3,
ACCELERATOR = 4,
}

View File

@@ -0,0 +1,30 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.neuralnetworks;
@Backing(type="int") @VintfStability
enum ErrorStatus {
NONE = 0,
DEVICE_UNAVAILABLE = 1,
GENERAL_FAILURE = 2,
OUTPUT_INSUFFICIENT_SIZE = 3,
INVALID_ARGUMENT = 4,
MISSED_DEADLINE_TRANSIENT = 5,
MISSED_DEADLINE_PERSISTENT = 6,
RESOURCE_EXHAUSTED_TRANSIENT = 7,
RESOURCE_EXHAUSTED_PERSISTENT = 8,
}

View File

@@ -0,0 +1,24 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.neuralnetworks;
@Backing(type="int") @VintfStability
enum ExecutionPreference {
LOW_POWER = 0,
FAST_SINGLE_ANSWER = 1,
SUSTAINED_SPEED = 2,
}

View File

@@ -0,0 +1,24 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.neuralnetworks;
@VintfStability
parcelable ExecutionResult {
boolean outputSufficientSize;
android.hardware.neuralnetworks.OutputShape[] outputShapes;
android.hardware.neuralnetworks.Timing timing;
}

View File

@@ -0,0 +1,23 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.neuralnetworks;
@VintfStability
parcelable Extension {
String name;
android.hardware.neuralnetworks.ExtensionOperandTypeInformation[] operandTypes;
}

View File

@@ -0,0 +1,23 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.neuralnetworks;
@VintfStability
parcelable ExtensionNameAndPrefix {
String name;
char prefix;
}

View File

@@ -0,0 +1,24 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.neuralnetworks;
@VintfStability
parcelable ExtensionOperandTypeInformation {
char type;
boolean isTensor;
int byteSize;
}

View File

@@ -0,0 +1,25 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.neuralnetworks;
@Backing(type="int") @VintfStability
enum FusedActivationFunc {
NONE = 0,
RELU = 1,
RELU1 = 2,
RELU6 = 3,
}

View File

@@ -0,0 +1,23 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.neuralnetworks;
@VintfStability
interface IBuffer {
void copyFrom(in android.hardware.neuralnetworks.Memory src, in int[] dimensions);
void copyTo(in android.hardware.neuralnetworks.Memory dst);
}

View File

@@ -0,0 +1,36 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.neuralnetworks;
@VintfStability
interface IDevice {
android.hardware.neuralnetworks.DeviceBuffer allocate(in android.hardware.neuralnetworks.BufferDesc desc, in android.hardware.neuralnetworks.IPreparedModelParcel[] preparedModels, in android.hardware.neuralnetworks.BufferRole[] inputRoles, in android.hardware.neuralnetworks.BufferRole[] outputRoles);
android.hardware.neuralnetworks.Capabilities getCapabilities();
android.hardware.neuralnetworks.NumberOfCacheFiles getNumberOfCacheFilesNeeded();
android.hardware.neuralnetworks.Extension[] getSupportedExtensions();
boolean[] getSupportedOperations(in android.hardware.neuralnetworks.Model model);
android.hardware.neuralnetworks.DeviceType getType();
String getVersionString();
void prepareModel(in android.hardware.neuralnetworks.Model model, in android.hardware.neuralnetworks.ExecutionPreference preference, in android.hardware.neuralnetworks.Priority priority, in long deadline, in ParcelFileDescriptor[] modelCache, in ParcelFileDescriptor[] dataCache, in byte[] token, in android.hardware.neuralnetworks.IPreparedModelCallback callback);
void prepareModelFromCache(in long deadline, in ParcelFileDescriptor[] modelCache, in ParcelFileDescriptor[] dataCache, in byte[] token, in android.hardware.neuralnetworks.IPreparedModelCallback callback);
const int BYTE_SIZE_OF_CACHE_TOKEN = 32;
const int MAX_NUMBER_OF_CACHE_FILES = 32;
const int EXTENSION_TYPE_HIGH_BITS_PREFIX = 15;
const int EXTENSION_TYPE_LOW_BITS_TYPE = 16;
const int OPERAND_TYPE_BASE_MAX = 65535;
const int OPERATION_TYPE_BASE_MAX = 65535;
}

View File

@@ -0,0 +1,22 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.neuralnetworks;
@VintfStability
interface IFencedExecutionCallback {
android.hardware.neuralnetworks.ErrorStatus getExecutionInfo(out android.hardware.neuralnetworks.Timing timingLaunched, out android.hardware.neuralnetworks.Timing timingFenced);
}

View File

@@ -0,0 +1,25 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.neuralnetworks;
@VintfStability
interface IPreparedModel {
android.hardware.neuralnetworks.ExecutionResult executeSynchronously(in android.hardware.neuralnetworks.Request request, in boolean measureTiming, in long deadline, in long loopTimeoutDuration);
android.hardware.neuralnetworks.IFencedExecutionCallback executeFenced(in android.hardware.neuralnetworks.Request request, in ParcelFileDescriptor[] waitFor, in boolean measureTiming, in long deadline, in long loopTimeoutDuration, in long duration, out @nullable ParcelFileDescriptor syncFence);
const long DEFAULT_LOOP_TIMEOUT_DURATION_NS = 2000000000;
const long MAXIMUM_LOOP_TIMEOUT_DURATION_NS = 15000000000;
}

View File

@@ -0,0 +1,22 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.neuralnetworks;
@VintfStability
interface IPreparedModelCallback {
void notify(in android.hardware.neuralnetworks.ErrorStatus status, in android.hardware.neuralnetworks.IPreparedModel preparedModel);
}

View File

@@ -0,0 +1,22 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.neuralnetworks;
@VintfStability
parcelable IPreparedModelParcel {
android.hardware.neuralnetworks.IPreparedModel preparedModel;
}

View File

@@ -0,0 +1,24 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.neuralnetworks;
@VintfStability
parcelable Memory {
android.hardware.common.NativeHandle handle;
long size;
String name;
}

View File

@@ -0,0 +1,27 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.neuralnetworks;
@VintfStability
parcelable Model {
android.hardware.neuralnetworks.Subgraph main;
android.hardware.neuralnetworks.Subgraph[] referenced;
byte[] operandValues;
android.hardware.neuralnetworks.Memory[] pools;
boolean relaxComputationFloat32toFloat16;
android.hardware.neuralnetworks.ExtensionNameAndPrefix[] extensionNameToPrefix;
}

View File

@@ -0,0 +1,23 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.neuralnetworks;
@VintfStability
parcelable NumberOfCacheFiles {
int numModelCache;
int numDataCache;
}

View File

@@ -0,0 +1,28 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.neuralnetworks;
@VintfStability
parcelable Operand {
android.hardware.neuralnetworks.OperandType type;
int[] dimensions;
float scale;
int zeroPoint;
android.hardware.neuralnetworks.OperandLifeTime lifetime;
android.hardware.neuralnetworks.DataLocation location;
@nullable android.hardware.neuralnetworks.OperandExtraParams extraParams;
}

View File

@@ -0,0 +1,23 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.neuralnetworks;
@VintfStability
union OperandExtraParams {
android.hardware.neuralnetworks.SymmPerChannelQuantParams channelQuant;
byte[] extension;
}

View File

@@ -0,0 +1,28 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.neuralnetworks;
@Backing(type="int") @VintfStability
enum OperandLifeTime {
TEMPORARY_VARIABLE = 0,
SUBGRAPH_INPUT = 1,
SUBGRAPH_OUTPUT = 2,
CONSTANT_COPY = 3,
CONSTANT_POOL = 4,
NO_VALUE = 5,
SUBGRAPH = 6,
}

View File

@@ -0,0 +1,23 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.neuralnetworks;
@VintfStability
parcelable OperandPerformance {
android.hardware.neuralnetworks.OperandType type;
android.hardware.neuralnetworks.PerformanceInfo info;
}

View File

@@ -0,0 +1,37 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.neuralnetworks;
@Backing(type="int") @VintfStability
enum OperandType {
FLOAT32 = 0,
INT32 = 1,
UINT32 = 2,
TENSOR_FLOAT32 = 3,
TENSOR_INT32 = 4,
TENSOR_QUANT8_ASYMM = 5,
BOOL = 6,
TENSOR_QUANT16_SYMM = 7,
TENSOR_FLOAT16 = 8,
TENSOR_BOOL8 = 9,
FLOAT16 = 10,
TENSOR_QUANT8_SYMM_PER_CHANNEL = 11,
TENSOR_QUANT16_ASYMM = 12,
TENSOR_QUANT8_SYMM = 13,
TENSOR_QUANT8_ASYMM_SIGNED = 14,
SUBGRAPH = 15,
}

View File

@@ -0,0 +1,24 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.neuralnetworks;
@VintfStability
parcelable Operation {
android.hardware.neuralnetworks.OperationType type;
int[] inputs;
int[] outputs;
}

View File

@@ -0,0 +1,123 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.neuralnetworks;
@Backing(type="int") @VintfStability
enum OperationType {
ADD = 0,
AVERAGE_POOL_2D = 1,
CONCATENATION = 2,
CONV_2D = 3,
DEPTHWISE_CONV_2D = 4,
DEPTH_TO_SPACE = 5,
DEQUANTIZE = 6,
EMBEDDING_LOOKUP = 7,
FLOOR = 8,
FULLY_CONNECTED = 9,
HASHTABLE_LOOKUP = 10,
L2_NORMALIZATION = 11,
L2_POOL_2D = 12,
LOCAL_RESPONSE_NORMALIZATION = 13,
LOGISTIC = 14,
LSH_PROJECTION = 15,
LSTM = 16,
MAX_POOL_2D = 17,
MUL = 18,
RELU = 19,
RELU1 = 20,
RELU6 = 21,
RESHAPE = 22,
RESIZE_BILINEAR = 23,
RNN = 24,
SOFTMAX = 25,
SPACE_TO_DEPTH = 26,
SVDF = 27,
TANH = 28,
BATCH_TO_SPACE_ND = 29,
DIV = 30,
MEAN = 31,
PAD = 32,
SPACE_TO_BATCH_ND = 33,
SQUEEZE = 34,
STRIDED_SLICE = 35,
SUB = 36,
TRANSPOSE = 37,
ABS = 38,
ARGMAX = 39,
ARGMIN = 40,
AXIS_ALIGNED_BBOX_TRANSFORM = 41,
BIDIRECTIONAL_SEQUENCE_LSTM = 42,
BIDIRECTIONAL_SEQUENCE_RNN = 43,
BOX_WITH_NMS_LIMIT = 44,
CAST = 45,
CHANNEL_SHUFFLE = 46,
DETECTION_POSTPROCESSING = 47,
EQUAL = 48,
EXP = 49,
EXPAND_DIMS = 50,
GATHER = 51,
GENERATE_PROPOSALS = 52,
GREATER = 53,
GREATER_EQUAL = 54,
GROUPED_CONV_2D = 55,
HEATMAP_MAX_KEYPOINT = 56,
INSTANCE_NORMALIZATION = 57,
LESS = 58,
LESS_EQUAL = 59,
LOG = 60,
LOGICAL_AND = 61,
LOGICAL_NOT = 62,
LOGICAL_OR = 63,
LOG_SOFTMAX = 64,
MAXIMUM = 65,
MINIMUM = 66,
NEG = 67,
NOT_EQUAL = 68,
PAD_V2 = 69,
POW = 70,
PRELU = 71,
QUANTIZE = 72,
QUANTIZED_16BIT_LSTM = 73,
RANDOM_MULTINOMIAL = 74,
REDUCE_ALL = 75,
REDUCE_ANY = 76,
REDUCE_MAX = 77,
REDUCE_MIN = 78,
REDUCE_PROD = 79,
REDUCE_SUM = 80,
ROI_ALIGN = 81,
ROI_POOLING = 82,
RSQRT = 83,
SELECT = 84,
SIN = 85,
SLICE = 86,
SPLIT = 87,
SQRT = 88,
TILE = 89,
TOPK_V2 = 90,
TRANSPOSE_CONV_2D = 91,
UNIDIRECTIONAL_SEQUENCE_LSTM = 92,
UNIDIRECTIONAL_SEQUENCE_RNN = 93,
RESIZE_NEAREST_NEIGHBOR = 94,
QUANTIZED_LSTM = 95,
IF = 96,
WHILE = 97,
ELU = 98,
HARD_SWISH = 99,
FILL = 100,
RANK = 101,
}

View File

@@ -0,0 +1,23 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.neuralnetworks;
@VintfStability
parcelable OutputShape {
int[] dimensions;
boolean isSufficient;
}

View File

@@ -0,0 +1,23 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.neuralnetworks;
@VintfStability
parcelable PerformanceInfo {
float execTime;
float powerUsage;
}

View File

@@ -0,0 +1,24 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.neuralnetworks;
@Backing(type="int") @VintfStability
enum Priority {
LOW = 0,
MEDIUM = 1,
HIGH = 2,
}

View File

@@ -0,0 +1,24 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.neuralnetworks;
@VintfStability
parcelable Request {
android.hardware.neuralnetworks.RequestArgument[] inputs;
android.hardware.neuralnetworks.RequestArgument[] outputs;
android.hardware.neuralnetworks.RequestMemoryPool[] pools;
}

View File

@@ -0,0 +1,24 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.neuralnetworks;
@VintfStability
parcelable RequestArgument {
boolean hasNoValue;
android.hardware.neuralnetworks.DataLocation location;
int[] dimensions;
}

View File

@@ -0,0 +1,23 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.neuralnetworks;
@VintfStability
union RequestMemoryPool {
android.hardware.neuralnetworks.Memory pool;
int token;
}

View File

@@ -0,0 +1,25 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.neuralnetworks;
@VintfStability
parcelable Subgraph {
android.hardware.neuralnetworks.Operand[] operands;
android.hardware.neuralnetworks.Operation[] operations;
int[] inputIndexes;
int[] outputIndexes;
}

View File

@@ -0,0 +1,23 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.neuralnetworks;
@VintfStability
parcelable SymmPerChannelQuantParams {
float[] scales;
int channelDim;
}

View File

@@ -0,0 +1,23 @@
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
// edit this file. It looks like you are doing that because you have modified
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
// from an interface or a field from a parcelable and it broke the build. That
// breakage is intended.
//
// You must not make a backward incompatible changes to the AIDL files built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.neuralnetworks;
@VintfStability
parcelable Timing {
long timeOnDevice;
long timeInDriver;
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.neuralnetworks;
/**
* A buffer descriptor. Describes the properties of a buffer.
*/
@VintfStability
parcelable BufferDesc {
/**
* Dimensions of the buffer. May have unknown dimensions or rank. A buffer with some number of
* unspecified dimensions is represented by setting each unspecified dimension to 0. A buffer
* with unspecified rank is represented by providing an empty dimensions vector.
*/
int[] dimensions;
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.neuralnetworks;
/**
* Describes a role of an input or output to a prepared model.
*/
@VintfStability
parcelable BufferRole {
/**
* The index of the IPreparedModel within the "preparedModel" argument passed in
* IDevice::allocate.
*/
int modelIndex;
/**
* The index of the input or output operand.
*/
int ioIndex;
/**
* A floating-point value within the range (0.0, 1.0]. Describes how likely the buffer is to be
* used in the specified role. This is provided as a hint to optimize the case when multiple
* roles prefer different buffer locations or data layouts.
*/
float frequency;
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.neuralnetworks;
import android.hardware.neuralnetworks.OperandPerformance;
import android.hardware.neuralnetworks.PerformanceInfo;
/**
* The capabilities of a driver.
*
* This represents performance of non-extension operations.
*
* Performance of an operation other than {@link OperationType::IF} and {@link OperationType::WHILE}
* comes from the type of its first operand.
*/
@VintfStability
parcelable Capabilities {
/**
* Driver performance when operating on float32 data but performing calculations with range
* and/or precision as low as that of the IEEE 754 16-bit floating-point format.
*/
PerformanceInfo relaxedFloat32toFloat16PerformanceScalar;
PerformanceInfo relaxedFloat32toFloat16PerformanceTensor;
/**
* Performance by operand type. Must be sorted by OperandType.
*
* If a particular {@link OperandType} is not present in operandPerformance, its performance is
* treated as { .execTime = FLT_MAX, .powerUsage = FLT_MAX }.
*
* Performance does not apply to {@link OperandType::SUBGRAPH}, and a driver must not report
* operand performance for {@link OperandType::SUBGRAPH}.
*/
OperandPerformance[] operandPerformance;
/**
* Performance of an {@link OperationType::IF} operation is the sum of
* {@link Capabilities::ifPerformance} and the mean of performance for the two branch subgraphs,
* where performance for a subgraph is the sum of the performance of all operations within the
* subgraph.
*/
PerformanceInfo ifPerformance;
/**
* Performance of a {@link OperationType::WHILE} operation is the sum of
* {@link Capabilities::whilePerformance}, performance for the condition subgraph and
* performance for the body subgraph, where performance for a subgraph is the sum of the
* performance of all operations within the subgraph.
*/
PerformanceInfo whilePerformance;
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.neuralnetworks;
/**
* Describes the location of a data object.
*/
@VintfStability
parcelable DataLocation {
/**
* The index of the memory pool where this location is found.
*/
int poolIndex;
/**
* Offset in bytes from the start of the pool.
*/
long offset;
/**
* The length of the data in bytes.
*/
long length;
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.neuralnetworks;
import android.hardware.neuralnetworks.IBuffer;
/**
* A type that is used to represent a driver allocated buffer and token that corresponds to it.
*/
@VintfStability
parcelable DeviceBuffer {
/**
* An IBuffer object used to interact with the device allocated buffer.
*/
IBuffer buffer;
/**
* A positive token identifying the allocated buffer. The token is provided when referencing the
* buffer as one of the memory pools in the request of an execution. The token must not collide
* with the tokens of other IBuffer objects that are currently alive in the same driver service.
*/
int token;
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.neuralnetworks;
/**
* Device types.
*
* The type of NNAPI device.
*/
@VintfStability
@Backing(type="int")
enum DeviceType {
/**
* The device does not fall into any category below.
*/
OTHER = 1,
/**
* The device runs NNAPI models on single or multi-core CPU.
*/
CPU = 2,
/**
* The device can run NNAPI models and also accelerate graphics APIs such as OpenGL ES and
* Vulkan.
*/
GPU = 3,
/**
* Dedicated accelerator for Machine Learning workloads.
*/
ACCELERATOR = 4,
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.neuralnetworks;
/**
* Calls to neural networks AIDL interfaces may return a ServiceSpecificException with the following
* error codes.
*/
@VintfStability
@Backing(type="int")
enum ErrorStatus {
NONE,
DEVICE_UNAVAILABLE,
GENERAL_FAILURE,
OUTPUT_INSUFFICIENT_SIZE,
INVALID_ARGUMENT,
/**
* Failure because a deadline could not be met for a task, but future deadlines may still be met
* for the same task after a short delay.
*/
MISSED_DEADLINE_TRANSIENT,
/**
* Failure because a deadline could not be met for a task, and future deadlines will likely also
* not be met for the same task even after a short delay.
*/
MISSED_DEADLINE_PERSISTENT,
/**
* Failure because of a resource limitation within the driver, but future calls for the same
* task may still succeed after a short delay.
*/
RESOURCE_EXHAUSTED_TRANSIENT,
/**
* Failure because of a resource limitation within the driver, and future calls for the same
* task will likely also fail even after a short delay.
*/
RESOURCE_EXHAUSTED_PERSISTENT,
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.neuralnetworks;
/**
* Execution preferences.
*/
@VintfStability
@Backing(type="int")
enum ExecutionPreference {
/**
* Prefer executing in a way that minimizes battery drain. This is desirable for compilations
* that will be executed often.
*/
LOW_POWER,
/**
* Prefer returning a single answer as fast as possible, even if this causes more power
* consumption.
*/
FAST_SINGLE_ANSWER,
/**
* Prefer maximizing the throughput of successive frames, for example when processing successive
* frames coming from the camera.
*/
SUSTAINED_SPEED,
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.neuralnetworks;
import android.hardware.neuralnetworks.ErrorStatus;
import android.hardware.neuralnetworks.OutputShape;
import android.hardware.neuralnetworks.Timing;
/**
* A result from running a synchronous execution of a prepared model.
*/
@VintfStability
parcelable ExecutionResult {
/**
* A value of "true" indicates that the execution was successful. A value of "false" indicates
* the execution failed because at least one output operand buffer was not large enough to store
* the corresponding output.
*/
boolean outputSufficientSize;
/**
* A list of shape information of model output operands. The index in "outputShapes" corresponds
* to the index of the output operand in the Request outputs vector.
*/
OutputShape[] outputShapes;
/**
* Duration of execution. Unless measure is true and the execution is successful, all times must
* be reported as -1. A driver may choose to report any time as -1, indicating that measurement
* is not available.
*/
Timing timing;
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.neuralnetworks;
import android.hardware.neuralnetworks.ExtensionOperandTypeInformation;
/**
* Information about an extension.
*/
@VintfStability
parcelable Extension {
/**
* The extension name.
*
* The name must consist of lowercase latin letters, numbers, periods, and underscore signs. The
* name must contain at least one period.
*
* The name must start with the reverse domain name of the vendor.
*
* Example: com.google.test_extension
*/
String name;
/**
* Information about operand types defined by the extension.
*/
ExtensionOperandTypeInformation[] operandTypes;
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.neuralnetworks;
/**
* The mapping between extension names and prefixes of operand and operation type values.
*
* An operand or operation whose numeric type value is above {@link IDevice::OPERAND_TYPE_BASE_MAX}
* or {@link IDevice::OPERATION_TYPE_BASE_MAX} respectively should be interpreted as an extension
* operand/operation. The low {@link IDevice::EXTENSION_TYPE_LOW_BITS_TYPE} bits of the value
* correspond to the type ID within the extension and the high
* {@link IDevice::EXTENSION_TYPE_HIGH_BITS_PREFIX} bits encode the "prefix", which maps uniquely to
* the extension name. The sign bit is always 0.
*
* For example, if a model contains an operation whose value is 0x7AAABBBB and extensionNameToPrefix
* contains an entry with prefix=0x7AAA and name="vendor.test.test_extension", then the operation
* should be interpreted as the operation 0xBBBB of the extension named vendor.test.test_extension.
*
* This is a one-to-one correspondence. That is, there must be at most one prefix corresponding to
* each extension name and at most one extension name corresponding to each prefix.
*/
@VintfStability
parcelable ExtensionNameAndPrefix {
/**
* The extension name.
*
* See {@link Extension::name} for the format specification.
*/
String name;
/**
* The extension prefix. Only the lowest 15 bits are used, so the value must be less than 32768.
*/
char prefix;
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.neuralnetworks;
/**
* Information about an extension operand type.
*/
@VintfStability
parcelable ExtensionOperandTypeInformation {
/**
* The extension operand type.
*/
char type;
/**
* Indicates whether the extension operand type represents a tensor or a scalar.
*/
boolean isTensor;
/**
* The byte size of the operand (if scalar) or of a single element (if tensor).
*/
int byteSize;
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.neuralnetworks;
/**
* Fused activation function types.
*/
@VintfStability
@Backing(type="int")
enum FusedActivationFunc {
NONE,
RELU,
RELU1,
RELU6,
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.neuralnetworks;
import android.hardware.neuralnetworks.Memory;
/**
* This interface represents a device memory buffer.
*/
@VintfStability
interface IBuffer {
/**
* Sets the content of this buffer from a shared memory region.
*
* @param src The source shared memory region.
* @param dimensions Updated dimensional information. If the dimensions of the IBuffer object
* are not fully specified, then the dimensions must be fully specified here.
* If the dimensions of the IBuffer object are fully specified, then the
* dimensions may be empty here. If dimensions.size() > 0, then all dimensions
* must be specified here, and any dimension that was specified in the IBuffer
* object must have the same value here.
* @throws ServiceSpecificException with one of the following ErrorStatus values:
* - DEVICE_UNAVAILABLE if driver is offline or busy
* - GENERAL_FAILURE if there is an unspecified error
* - INVALID_ARGUMENT if provided memory is invalid, or if the dimensions is invalid
*/
void copyFrom(in Memory src, in int[] dimensions);
/**
* Retrieves the content of this buffer to a shared memory region.
*
* The IBuffer object must have been initialized before the call to IBuffer::copyTo. For more
* information on the state of the IBuffer object, refer to IDevice::allocate.
*
* @param dst The destination shared memory region.
* @throws ServiceSpecificException with one of the following ErrorStatus values:
* - DEVICE_UNAVAILABLE if driver is offline or busy
* - GENERAL_FAILURE if the IBuffer object is uninitialized, or there is an unspecified
* error
* - INVALID_ARGUMENT if provided memory is invalid
*/
void copyTo(in Memory dst);
}

View File

@@ -0,0 +1,431 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.neuralnetworks;
import android.hardware.neuralnetworks.BufferDesc;
import android.hardware.neuralnetworks.BufferRole;
import android.hardware.neuralnetworks.Capabilities;
import android.hardware.neuralnetworks.DeviceBuffer;
import android.hardware.neuralnetworks.DeviceType;
import android.hardware.neuralnetworks.ExecutionPreference;
import android.hardware.neuralnetworks.Extension;
import android.hardware.neuralnetworks.IPreparedModel;
import android.hardware.neuralnetworks.IPreparedModelCallback;
import android.hardware.neuralnetworks.IPreparedModelParcel;
import android.hardware.neuralnetworks.Model;
import android.hardware.neuralnetworks.NumberOfCacheFiles;
import android.hardware.neuralnetworks.Priority;
/**
* This interface represents a device driver.
*/
@VintfStability
interface IDevice {
/**
* The byte size of the cache token.
*/
const int BYTE_SIZE_OF_CACHE_TOKEN = 32;
/**
* The maximum number of files for each type of cache in compilation caching.
*/
const int MAX_NUMBER_OF_CACHE_FILES = 32;
/**
* Numeric values of extension operand and operation types have the following structure:
* - The sign bit is always 0.
* - 15 high bits represent the "prefix", which corresponds uniquely to the extension name.
* - 16 low bits represent the type ID within the extension.
*/
const int EXTENSION_TYPE_HIGH_BITS_PREFIX = 15;
const int EXTENSION_TYPE_LOW_BITS_TYPE = 16;
/**
* OperandType with any value above {@link IDevice::OPERAND_TYPE_BASE_MAX} must be interpreted
* as an extension type according to {@link Model::extensionNameToPrefix}.
*/
const int OPERAND_TYPE_BASE_MAX = 0xFFFF;
/**
* OperationType with any value above {@link IDevice::OPERATION_TYPE_BASE_MAX} must be
* interpreted as an extension type according to {@link Model::extensionNameToPrefix}.
*/
const int OPERATION_TYPE_BASE_MAX = 0xFFFF;
/**
* Allocates a driver-managed buffer with the properties specified by the buffer descriptor as
* well as the input and output roles.
*
* The allocate function must verify its inputs are correct. If there is an error, or if a
* certain role or property is not supported by the driver, the allocate function must return a
* service specific exception with an appropriate ErrorStatus. If the allocation is successful,
* this method must return a DeviceBuffer object with the produced IBuffer and a positive token
* identifying the allocated buffer. A successful allocation must accommodate all of the
* specified roles and buffer properties.
*
* The buffer is allocated to an uninitialized state. An uninitialized buffer may only be used
* in ways that are specified by outputRoles. A buffer is initialized after it is used as an
* output in a successful execution, or after a successful invocation of IBuffer::copyFrom on
* the buffer. An initialized buffer may be used according to all roles specified in inputRoles
* and outputRoles. A buffer will return to the uninitialized state if it is used as an output
* in a failed execution, or after a failed invocation of IBuffer::copyFrom on the buffer.
*
* The dimensions of the buffer can be deduced from the buffer descriptor as well as the
* dimensions of the corresponding model operands of the input and output roles. The dimensions
* or rank of the buffer may be unknown at this stage. As such, some driver services may only
* create a placeholder and defer the actual allocation until execution time. Note that the same
* buffer may be used for different shapes of outputs on different executions. When the buffer
* is used as an input, the input shape must be the same as the output shape from the last
* execution using this buffer as an output.
*
* The driver must apply proper validatation upon every usage of the buffer, and must fail the
* execution immediately if the usage is illegal.
*
* @param desc A buffer descriptor specifying the properties of the buffer to allocate.
* @param preparedModels A vector of IPreparedModel objects. Must only contain IPreparedModel
* objects from the same IDevice as this method is being invoked on.
* @param inputRoles A vector of roles with each specifying an input to a prepared model.
* @param outputRoles A vector of roles with each specifying an output to a prepared model. Each
* role specified in inputRoles and outputRoles must be unique. The
* corresponding model operands of the roles must have the same OperandType,
* scale, zero point, and ExtraParams. The dimensions of the operands and the
* dimensions specified in the buffer descriptor must be compatible with each
* other. Two dimensions are incompatible if there is at least one axis that
* is fully specified in both but has different values.
* @return DeviceBuffer object containing the allocated IBuffer object and a positive token that
* can be used to reference the buffer as one of the memory pools.
* @throws ServiceSpecificException with one of the following ErrorStatus values:
* - DEVICE_UNAVAILABLE if driver is offline or busy
* - GENERAL_FAILURE if a certain buffer property or a certain role is not supported,
* or if there is an unspecified error
* - INVALID_ARGUMENT if one of the input arguments is invalid
* - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
*/
DeviceBuffer allocate(in BufferDesc desc, in IPreparedModelParcel[] preparedModels,
in BufferRole[] inputRoles, in BufferRole[] outputRoles);
/**
* Gets the capabilities of a driver.
*
* @return Capabilities of the driver.
* @throws ServiceSpecificException with one of the following ErrorStatus values:
* - DEVICE_UNAVAILABLE if driver is offline or busy
* - GENERAL_FAILURE if there is an unspecified error
*/
Capabilities getCapabilities();
/**
* Gets the caching requirements of the driver implementation.
*
* There are two types of cache file descriptors provided to the driver: model cache and data
* cache.
*
* The data cache is for caching constant data, possibly including preprocessed and transformed
* tensor buffers. Any modification to the data cache should have no worse effect than
* generating bad output values at execution time.
*
* The model cache is for caching security-sensitive data such as compiled executable machine
* code in the device's native binary format. A modification to the model cache may affect the
* driver's execution behavior, and a malicious client could make use of this to execute beyond
* the granted permission. Thus, the driver must always check whether the model cache is
* corrupted before preparing the model from cache.
*
* getNumberOfCacheFilesNeeded returns how many of each type of cache files the driver
* implementation needs to cache a single prepared model. Returning 0 for both types indicates
* compilation caching is not supported by this driver. The driver may still choose not to cache
* certain compiled models even if it reports that caching is supported.
*
* If the device reports that caching is not supported, the user may avoid calling
* IDevice::prepareModelFromCache or providing cache file descriptors to
* IDevice::prepareModel.
*
* @return NumberOfCacheFiles structure indicating how many files for model and data cache the
* driver needs to cache a single prepared model. It must be less than or equal to
* MAX_NUMBER_OF_CACHE_FILES.
* @throws ServiceSpecificException with one of the following ErrorStatus values:
* - DEVICE_UNAVAILABLE if driver is offline or busy
* - GENERAL_FAILURE if there is an unspecified error
*/
NumberOfCacheFiles getNumberOfCacheFilesNeeded();
/**
* Gets information about extensions supported by the driver implementation.
*
* All extension operations and operands must be fully supported for the extension to appear in
* the list of supported extensions.
*
* @return A list of supported extensions.
* @throws ServiceSpecificException with one of the following ErrorStatus values:
* - DEVICE_UNAVAILABLE if driver is offline or busy
* - GENERAL_FAILURE if there is an unspecified error
*/
Extension[] getSupportedExtensions();
/**
* Gets the supported operations in a model.
*
* getSupportedOperations indicates which operations of the top-level subgraph are fully
* supported by the vendor driver. If an operation may not be supported for any reason,
* getSupportedOperations must return false for that operation.
*
* The {@link OperationType::IF} and {@link OperationType::WHILE} operations may only be fully
* supported if the vendor driver fully supports all operations in the referenced subgraphs.
*
* @param model A model whose operations -- and their corresponding operands -- are to be
* verified by the driver.
* @return A list of supported operations, where true indicates the operation is supported and
* false indicates the operation is not supported. The index of "supported" corresponds with
* the index of the operation it is describing in the main subgraph.
* @throws ServiceSpecificException with one of the following ErrorStatus values:
* - DEVICE_UNAVAILABLE if driver is offline or busy
* - GENERAL_FAILURE if there is an unspecified error
* - INVALID_ARGUMENT if provided model is invalid
*/
boolean[] getSupportedOperations(in Model model);
/**
* Get the type of a given device.
*
* The device type can be used to help application developers to distribute Machine Learning
* workloads and other workloads such as graphical rendering. E.g., for an app which renders AR
* scenes based on real time object detection results, the developer could choose an ACCELERATOR
* type device for ML workloads, and reserve GPU for graphical rendering.
*
* @return The DeviceType of the device. Please note, this is not a bitfield of DeviceTypes.
* Each device must only be of a single DeviceType.
* @throws ServiceSpecificException with one of the following ErrorStatus values:
* - DEVICE_UNAVAILABLE if driver is offline or busy
* - GENERAL_FAILURE if the query resulted in an unspecified error
*/
DeviceType getType();
/**
* Get the version string of the driver implementation.
*
* The version string must be a unique token among the set of version strings of drivers of a
* specific device. The token identifies the device driver's implementation. The token must not
* be confused with the feature level which is solely defined by the interface version. This API
* is opaque to the Android framework, but the Android framework may use the information for
* debugging or to pass on to NNAPI applications.
*
* Application developers sometimes have specific requirements to ensure good user experiences,
* and they need more information to make intelligent decisions when the Android framework
* cannot. For example, combined with the device name and other information, the token can help
* NNAPI applications filter devices based on their needs:
* - An application demands a certain level of performance, but a specific version of the
* driver cannot meet that requirement because of a performance regression.
* The application can disallow the driver based on the version provided.
* - An application has a minimum precision requirement, but certain versions of
* the driver cannot meet that requirement because of bugs or certain optimizations.
* The application can filter out versions of these drivers.
*
* @return The version string of the device implementation. Must have nonzero length.
* @throws ServiceSpecificException with one of the following ErrorStatus values:
* - DEVICE_UNAVAILABLE if driver is offline or busy
* - GENERAL_FAILURE if the query resulted in an unspecified error
*/
String getVersionString();
/**
* Asynchronously creates a prepared model for execution and optionally saves it into cache
* files.
*
* prepareModel is used to make any necessary transformations to or alternative representations
* to a model for execution, possibly including transformations on the constant data,
* optimization on the model's graph, or compilation into the device's native binary format. The
* model itself is not changed.
*
* Optionally, caching information may be provided for the driver to save the prepared model to
* cache files for faster model compilation time when the same model preparation is requested in
* the future. There are two types of cache file descriptors provided to the driver: model cache
* and data cache. For more information on the two types of cache, refer to
* getNumberOfCacheFilesNeeded.
*
* The file descriptors must be opened with read and write permission. A file may have any size,
* and the corresponding file descriptor may have any offset. The driver must truncate a file to
* zero size before writing to that file. The file descriptors may be closed by the client once
* the asynchronous preparation has finished. The driver must dup a file descriptor if it wants
* to get access to the cache file later.
*
* The model is prepared asynchronously with respect to the caller. The prepareModel function
* must verify the inputs to the preparedModel function related to preparing the model (as
* opposed to saving the prepared model to cache) are correct. If there is an error,
* prepareModel must immediately invoke the callback with the appropriate ErrorStatus value and
* nullptr for the IPreparedModel, then return a status with a service specific exception with
* the same ErrorStatus. If the inputs to the prepareModel function that are related to
* preparing the model are valid and there is no error, prepareModel must launch an asynchronous
* task to prepare the model in the background, and immediately return from prepareModel. If the
* asynchronous task fails to launch, prepareModel must immediately invoke the callback with
* ErrorStatus::GENERAL_FAILURE and nullptr for the IPreparedModel, then return a service
* specific exception with ErrorStatus::GENERAL_FAILURE.
*
* When the asynchronous task has finished preparing the model, it must immediately invoke the
* callback function provided as an input to prepareModel. If the model was prepared
* successfully, the callback object must be invoked with an error status of ErrorStatus::NONE
* and the produced IPreparedModel object. If an error occurred preparing the model, the
* callback object must be invoked with the appropriate ErrorStatus value and nullptr for the
* IPreparedModel.
*
* The model is prepared with a priority. This priority is relative to other prepared models
* owned by the same client. Higher priority executions may use more compute resources than
* lower priority executions, and may preempt or starve lower priority executions.
*
* prepareModel can be called with an optional deadline. If the model is not able to be prepared
* before the provided deadline, the model preparation may be aborted, and either
* {@link ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link
* ErrorStatus::MISSED_DEADLINE_PERSISTENT} may be returned. The error due to an abort must be
* sent the same way as other errors, described above.
*
* Optionally, the driver may save the prepared model to cache during the asynchronous
* preparation. Any error that occurs when saving to cache must not affect the status of
* preparing the model. Even if the input arguments related to the cache may be invalid, or the
* driver may fail to save to cache, the prepareModel function must finish preparing the model.
* The driver may choose not to save to cache even if the caching information is provided and
* valid.
*
* The only information that may be unknown to the model at this stage is the shape of the
* tensors, which may only be known at execution time. As such, some driver services may return
* partially prepared models, where the prepared model may only be finished when it is paired
* with a set of inputs to the model. Note that the same prepared model object may be used with
* different shapes of inputs on different (possibly concurrent) executions.
*
* Multiple threads may call prepareModel on the same model concurrently.
*
* @param model The model to be prepared for execution.
* @param preference Indicates the intended execution behavior of a prepared model.
* @param priority The priority of the prepared model relative to other prepared models owned by
* the client.
* @param deadline The time by which the model is expected to be prepared. The time is measured
* in nanoseconds since epoch of the steady clock (as from
* std::chrono::steady_clock). If the model cannot be prepared by the deadline,
* the preparation may be aborted. Passing -1 means the deadline is omitted.
* Other negative values are invalid.
* @param modelCache A vector of file descriptors for the security-sensitive cache. The length
* of the vector must either be 0 indicating that caching information is not
* provided, or match the numModelCache returned from
* getNumberOfCacheFilesNeeded. The cache file descriptors will be provided in
* the same order when retrieving the preparedModel from cache files with
* prepareModelFromCache.
* @param dataCache A vector of file descriptors for the constants' cache. The length of the
* vector must either be 0 indicating that caching information is not provided,
* or match the numDataCache returned from getNumberOfCacheFilesNeeded. The
* cache file descriptors will be provided in the same order when retrieving
* the preparedModel from cache files with prepareModelFromCache.
* @param token A caching token of length BYTE_SIZE_OF_CACHE_TOKEN identifying the prepared
* model. The same token will be provided when retrieving the prepared model from
* the cache files with prepareModelFromCache. Tokens should be chosen to have a
* low rate of collision for a particular application. The driver cannot detect a
* collision; a collision will result in a failed execution or in a successful
* execution that produces incorrect output values. If both modelCache and
* dataCache are empty indicating that caching information is not provided, this
* token must be ignored.
* @param callback A callback object used to return the error status of preparing the model for
* execution and the prepared model if successful, nullptr otherwise. The
* callback object's notify function must be called exactly once, even if the
* model could not be prepared.
* @throws ServiceSpecificException with one of the following ErrorStatus values:
* - DEVICE_UNAVAILABLE if driver is offline or busy
* - GENERAL_FAILURE if there is an unspecified error
* - INVALID_ARGUMENT if one of the input arguments related to preparing the model is
* invalid
* - MISSED_DEADLINE_* if the preparation is aborted because the model cannot be prepared by
* the deadline
* - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
*/
void prepareModel(in Model model, in ExecutionPreference preference, in Priority priority,
in long deadline, in ParcelFileDescriptor[] modelCache, in ParcelFileDescriptor[] dataCache,
in byte[] token, in IPreparedModelCallback callback);
/**
* Creates a prepared model from cache files for execution.
*
* prepareModelFromCache is used to retrieve a prepared model directly from cache files to avoid
* slow model compilation time. There are two types of cache file descriptors provided to the
* driver: model cache and data cache. For more information on the two types of cache files,
* refer to getNumberOfCacheFilesNeeded.
*
* The file descriptors must be opened with read and write permission. A file may have any size,
* and the corresponding file descriptor may have any offset. The driver must truncate a file to
* zero size before writing to that file. The file descriptors may be closed by the client once
* the asynchronous preparation has finished. The driver must dup a file descriptor if it wants
* to get access to the cache file later.
*
* The model is prepared asynchronously with respect to the caller. The prepareModelFromCache
* function must verify the inputs to the prepareModelFromCache function are correct, and that
* the security-sensitive cache has not been modified since it was last written by the driver.
* If there is an error, or if compilation caching is not supported, or if the
* security-sensitive cache has been modified, prepareModelFromCache must immediately invoke the
* callback with the appropriate ErrorStatus value and nullptr for the IPreparedModel, then
* return a status with a service specific exception with the same ErrorStatus. If the inputs to
* the prepareModelFromCache function are valid, the security-sensitive cache is not modified,
* and there is no error, prepareModelFromCache must launch an asynchronous task to prepare the
* model in the background, and immediately return from prepareModelFromCache. If the
* asynchronous task fails to launch, prepareModelFromCache must immediately invoke the callback
* with ErrorStatus::GENERAL_FAILURE and nullptr for the IPreparedModel, then return a service
* specific exception with ErrorStatus::GENERAL_FAILURE.
*
* When the asynchronous task has finished preparing the model, it must immediately invoke the
* callback function provided as an input to prepareModelFromCache. If the model was prepared
* successfully, the callback object must be invoked with an error status of ErrorStatus::NONE
* and the produced IPreparedModel object. If an error occurred preparing the model, the
* callback object must be invoked with the appropriate ErrorStatus value and nullptr for the
* IPreparedModel.
*
* prepareModelFromCache can be called with an optional deadline. If the model is not able to
* prepared before the provided deadline, the model preparation may be aborted, and either
* {@link ErrorStatus::MISSED_DEADLINE_TRANSIENT} or
* {@link ErrorStatus::MISSED_DEADLINE_PERSISTENT} may be returned. The error due to an abort
* must be sent the same way as other errors, described above.
*
* The only information that may be unknown to the model at this stage is the shape of the
* tensors, which may only be known at execution time. As such, some driver services may return
* partially prepared models, where the prepared model may only be finished when it is paired
* with a set of inputs to the model. Note that the same prepared model object may be used with
* different shapes of inputs on different (possibly concurrent) executions.
*
* @param deadline The time by which the model is expected to be prepared. The time is measured
* in nanoseconds since epoch of the steady clock (as from
* std::chrono::steady_clock). If the model cannot be prepared by the deadline,
* the preparation may be aborted. Passing -1 means the deadline is omitted.
* Other negative values are invalid.
* @param modelCache A vector of file descriptors for the security-sensitive cache. The length
* of the vector must match the numModelCache returned from
* getNumberOfCacheFilesNeeded. The cache file descriptors will be provided in
* the same order as with prepareModel.
* @param dataCache A vector of file descriptors for the constants' cache. The length of the
* vector must match the numDataCache returned from
* getNumberOfCacheFilesNeeded. The cache file descriptors will be provided in
* the same order as with prepareModel.
* @param token A caching token of length BYTE_SIZE_OF_CACHE_TOKEN identifying the prepared
* model. It is the same token provided when saving the cache files with
* prepareModel. Tokens should be chosen to have a low rate of collision for a
* particular application. The driver cannot detect a collision; a collision will
* result in a failed execution or in a successful execution that produces
* incorrect output values.
* @param callback A callback object used to return the error status of preparing the model for
* execution and the prepared model if successful, nullptr otherwise. The
* callback object's notify function must be called exactly once, even if the
* model could not be prepared.
* @throws ServiceSpecificException with one of the following ErrorStatus values:
* - DEVICE_UNAVAILABLE if driver is offline or busy
* - GENERAL_FAILURE if caching is not supported or if there is an unspecified error
* - INVALID_ARGUMENT if one of the input arguments is invalid
* - MISSED_DEADLINE_* if the preparation is aborted because the model cannot be prepared by
* the deadline
* - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
*/
void prepareModelFromCache(in long deadline, in ParcelFileDescriptor[] modelCache,
in ParcelFileDescriptor[] dataCache, in byte[] token, in IPreparedModelCallback callback);
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.neuralnetworks;
import android.hardware.neuralnetworks.ErrorStatus;
import android.hardware.neuralnetworks.Timing;
/**
* IFencedExecutionCallback can be used to query the error status result and duration information
* from an IPreparedModel::executeFenced call.
*/
@VintfStability
interface IFencedExecutionCallback {
/**
* The getExecutionInfo method is used by the clients to query error status result and duration
* information. The method must only be called after the actual evaluation has finished or
* resulted in an runtime error, as indicated by the status of the sync fence returned by the
* IPreparedModel::executeFenced call, otherwise GENERAL_FAILURE must be returned.
*
* @param out timingLaunched The duration starts when executeFenced is called and ends when
* executeFenced signals the returned syncFence. Unless measureTiming
* was set to true when launching the execution and status is NONE,
* all times must be reported as -1. A driver may choose to report any
* time as -1, indicating that particular measurement is not
* available.
* @param out timingFenced The duration starts when all waitFor sync fences have been signaled
* and ends when executeFenced signals the returned syncFence. Unless
* measureTiming was set to true when launching the execution and status
* is NONE, all times must be reported as -1. A driver may choose to
* report any time as -1, indicating that particular measurement is not
* available.
* @return Error status returned from the asynchronously dispatched execution must be:
* - NONE if the asynchronous execution was successful
* - DEVICE_UNAVAILABLE if driver is offline or busy
* - GENERAL_FAILURE if the asynchronous task resulted in an unspecified error
* - MISSED_DEADLINE_* if the execution is aborted because it cannot be completed by the
* deadline
* - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
*/
ErrorStatus getExecutionInfo(out Timing timingLaunched, out Timing timingFenced);
}

View File

@@ -0,0 +1,173 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.neuralnetworks;
import android.hardware.common.NativeHandle;
import android.hardware.neuralnetworks.ErrorStatus;
import android.hardware.neuralnetworks.ExecutionResult;
import android.hardware.neuralnetworks.IFencedExecutionCallback;
import android.hardware.neuralnetworks.Request;
/**
* IPreparedModel describes a model that has been prepared for execution and is used to launch
* executions.
*/
@VintfStability
interface IPreparedModel {
/**
* Each {@link OperationType::WHILE} operation in the model has an implicit execution timeout
* duration associated with it ("loop timeout duration"). This duration is configurable on a
* per-execution basis and must not exceed 15 seconds. The default value is 2 seconds. The units
* are nanoseconds.
*/
const long DEFAULT_LOOP_TIMEOUT_DURATION_NS = 2000000000;
const long MAXIMUM_LOOP_TIMEOUT_DURATION_NS = 15000000000;
/**
* Performs a synchronous execution on a prepared model.
*
* The execution is performed synchronously with respect to the caller. executeSynchronously
* must verify the inputs to the function are correct, and the usages of memory pools allocated
* by IDevice::allocate are valid. If there is an error, executeSynchronously must immediately
* return a service specific exception with the appropriate ErrorStatus value. If the inputs to
* the function are valid and there is no error, executeSynchronously must perform the
* execution, and must not return until the execution is complete.
*
* The caller must not change the content of any data object referenced by 'request' (described
* by the {@link DataLocation} of a {@link RequestArgument}) until executeSynchronously returns.
* executeSynchronously must not change the content of any of the data objects corresponding to
* 'request' inputs.
*
* If the prepared model was prepared from a model wherein all tensor operands have fully
* specified dimensions, and the inputs to the function are valid, and at execution time every
* operation's input operands have legal values, then the execution should complete
* successfully: there must be no failure unless the device itself is in a bad state.
*
* executeSynchronously may be called with an optional deadline. If the execution is not able to
* be completed before the provided deadline, the execution may be aborted, and either
* {@link ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link
* ErrorStatus::MISSED_DEADLINE_PERSISTENT} may be returned. The error due to an abort must be
* sent the same way as other errors, described above.
*
* Any number of calls to the execute* functions, in any combination, may be made concurrently,
* even on the same IPreparedModel object.
*
* @param request The input and output information on which the prepared model is to be
* executed.
* @param measure Specifies whether or not to measure duration of the execution. The duration
* runs from the time the driver sees the call to the executeSynchronously
* function to the time the driver returns from the function.
* @param deadline The time by which the execution is expected to complete. The time is measured
* in nanoseconds since epoch of the steady clock (as from
* std::chrono::steady_clock). If the execution cannot be finished by the
* deadline, the execution may be aborted. Passing -1 means the deadline is
* omitted. Other negative values are invalid.
* @param loopTimeoutDuration The maximum amount of time in nanoseconds that should be spent
* executing a {@link OperationType::WHILE} operation. If a loop
* condition model does not output false within this duration, the
* execution must be aborted. If -1 is provided, the maximum amount
* of time is {@link DEFAULT_LOOP_TIMEOUT_DURATION_NS}. Other
* negative values are invalid. When provided, the duration must not
* exceed {@link MAXIMUM_LOOP_TIMEOUT_DURATION_NS}.
* @return ExecutionResult parcelable, containing the status of the execution, output shapes and
* timing information.
* @throws ServiceSpecificException with one of the following ErrorStatus values:
* - DEVICE_UNAVAILABLE if driver is offline or busy
* - GENERAL_FAILURE if there is an unspecified error
* - INVALID_ARGUMENT if one of the input arguments is invalid
* - MISSED_DEADLINE_* if the execution is aborted because it cannot be completed by the
* deadline
* - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
*/
ExecutionResult executeSynchronously(in Request request, in boolean measureTiming,
in long deadline, in long loopTimeoutDuration);
/**
* Launch a fenced asynchronous execution on a prepared model.
*
* The execution is performed asynchronously with respect to the caller. executeFenced must
* verify the inputs to the function are correct, and the usages of memory pools allocated by
* IDevice::allocate are valid. If there is an error, executeFenced must immediately return a
* service specific exception with the corresponding ErrorStatus. If the inputs to the function
* are valid and there is no error, executeFenced must dispatch an asynchronous task to perform
* the execution in the background, assign a sync fence that will be signaled once the execution
* is completed and immediately return a callback that can be used by the client to query the
* duration and runtime error status. If the task has finished before the call returns,
* syncFence file descriptor may be set to -1. The execution must wait for all the sync fences
* (if any) in waitFor to be signaled before starting the actual execution.
*
* When the asynchronous task has finished its execution, it must immediately signal the
* syncFence returned from the executeFenced call. After the syncFence is signaled, the task
* must not modify the content of any data object referenced by 'request' (described by the
* {@link DataLocation} of a {@link RequestArgument}).
*
* executeFenced may be called with an optional deadline and an optional duration. If the
* execution is not able to be completed before the provided deadline or within the timeout
* duration (measured from when all sync fences in waitFor are signaled), whichever comes
* earlier, the execution may be aborted, and either
* {@link ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link
* ErrorStatus::MISSED_DEADLINE_PERSISTENT} may be returned. The error due to an abort must be
* sent the same way as other errors, described above.
*
* If any of the sync fences in waitFor changes to error status after the executeFenced call
* succeeds, or the execution is aborted because it cannot finish before the deadline has been
* reached or the duration has elapsed, the driver must immediately set the returned syncFence
* to error status.
*
* Any number of calls to the execute* functions, in any combination, may be made concurrently,
* even on the same IPreparedModel object.
*
* @param request The input and output information on which the prepared model is to be
* executed. The outputs in the request must have fully specified dimensions.
* @param waitFor A vector of sync fence file descriptors. Execution must not start until all
* sync fences have been signaled.
* @param measure Specifies whether or not to measure duration of the execution.
* @param deadline The time by which the execution is expected to complete. The time is measured
* in nanoseconds since epoch of the steady clock (as from
* std::chrono::steady_clock).If the execution cannot be finished by the
* deadline, the execution may be aborted. Passing -1 means the deadline is
* omitted. Other negative values are invalid.
* @param loopTimeoutDuration The maximum amount of time in nanoseconds that should be spent
* executing a {@link OperationType::WHILE} operation. If a loop
* condition model does not output false within this duration, the
* execution must be aborted. If -1 is provided, the maximum amount
* of time is {@link DEFAULT_LOOP_TIMEOUT_DURATION_NS}. Other
* negative values are invalid. When provided, the duration must not
* exceed {@link MAXIMUM_LOOP_TIMEOUT_DURATION_NS}.
* @param duration The length of time in nanoseconds within which the execution is expected to
* complete after all sync fences in waitFor are signaled. If the execution
* cannot be finished within the duration, the execution may be aborted. Passing
* -1 means the duration is omitted. Other negative values are invalid.
* @param out syncFence The sync fence that will be signaled when the task is completed. The
* sync fence will be set to error if a critical error, e.g. hardware
* failure or kernel panic, occurs when doing execution.
* @return The IFencedExecutionCallback can be used to query information like duration and error
* status when the execution is completed.
* @throws ServiceSpecificException with one of the following ErrorStatus values:
* - DEVICE_UNAVAILABLE if driver is offline or busy
* - GENERAL_FAILURE if there is an unspecified error
* - INVALID_ARGUMENT if one of the input arguments is invalid, including fences in error
* states.
* - MISSED_DEADLINE_* if the execution is aborted because it cannot be completed by the
* deadline
* - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
*/
IFencedExecutionCallback executeFenced(in Request request, in ParcelFileDescriptor[] waitFor,
in boolean measureTiming, in long deadline, in long loopTimeoutDuration, in long duration,
out @nullable ParcelFileDescriptor syncFence);
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.neuralnetworks;
import android.hardware.neuralnetworks.ErrorStatus;
import android.hardware.neuralnetworks.IPreparedModel;
/**
* IPreparedModelCallback must be used to return a prepared model produced by an asynchronous task
* launched from IDevice::prepareModel*.
*/
@VintfStability
interface IPreparedModelCallback {
/**
* Notify must be invoked immediately after the asynchronous task holding this callback has
* finished preparing the model. If the model was successfully prepared, the method must be
* invoked with ErrorStatus::NONE and the prepared model. If the model was not able to be
* successfully prepared, the method must be invoked with the appropriate ErrorStatus and
* nullptr as the IPreparedModel. If the asynchronous task holding this callback fails to launch
* or if the model provided to IDevice::prepareModel is invalid, notify method must be invoked
* with the appropriate error as well as nullptr for the IPreparedModel.
*
* @param status Error status returned from the asynchronous model preparation task; must be:
* - NONE if the asynchronous task successfully prepared the model
* - DEVICE_UNAVAILABLE if driver is offline or busy
* - GENERAL_FAILURE if the asynchronous task resulted in an unspecified error
* - INVALID_ARGUMENT if one of the input arguments to prepareModel is invalid
* - MISSED_DEADLINE_* if the preparation is aborted because the model cannot be
* prepared by the deadline
* - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
* @param preparedModel A model that has been asynchronously prepared for execution. If the
* model was unable to be prepared due to an error, nullptr must be passed
* in place of the IPreparedModel object.
*/
void notify(in ErrorStatus status, in IPreparedModel preparedModel);
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.neuralnetworks;
import android.hardware.neuralnetworks.IPreparedModel;
/**
* A parcelable for passing a vector of IPreparedModel objects.
*/
@VintfStability
parcelable IPreparedModelParcel {
IPreparedModel preparedModel;
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.neuralnetworks;
import android.hardware.common.NativeHandle;
import android.os.ParcelFileDescriptor;
/**
* A type that is used to pass pieces of shared memory between processes.
* The type structure mimics hidl_memory type from HIDL.
*/
@VintfStability
parcelable Memory {
NativeHandle handle;
long size;
String name;
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.neuralnetworks;
import android.hardware.neuralnetworks.ExtensionNameAndPrefix;
import android.hardware.neuralnetworks.Subgraph;
import android.hardware.neuralnetworks.Memory;
/**
* A Neural Network Model.
*
* This includes not only the execution graph, but also constant data such as weights or scalars
* added at construction time. The only information that may not be known is the shape of the input
* tensors.
*/
@VintfStability
parcelable Model {
/**
* The top-level subgraph.
*/
Subgraph main;
/**
* Referenced subgraphs.
*
* Each subgraph is referenced by the main subgraph or at least one other referenced subgraph.
*
* There must be no reference cycles.
*/
Subgraph[] referenced;
/**
* A byte buffer containing operand data that were copied into the model.
*
* An operand's value must be located here if and only if Operand::lifetime equals
* OperandLifeTime::CONSTANT_COPY.
*/
byte[] operandValues;
/**
* A collection of shared memory pools containing operand values.
*
* An operand's value must be located here if and only if Operand::lifetime equals
* OperandLifeTime::CONSTANT_POOL.
*/
Memory[] pools;
/**
* 'true' indicates TENSOR_FLOAT32 may be calculated with range and/or precision as low as that
* of the IEEE 754 16-bit floating-point format.
* 'false' indicates TENSOR_FLOAT32 must be calculated using at least the range and precision of
* the IEEE 754 32-bit floating-point format.
*/
boolean relaxComputationFloat32toFloat16;
/**
* The mapping between extension names and prefixes of operand and operation type values.
*/
ExtensionNameAndPrefix[] extensionNameToPrefix;
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.neuralnetworks;
/**
* Structure indicating how many files for model and numDataCache cache the driver needs to cache a
* single prepared model.
*/
@VintfStability
parcelable NumberOfCacheFiles {
int numModelCache;
int numDataCache;
}

View File

@@ -0,0 +1,113 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.neuralnetworks;
import android.hardware.neuralnetworks.DataLocation;
import android.hardware.neuralnetworks.OperandExtraParams;
import android.hardware.neuralnetworks.OperandLifeTime;
import android.hardware.neuralnetworks.OperandType;
/**
* Describes one operand of the model's graph.
*/
@VintfStability
parcelable Operand {
/**
* The data type.
*
* Besides the values listed in {@link OperandType}, any value above
* {@link IDevice::OPERAND_TYPE_BASE_MAX} is possible and should be interpreted as an extension
* type according to {@link Model::extensionNameToPrefix}.
*/
OperandType type;
/**
* Dimensions of the operand.
*
* For a scalar operand, dimensions.size() must be 0.
*
* A tensor operand with all dimensions specified has "fully specified" dimensions. Whenever
* possible (i.e., whenever the dimensions are known at model construction time), a tensor
* operand should have (but is not required to have) fully specified dimensions, in order to
* enable the best possible performance.
*
* If a tensor operand's dimensions are not fully specified, the dimensions of the operand are
* deduced from the operand dimensions and values of the operation for which that operand is an
* output or from the corresponding {@link OperationType::IF} or {@link OperationType::WHILE}
* operation input operand dimensions in the case of referenced subgraph input operands.
*
* In the following situations, a tensor operand's dimensions must be fully specified:
*
* . The operand has lifetime CONSTANT_COPY or CONSTANT_POOL.
*
* . The operand has lifetime SUBGRAPH_INPUT and belongs to the main subgraph. Fully
* specified dimensions must either be present in the Operand or they must be provided in
* the corresponding RequestArgument.
* EXCEPTION: If the input is optional and omitted (by setting the hasNoValue field of the
* corresponding RequestArgument to true) then it need not have fully specified
* dimensions.
*
* A tensor operand with some number of unspecified dimensions is represented by setting each
* unspecified dimension to 0.
*
* A tensor operand with unspecified rank is represented by providing an empty dimensions
* vector.
*/
int[] dimensions;
/**
* Quantized scale of the operand.
*
* Must be 0 when not applicable to an operand type.
*
* See {@link OperandType}.
*/
float scale;
/**
* Quantized zero-point offset of the operand.
*
* Must be 0 when not applicable to an operand type.
*
* See {@link OperandType}.
*/
int zeroPoint;
/**
* How the operand is used.
*/
OperandLifeTime lifetime;
/**
* Where to find the data for this operand.
* If the lifetime is TEMPORARY_VARIABLE, SUBGRAPH_INPUT, SUBGRAPH_OUTPUT, or NO_VALUE:
* - All the fields must be 0.
* If the lifetime is CONSTANT_COPY:
* - location.poolIndex is 0.
* - location.offset is the offset in bytes into Model.operandValues.
* - location.length is set.
* If the lifetime is CONSTANT_POOL:
* - location.poolIndex is set.
* - location.offset is the offset in bytes into the specified pool.
* - location.length is set.
* If the lifetime is SUBGRAPH:
* - location.poolIndex is 0.
* - location.offset is the index of the referenced subgraph in {@link Model::referenced}.
* - location.length is 0.
*/
DataLocation location;
/**
* Additional parameters specific to a particular operand type.
*/
@nullable OperandExtraParams extraParams;
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.neuralnetworks;
import android.hardware.neuralnetworks.SymmPerChannelQuantParams;
/**
* Parameters specific to a particular operand type.
*/
@VintfStability
union OperandExtraParams {
/**
* Symmetric per-channel quantization parameters.
*
* Only applicable to operands of type TENSOR_QUANT8_SYMM_PER_CHANNEL.
*/
SymmPerChannelQuantParams channelQuant;
/**
* Extension operand parameters.
*
* The framework treats this as an opaque data blob.
* The format is up to individual extensions.
*/
byte[] extension;
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.neuralnetworks;
/**
* How an operand is used.
*/
@VintfStability
@Backing(type="int")
enum OperandLifeTime {
/**
* The operand is internal to the model. It's created by an operation and consumed by other
* operations. It must be an output operand of exactly one operation.
*/
TEMPORARY_VARIABLE,
/**
* The operand is an input of a subgraph. It must not be an output operand of any operation.
*
* An operand can't be both input and output of a subgraph.
*/
SUBGRAPH_INPUT,
/**
* The operand is an output of a subgraph. It must be an output operand of exactly one
* operation.
*
* An operand can't be both input and output of a subgraph.
*/
SUBGRAPH_OUTPUT,
/**
* The operand is a constant found in Model.operandValues. It must not be an output operand of
* any operation.
*/
CONSTANT_COPY,
/**
* The operand is a constant that was specified via a Memory object. It must not be an output
* operand of any operation.
*/
CONSTANT_POOL,
/**
* The operand does not have a value. This is valid only for optional arguments of operations.
*/
NO_VALUE,
/**
* The operand is a reference to a subgraph. It must be an input to one or more
* {@link OperationType::IF} or {@link OperationType::WHILE} operations.
*/
SUBGRAPH,
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.neuralnetworks;
import android.hardware.neuralnetworks.OperandType;
import android.hardware.neuralnetworks.PerformanceInfo;
/**
* Driver performance when operating on a particular data type. In the case of float32 data, this is
* used when the calculations are not relaxed.
*/
@VintfStability
parcelable OperandPerformance {
OperandType type;
PerformanceInfo info;
}

View File

@@ -0,0 +1,154 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.neuralnetworks;
/**
* Operand types.
*
* The type of an operand in a model.
*
* Types prefaced with TENSOR_* must be used for tensor data (i.e., tensors
* with at least one dimension). Types not prefaced by TENSOR_* represent
* scalar values and must have no dimensions.
*/
@VintfStability
@Backing(type="int")
enum OperandType {
/**
* A 32 bit floating point scalar value.
*/
FLOAT32 = 0,
/**
* A signed 32 bit integer scalar value.
*/
INT32 = 1,
/**
* An unsigned 32 bit integer scalar value.
*/
UINT32 = 2,
/**
* A tensor of 32 bit floating point values.
*/
TENSOR_FLOAT32 = 3,
/**
* A tensor of 32 bit integer values.
*/
TENSOR_INT32 = 4,
/**
* A tensor of 8 bit unsigned integers that represent real numbers.
*
* Attached to this tensor are two numbers that can be used to convert the 8 bit integer to the
* real value and vice versa. These two numbers are:
* - scale: a 32 bit floating point value greater than zero.
* - zeroPoint: a 32 bit integer, in range [0, 255].
*
* The formula is:
* real_value = (integer_value - zeroPoint) * scale.
*/
TENSOR_QUANT8_ASYMM = 5,
/**
* An 8 bit boolean scalar value.
*
* Values of this operand type are either true or false. A zero value represents false; any
* other value represents true.
*/
BOOL = 6,
/**
* A tensor of 16 bit signed integers that represent real numbers.
*
* Attached to this tensor is a number representing real value scale that is used to convert the
* 16 bit number to a real value in the following way:
* realValue = integerValue * scale.
*
* scale is a 32 bit floating point with value greater than zero.
*/
TENSOR_QUANT16_SYMM = 7,
/**
* A tensor of IEEE 754 16 bit floating point values.
*/
TENSOR_FLOAT16 = 8,
/**
* A tensor of 8 bit boolean values.
*
* Values of this operand type are either true or false. A zero value represents false; any
* other value represents true.
*/
TENSOR_BOOL8 = 9,
/**
* An IEEE 754 16 bit floating point scalar value.
*/
FLOAT16 = 10,
/**
* A tensor of 8 bit signed integers that represent real numbers.
*
* This tensor is associated with additional fields that can be used to convert the 8 bit signed
* integer to the real value and vice versa. These fields are:
* - channelDim: a 32 bit unsigned integer indicating channel dimension.
* - scales: an array of positive 32 bit floating point values.
* The size of the scales array must be equal to dimensions[channelDim].
*
* {@link SymmPerChannelQuantParams} must hold the parameters for an Operand of this type.
* The channel dimension of this tensor must not be unknown (dimensions[channelDim] != 0).
*
* The formula is:
* realValue[..., C, ...] =
* integerValue[..., C, ...] * scales[C]
* where C is an index in the Channel dimension.
*/
TENSOR_QUANT8_SYMM_PER_CHANNEL = 11,
/**
* A tensor of 16 bit unsigned integers that represent real numbers.
*
* Attached to this tensor are two numbers that can be used to convert the 16 bit integer to the
* real value and vice versa. These two numbers are:
* - scale: a 32 bit floating point value greater than zero.
* - zeroPoint: a 32 bit integer, in range [0, 65535].
*
* The formula is:
* real_value = (integer_value - zeroPoint) * scale.
*/
TENSOR_QUANT16_ASYMM = 12,
/**
* A tensor of 8 bit signed integers that represent real numbers.
*
* Attached to this tensor is a number representing real value scale that is used to convert the
* 8 bit number to a real value in the following way:
* realValue = integerValue * scale.
*
* scale is a 32 bit floating point with value greater than zero.
*/
TENSOR_QUANT8_SYMM = 13,
/**
* A tensor of 8 bit signed integers that represent real numbers.
*
* Attached to this tensor are two numbers that can be used to convert the 8 bit integer to the
* real value and vice versa. These two numbers are:
* - scale: a 32 bit floating point value greater than zero.
* - zeroPoint: a 32 bit integer, in range [-128, 127].
*
* The formula is:
* real_value = (integer_value - zeroPoint) * scale.
*/
TENSOR_QUANT8_ASYMM_SIGNED = 14,
/**
* A reference to a subgraph.
*
* Must have the lifetime {@link OperandLifeTime::SUBGRAPH}.
*/
SUBGRAPH = 15,
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.neuralnetworks;
import android.hardware.neuralnetworks.OperationType;
/**
* Describes one operation of the model's graph.
*/
@VintfStability
parcelable Operation {
/**
* The operation type.
*
* Besides the values listed in {@link OperationType}, any value above
* {@link IDevice::OPERATION_TYPE_BASE_MAX} is possible and should be interpreted as an
* extension type according to {@link Model::extensionNameToPrefix}.
*/
OperationType type;
/**
* Describes the table that contains the indexes of the inputs of the operation. The offset is
* the index in the operandIndexes table.
*/
int[] inputs;
/**
* Describes the table that contains the indexes of the outputs of the operation. The offset is
* the index in the operandIndexes table.
*/
int[] outputs;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,33 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.neuralnetworks;
/**
* Describes the shape information of an output operand after execution.
*/
@VintfStability
parcelable OutputShape {
/**
* Dimensions of the operand.
*/
int[] dimensions;
/**
* Whether the provided buffer size is sufficient for the output.
*/
boolean isSufficient;
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.neuralnetworks;
/**
* Performance information for the reference workload.
*
* Used by a driver to report its performance characteristics.
*/
@VintfStability
parcelable PerformanceInfo {
/**
* Ratio of the time taken by the driver to execute the workload compared to the time the CPU
* would take for the same workload. A lower number is better.
*/
float execTime;
/**
* Ratio of the energy used by the driver compared to what the CPU would use for doing the same
* workload. A lower number is better.
*/
float powerUsage;
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.neuralnetworks;
/**
* Priority given to a prepared model for execution.
*/
@VintfStability
@Backing(type="int")
enum Priority {
LOW,
MEDIUM,
HIGH,
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.neuralnetworks;
import android.hardware.neuralnetworks.RequestArgument;
import android.hardware.neuralnetworks.RequestMemoryPool;
/**
* Inputs to be sent to and outputs to be retrieved from a prepared model.
*
* A Request serves two primary tasks:
* 1) Provides the input and output data to be used when executing the model.
* 2) Specifies any updates to the input operand metadata that were left unspecified at model
* preparation time.
*
* An output must not overlap with any other output, with an input, or with an operand of lifetime
* CONSTANT_POOL.
*/
@VintfStability
parcelable Request {
/**
* Input data and information to be used in the execution of a prepared model.
*
* The index of the input corresponds to the index in Model.main.inputIndexes.
* E.g., input[i] corresponds to Model.main.inputIndexes[i].
*/
RequestArgument[] inputs;
/**
* Output data and information to be used in the execution of a prepared model.
*
* The index of the output corresponds to the index in Model.main.outputIndexes.
* E.g., output[i] corresponds to Model.main.outputIndexes[i].
*/
RequestArgument[] outputs;
/**
* A collection of memory pools containing operand data for both the inputs and the outputs to a
* model.
*/
RequestMemoryPool[] pools;
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.neuralnetworks;
import android.hardware.neuralnetworks.DataLocation;
/**
* Metadata information specifying the location of the input or output data and any updates to the
* input or output operand.
*/
@VintfStability
parcelable RequestArgument {
/**
* If true, the argument does not have a value. This can be used for operations that take
* optional arguments. If true, the fields of location are set to 0 and the dimensions vector is
* left empty.
*/
boolean hasNoValue;
/**
* The location within one of the memory pools passed in the Request.
*/
DataLocation location;
/**
* Updated dimension information.
*
* If dimensions.size() > 0, dimension information was provided along with the argument. This
* can be the case for models that accept inputs of varying size. This can't change the rank,
* just the value of the dimensions that were unspecified in the model. If dimensions.size() >
* 0, then all dimensions must be specified here; and any dimension that was specified in the
* model must have the same value here.
*
* If the dimensions in the model are not fully specified, then they must be fully specified
* here, unless hasNoValue is set to true. If the dimensions in the model are fully specified,
* then either dimensions.size() may be 0, or the dimensions in the model must be identical to
* the dimensions here.
*/
int[] dimensions;
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.neuralnetworks;
import android.hardware.neuralnetworks.Memory;
/**
* A memory pool.
*/
@VintfStability
union RequestMemoryPool {
/**
* Specifies a client-managed shared memory pool.
*/
Memory pool;
/**
* Specifies a driver-managed buffer. It is the token returned from IDevice::allocate, and is
* specific to the IDevice object.
*/
int token;
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.neuralnetworks;
import android.hardware.neuralnetworks.Operand;
import android.hardware.neuralnetworks.Operation;
/**
* An excerpt of the execution graph.
*/
@VintfStability
parcelable Subgraph {
/**
* All operands included in the subgraph.
*/
Operand[] operands;
/**
* All operations included in the subgraph.
*
* The operations are sorted into execution order. Every operand with lifetime SUBGRAPH_OUTPUT
* or TEMPORARY_VARIABLE must be written before it is read.
*/
Operation[] operations;
/**
* Input indexes of the subgraph. There must be at least one.
*
* Each value corresponds to the index of the operand in "operands".
*/
int[] inputIndexes;
/**
* Output indexes of the subgraph. There must be at least one.
*
* Each value corresponds to the index of the operand in "operands".
*/
int[] outputIndexes;
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.neuralnetworks;
/**
* Parameters for TENSOR_QUANT8_SYMM_PER_CHANNEL operand.
*/
@VintfStability
parcelable SymmPerChannelQuantParams {
/**
* Array of scaling values for each channel. Each value must be greater than zero.
*/
float[] scales;
/**
* Index of the channel dimension
*/
int channelDim;
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.neuralnetworks;
/**
* Timing information measured during execution. Each time is a duration from the beginning of some
* task to the end of that task, including time when that task is not active (for example, preempted
* by some other task, or waiting for some resource to become available).
*
* Times are measured in nanoseconds. When a time is not available, it must be reported as -1.
*/
@VintfStability
parcelable Timing {
/**
* Execution time on device (not driver, which runs on host processor).
*/
long timeOnDevice;
/**
* Execution time in driver (including time on device).
*/
long timeInDriver;
}

View File

@@ -0,0 +1,32 @@
//
// Copyright (C) 2021 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
cc_library_static {
name: "neuralnetworks_utils_hal_aidl",
defaults: ["neuralnetworks_utils_defaults"],
srcs: ["src/*"],
local_include_dirs: ["include/nnapi/hal/aidl/"],
export_include_dirs: ["include"],
static_libs: [
"neuralnetworks_types",
"neuralnetworks_utils_hal_common",
],
shared_libs: [
"libhidlbase",
"android.hardware.neuralnetworks-V1-ndk_platform",
"libbinder_ndk",
],
}

View File

@@ -0,0 +1,11 @@
# Neuralnetworks team
butlermichael@google.com
dgross@google.com
galarragas@google.com
jeanluc@google.com
levp@google.com
miaowang@google.com
pszczepaniak@google.com
slavash@google.com
vddang@google.com
xusongw@google.com

View File

@@ -0,0 +1,134 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_CONVERSIONS_H
#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_CONVERSIONS_H
#include <aidl/android/hardware/neuralnetworks/BufferDesc.h>
#include <aidl/android/hardware/neuralnetworks/BufferRole.h>
#include <aidl/android/hardware/neuralnetworks/Capabilities.h>
#include <aidl/android/hardware/neuralnetworks/DataLocation.h>
#include <aidl/android/hardware/neuralnetworks/DeviceType.h>
#include <aidl/android/hardware/neuralnetworks/ErrorStatus.h>
#include <aidl/android/hardware/neuralnetworks/ExecutionPreference.h>
#include <aidl/android/hardware/neuralnetworks/Extension.h>
#include <aidl/android/hardware/neuralnetworks/ExtensionNameAndPrefix.h>
#include <aidl/android/hardware/neuralnetworks/ExtensionOperandTypeInformation.h>
#include <aidl/android/hardware/neuralnetworks/Memory.h>
#include <aidl/android/hardware/neuralnetworks/Model.h>
#include <aidl/android/hardware/neuralnetworks/Operand.h>
#include <aidl/android/hardware/neuralnetworks/OperandExtraParams.h>
#include <aidl/android/hardware/neuralnetworks/OperandLifeTime.h>
#include <aidl/android/hardware/neuralnetworks/OperandPerformance.h>
#include <aidl/android/hardware/neuralnetworks/OperandType.h>
#include <aidl/android/hardware/neuralnetworks/Operation.h>
#include <aidl/android/hardware/neuralnetworks/OperationType.h>
#include <aidl/android/hardware/neuralnetworks/OutputShape.h>
#include <aidl/android/hardware/neuralnetworks/PerformanceInfo.h>
#include <aidl/android/hardware/neuralnetworks/Priority.h>
#include <aidl/android/hardware/neuralnetworks/Request.h>
#include <aidl/android/hardware/neuralnetworks/RequestArgument.h>
#include <aidl/android/hardware/neuralnetworks/RequestMemoryPool.h>
#include <aidl/android/hardware/neuralnetworks/Subgraph.h>
#include <aidl/android/hardware/neuralnetworks/SymmPerChannelQuantParams.h>
#include <aidl/android/hardware/neuralnetworks/Timing.h>
#include <nnapi/Result.h>
#include <nnapi/Types.h>
#include <nnapi/hal/CommonUtils.h>
#include <vector>
namespace android::nn {
GeneralResult<OperandType> unvalidatedConvert(const aidl_hal::OperandType& operandType);
GeneralResult<OperationType> unvalidatedConvert(const aidl_hal::OperationType& operationType);
GeneralResult<DeviceType> unvalidatedConvert(const aidl_hal::DeviceType& deviceType);
GeneralResult<Priority> unvalidatedConvert(const aidl_hal::Priority& priority);
GeneralResult<Capabilities> unvalidatedConvert(const aidl_hal::Capabilities& capabilities);
GeneralResult<Capabilities::OperandPerformance> unvalidatedConvert(
const aidl_hal::OperandPerformance& operandPerformance);
GeneralResult<Capabilities::PerformanceInfo> unvalidatedConvert(
const aidl_hal::PerformanceInfo& performanceInfo);
GeneralResult<DataLocation> unvalidatedConvert(const aidl_hal::DataLocation& location);
GeneralResult<Operand> unvalidatedConvert(const aidl_hal::Operand& operand);
GeneralResult<Operand::ExtraParams> unvalidatedConvert(
const std::optional<aidl_hal::OperandExtraParams>& optionalExtraParams);
GeneralResult<Operand::LifeTime> unvalidatedConvert(
const aidl_hal::OperandLifeTime& operandLifeTime);
GeneralResult<Operand::SymmPerChannelQuantParams> unvalidatedConvert(
const aidl_hal::SymmPerChannelQuantParams& symmPerChannelQuantParams);
GeneralResult<Operation> unvalidatedConvert(const aidl_hal::Operation& operation);
GeneralResult<Model> unvalidatedConvert(const aidl_hal::Model& model);
GeneralResult<Model::ExtensionNameAndPrefix> unvalidatedConvert(
const aidl_hal::ExtensionNameAndPrefix& extensionNameAndPrefix);
GeneralResult<Model::OperandValues> unvalidatedConvert(const std::vector<uint8_t>& operandValues);
GeneralResult<Model::Subgraph> unvalidatedConvert(const aidl_hal::Subgraph& subgraph);
GeneralResult<OutputShape> unvalidatedConvert(const aidl_hal::OutputShape& outputShape);
GeneralResult<MeasureTiming> unvalidatedConvert(bool measureTiming);
GeneralResult<Memory> unvalidatedConvert(const aidl_hal::Memory& memory);
GeneralResult<Timing> unvalidatedConvert(const aidl_hal::Timing& timing);
GeneralResult<BufferDesc> unvalidatedConvert(const aidl_hal::BufferDesc& bufferDesc);
GeneralResult<BufferRole> unvalidatedConvert(const aidl_hal::BufferRole& bufferRole);
GeneralResult<Request> unvalidatedConvert(const aidl_hal::Request& request);
GeneralResult<Request::Argument> unvalidatedConvert(
const aidl_hal::RequestArgument& requestArgument);
GeneralResult<Request::MemoryPool> unvalidatedConvert(
const aidl_hal::RequestMemoryPool& memoryPool);
GeneralResult<ErrorStatus> unvalidatedConvert(const aidl_hal::ErrorStatus& errorStatus);
GeneralResult<ExecutionPreference> unvalidatedConvert(
const aidl_hal::ExecutionPreference& executionPreference);
GeneralResult<Extension> unvalidatedConvert(const aidl_hal::Extension& extension);
GeneralResult<Extension::OperandTypeInformation> unvalidatedConvert(
const aidl_hal::ExtensionOperandTypeInformation& operandTypeInformation);
GeneralResult<SharedHandle> unvalidatedConvert(
const ::aidl::android::hardware::common::NativeHandle& handle);
GeneralResult<ExecutionPreference> convert(
const aidl_hal::ExecutionPreference& executionPreference);
GeneralResult<Memory> convert(const aidl_hal::Memory& memory);
GeneralResult<Model> convert(const aidl_hal::Model& model);
GeneralResult<Operand> convert(const aidl_hal::Operand& operand);
GeneralResult<OperandType> convert(const aidl_hal::OperandType& operandType);
GeneralResult<Priority> convert(const aidl_hal::Priority& priority);
GeneralResult<Request::MemoryPool> convert(const aidl_hal::RequestMemoryPool& memoryPool);
GeneralResult<Request> convert(const aidl_hal::Request& request);
GeneralResult<std::vector<Operation>> convert(const std::vector<aidl_hal::Operation>& outputShapes);
GeneralResult<std::vector<Memory>> convert(const std::vector<aidl_hal::Memory>& memories);
GeneralResult<std::vector<uint32_t>> toUnsigned(const std::vector<int32_t>& vec);
} // namespace android::nn
namespace aidl::android::hardware::neuralnetworks::utils {
namespace nn = ::android::nn;
nn::GeneralResult<Memory> unvalidatedConvert(const nn::Memory& memory);
nn::GeneralResult<OutputShape> unvalidatedConvert(const nn::OutputShape& outputShape);
nn::GeneralResult<ErrorStatus> unvalidatedConvert(const nn::ErrorStatus& errorStatus);
nn::GeneralResult<Memory> convert(const nn::Memory& memory);
nn::GeneralResult<ErrorStatus> convert(const nn::ErrorStatus& errorStatus);
nn::GeneralResult<std::vector<OutputShape>> convert(
const std::vector<nn::OutputShape>& outputShapes);
nn::GeneralResult<std::vector<int32_t>> toSigned(const std::vector<uint32_t>& vec);
} // namespace aidl::android::hardware::neuralnetworks::utils
#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_CONVERSIONS_H

View File

@@ -0,0 +1,57 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_H
#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_H
#include "nnapi/hal/aidl/Conversions.h"
#include <android-base/logging.h>
#include <nnapi/Result.h>
#include <nnapi/Types.h>
#include <nnapi/Validation.h>
namespace aidl::android::hardware::neuralnetworks::utils {
constexpr auto kDefaultPriority = Priority::MEDIUM;
constexpr auto kVersion = nn::Version::ANDROID_S;
template <typename Type>
nn::Result<void> validate(const Type& halObject) {
const auto maybeCanonical = nn::convert(halObject);
if (!maybeCanonical.has_value()) {
return nn::error() << maybeCanonical.error().message;
}
return {};
}
template <typename Type>
bool valid(const Type& halObject) {
const auto result = utils::validate(halObject);
if (!result.has_value()) {
LOG(ERROR) << result.error();
}
return result.has_value();
}
nn::GeneralResult<Memory> clone(const Memory& memory);
nn::GeneralResult<Request> clone(const Request& request);
nn::GeneralResult<RequestMemoryPool> clone(const RequestMemoryPool& requestPool);
nn::GeneralResult<Model> clone(const Model& model);
} // namespace aidl::android::hardware::neuralnetworks::utils
#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_H

View File

@@ -0,0 +1,269 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <aidl/android/hardware/neuralnetworks/DeviceType.h>
#include <aidl/android/hardware/neuralnetworks/ErrorStatus.h>
#include <aidl/android/hardware/neuralnetworks/ExecutionPreference.h>
#include <aidl/android/hardware/neuralnetworks/FusedActivationFunc.h>
#include <aidl/android/hardware/neuralnetworks/IDevice.h>
#include <aidl/android/hardware/neuralnetworks/OperandLifeTime.h>
#include <aidl/android/hardware/neuralnetworks/OperandType.h>
#include <aidl/android/hardware/neuralnetworks/OperationType.h>
#include <aidl/android/hardware/neuralnetworks/Priority.h>
#include <ControlFlow.h>
#include <nnapi/OperandTypes.h>
#include <nnapi/OperationTypes.h>
#include <nnapi/Types.h>
#include <type_traits>
namespace {
#define COMPARE_ENUMS_TYPES(lhsType, rhsType) \
static_assert( \
std::is_same_v< \
std::underlying_type_t<::aidl::android::hardware::neuralnetworks::lhsType>, \
std::underlying_type_t<::android::nn::rhsType>>, \
"::aidl::android::hardware::neuralnetworks::" #lhsType \
" does not have the same underlying type as ::android::nn::" #rhsType)
COMPARE_ENUMS_TYPES(OperandType, OperandType);
COMPARE_ENUMS_TYPES(OperationType, OperationType);
COMPARE_ENUMS_TYPES(Priority, Priority);
COMPARE_ENUMS_TYPES(OperandLifeTime, Operand::LifeTime);
COMPARE_ENUMS_TYPES(ErrorStatus, ErrorStatus);
#undef COMPARE_ENUMS_TYPES
#define COMPARE_ENUMS_FULL(lhsSymbol, rhsSymbol, lhsType, rhsType) \
static_assert( \
static_cast< \
std::underlying_type_t<::aidl::android::hardware::neuralnetworks::lhsType>>( \
::aidl::android::hardware::neuralnetworks::lhsType::lhsSymbol) == \
static_cast<std::underlying_type_t<::android::nn::rhsType>>( \
::android::nn::rhsType::rhsSymbol), \
"::aidl::android::hardware::neuralnetworks::" #lhsType "::" #lhsSymbol \
" does not match ::android::nn::" #rhsType "::" #rhsSymbol)
#define COMPARE_ENUMS(symbol) COMPARE_ENUMS_FULL(symbol, symbol, OperandType, OperandType)
COMPARE_ENUMS(FLOAT32);
COMPARE_ENUMS(INT32);
COMPARE_ENUMS(UINT32);
COMPARE_ENUMS(TENSOR_FLOAT32);
COMPARE_ENUMS(TENSOR_INT32);
COMPARE_ENUMS(TENSOR_QUANT8_ASYMM);
COMPARE_ENUMS(BOOL);
COMPARE_ENUMS(TENSOR_QUANT16_SYMM);
COMPARE_ENUMS(TENSOR_FLOAT16);
COMPARE_ENUMS(TENSOR_BOOL8);
COMPARE_ENUMS(FLOAT16);
COMPARE_ENUMS(TENSOR_QUANT8_SYMM_PER_CHANNEL);
COMPARE_ENUMS(TENSOR_QUANT16_ASYMM);
COMPARE_ENUMS(TENSOR_QUANT8_SYMM);
COMPARE_ENUMS(TENSOR_QUANT8_ASYMM_SIGNED);
COMPARE_ENUMS(SUBGRAPH);
#undef COMPARE_ENUMS
#define COMPARE_ENUMS(symbol) COMPARE_ENUMS_FULL(symbol, symbol, OperationType, OperationType)
COMPARE_ENUMS(ADD);
COMPARE_ENUMS(AVERAGE_POOL_2D);
COMPARE_ENUMS(CONCATENATION);
COMPARE_ENUMS(CONV_2D);
COMPARE_ENUMS(DEPTHWISE_CONV_2D);
COMPARE_ENUMS(DEPTH_TO_SPACE);
COMPARE_ENUMS(DEQUANTIZE);
COMPARE_ENUMS(EMBEDDING_LOOKUP);
COMPARE_ENUMS(FLOOR);
COMPARE_ENUMS(FULLY_CONNECTED);
COMPARE_ENUMS(HASHTABLE_LOOKUP);
COMPARE_ENUMS(L2_NORMALIZATION);
COMPARE_ENUMS(L2_POOL_2D);
COMPARE_ENUMS(LOCAL_RESPONSE_NORMALIZATION);
COMPARE_ENUMS(LOGISTIC);
COMPARE_ENUMS(LSH_PROJECTION);
COMPARE_ENUMS(LSTM);
COMPARE_ENUMS(MAX_POOL_2D);
COMPARE_ENUMS(MUL);
COMPARE_ENUMS(RELU);
COMPARE_ENUMS(RELU1);
COMPARE_ENUMS(RELU6);
COMPARE_ENUMS(RESHAPE);
COMPARE_ENUMS(RESIZE_BILINEAR);
COMPARE_ENUMS(RNN);
COMPARE_ENUMS(SOFTMAX);
COMPARE_ENUMS(SPACE_TO_DEPTH);
COMPARE_ENUMS(SVDF);
COMPARE_ENUMS(TANH);
COMPARE_ENUMS(BATCH_TO_SPACE_ND);
COMPARE_ENUMS(DIV);
COMPARE_ENUMS(MEAN);
COMPARE_ENUMS(PAD);
COMPARE_ENUMS(SPACE_TO_BATCH_ND);
COMPARE_ENUMS(SQUEEZE);
COMPARE_ENUMS(STRIDED_SLICE);
COMPARE_ENUMS(SUB);
COMPARE_ENUMS(TRANSPOSE);
COMPARE_ENUMS(ABS);
COMPARE_ENUMS(ARGMAX);
COMPARE_ENUMS(ARGMIN);
COMPARE_ENUMS(AXIS_ALIGNED_BBOX_TRANSFORM);
COMPARE_ENUMS(BIDIRECTIONAL_SEQUENCE_LSTM);
COMPARE_ENUMS(BIDIRECTIONAL_SEQUENCE_RNN);
COMPARE_ENUMS(BOX_WITH_NMS_LIMIT);
COMPARE_ENUMS(CAST);
COMPARE_ENUMS(CHANNEL_SHUFFLE);
COMPARE_ENUMS(DETECTION_POSTPROCESSING);
COMPARE_ENUMS(EQUAL);
COMPARE_ENUMS(EXP);
COMPARE_ENUMS(EXPAND_DIMS);
COMPARE_ENUMS(GATHER);
COMPARE_ENUMS(GENERATE_PROPOSALS);
COMPARE_ENUMS(GREATER);
COMPARE_ENUMS(GREATER_EQUAL);
COMPARE_ENUMS(GROUPED_CONV_2D);
COMPARE_ENUMS(HEATMAP_MAX_KEYPOINT);
COMPARE_ENUMS(INSTANCE_NORMALIZATION);
COMPARE_ENUMS(LESS);
COMPARE_ENUMS(LESS_EQUAL);
COMPARE_ENUMS(LOG);
COMPARE_ENUMS(LOGICAL_AND);
COMPARE_ENUMS(LOGICAL_NOT);
COMPARE_ENUMS(LOGICAL_OR);
COMPARE_ENUMS(LOG_SOFTMAX);
COMPARE_ENUMS(MAXIMUM);
COMPARE_ENUMS(MINIMUM);
COMPARE_ENUMS(NEG);
COMPARE_ENUMS(NOT_EQUAL);
COMPARE_ENUMS(PAD_V2);
COMPARE_ENUMS(POW);
COMPARE_ENUMS(PRELU);
COMPARE_ENUMS(QUANTIZE);
COMPARE_ENUMS(QUANTIZED_16BIT_LSTM);
COMPARE_ENUMS(RANDOM_MULTINOMIAL);
COMPARE_ENUMS(REDUCE_ALL);
COMPARE_ENUMS(REDUCE_ANY);
COMPARE_ENUMS(REDUCE_MAX);
COMPARE_ENUMS(REDUCE_MIN);
COMPARE_ENUMS(REDUCE_PROD);
COMPARE_ENUMS(REDUCE_SUM);
COMPARE_ENUMS(ROI_ALIGN);
COMPARE_ENUMS(ROI_POOLING);
COMPARE_ENUMS(RSQRT);
COMPARE_ENUMS(SELECT);
COMPARE_ENUMS(SIN);
COMPARE_ENUMS(SLICE);
COMPARE_ENUMS(SPLIT);
COMPARE_ENUMS(SQRT);
COMPARE_ENUMS(TILE);
COMPARE_ENUMS(TOPK_V2);
COMPARE_ENUMS(TRANSPOSE_CONV_2D);
COMPARE_ENUMS(UNIDIRECTIONAL_SEQUENCE_LSTM);
COMPARE_ENUMS(UNIDIRECTIONAL_SEQUENCE_RNN);
COMPARE_ENUMS(RESIZE_NEAREST_NEIGHBOR);
COMPARE_ENUMS(QUANTIZED_LSTM);
COMPARE_ENUMS(IF);
COMPARE_ENUMS(WHILE);
COMPARE_ENUMS(ELU);
COMPARE_ENUMS(HARD_SWISH);
COMPARE_ENUMS(FILL);
COMPARE_ENUMS(RANK);
#undef COMPARE_ENUMS
#define COMPARE_ENUMS(symbol) COMPARE_ENUMS_FULL(symbol, symbol, Priority, Priority)
COMPARE_ENUMS(LOW);
COMPARE_ENUMS(MEDIUM);
COMPARE_ENUMS(HIGH);
#undef COMPARE_ENUMS
#define COMPARE_ENUMS(lhsSymbol, rhsSymbol) \
COMPARE_ENUMS_FULL(lhsSymbol, rhsSymbol, OperandLifeTime, Operand::LifeTime)
COMPARE_ENUMS(TEMPORARY_VARIABLE, TEMPORARY_VARIABLE);
COMPARE_ENUMS(SUBGRAPH_INPUT, SUBGRAPH_INPUT);
COMPARE_ENUMS(SUBGRAPH_OUTPUT, SUBGRAPH_OUTPUT);
COMPARE_ENUMS(CONSTANT_COPY, CONSTANT_COPY);
COMPARE_ENUMS(CONSTANT_POOL, CONSTANT_REFERENCE);
COMPARE_ENUMS(NO_VALUE, NO_VALUE);
COMPARE_ENUMS(SUBGRAPH, SUBGRAPH);
#undef COMPARE_ENUMS
#define COMPARE_ENUMS(symbol) COMPARE_ENUMS_FULL(symbol, symbol, ErrorStatus, ErrorStatus)
COMPARE_ENUMS(NONE);
COMPARE_ENUMS(DEVICE_UNAVAILABLE);
COMPARE_ENUMS(GENERAL_FAILURE);
COMPARE_ENUMS(OUTPUT_INSUFFICIENT_SIZE);
COMPARE_ENUMS(INVALID_ARGUMENT);
COMPARE_ENUMS(MISSED_DEADLINE_TRANSIENT);
COMPARE_ENUMS(MISSED_DEADLINE_PERSISTENT);
COMPARE_ENUMS(RESOURCE_EXHAUSTED_TRANSIENT);
COMPARE_ENUMS(RESOURCE_EXHAUSTED_PERSISTENT);
#undef COMPARE_ENUMS
#define COMPARE_ENUMS(symbol) \
COMPARE_ENUMS_FULL(symbol, symbol, ExecutionPreference, ExecutionPreference)
COMPARE_ENUMS(LOW_POWER);
COMPARE_ENUMS(FAST_SINGLE_ANSWER);
COMPARE_ENUMS(SUSTAINED_SPEED);
#undef COMPARE_ENUMS
#define COMPARE_ENUMS(symbol) COMPARE_ENUMS_FULL(symbol, symbol, DeviceType, DeviceType)
COMPARE_ENUMS(OTHER);
COMPARE_ENUMS(CPU);
COMPARE_ENUMS(GPU);
COMPARE_ENUMS(ACCELERATOR);
#undef COMPARE_ENUMS
#define COMPARE_ENUMS(symbol) \
COMPARE_ENUMS_FULL(symbol, symbol, FusedActivationFunc, FusedActivationFunc)
COMPARE_ENUMS(NONE);
COMPARE_ENUMS(RELU);
COMPARE_ENUMS(RELU1);
COMPARE_ENUMS(RELU6);
#undef COMPARE_ENUMS
#undef COMPARE_ENUMS_FULL
#define COMPARE_CONSTANTS(halSymbol, canonicalSymbol) \
static_assert(::aidl::android::hardware::neuralnetworks::halSymbol == \
::android::nn::canonicalSymbol);
COMPARE_CONSTANTS(IDevice::BYTE_SIZE_OF_CACHE_TOKEN, kByteSizeOfCacheToken);
COMPARE_CONSTANTS(IDevice::MAX_NUMBER_OF_CACHE_FILES, kMaxNumberOfCacheFiles);
COMPARE_CONSTANTS(IDevice::EXTENSION_TYPE_HIGH_BITS_PREFIX, kExtensionPrefixBits - 1);
COMPARE_CONSTANTS(IDevice::EXTENSION_TYPE_LOW_BITS_TYPE, kExtensionTypeBits);
COMPARE_CONSTANTS(IPreparedModel::DEFAULT_LOOP_TIMEOUT_DURATION_NS,
operation_while::kTimeoutNsDefault);
COMPARE_CONSTANTS(IPreparedModel::MAXIMUM_LOOP_TIMEOUT_DURATION_NS,
operation_while::kTimeoutNsMaximum);
#undef COMPARE_CONSTANTS
} // anonymous namespace

View File

@@ -0,0 +1,582 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "Conversions.h"
#include <aidl/android/hardware/common/NativeHandle.h>
#include <android-base/logging.h>
#include <nnapi/OperandTypes.h>
#include <nnapi/OperationTypes.h>
#include <nnapi/Result.h>
#include <nnapi/SharedMemory.h>
#include <nnapi/TypeUtils.h>
#include <nnapi/Types.h>
#include <nnapi/Validation.h>
#include <nnapi/hal/CommonUtils.h>
#include <nnapi/hal/HandleError.h>
#include <algorithm>
#include <chrono>
#include <functional>
#include <iterator>
#include <limits>
#include <type_traits>
#include <utility>
#define VERIFY_NON_NEGATIVE(value) \
while (UNLIKELY(value < 0)) return NN_ERROR()
namespace {
template <typename Type>
constexpr std::underlying_type_t<Type> underlyingType(Type value) {
return static_cast<std::underlying_type_t<Type>>(value);
}
constexpr auto kVersion = android::nn::Version::ANDROID_S;
} // namespace
namespace android::nn {
namespace {
constexpr auto validOperandType(nn::OperandType operandType) {
switch (operandType) {
case nn::OperandType::FLOAT32:
case nn::OperandType::INT32:
case nn::OperandType::UINT32:
case nn::OperandType::TENSOR_FLOAT32:
case nn::OperandType::TENSOR_INT32:
case nn::OperandType::TENSOR_QUANT8_ASYMM:
case nn::OperandType::BOOL:
case nn::OperandType::TENSOR_QUANT16_SYMM:
case nn::OperandType::TENSOR_FLOAT16:
case nn::OperandType::TENSOR_BOOL8:
case nn::OperandType::FLOAT16:
case nn::OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL:
case nn::OperandType::TENSOR_QUANT16_ASYMM:
case nn::OperandType::TENSOR_QUANT8_SYMM:
case nn::OperandType::TENSOR_QUANT8_ASYMM_SIGNED:
case nn::OperandType::SUBGRAPH:
return true;
case nn::OperandType::OEM:
case nn::OperandType::TENSOR_OEM_BYTE:
return false;
}
return nn::isExtension(operandType);
}
template <typename Input>
using UnvalidatedConvertOutput =
std::decay_t<decltype(unvalidatedConvert(std::declval<Input>()).value())>;
template <typename Type>
GeneralResult<std::vector<UnvalidatedConvertOutput<Type>>> unvalidatedConvertVec(
const std::vector<Type>& arguments) {
std::vector<UnvalidatedConvertOutput<Type>> canonical;
canonical.reserve(arguments.size());
for (const auto& argument : arguments) {
canonical.push_back(NN_TRY(nn::unvalidatedConvert(argument)));
}
return canonical;
}
template <typename Type>
GeneralResult<std::vector<UnvalidatedConvertOutput<Type>>> unvalidatedConvert(
const std::vector<Type>& arguments) {
return unvalidatedConvertVec(arguments);
}
template <typename Type>
GeneralResult<UnvalidatedConvertOutput<Type>> validatedConvert(const Type& halObject) {
auto canonical = NN_TRY(nn::unvalidatedConvert(halObject));
const auto maybeVersion = validate(canonical);
if (!maybeVersion.has_value()) {
return error() << maybeVersion.error();
}
const auto version = maybeVersion.value();
if (version > kVersion) {
return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
}
return canonical;
}
template <typename Type>
GeneralResult<std::vector<UnvalidatedConvertOutput<Type>>> validatedConvert(
const std::vector<Type>& arguments) {
std::vector<UnvalidatedConvertOutput<Type>> canonical;
canonical.reserve(arguments.size());
for (const auto& argument : arguments) {
canonical.push_back(NN_TRY(validatedConvert(argument)));
}
return canonical;
}
} // anonymous namespace
GeneralResult<OperandType> unvalidatedConvert(const aidl_hal::OperandType& operandType) {
VERIFY_NON_NEGATIVE(underlyingType(operandType)) << "Negative operand types are not allowed.";
return static_cast<OperandType>(operandType);
}
GeneralResult<OperationType> unvalidatedConvert(const aidl_hal::OperationType& operationType) {
VERIFY_NON_NEGATIVE(underlyingType(operationType))
<< "Negative operation types are not allowed.";
return static_cast<OperationType>(operationType);
}
GeneralResult<DeviceType> unvalidatedConvert(const aidl_hal::DeviceType& deviceType) {
return static_cast<DeviceType>(deviceType);
}
GeneralResult<Priority> unvalidatedConvert(const aidl_hal::Priority& priority) {
return static_cast<Priority>(priority);
}
GeneralResult<Capabilities> unvalidatedConvert(const aidl_hal::Capabilities& capabilities) {
const bool validOperandTypes = std::all_of(
capabilities.operandPerformance.begin(), capabilities.operandPerformance.end(),
[](const aidl_hal::OperandPerformance& operandPerformance) {
const auto maybeType = unvalidatedConvert(operandPerformance.type);
return !maybeType.has_value() ? false : validOperandType(maybeType.value());
});
if (!validOperandTypes) {
return NN_ERROR() << "Invalid OperandType when unvalidatedConverting OperandPerformance in "
"Capabilities";
}
auto operandPerformance = NN_TRY(unvalidatedConvert(capabilities.operandPerformance));
auto table = NN_TRY(hal::utils::makeGeneralFailure(
Capabilities::OperandPerformanceTable::create(std::move(operandPerformance)),
nn::ErrorStatus::GENERAL_FAILURE));
return Capabilities{
.relaxedFloat32toFloat16PerformanceScalar = NN_TRY(
unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceScalar)),
.relaxedFloat32toFloat16PerformanceTensor = NN_TRY(
unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceTensor)),
.operandPerformance = std::move(table),
.ifPerformance = NN_TRY(unvalidatedConvert(capabilities.ifPerformance)),
.whilePerformance = NN_TRY(unvalidatedConvert(capabilities.whilePerformance)),
};
}
GeneralResult<Capabilities::OperandPerformance> unvalidatedConvert(
const aidl_hal::OperandPerformance& operandPerformance) {
return Capabilities::OperandPerformance{
.type = NN_TRY(unvalidatedConvert(operandPerformance.type)),
.info = NN_TRY(unvalidatedConvert(operandPerformance.info)),
};
}
GeneralResult<Capabilities::PerformanceInfo> unvalidatedConvert(
const aidl_hal::PerformanceInfo& performanceInfo) {
return Capabilities::PerformanceInfo{
.execTime = performanceInfo.execTime,
.powerUsage = performanceInfo.powerUsage,
};
}
GeneralResult<DataLocation> unvalidatedConvert(const aidl_hal::DataLocation& location) {
VERIFY_NON_NEGATIVE(location.poolIndex) << "DataLocation: pool index must not be negative";
VERIFY_NON_NEGATIVE(location.offset) << "DataLocation: offset must not be negative";
VERIFY_NON_NEGATIVE(location.length) << "DataLocation: length must not be negative";
if (location.offset > std::numeric_limits<uint32_t>::max()) {
return NN_ERROR() << "DataLocation: offset must be <= std::numeric_limits<uint32_t>::max()";
}
if (location.length > std::numeric_limits<uint32_t>::max()) {
return NN_ERROR() << "DataLocation: length must be <= std::numeric_limits<uint32_t>::max()";
}
return DataLocation{
.poolIndex = static_cast<uint32_t>(location.poolIndex),
.offset = static_cast<uint32_t>(location.offset),
.length = static_cast<uint32_t>(location.length),
};
}
GeneralResult<Operation> unvalidatedConvert(const aidl_hal::Operation& operation) {
return Operation{
.type = NN_TRY(unvalidatedConvert(operation.type)),
.inputs = NN_TRY(toUnsigned(operation.inputs)),
.outputs = NN_TRY(toUnsigned(operation.outputs)),
};
}
GeneralResult<Operand::LifeTime> unvalidatedConvert(
const aidl_hal::OperandLifeTime& operandLifeTime) {
return static_cast<Operand::LifeTime>(operandLifeTime);
}
GeneralResult<Operand> unvalidatedConvert(const aidl_hal::Operand& operand) {
return Operand{
.type = NN_TRY(unvalidatedConvert(operand.type)),
.dimensions = NN_TRY(toUnsigned(operand.dimensions)),
.scale = operand.scale,
.zeroPoint = operand.zeroPoint,
.lifetime = NN_TRY(unvalidatedConvert(operand.lifetime)),
.location = NN_TRY(unvalidatedConvert(operand.location)),
.extraParams = NN_TRY(unvalidatedConvert(operand.extraParams)),
};
}
GeneralResult<Operand::ExtraParams> unvalidatedConvert(
const std::optional<aidl_hal::OperandExtraParams>& optionalExtraParams) {
if (!optionalExtraParams.has_value()) {
return Operand::NoParams{};
}
const auto& extraParams = optionalExtraParams.value();
using Tag = aidl_hal::OperandExtraParams::Tag;
switch (extraParams.getTag()) {
case Tag::channelQuant:
return unvalidatedConvert(extraParams.get<Tag::channelQuant>());
case Tag::extension:
return extraParams.get<Tag::extension>();
}
return NN_ERROR() << "Unrecognized Operand::ExtraParams tag: "
<< underlyingType(extraParams.getTag());
}
GeneralResult<Operand::SymmPerChannelQuantParams> unvalidatedConvert(
const aidl_hal::SymmPerChannelQuantParams& symmPerChannelQuantParams) {
VERIFY_NON_NEGATIVE(symmPerChannelQuantParams.channelDim)
<< "Per-channel quantization channel dimension must not be negative.";
return Operand::SymmPerChannelQuantParams{
.scales = symmPerChannelQuantParams.scales,
.channelDim = static_cast<uint32_t>(symmPerChannelQuantParams.channelDim),
};
}
GeneralResult<Model> unvalidatedConvert(const aidl_hal::Model& model) {
return Model{
.main = NN_TRY(unvalidatedConvert(model.main)),
.referenced = NN_TRY(unvalidatedConvert(model.referenced)),
.operandValues = NN_TRY(unvalidatedConvert(model.operandValues)),
.pools = NN_TRY(unvalidatedConvert(model.pools)),
.relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16,
.extensionNameToPrefix = NN_TRY(unvalidatedConvert(model.extensionNameToPrefix)),
};
}
GeneralResult<Model::Subgraph> unvalidatedConvert(const aidl_hal::Subgraph& subgraph) {
return Model::Subgraph{
.operands = NN_TRY(unvalidatedConvert(subgraph.operands)),
.operations = NN_TRY(unvalidatedConvert(subgraph.operations)),
.inputIndexes = NN_TRY(toUnsigned(subgraph.inputIndexes)),
.outputIndexes = NN_TRY(toUnsigned(subgraph.outputIndexes)),
};
}
GeneralResult<Model::ExtensionNameAndPrefix> unvalidatedConvert(
const aidl_hal::ExtensionNameAndPrefix& extensionNameAndPrefix) {
return Model::ExtensionNameAndPrefix{
.name = extensionNameAndPrefix.name,
.prefix = extensionNameAndPrefix.prefix,
};
}
GeneralResult<Extension> unvalidatedConvert(const aidl_hal::Extension& extension) {
return Extension{
.name = extension.name,
.operandTypes = NN_TRY(unvalidatedConvert(extension.operandTypes)),
};
}
GeneralResult<Extension::OperandTypeInformation> unvalidatedConvert(
const aidl_hal::ExtensionOperandTypeInformation& operandTypeInformation) {
VERIFY_NON_NEGATIVE(operandTypeInformation.byteSize)
<< "Extension operand type byte size must not be negative";
return Extension::OperandTypeInformation{
.type = operandTypeInformation.type,
.isTensor = operandTypeInformation.isTensor,
.byteSize = static_cast<uint32_t>(operandTypeInformation.byteSize),
};
}
GeneralResult<OutputShape> unvalidatedConvert(const aidl_hal::OutputShape& outputShape) {
return OutputShape{
.dimensions = NN_TRY(toUnsigned(outputShape.dimensions)),
.isSufficient = outputShape.isSufficient,
};
}
GeneralResult<MeasureTiming> unvalidatedConvert(bool measureTiming) {
return measureTiming ? MeasureTiming::YES : MeasureTiming::NO;
}
GeneralResult<Memory> unvalidatedConvert(const aidl_hal::Memory& memory) {
VERIFY_NON_NEGATIVE(memory.size) << "Memory size must not be negative";
return Memory{
.handle = NN_TRY(unvalidatedConvert(memory.handle)),
.size = static_cast<uint32_t>(memory.size),
.name = memory.name,
};
}
GeneralResult<Model::OperandValues> unvalidatedConvert(const std::vector<uint8_t>& operandValues) {
return Model::OperandValues(operandValues.data(), operandValues.size());
}
GeneralResult<BufferDesc> unvalidatedConvert(const aidl_hal::BufferDesc& bufferDesc) {
return BufferDesc{.dimensions = NN_TRY(toUnsigned(bufferDesc.dimensions))};
}
GeneralResult<BufferRole> unvalidatedConvert(const aidl_hal::BufferRole& bufferRole) {
VERIFY_NON_NEGATIVE(bufferRole.modelIndex) << "BufferRole: modelIndex must not be negative";
VERIFY_NON_NEGATIVE(bufferRole.ioIndex) << "BufferRole: ioIndex must not be negative";
return BufferRole{
.modelIndex = static_cast<uint32_t>(bufferRole.modelIndex),
.ioIndex = static_cast<uint32_t>(bufferRole.ioIndex),
.frequency = bufferRole.frequency,
};
}
GeneralResult<Request> unvalidatedConvert(const aidl_hal::Request& request) {
return Request{
.inputs = NN_TRY(unvalidatedConvert(request.inputs)),
.outputs = NN_TRY(unvalidatedConvert(request.outputs)),
.pools = NN_TRY(unvalidatedConvert(request.pools)),
};
}
GeneralResult<Request::Argument> unvalidatedConvert(const aidl_hal::RequestArgument& argument) {
const auto lifetime = argument.hasNoValue ? Request::Argument::LifeTime::NO_VALUE
: Request::Argument::LifeTime::POOL;
return Request::Argument{
.lifetime = lifetime,
.location = NN_TRY(unvalidatedConvert(argument.location)),
.dimensions = NN_TRY(toUnsigned(argument.dimensions)),
};
}
GeneralResult<Request::MemoryPool> unvalidatedConvert(
const aidl_hal::RequestMemoryPool& memoryPool) {
using Tag = aidl_hal::RequestMemoryPool::Tag;
switch (memoryPool.getTag()) {
case Tag::pool:
return unvalidatedConvert(memoryPool.get<Tag::pool>());
case Tag::token: {
const auto token = memoryPool.get<Tag::token>();
VERIFY_NON_NEGATIVE(token) << "Memory pool token must not be negative";
return static_cast<Request::MemoryDomainToken>(token);
}
}
return NN_ERROR() << "Invalid Request::MemoryPool tag " << underlyingType(memoryPool.getTag());
}
GeneralResult<ErrorStatus> unvalidatedConvert(const aidl_hal::ErrorStatus& status) {
switch (status) {
case aidl_hal::ErrorStatus::NONE:
case aidl_hal::ErrorStatus::DEVICE_UNAVAILABLE:
case aidl_hal::ErrorStatus::GENERAL_FAILURE:
case aidl_hal::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
case aidl_hal::ErrorStatus::INVALID_ARGUMENT:
case aidl_hal::ErrorStatus::MISSED_DEADLINE_TRANSIENT:
case aidl_hal::ErrorStatus::MISSED_DEADLINE_PERSISTENT:
case aidl_hal::ErrorStatus::RESOURCE_EXHAUSTED_TRANSIENT:
case aidl_hal::ErrorStatus::RESOURCE_EXHAUSTED_PERSISTENT:
return static_cast<ErrorStatus>(status);
}
return NN_ERROR() << "Invalid ErrorStatus " << underlyingType(status);
}
GeneralResult<ExecutionPreference> unvalidatedConvert(
const aidl_hal::ExecutionPreference& executionPreference) {
return static_cast<ExecutionPreference>(executionPreference);
}
GeneralResult<SharedHandle> unvalidatedConvert(
const ::aidl::android::hardware::common::NativeHandle& aidlNativeHandle) {
std::vector<base::unique_fd> fds;
fds.reserve(aidlNativeHandle.fds.size());
for (const auto& fd : aidlNativeHandle.fds) {
int dupFd = dup(fd.get());
if (dupFd == -1) {
// TODO(b/120417090): is ANEURALNETWORKS_UNEXPECTED_NULL the correct error to return
// here?
return NN_ERROR() << "Failed to dup the fd";
}
fds.emplace_back(dupFd);
}
return std::make_shared<const Handle>(Handle{
.fds = std::move(fds),
.ints = aidlNativeHandle.ints,
});
}
GeneralResult<ExecutionPreference> convert(
const aidl_hal::ExecutionPreference& executionPreference) {
return validatedConvert(executionPreference);
}
GeneralResult<Memory> convert(const aidl_hal::Memory& operand) {
return validatedConvert(operand);
}
GeneralResult<Model> convert(const aidl_hal::Model& model) {
return validatedConvert(model);
}
GeneralResult<Operand> convert(const aidl_hal::Operand& operand) {
return unvalidatedConvert(operand);
}
GeneralResult<OperandType> convert(const aidl_hal::OperandType& operandType) {
return unvalidatedConvert(operandType);
}
GeneralResult<Priority> convert(const aidl_hal::Priority& priority) {
return validatedConvert(priority);
}
GeneralResult<Request::MemoryPool> convert(const aidl_hal::RequestMemoryPool& memoryPool) {
return unvalidatedConvert(memoryPool);
}
GeneralResult<Request> convert(const aidl_hal::Request& request) {
return validatedConvert(request);
}
GeneralResult<std::vector<Operation>> convert(const std::vector<aidl_hal::Operation>& operations) {
return unvalidatedConvert(operations);
}
GeneralResult<std::vector<Memory>> convert(const std::vector<aidl_hal::Memory>& memories) {
return validatedConvert(memories);
}
GeneralResult<std::vector<uint32_t>> toUnsigned(const std::vector<int32_t>& vec) {
if (!std::all_of(vec.begin(), vec.end(), [](int32_t v) { return v >= 0; })) {
return NN_ERROR() << "Negative value passed to conversion from signed to unsigned";
}
return std::vector<uint32_t>(vec.begin(), vec.end());
}
} // namespace android::nn
namespace aidl::android::hardware::neuralnetworks::utils {
namespace {
template <typename Input>
using UnvalidatedConvertOutput =
std::decay_t<decltype(unvalidatedConvert(std::declval<Input>()).value())>;
template <typename Type>
nn::GeneralResult<std::vector<UnvalidatedConvertOutput<Type>>> unvalidatedConvertVec(
const std::vector<Type>& arguments) {
std::vector<UnvalidatedConvertOutput<Type>> halObject(arguments.size());
for (size_t i = 0; i < arguments.size(); ++i) {
halObject[i] = NN_TRY(unvalidatedConvert(arguments[i]));
}
return halObject;
}
template <typename Type>
nn::GeneralResult<UnvalidatedConvertOutput<Type>> validatedConvert(const Type& canonical) {
const auto maybeVersion = nn::validate(canonical);
if (!maybeVersion.has_value()) {
return nn::error() << maybeVersion.error();
}
const auto version = maybeVersion.value();
if (version > kVersion) {
return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
}
return utils::unvalidatedConvert(canonical);
}
template <typename Type>
nn::GeneralResult<std::vector<UnvalidatedConvertOutput<Type>>> validatedConvert(
const std::vector<Type>& arguments) {
std::vector<UnvalidatedConvertOutput<Type>> halObject(arguments.size());
for (size_t i = 0; i < arguments.size(); ++i) {
halObject[i] = NN_TRY(validatedConvert(arguments[i]));
}
return halObject;
}
} // namespace
nn::GeneralResult<common::NativeHandle> unvalidatedConvert(const nn::SharedHandle& sharedHandle) {
common::NativeHandle aidlNativeHandle;
aidlNativeHandle.fds.reserve(sharedHandle->fds.size());
for (const auto& fd : sharedHandle->fds) {
int dupFd = dup(fd.get());
if (dupFd == -1) {
// TODO(b/120417090): is ANEURALNETWORKS_UNEXPECTED_NULL the correct error to return
// here?
return NN_ERROR() << "Failed to dup the fd";
}
aidlNativeHandle.fds.emplace_back(dupFd);
}
aidlNativeHandle.ints = sharedHandle->ints;
return aidlNativeHandle;
}
nn::GeneralResult<Memory> unvalidatedConvert(const nn::Memory& memory) {
if (memory.size > std::numeric_limits<int64_t>::max()) {
return NN_ERROR() << "Memory size doesn't fit into int64_t.";
}
return Memory{
.handle = NN_TRY(unvalidatedConvert(memory.handle)),
.size = static_cast<int64_t>(memory.size),
.name = memory.name,
};
}
nn::GeneralResult<ErrorStatus> unvalidatedConvert(const nn::ErrorStatus& errorStatus) {
switch (errorStatus) {
case nn::ErrorStatus::NONE:
case nn::ErrorStatus::DEVICE_UNAVAILABLE:
case nn::ErrorStatus::GENERAL_FAILURE:
case nn::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
case nn::ErrorStatus::INVALID_ARGUMENT:
case nn::ErrorStatus::MISSED_DEADLINE_TRANSIENT:
case nn::ErrorStatus::MISSED_DEADLINE_PERSISTENT:
case nn::ErrorStatus::RESOURCE_EXHAUSTED_TRANSIENT:
case nn::ErrorStatus::RESOURCE_EXHAUSTED_PERSISTENT:
return static_cast<ErrorStatus>(errorStatus);
default:
return ErrorStatus::GENERAL_FAILURE;
}
}
nn::GeneralResult<OutputShape> unvalidatedConvert(const nn::OutputShape& outputShape) {
return OutputShape{.dimensions = NN_TRY(toSigned(outputShape.dimensions)),
.isSufficient = outputShape.isSufficient};
}
nn::GeneralResult<Memory> convert(const nn::Memory& memory) {
return validatedConvert(memory);
}
nn::GeneralResult<ErrorStatus> convert(const nn::ErrorStatus& errorStatus) {
return validatedConvert(errorStatus);
}
nn::GeneralResult<std::vector<OutputShape>> convert(
const std::vector<nn::OutputShape>& outputShapes) {
return validatedConvert(outputShapes);
}
nn::GeneralResult<std::vector<int32_t>> toSigned(const std::vector<uint32_t>& vec) {
if (!std::all_of(vec.begin(), vec.end(),
[](uint32_t v) { return v <= std::numeric_limits<int32_t>::max(); })) {
return NN_ERROR() << "Vector contains a value that doesn't fit into int32_t.";
}
return std::vector<int32_t>(vec.begin(), vec.end());
}
} // namespace aidl::android::hardware::neuralnetworks::utils

View File

@@ -0,0 +1,95 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "Utils.h"
#include <nnapi/Result.h>
namespace aidl::android::hardware::neuralnetworks::utils {
namespace {
using ::android::nn::GeneralResult;
template <typename Type>
nn::GeneralResult<std::vector<Type>> cloneVec(const std::vector<Type>& arguments) {
std::vector<Type> clonedObjects;
clonedObjects.reserve(arguments.size());
for (const auto& argument : arguments) {
clonedObjects.push_back(NN_TRY(clone(argument)));
}
return clonedObjects;
}
template <typename Type>
GeneralResult<std::vector<Type>> clone(const std::vector<Type>& arguments) {
return cloneVec(arguments);
}
} // namespace
GeneralResult<Memory> clone(const Memory& memory) {
common::NativeHandle nativeHandle;
nativeHandle.ints = memory.handle.ints;
nativeHandle.fds.reserve(memory.handle.fds.size());
for (const auto& fd : memory.handle.fds) {
const int newFd = dup(fd.get());
if (newFd < 0) {
return NN_ERROR() << "Couldn't dup a file descriptor";
}
nativeHandle.fds.emplace_back(newFd);
}
return Memory{
.handle = std::move(nativeHandle),
.size = memory.size,
.name = memory.name,
};
}
GeneralResult<RequestMemoryPool> clone(const RequestMemoryPool& requestPool) {
using Tag = RequestMemoryPool::Tag;
switch (requestPool.getTag()) {
case Tag::pool:
return RequestMemoryPool::make<Tag::pool>(NN_TRY(clone(requestPool.get<Tag::pool>())));
case Tag::token:
return RequestMemoryPool::make<Tag::token>(requestPool.get<Tag::token>());
}
// Using explicit type conversion because std::variant inside the RequestMemoryPool confuses the
// compiler.
return (NN_ERROR() << "Unrecognized request pool tag: " << requestPool.getTag())
.
operator GeneralResult<RequestMemoryPool>();
}
GeneralResult<Request> clone(const Request& request) {
return Request{
.inputs = request.inputs,
.outputs = request.outputs,
.pools = NN_TRY(clone(request.pools)),
};
}
GeneralResult<Model> clone(const Model& model) {
return Model{
.main = model.main,
.referenced = model.referenced,
.operandValues = model.operandValues,
.pools = NN_TRY(clone(model.pools)),
.relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16,
.extensionNameToPrefix = model.extensionNameToPrefix,
};
}
} // namespace aidl::android::hardware::neuralnetworks::utils

View File

@@ -0,0 +1,12 @@
# Neuralnetworks team
butlermichael@google.com
dgross@google.com
jeanluc@google.com
levp@google.com
miaowang@google.com
mikie@google.com
mks@google.com
pszczepaniak@google.com
slavash@google.com
vddang@google.com
xusongw@google.com

View File

@@ -0,0 +1,68 @@
//
// Copyright (C) 2021 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
cc_test {
name: "VtsHalNeuralnetworksTargetTest",
defaults: [
"neuralnetworks_vts_functional_defaults",
"use_libaidlvintf_gtest_helper_static",
],
srcs: [
"BasicTests.cpp",
"Callbacks.cpp",
"CompilationCachingTests.cpp",
"GeneratedTestHarness.cpp",
"MemoryDomainTests.cpp",
"QualityOfServiceTests.cpp",
"TestAssertions.cpp",
"TestMain.cpp",
"Utils.cpp",
"ValidateModel.cpp",
"ValidateRequest.cpp",
"VtsHalNeuralnetworks.cpp",
],
shared_libs: [
"libbinder_ndk",
"libnativewindow",
"libvndksupport",
],
static_libs: [
"android.hardware.common-V2-ndk_platform",
"android.hardware.neuralnetworks-V1-ndk_platform",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
"libgmock",
"libhidlmemory",
"libneuralnetworks_generated_test_harness",
"libneuralnetworks_utils",
"libsync",
"neuralnetworks_utils_hal_aidl",
],
whole_static_libs: [
"neuralnetworks_generated_V1_0_example",
"neuralnetworks_generated_V1_1_example",
"neuralnetworks_generated_V1_2_example",
"neuralnetworks_generated_V1_3_example",
],
header_libs: [
"libbase_headers",
"libneuralnetworks_headers",
],
test_suites: [
"general-tests",
"vts",
],
}

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2020 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<configuration description="Runs VtsHalNeuralnetworksTargetTest.">
<option name="test-suite-tag" value="apct" />
<option name="test-suite-tag" value="apct-native" />
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
<option name="cleanup" value="true" />
<option name="push" value="VtsHalNeuralnetworksTargetTest->/data/local/tmp/VtsHalNeuralnetworksTargetTest" />
</target_preparer>
<test class="com.android.tradefed.testtype.GTest" >
<option name="native-test-device-path" value="/data/local/tmp" />
<option name="module-name" value="VtsHalNeuralnetworksTargetTest" />
<option name="native-test-timeout" value="20m" />
</test>
</configuration>

View File

@@ -0,0 +1,193 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "neuralnetworks_aidl_hal_test"
#include <aidl/android/hardware/neuralnetworks/Capabilities.h>
#include <aidl/android/hardware/neuralnetworks/IDevice.h>
#include <aidl/android/hardware/neuralnetworks/Operand.h>
#include <aidl/android/hardware/neuralnetworks/OperandType.h>
#include <aidl/android/hardware/neuralnetworks/Priority.h>
#include <android/binder_interface_utils.h>
#include "Utils.h"
#include "VtsHalNeuralnetworks.h"
namespace aidl::android::hardware::neuralnetworks::vts::functional {
using implementation::PreparedModelCallback;
// create device test
TEST_P(NeuralNetworksAidlTest, CreateDevice) {}
// initialization
TEST_P(NeuralNetworksAidlTest, GetCapabilitiesTest) {
Capabilities capabilities;
const auto retStatus = kDevice->getCapabilities(&capabilities);
ASSERT_TRUE(retStatus.isOk());
auto isPositive = [](const PerformanceInfo& perf) {
return perf.execTime > 0.0f && perf.powerUsage > 0.0f;
};
EXPECT_TRUE(isPositive(capabilities.relaxedFloat32toFloat16PerformanceScalar));
EXPECT_TRUE(isPositive(capabilities.relaxedFloat32toFloat16PerformanceTensor));
const auto& opPerf = capabilities.operandPerformance;
EXPECT_TRUE(
std::all_of(opPerf.begin(), opPerf.end(),
[isPositive](const OperandPerformance& a) { return isPositive(a.info); }));
EXPECT_TRUE(std::is_sorted(opPerf.begin(), opPerf.end(),
[](const OperandPerformance& a, const OperandPerformance& b) {
return a.type < b.type;
}));
EXPECT_TRUE(std::all_of(opPerf.begin(), opPerf.end(), [](const OperandPerformance& a) {
return a.type != OperandType::SUBGRAPH;
}));
EXPECT_TRUE(isPositive(capabilities.ifPerformance));
EXPECT_TRUE(isPositive(capabilities.whilePerformance));
}
// detect cycle
TEST_P(NeuralNetworksAidlTest, CycleTest) {
// opnd0 = TENSOR_FLOAT32 // model input
// opnd1 = TENSOR_FLOAT32 // model input
// opnd2 = INT32 // model input
// opnd3 = ADD(opnd0, opnd4, opnd2)
// opnd4 = ADD(opnd1, opnd3, opnd2)
// opnd5 = ADD(opnd4, opnd0, opnd2) // model output
//
// +-----+
// | |
// v |
// 3 = ADD(0, 4, 2) |
// | |
// +----------+ |
// | |
// v |
// 4 = ADD(1, 3, 2) |
// | |
// +----------------+
// |
// |
// +-------+
// |
// v
// 5 = ADD(4, 0, 2)
const std::vector<Operand> operands = {
{
// operands[0]
.type = OperandType::TENSOR_FLOAT32,
.dimensions = {1},
.scale = 0.0f,
.zeroPoint = 0,
.lifetime = OperandLifeTime::SUBGRAPH_INPUT,
.location = {.poolIndex = 0, .offset = 0, .length = 0},
},
{
// operands[1]
.type = OperandType::TENSOR_FLOAT32,
.dimensions = {1},
.scale = 0.0f,
.zeroPoint = 0,
.lifetime = OperandLifeTime::SUBGRAPH_INPUT,
.location = {.poolIndex = 0, .offset = 0, .length = 0},
},
{
// operands[2]
.type = OperandType::INT32,
.dimensions = {},
.scale = 0.0f,
.zeroPoint = 0,
.lifetime = OperandLifeTime::SUBGRAPH_INPUT,
.location = {.poolIndex = 0, .offset = 0, .length = 0},
},
{
// operands[3]
.type = OperandType::TENSOR_FLOAT32,
.dimensions = {1},
.scale = 0.0f,
.zeroPoint = 0,
.lifetime = OperandLifeTime::TEMPORARY_VARIABLE,
.location = {.poolIndex = 0, .offset = 0, .length = 0},
},
{
// operands[4]
.type = OperandType::TENSOR_FLOAT32,
.dimensions = {1},
.scale = 0.0f,
.zeroPoint = 0,
.lifetime = OperandLifeTime::TEMPORARY_VARIABLE,
.location = {.poolIndex = 0, .offset = 0, .length = 0},
},
{
// operands[5]
.type = OperandType::TENSOR_FLOAT32,
.dimensions = {1},
.scale = 0.0f,
.zeroPoint = 0,
.lifetime = OperandLifeTime::SUBGRAPH_OUTPUT,
.location = {.poolIndex = 0, .offset = 0, .length = 0},
},
};
const std::vector<Operation> operations = {
{.type = OperationType::ADD, .inputs = {0, 4, 2}, .outputs = {3}},
{.type = OperationType::ADD, .inputs = {1, 3, 2}, .outputs = {4}},
{.type = OperationType::ADD, .inputs = {4, 0, 2}, .outputs = {5}},
};
Subgraph subgraph = {
.operands = operands,
.operations = operations,
.inputIndexes = {0, 1, 2},
.outputIndexes = {5},
};
const Model model = {
.main = std::move(subgraph),
.referenced = {},
.operandValues = {},
.pools = {},
};
// ensure that getSupportedOperations() checks model validity
std::vector<bool> supportedOps;
const auto supportedOpsStatus = kDevice->getSupportedOperations(model, &supportedOps);
ASSERT_FALSE(supportedOpsStatus.isOk());
ASSERT_EQ(supportedOpsStatus.getExceptionCode(), EX_SERVICE_SPECIFIC);
ASSERT_EQ(static_cast<ErrorStatus>(supportedOpsStatus.getServiceSpecificError()),
ErrorStatus::INVALID_ARGUMENT);
// ensure that prepareModel() checks model validity
auto preparedModelCallback = ndk::SharedRefBase::make<PreparedModelCallback>();
auto prepareLaunchStatus =
kDevice->prepareModel(model, ExecutionPreference::FAST_SINGLE_ANSWER, kDefaultPriority,
kNoDeadline, {}, {}, kEmptyCacheToken, preparedModelCallback);
// Note that preparation can fail for reasons other than an
// invalid model (invalid model should result in
// INVALID_ARGUMENT) -- for example, perhaps not all
// operations are supported, or perhaps the device hit some
// kind of capacity limit.
ASSERT_FALSE(prepareLaunchStatus.isOk());
EXPECT_EQ(prepareLaunchStatus.getExceptionCode(), EX_SERVICE_SPECIFIC);
EXPECT_NE(static_cast<ErrorStatus>(prepareLaunchStatus.getServiceSpecificError()),
ErrorStatus::NONE);
EXPECT_NE(preparedModelCallback->getStatus(), ErrorStatus::NONE);
EXPECT_EQ(preparedModelCallback->getPreparedModel(), nullptr);
}
} // namespace aidl::android::hardware::neuralnetworks::vts::functional

View File

@@ -0,0 +1,59 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "Callbacks"
#include "Callbacks.h"
#include <android-base/logging.h>
#include <android/binder_auto_utils.h>
#include <limits>
namespace aidl::android::hardware::neuralnetworks::implementation {
ndk::ScopedAStatus PreparedModelCallback::notify(
ErrorStatus errorStatus, const std::shared_ptr<IPreparedModel>& preparedModel) {
{
std::lock_guard<std::mutex> hold(mMutex);
// quick-return if object has already been notified
if (mNotified) {
return ndk::ScopedAStatus::ok();
}
// store results and mark as notified
mErrorStatus = errorStatus;
mPreparedModel = preparedModel;
mNotified = true;
}
mCondition.notify_all();
return ndk::ScopedAStatus::ok();
}
void PreparedModelCallback::wait() const {
std::unique_lock<std::mutex> lock(mMutex);
mCondition.wait(lock, [this] { return mNotified; });
}
ErrorStatus PreparedModelCallback::getStatus() const {
wait();
return mErrorStatus;
}
std::shared_ptr<IPreparedModel> PreparedModelCallback::getPreparedModel() const {
wait();
return mPreparedModel;
}
} // namespace aidl::android::hardware::neuralnetworks::implementation

View File

@@ -0,0 +1,131 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_HARDWARE_NEURALNETWORKS_AIDL_CALLBACKS_H
#define ANDROID_HARDWARE_NEURALNETWORKS_AIDL_CALLBACKS_H
#include <android-base/thread_annotations.h>
#include <condition_variable>
#include <mutex>
#include <aidl/android/hardware/neuralnetworks/BnPreparedModelCallback.h>
#include <aidl/android/hardware/neuralnetworks/ErrorStatus.h>
#include <aidl/android/hardware/neuralnetworks/IPreparedModel.h>
/*
* The Callback classes are used internally by the NeuralNetworks runtime to
* synchronize between different threads. An asynchronous task is launched
* paired with a callback object. When a client thread requires the output being
* generated by the asynchronous task, the client thread can wait for the result
* and be blocked until it has completed. Any wait may safely be called
* concurrently, even on the same callback object. When the asynchronous task
* has finished its workload, it must immediately call "notify". If the
* asynchronous task has failed to launch, the function that tried to launch the
* asynchronous task must immediately call "notify". This "notify" call
* awakens any client threads waiting on the callback object.
*
* These classes exist to enable synchronization across AIDL. When
* synchronization is only required in the same process, consider using
* std::future, std::mutex, std::condition_variable, or std::experimental::latch
* instead.
*/
namespace aidl::android::hardware::neuralnetworks::implementation {
/**
* The PreparedModelCallback class is used to receive the error status of
* preparing a model as well as the prepared model from a task executing
* asynchronously with respect to the runtime. If a calling thread calls wait
* or get* on a PreparedModelCallback object and the corresponding asynchronous
* task has not finished preparing the model, the calling thread will block
* until the asynchronous task has called notify.
*
* If the callback object is notified more than once, only the results of the
* first call to notify are used, and the results from subsequent calls are
* discarded.
*
* This callback object is passed as an argument to IDevice::prepareModel*.
*/
class PreparedModelCallback : public BnPreparedModelCallback {
public:
/**
* IPreparedModelCallback::notify marks the callback object with the return
* status of the asynchronous model preparation along with the prepared
* model, and allows all prior and future wait calls on the
* PreparedModelCallback object to proceed.
*
* IPreparedModelCallback::notify must be called on a given PreparedModelCallback object.
*
* If the callback object is notified more than once, only the results of
* the first call to notify are used, and the results from subsequent calls
* are discarded.
*
* @param status Error status returned from asynchronously preparing the
* model; will be:
* - NONE if the asynchronous preparation was successful
* - DEVICE_UNAVAILABLE if driver is offline or busy
* - GENERAL_FAILURE if there is an unspecified error
* - INVALID_ARGUMENT if the input model is invalid
* @param preparedModel Returned model that has been prepared for execution,
* nullptr if the model was unable to be prepared.
*/
ndk::ScopedAStatus notify(ErrorStatus status,
const std::shared_ptr<IPreparedModel>& preparedModel) override;
/**
* PreparedModelCallback::wait blocks until notify has been called on the
* callback object.
*/
void wait() const;
/**
* Retrieves the error status returned from the asynchronous task launched
* by IDevice::prepareModel*. If IDevice::prepareModel* has not finished
* asynchronously preparing the model, this call will block until the
* asynchronous task notifies the object.
*
* @return status Error status returned from asynchronously preparing the
* model; will be:
* - NONE if the asynchronous preparation was successful
* - DEVICE_UNAVAILABLE if driver is offline or busy
* - GENERAL_FAILURE if there is an unspecified error
* - INVALID_ARGUMENT if the input model is invalid
*/
ErrorStatus getStatus() const;
/**
* Retrieves the model that has been prepared for execution from the
* asynchronous task launched by IDevice::prepareModel*. If
* IDevice::prepareModel* has not finished asynchronously preparing the
* model, this call will block until the asynchronous task notifies the
* object.
*
* @return preparedModel Returned model that has been prepared for
* execution, nullptr if the model was unable to be prepared.
*/
std::shared_ptr<IPreparedModel> getPreparedModel() const;
private:
mutable std::mutex mMutex;
mutable std::condition_variable mCondition;
bool mNotified GUARDED_BY(mMutex) = false;
ErrorStatus mErrorStatus = ErrorStatus::GENERAL_FAILURE;
std::shared_ptr<IPreparedModel> mPreparedModel;
};
} // namespace aidl::android::hardware::neuralnetworks::implementation
#endif // ANDROID_HARDWARE_NEURALNETWORKS_AIDL_CALLBACKS_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,925 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "GeneratedTestHarness.h"
#include <aidl/android/hardware/neuralnetworks/ErrorStatus.h>
#include <android-base/logging.h>
#include <android/binder_auto_utils.h>
#include <android/sync.h>
#include <gtest/gtest.h>
#include <algorithm>
#include <chrono>
#include <iostream>
#include <iterator>
#include <numeric>
#include <vector>
#include <MemoryUtils.h>
#include <android/binder_status.h>
#include <nnapi/Result.h>
#include <nnapi/SharedMemory.h>
#include <nnapi/Types.h>
#include <nnapi/hal/aidl/Conversions.h>
#include <nnapi/hal/aidl/Utils.h>
#include "Callbacks.h"
#include "TestHarness.h"
#include "Utils.h"
#include "VtsHalNeuralnetworks.h"
namespace aidl::android::hardware::neuralnetworks::vts::functional {
namespace nn = ::android::nn;
using namespace test_helper;
using implementation::PreparedModelCallback;
namespace {
enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT, MISSED_DEADLINE };
struct TestConfig {
Executor executor;
bool measureTiming;
OutputType outputType;
MemoryType memoryType;
// `reportSkipping` indicates if a test should print an info message in case
// it is skipped. The field is set to true by default and is set to false in
// quantization coupling tests to suppress skipping a test
bool reportSkipping;
TestConfig(Executor executor, bool measureTiming, OutputType outputType, MemoryType memoryType)
: executor(executor),
measureTiming(measureTiming),
outputType(outputType),
memoryType(memoryType),
reportSkipping(true) {}
TestConfig(Executor executor, bool measureTiming, OutputType outputType, MemoryType memoryType,
bool reportSkipping)
: executor(executor),
measureTiming(measureTiming),
outputType(outputType),
memoryType(memoryType),
reportSkipping(reportSkipping) {}
};
enum class IOType { INPUT, OUTPUT };
class DeviceMemoryAllocator {
public:
DeviceMemoryAllocator(const std::shared_ptr<IDevice>& device,
const std::shared_ptr<IPreparedModel>& preparedModel,
const TestModel& testModel)
: kDevice(device), kPreparedModel(preparedModel), kTestModel(testModel) {}
// Allocate device memory for a target input/output operand.
// Return {IBuffer object, token} if successful.
// Return {nullptr, 0} if device memory is not supported.
template <IOType ioType>
std::pair<std::shared_ptr<IBuffer>, int32_t> allocate(uint32_t index) {
std::pair<std::shared_ptr<IBuffer>, int32_t> buffer;
allocateInternal<ioType>(index, &buffer);
return buffer;
}
private:
template <IOType ioType>
void allocateInternal(int32_t index, std::pair<std::shared_ptr<IBuffer>, int32_t>* result) {
ASSERT_NE(result, nullptr);
// Prepare arguments.
BufferRole role = {.modelIndex = 0, .ioIndex = index, .frequency = 1.0f};
std::vector<BufferRole> inputRoles, outputRoles;
if constexpr (ioType == IOType::INPUT) {
inputRoles = {role};
} else {
outputRoles = {role};
}
// Allocate device memory.
DeviceBuffer buffer;
IPreparedModelParcel parcel;
parcel.preparedModel = kPreparedModel;
const auto ret = kDevice->allocate({}, {parcel}, inputRoles, outputRoles, &buffer);
// Check allocation results.
if (ret.isOk()) {
ASSERT_NE(buffer.buffer, nullptr);
ASSERT_GT(buffer.token, 0);
} else {
ASSERT_EQ(ret.getExceptionCode(), EX_SERVICE_SPECIFIC);
ASSERT_EQ(static_cast<ErrorStatus>(ret.getServiceSpecificError()),
ErrorStatus::GENERAL_FAILURE);
buffer.buffer = nullptr;
buffer.token = 0;
}
// Initialize input data from TestBuffer.
if constexpr (ioType == IOType::INPUT) {
if (buffer.buffer != nullptr) {
// TestBuffer -> Shared memory.
const auto& testBuffer =
kTestModel.main.operands[kTestModel.main.inputIndexes[index]].data;
ASSERT_GT(testBuffer.size(), 0);
const auto sharedMemory = nn::createSharedMemory(testBuffer.size()).value();
const auto memory = utils::convert(sharedMemory).value();
const auto mapping = nn::map(sharedMemory).value();
uint8_t* inputPtr = static_cast<uint8_t*>(std::get<void*>(mapping.pointer));
ASSERT_NE(inputPtr, nullptr);
const uint8_t* begin = testBuffer.get<uint8_t>();
const uint8_t* end = begin + testBuffer.size();
std::copy(begin, end, inputPtr);
// Shared memory -> IBuffer.
auto ret = buffer.buffer->copyFrom(memory, {});
ASSERT_TRUE(ret.isOk());
}
}
*result = {std::move(buffer.buffer), buffer.token};
}
const std::shared_ptr<IDevice> kDevice;
const std::shared_ptr<IPreparedModel> kPreparedModel;
const TestModel& kTestModel;
};
Subgraph createSubgraph(const TestSubgraph& testSubgraph, uint32_t* constCopySize,
std::vector<const TestBuffer*>* constCopies, uint32_t* constRefSize,
std::vector<const TestBuffer*>* constReferences) {
CHECK(constCopySize != nullptr);
CHECK(constCopies != nullptr);
CHECK(constRefSize != nullptr);
CHECK(constReferences != nullptr);
// Operands.
std::vector<Operand> operands(testSubgraph.operands.size());
for (uint32_t i = 0; i < testSubgraph.operands.size(); i++) {
const auto& op = testSubgraph.operands[i];
DataLocation loc = {};
if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) {
loc = {
.poolIndex = 0,
.offset = *constCopySize,
.length = static_cast<int64_t>(op.data.size()),
};
constCopies->push_back(&op.data);
*constCopySize += op.data.alignedSize();
} else if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) {
loc = {
.poolIndex = 0,
.offset = *constRefSize,
.length = static_cast<int64_t>(op.data.size()),
};
constReferences->push_back(&op.data);
*constRefSize += op.data.alignedSize();
} else if (op.lifetime == TestOperandLifeTime::SUBGRAPH) {
loc = {
.poolIndex = 0,
.offset = *op.data.get<uint32_t>(),
.length = 0,
};
}
std::optional<OperandExtraParams> extraParams;
if (op.type == TestOperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL) {
using Tag = OperandExtraParams::Tag;
extraParams = OperandExtraParams::make<Tag::channelQuant>(SymmPerChannelQuantParams{
.scales = op.channelQuant.scales,
.channelDim = static_cast<int32_t>(op.channelQuant.channelDim)});
}
operands[i] = {.type = static_cast<OperandType>(op.type),
.dimensions = utils::toSigned(op.dimensions).value(),
.scale = op.scale,
.zeroPoint = op.zeroPoint,
.lifetime = static_cast<OperandLifeTime>(op.lifetime),
.location = loc,
.extraParams = std::move(extraParams)};
}
// Operations.
std::vector<Operation> operations(testSubgraph.operations.size());
std::transform(testSubgraph.operations.begin(), testSubgraph.operations.end(),
operations.begin(), [](const TestOperation& op) -> Operation {
return {.type = static_cast<OperationType>(op.type),
.inputs = utils::toSigned(op.inputs).value(),
.outputs = utils::toSigned(op.outputs).value()};
});
return {.operands = std::move(operands),
.operations = std::move(operations),
.inputIndexes = utils::toSigned(testSubgraph.inputIndexes).value(),
.outputIndexes = utils::toSigned(testSubgraph.outputIndexes).value()};
}
void copyTestBuffers(const std::vector<const TestBuffer*>& buffers, uint8_t* output) {
uint32_t offset = 0;
for (const TestBuffer* buffer : buffers) {
const uint8_t* begin = buffer->get<uint8_t>();
const uint8_t* end = begin + buffer->size();
std::copy(begin, end, output + offset);
offset += buffer->alignedSize();
}
}
} // namespace
void waitForSyncFence(int syncFd) {
constexpr int kInfiniteTimeout = -1;
ASSERT_GT(syncFd, 0);
int r = sync_wait(syncFd, kInfiniteTimeout);
ASSERT_GE(r, 0);
}
Model createModel(const TestModel& testModel) {
uint32_t constCopySize = 0;
uint32_t constRefSize = 0;
std::vector<const TestBuffer*> constCopies;
std::vector<const TestBuffer*> constReferences;
Subgraph mainSubgraph = createSubgraph(testModel.main, &constCopySize, &constCopies,
&constRefSize, &constReferences);
std::vector<Subgraph> refSubgraphs(testModel.referenced.size());
std::transform(testModel.referenced.begin(), testModel.referenced.end(), refSubgraphs.begin(),
[&constCopySize, &constCopies, &constRefSize,
&constReferences](const TestSubgraph& testSubgraph) {
return createSubgraph(testSubgraph, &constCopySize, &constCopies,
&constRefSize, &constReferences);
});
// Constant copies.
std::vector<uint8_t> operandValues(constCopySize);
copyTestBuffers(constCopies, operandValues.data());
// Shared memory.
std::vector<nn::Memory> pools = {};
if (constRefSize > 0) {
const auto pool = nn::createSharedMemory(constRefSize).value();
pools.push_back(pool);
// load data
const auto mappedMemory = nn::map(pool).value();
uint8_t* mappedPtr = static_cast<uint8_t*>(std::get<void*>(mappedMemory.pointer));
CHECK(mappedPtr != nullptr);
copyTestBuffers(constReferences, mappedPtr);
}
std::vector<Memory> aidlPools;
aidlPools.reserve(pools.size());
for (auto& pool : pools) {
auto aidlPool = utils::convert(pool).value();
aidlPools.push_back(std::move(aidlPool));
}
return {.main = std::move(mainSubgraph),
.referenced = std::move(refSubgraphs),
.operandValues = std::move(operandValues),
.pools = std::move(aidlPools),
.relaxComputationFloat32toFloat16 = testModel.isRelaxed};
}
static bool isOutputSizeGreaterThanOne(const TestModel& testModel, uint32_t index) {
const auto byteSize = testModel.main.operands[testModel.main.outputIndexes[index]].data.size();
return byteSize > 1u;
}
static void makeOutputInsufficientSize(uint32_t outputIndex, Request* request) {
auto& length = request->outputs[outputIndex].location.length;
ASSERT_GT(length, 1u);
length -= 1u;
}
static void makeOutputDimensionsUnspecified(Model* model) {
for (auto i : model->main.outputIndexes) {
auto& dims = model->main.operands[i].dimensions;
std::fill(dims.begin(), dims.end(), 0);
}
}
// Manages the lifetime of memory resources used in an execution.
class ExecutionContext {
public:
ExecutionContext(std::shared_ptr<IDevice> device, std::shared_ptr<IPreparedModel> preparedModel)
: kDevice(std::move(device)), kPreparedModel(std::move(preparedModel)) {}
std::optional<Request> createRequest(const TestModel& testModel, MemoryType memoryType);
std::vector<TestBuffer> getOutputBuffers(const TestModel& testModel,
const Request& request) const;
private:
// Get a TestBuffer with data copied from an IBuffer object.
void getBuffer(const std::shared_ptr<IBuffer>& buffer, size_t size,
TestBuffer* testBuffer) const;
static constexpr uint32_t kInputPoolIndex = 0;
static constexpr uint32_t kOutputPoolIndex = 1;
static constexpr uint32_t kDeviceMemoryBeginIndex = 2;
const std::shared_ptr<IDevice> kDevice;
const std::shared_ptr<IPreparedModel> kPreparedModel;
std::unique_ptr<TestMemoryBase> mInputMemory, mOutputMemory;
std::vector<std::shared_ptr<IBuffer>> mBuffers;
};
std::optional<Request> ExecutionContext::createRequest(const TestModel& testModel,
MemoryType memoryType) {
// Memory pools are organized as:
// - 0: Input shared memory pool
// - 1: Output shared memory pool
// - [2, 2+i): Input device memories
// - [2+i, 2+i+o): Output device memories
DeviceMemoryAllocator allocator(kDevice, kPreparedModel, testModel);
std::vector<int32_t> tokens;
mBuffers.clear();
// Model inputs.
std::vector<RequestArgument> inputs(testModel.main.inputIndexes.size());
size_t inputSize = 0;
for (uint32_t i = 0; i < testModel.main.inputIndexes.size(); i++) {
const auto& op = testModel.main.operands[testModel.main.inputIndexes[i]];
if (op.data.size() == 0) {
// Omitted input.
inputs[i] = {.hasNoValue = true};
continue;
} else if (memoryType == MemoryType::DEVICE) {
SCOPED_TRACE("Input index = " + std::to_string(i));
auto [buffer, token] = allocator.allocate<IOType::INPUT>(i);
if (buffer != nullptr) {
DataLocation loc = {.poolIndex = static_cast<int32_t>(mBuffers.size() +
kDeviceMemoryBeginIndex)};
mBuffers.push_back(std::move(buffer));
tokens.push_back(token);
inputs[i] = {.hasNoValue = false, .location = loc, .dimensions = {}};
continue;
}
}
// Reserve shared memory for input.
DataLocation loc = {.poolIndex = kInputPoolIndex,
.offset = static_cast<int64_t>(inputSize),
.length = static_cast<int64_t>(op.data.size())};
inputSize += op.data.alignedSize();
inputs[i] = {.hasNoValue = false, .location = loc, .dimensions = {}};
}
// Model outputs.
std::vector<RequestArgument> outputs(testModel.main.outputIndexes.size());
size_t outputSize = 0;
for (uint32_t i = 0; i < testModel.main.outputIndexes.size(); i++) {
const auto& op = testModel.main.operands[testModel.main.outputIndexes[i]];
if (memoryType == MemoryType::DEVICE) {
SCOPED_TRACE("Output index = " + std::to_string(i));
auto [buffer, token] = allocator.allocate<IOType::OUTPUT>(i);
if (buffer != nullptr) {
DataLocation loc = {.poolIndex = static_cast<int32_t>(mBuffers.size() +
kDeviceMemoryBeginIndex)};
mBuffers.push_back(std::move(buffer));
tokens.push_back(token);
outputs[i] = {.hasNoValue = false, .location = loc, .dimensions = {}};
continue;
}
}
// In the case of zero-sized output, we should at least provide a one-byte buffer.
// This is because zero-sized tensors are only supported internally to the driver, or
// reported in output shapes. It is illegal for the client to pre-specify a zero-sized
// tensor as model output. Otherwise, we will have two semantic conflicts:
// - "Zero dimension" conflicts with "unspecified dimension".
// - "Omitted operand buffer" conflicts with "zero-sized operand buffer".
size_t bufferSize = std::max<size_t>(op.data.size(), 1);
// Reserve shared memory for output.
DataLocation loc = {.poolIndex = kOutputPoolIndex,
.offset = static_cast<int64_t>(outputSize),
.length = static_cast<int64_t>(bufferSize)};
outputSize += op.data.size() == 0 ? TestBuffer::kAlignment : op.data.alignedSize();
outputs[i] = {.hasNoValue = false, .location = loc, .dimensions = {}};
}
if (memoryType == MemoryType::DEVICE && mBuffers.empty()) {
return std::nullopt;
}
// Memory pools.
if (memoryType == MemoryType::BLOB_AHWB) {
mInputMemory = TestBlobAHWB::create(std::max<size_t>(inputSize, 1));
mOutputMemory = TestBlobAHWB::create(std::max<size_t>(outputSize, 1));
} else {
mInputMemory = TestAshmem::create(std::max<size_t>(inputSize, 1));
mOutputMemory = TestAshmem::create(std::max<size_t>(outputSize, 1));
}
CHECK_NE(mInputMemory, nullptr);
CHECK_NE(mOutputMemory, nullptr);
std::vector<RequestMemoryPool> pools;
pools.reserve(kDeviceMemoryBeginIndex + mBuffers.size());
auto copiedInputMemory = utils::clone(*mInputMemory->getAidlMemory());
CHECK(copiedInputMemory.has_value()) << copiedInputMemory.error().message;
auto copiedOutputMemory = utils::clone(*mOutputMemory->getAidlMemory());
CHECK(copiedOutputMemory.has_value()) << copiedOutputMemory.error().message;
pools.push_back(RequestMemoryPool::make<RequestMemoryPool::Tag::pool>(
std::move(copiedInputMemory).value()));
pools.push_back(RequestMemoryPool::make<RequestMemoryPool::Tag::pool>(
std::move(copiedOutputMemory).value()));
for (const auto& token : tokens) {
pools.push_back(RequestMemoryPool::make<RequestMemoryPool::Tag::token>(token));
}
// Copy input data to the input shared memory pool.
uint8_t* inputPtr = mInputMemory->getPointer();
for (uint32_t i = 0; i < testModel.main.inputIndexes.size(); i++) {
if (!inputs[i].hasNoValue && inputs[i].location.poolIndex == kInputPoolIndex) {
const auto& op = testModel.main.operands[testModel.main.inputIndexes[i]];
const uint8_t* begin = op.data.get<uint8_t>();
const uint8_t* end = begin + op.data.size();
std::copy(begin, end, inputPtr + inputs[i].location.offset);
}
}
return Request{
.inputs = std::move(inputs), .outputs = std::move(outputs), .pools = std::move(pools)};
}
std::vector<TestBuffer> ExecutionContext::getOutputBuffers(const TestModel& testModel,
const Request& request) const {
// Copy out output results.
uint8_t* outputPtr = mOutputMemory->getPointer();
std::vector<TestBuffer> outputBuffers;
for (uint32_t i = 0; i < request.outputs.size(); i++) {
const auto& outputLoc = request.outputs[i].location;
if (outputLoc.poolIndex == kOutputPoolIndex) {
outputBuffers.emplace_back(outputLoc.length, outputPtr + outputLoc.offset);
} else {
const auto& op = testModel.main.operands[testModel.main.outputIndexes[i]];
if (op.data.size() == 0) {
outputBuffers.emplace_back(0, nullptr);
} else {
SCOPED_TRACE("Output index = " + std::to_string(i));
const uint32_t bufferIndex = outputLoc.poolIndex - kDeviceMemoryBeginIndex;
TestBuffer buffer;
getBuffer(mBuffers[bufferIndex], op.data.size(), &buffer);
outputBuffers.push_back(std::move(buffer));
}
}
}
return outputBuffers;
}
// Get a TestBuffer with data copied from an IBuffer object.
void ExecutionContext::getBuffer(const std::shared_ptr<IBuffer>& buffer, size_t size,
TestBuffer* testBuffer) const {
// IBuffer -> Shared memory.
auto sharedMemory = nn::createSharedMemory(size).value();
auto aidlMemory = utils::convert(sharedMemory).value();
const auto ret = buffer->copyTo(aidlMemory);
ASSERT_TRUE(ret.isOk());
// Shared memory -> TestBuffer.
const auto outputMemory = nn::map(sharedMemory).value();
const uint8_t* outputPtr = std::visit(
[](auto* ptr) { return static_cast<const uint8_t*>(ptr); }, outputMemory.pointer);
ASSERT_NE(outputPtr, nullptr);
ASSERT_NE(testBuffer, nullptr);
*testBuffer = TestBuffer(size, outputPtr);
}
static bool hasZeroSizedOutput(const TestModel& testModel) {
return std::any_of(testModel.main.outputIndexes.begin(), testModel.main.outputIndexes.end(),
[&testModel](uint32_t index) {
return testModel.main.operands[index].data.size() == 0;
});
}
void EvaluatePreparedModel(const std::shared_ptr<IDevice>& device,
const std::shared_ptr<IPreparedModel>& preparedModel,
const TestModel& testModel, const TestConfig& testConfig,
bool* skipped = nullptr) {
if (skipped != nullptr) {
*skipped = false;
}
// If output0 does not have size larger than one byte, we can not test with insufficient buffer.
if (testConfig.outputType == OutputType::INSUFFICIENT &&
!isOutputSizeGreaterThanOne(testModel, 0)) {
return;
}
ExecutionContext context(device, preparedModel);
auto maybeRequest = context.createRequest(testModel, testConfig.memoryType);
// Skip if testing memory domain but no device memory has been allocated.
if (!maybeRequest.has_value()) {
return;
}
Request request = std::move(maybeRequest).value();
constexpr uint32_t kInsufficientOutputIndex = 0;
if (testConfig.outputType == OutputType::INSUFFICIENT) {
makeOutputInsufficientSize(kInsufficientOutputIndex, &request);
}
int64_t loopTimeoutDuration = kOmittedTimeoutDuration;
// OutputType::MISSED_DEADLINE is only used by
// TestKind::INTINITE_LOOP_TIMEOUT tests to verify that an infinite loop is
// aborted after a timeout.
if (testConfig.outputType == OutputType::MISSED_DEADLINE) {
// Override the default loop timeout duration with a small value to
// speed up test execution.
constexpr int64_t kMillisecond = 1'000'000;
loopTimeoutDuration = 1 * kMillisecond;
}
ErrorStatus executionStatus;
std::vector<OutputShape> outputShapes;
Timing timing = kNoTiming;
switch (testConfig.executor) {
case Executor::SYNC: {
SCOPED_TRACE("synchronous");
ExecutionResult executionResult;
// execute
const auto ret = preparedModel->executeSynchronously(request, testConfig.measureTiming,
kNoDeadline, loopTimeoutDuration,
&executionResult);
ASSERT_TRUE(ret.isOk() || ret.getExceptionCode() == EX_SERVICE_SPECIFIC)
<< ret.getDescription();
if (ret.isOk()) {
executionStatus = executionResult.outputSufficientSize
? ErrorStatus::NONE
: ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
outputShapes = std::move(executionResult.outputShapes);
timing = executionResult.timing;
} else {
executionStatus = static_cast<ErrorStatus>(ret.getServiceSpecificError());
}
break;
}
case Executor::FENCED: {
SCOPED_TRACE("fenced");
ErrorStatus result = ErrorStatus::NONE;
ndk::ScopedFileDescriptor syncFenceFd;
std::shared_ptr<IFencedExecutionCallback> fencedCallback;
auto ret = preparedModel->executeFenced(request, {}, testConfig.measureTiming,
kNoDeadline, loopTimeoutDuration, kNoDuration,
&syncFenceFd, &fencedCallback);
ASSERT_TRUE(ret.isOk() || ret.getExceptionCode() == EX_SERVICE_SPECIFIC)
<< ret.getDescription();
if (!ret.isOk()) {
result = static_cast<ErrorStatus>(ret.getServiceSpecificError());
executionStatus = result;
} else if (syncFenceFd.get() != -1) {
std::vector<ndk::ScopedFileDescriptor> waitFor;
auto dupFd = dup(syncFenceFd.get());
ASSERT_NE(dupFd, -1);
waitFor.emplace_back(dupFd);
// If a sync fence is returned, try start another run waiting for the sync fence.
ret = preparedModel->executeFenced(request, waitFor, testConfig.measureTiming,
kNoDeadline, loopTimeoutDuration, kNoDuration,
&syncFenceFd, &fencedCallback);
ASSERT_TRUE(ret.isOk());
waitForSyncFence(syncFenceFd.get());
}
if (result == ErrorStatus::NONE) {
ASSERT_NE(fencedCallback, nullptr);
Timing timingFenced;
auto ret =
fencedCallback->getExecutionInfo(&timing, &timingFenced, &executionStatus);
ASSERT_TRUE(ret.isOk());
}
break;
}
default: {
FAIL() << "Unsupported execution mode for AIDL interface.";
}
}
if (testConfig.outputType != OutputType::FULLY_SPECIFIED &&
executionStatus == ErrorStatus::GENERAL_FAILURE) {
if (skipped != nullptr) {
*skipped = true;
}
if (!testConfig.reportSkipping) {
return;
}
LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
"execute model that it does not support.";
std::cout << "[ ] Early termination of test because vendor service cannot "
"execute model that it does not support."
<< std::endl;
GTEST_SKIP();
}
if (!testConfig.measureTiming) {
EXPECT_EQ(timing, kNoTiming);
} else {
if (timing.timeOnDevice != -1 && timing.timeInDriver != -1) {
EXPECT_LE(timing.timeOnDevice, timing.timeInDriver);
}
}
switch (testConfig.outputType) {
case OutputType::FULLY_SPECIFIED:
if (testConfig.executor == Executor::FENCED && hasZeroSizedOutput(testModel)) {
// Executor::FENCED does not support zero-sized output.
ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, executionStatus);
return;
}
// If the model output operands are fully specified, outputShapes must be either
// either empty, or have the same number of elements as the number of outputs.
ASSERT_EQ(ErrorStatus::NONE, executionStatus);
ASSERT_TRUE(outputShapes.size() == 0 ||
outputShapes.size() == testModel.main.outputIndexes.size());
break;
case OutputType::UNSPECIFIED:
if (testConfig.executor == Executor::FENCED) {
// For Executor::FENCED, the output shape must be fully specified.
ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, executionStatus);
return;
}
// If the model output operands are not fully specified, outputShapes must have
// the same number of elements as the number of outputs.
ASSERT_EQ(ErrorStatus::NONE, executionStatus);
ASSERT_EQ(outputShapes.size(), testModel.main.outputIndexes.size());
break;
case OutputType::INSUFFICIENT:
if (testConfig.executor == Executor::FENCED) {
// For Executor::FENCED, the output shape must be fully specified.
ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, executionStatus);
return;
}
ASSERT_EQ(ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, executionStatus);
ASSERT_EQ(outputShapes.size(), testModel.main.outputIndexes.size());
// Check that all returned output dimensions are at least as fully specified as the
// union of the information about the corresponding operand in the model and in the
// request. In this test, all model outputs have known rank with all dimensions
// unspecified, and no dimensional information is provided in the request.
for (uint32_t i = 0; i < outputShapes.size(); i++) {
ASSERT_EQ(outputShapes[i].isSufficient, i != kInsufficientOutputIndex);
const auto& actual = outputShapes[i].dimensions;
const auto& golden =
testModel.main.operands[testModel.main.outputIndexes[i]].dimensions;
ASSERT_EQ(actual.size(), golden.size());
for (uint32_t j = 0; j < actual.size(); j++) {
if (actual[j] == 0) continue;
EXPECT_EQ(actual[j], golden[j]) << "index: " << j;
}
}
return;
case OutputType::MISSED_DEADLINE:
ASSERT_TRUE(executionStatus == ErrorStatus::MISSED_DEADLINE_TRANSIENT ||
executionStatus == ErrorStatus::MISSED_DEADLINE_PERSISTENT)
<< "executionStatus = " << executionStatus;
return;
}
// Go through all outputs, check returned output shapes.
for (uint32_t i = 0; i < outputShapes.size(); i++) {
EXPECT_TRUE(outputShapes[i].isSufficient);
const auto& expect = testModel.main.operands[testModel.main.outputIndexes[i]].dimensions;
const auto unsignedActual = nn::toUnsigned(outputShapes[i].dimensions);
ASSERT_TRUE(unsignedActual.has_value());
const std::vector<uint32_t>& actual = unsignedActual.value();
EXPECT_EQ(expect, actual);
}
// Retrieve execution results.
const std::vector<TestBuffer> outputs = context.getOutputBuffers(testModel, request);
// We want "close-enough" results.
checkResults(testModel, outputs);
}
void EvaluatePreparedModel(const std::shared_ptr<IDevice>& device,
const std::shared_ptr<IPreparedModel>& preparedModel,
const TestModel& testModel, TestKind testKind) {
std::vector<OutputType> outputTypesList;
std::vector<bool> measureTimingList;
std::vector<Executor> executorList;
std::vector<MemoryType> memoryTypeList;
switch (testKind) {
case TestKind::GENERAL: {
outputTypesList = {OutputType::FULLY_SPECIFIED};
measureTimingList = {false, true};
executorList = {Executor::SYNC};
memoryTypeList = {MemoryType::ASHMEM};
} break;
case TestKind::DYNAMIC_SHAPE: {
outputTypesList = {OutputType::UNSPECIFIED, OutputType::INSUFFICIENT};
measureTimingList = {false, true};
executorList = {Executor::SYNC, Executor::FENCED};
memoryTypeList = {MemoryType::ASHMEM};
} break;
case TestKind::MEMORY_DOMAIN: {
outputTypesList = {OutputType::FULLY_SPECIFIED};
measureTimingList = {false};
executorList = {Executor::SYNC, Executor::FENCED};
memoryTypeList = {MemoryType::BLOB_AHWB, MemoryType::DEVICE};
} break;
case TestKind::FENCED_COMPUTE: {
outputTypesList = {OutputType::FULLY_SPECIFIED};
measureTimingList = {false, true};
executorList = {Executor::FENCED};
memoryTypeList = {MemoryType::ASHMEM};
} break;
case TestKind::QUANTIZATION_COUPLING: {
LOG(FATAL) << "Wrong TestKind for EvaluatePreparedModel";
return;
} break;
case TestKind::INTINITE_LOOP_TIMEOUT: {
outputTypesList = {OutputType::MISSED_DEADLINE};
measureTimingList = {false, true};
executorList = {Executor::SYNC, Executor::FENCED};
memoryTypeList = {MemoryType::ASHMEM};
} break;
}
for (const OutputType outputType : outputTypesList) {
for (const bool measureTiming : measureTimingList) {
for (const Executor executor : executorList) {
for (const MemoryType memoryType : memoryTypeList) {
const TestConfig testConfig(executor, measureTiming, outputType, memoryType);
EvaluatePreparedModel(device, preparedModel, testModel, testConfig);
}
}
}
}
}
void EvaluatePreparedCoupledModels(const std::shared_ptr<IDevice>& device,
const std::shared_ptr<IPreparedModel>& preparedModel,
const TestModel& testModel,
const std::shared_ptr<IPreparedModel>& preparedCoupledModel,
const TestModel& coupledModel) {
const std::vector<OutputType> outputTypesList = {OutputType::FULLY_SPECIFIED};
const std::vector<bool> measureTimingList = {false, true};
const std::vector<Executor> executorList = {Executor::SYNC, Executor::FENCED};
for (const OutputType outputType : outputTypesList) {
for (const bool measureTiming : measureTimingList) {
for (const Executor executor : executorList) {
const TestConfig testConfig(executor, measureTiming, outputType, MemoryType::ASHMEM,
/*reportSkipping=*/false);
bool baseSkipped = false;
EvaluatePreparedModel(device, preparedModel, testModel, testConfig, &baseSkipped);
bool coupledSkipped = false;
EvaluatePreparedModel(device, preparedCoupledModel, coupledModel, testConfig,
&coupledSkipped);
ASSERT_EQ(baseSkipped, coupledSkipped);
if (baseSkipped) {
LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
"execute model that it does not support.";
std::cout << "[ ] Early termination of test because vendor service "
"cannot "
"execute model that it does not support."
<< std::endl;
GTEST_SKIP();
}
}
}
}
}
void Execute(const std::shared_ptr<IDevice>& device, const TestModel& testModel,
TestKind testKind) {
Model model = createModel(testModel);
if (testKind == TestKind::DYNAMIC_SHAPE) {
makeOutputDimensionsUnspecified(&model);
}
std::shared_ptr<IPreparedModel> preparedModel;
switch (testKind) {
case TestKind::GENERAL:
case TestKind::DYNAMIC_SHAPE:
case TestKind::MEMORY_DOMAIN:
case TestKind::FENCED_COMPUTE:
case TestKind::INTINITE_LOOP_TIMEOUT: {
createPreparedModel(device, model, &preparedModel);
if (preparedModel == nullptr) return;
EvaluatePreparedModel(device, preparedModel, testModel, testKind);
} break;
case TestKind::QUANTIZATION_COUPLING: {
ASSERT_TRUE(testModel.hasQuant8CoupledOperands());
createPreparedModel(device, model, &preparedModel,
/*reportSkipping*/ false);
TestModel signedQuantizedModel = convertQuant8AsymmOperandsToSigned(testModel);
std::shared_ptr<IPreparedModel> preparedCoupledModel;
createPreparedModel(device, createModel(signedQuantizedModel), &preparedCoupledModel,
/*reportSkipping*/ false);
// If we couldn't prepare a model with unsigned quantization, we must
// fail to prepare a model with signed quantization as well.
if (preparedModel == nullptr) {
ASSERT_EQ(preparedCoupledModel, nullptr);
// If we failed to prepare both of the models, we can safely skip
// the test.
LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
"prepare model that it does not support.";
std::cout
<< "[ ] Early termination of test because vendor service cannot "
"prepare model that it does not support."
<< std::endl;
GTEST_SKIP();
}
ASSERT_NE(preparedCoupledModel, nullptr);
EvaluatePreparedCoupledModels(device, preparedModel, testModel, preparedCoupledModel,
signedQuantizedModel);
} break;
}
}
void GeneratedTestBase::SetUp() {
testing::TestWithParam<GeneratedTestParam>::SetUp();
ASSERT_NE(kDevice, nullptr);
}
std::vector<NamedModel> getNamedModels(const FilterFn& filter) {
return TestModelManager::get().getTestModels(filter);
}
std::vector<NamedModel> getNamedModels(const FilterNameFn& filter) {
return TestModelManager::get().getTestModels(filter);
}
std::string printGeneratedTest(const testing::TestParamInfo<GeneratedTestParam>& info) {
const auto& [namedDevice, namedModel] = info.param;
return gtestCompliantName(getName(namedDevice) + "_" + getName(namedModel));
}
// Tag for the generated tests
class GeneratedTest : public GeneratedTestBase {};
// Tag for the dynamic output shape tests
class DynamicOutputShapeTest : public GeneratedTest {};
// Tag for the memory domain tests
class MemoryDomainTest : public GeneratedTest {};
// Tag for the fenced compute tests
class FencedComputeTest : public GeneratedTest {};
// Tag for the dynamic output shape tests
class QuantizationCouplingTest : public GeneratedTest {};
// Tag for the loop timeout tests
class InfiniteLoopTimeoutTest : public GeneratedTest {};
TEST_P(GeneratedTest, Test) {
Execute(kDevice, kTestModel, TestKind::GENERAL);
}
TEST_P(DynamicOutputShapeTest, Test) {
Execute(kDevice, kTestModel, TestKind::DYNAMIC_SHAPE);
}
TEST_P(MemoryDomainTest, Test) {
Execute(kDevice, kTestModel, TestKind::MEMORY_DOMAIN);
}
TEST_P(FencedComputeTest, Test) {
Execute(kDevice, kTestModel, TestKind::FENCED_COMPUTE);
}
TEST_P(QuantizationCouplingTest, Test) {
Execute(kDevice, kTestModel, TestKind::QUANTIZATION_COUPLING);
}
TEST_P(InfiniteLoopTimeoutTest, Test) {
Execute(kDevice, kTestModel, TestKind::INTINITE_LOOP_TIMEOUT);
}
INSTANTIATE_GENERATED_TEST(GeneratedTest,
[](const TestModel& testModel) { return !testModel.expectFailure; });
INSTANTIATE_GENERATED_TEST(DynamicOutputShapeTest, [](const TestModel& testModel) {
return !testModel.expectFailure && !testModel.hasScalarOutputs();
});
INSTANTIATE_GENERATED_TEST(MemoryDomainTest,
[](const TestModel& testModel) { return !testModel.expectFailure; });
INSTANTIATE_GENERATED_TEST(FencedComputeTest,
[](const TestModel& testModel) { return !testModel.expectFailure; });
INSTANTIATE_GENERATED_TEST(QuantizationCouplingTest, [](const TestModel& testModel) {
return !testModel.expectFailure && testModel.hasQuant8CoupledOperands() &&
testModel.main.operations.size() == 1;
});
INSTANTIATE_GENERATED_TEST(InfiniteLoopTimeoutTest, [](const TestModel& testModel) {
return testModel.isInfiniteLoopTimeoutTest();
});
} // namespace aidl::android::hardware::neuralnetworks::vts::functional

Some files were not shown because too many files have changed in this diff Show More